aboutsummaryrefslogtreecommitdiff
path: root/lib/geom/virstor/geom_virstor.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/geom/virstor/geom_virstor.c')
-rw-r--r--lib/geom/virstor/geom_virstor.c104
1 files changed, 58 insertions, 46 deletions
diff --git a/lib/geom/virstor/geom_virstor.c b/lib/geom/virstor/geom_virstor.c
index bd8da7337a55..5f5087e99213 100644
--- a/lib/geom/virstor/geom_virstor.c
+++ b/lib/geom/virstor/geom_virstor.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Ivan Voras <ivoras@freebsd.org>
*
@@ -25,9 +25,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <errno.h>
#include <paths.h>
@@ -160,8 +157,7 @@ virstor_label(struct gctl_req *req)
char param[32];
int hardcode, nargs, error;
struct virstor_map_entry *map;
- size_t total_chunks; /* We'll run out of memory if
- this needs to be bigger. */
+ size_t total_chunks, write_max_map_entries;
unsigned int map_chunks; /* Chunks needed by the map (map size). */
size_t map_size; /* In bytes. */
ssize_t written;
@@ -199,27 +195,6 @@ virstor_label(struct gctl_req *req)
return;
}
- if (md.md_chunk_size % MAXPHYS != 0) {
- /* XXX: This is not strictly needed, but it's convenient to
- * impose some limitations on it, so why not MAXPHYS. */
- size_t new_size = rounddown(md.md_chunk_size, MAXPHYS);
- if (new_size < md.md_chunk_size)
- new_size += MAXPHYS;
- fprintf(stderr, "Resizing chunk size to be a multiple of "
- "MAXPHYS (%d kB).\n", MAXPHYS / 1024);
- fprintf(stderr, "New chunk size: %zu kB\n", new_size / 1024);
- md.md_chunk_size = new_size;
- }
-
- if (md.md_virsize % md.md_chunk_size != 0) {
- off_t chunk_count = md.md_virsize / md.md_chunk_size;
- md.md_virsize = chunk_count * md.md_chunk_size;
- fprintf(stderr, "Resizing virtual size to be a multiple of "
- "chunk size.\n");
- fprintf(stderr, "New virtual size: %zu MB\n",
- (size_t)(md.md_virsize/(1024 * 1024)));
- }
-
msize = secsize = 0;
for (i = 1; i < (unsigned)nargs; i++) {
snprintf(param, sizeof(param), "arg%u", i);
@@ -244,11 +219,20 @@ virstor_label(struct gctl_req *req)
}
if (md.md_chunk_size % secsize != 0) {
- fprintf(stderr, "Error: chunk size is not a multiple of sector "
- "size.");
- gctl_error(req, "Chunk size (in bytes) must be multiple of %u.",
- (unsigned int)secsize);
- return;
+ size_t new_size = roundup(md.md_chunk_size, secsize);
+ fprintf(stderr, "Resizing chunk size to be a multiple of "
+ "sector size (%zu bytes).\n", secsize);
+ fprintf(stderr, "New chunk size: %zu kB\n", new_size / 1024);
+ md.md_chunk_size = new_size;
+ }
+
+ if (md.md_virsize % md.md_chunk_size != 0) {
+ off_t chunk_count = md.md_virsize / md.md_chunk_size;
+ md.md_virsize = chunk_count * md.md_chunk_size;
+ fprintf(stderr, "Resizing virtual size to be a multiple of "
+ "chunk size.\n");
+ fprintf(stderr, "New virtual size: %zu MB\n",
+ (size_t)(md.md_virsize / (1024 * 1024)));
}
total_chunks = md.md_virsize / md.md_chunk_size;
@@ -328,28 +312,56 @@ virstor_label(struct gctl_req *req)
sprintf(param, "%s%s", _PATH_DEV, name);
fd = open(param, O_RDWR);
}
- if (fd < 0)
+ if (fd < 0) {
gctl_error(req, "Cannot open provider %s to write map", name);
+ return;
+ }
- /* Do it with calloc because there might be a need to set up chunk flags
- * in the future */
- map = calloc(total_chunks, sizeof(*map));
+ /*
+ * Initialize and write the map. Don't malloc the whole map at once,
+ * in case it's large. Use calloc because there might be a need to set
+ * up chunk flags in the future.
+ */
+ write_max_map_entries = 1024 * 1024 / sizeof(*map);
+ if (write_max_map_entries > total_chunks)
+ write_max_map_entries = total_chunks;
+ map = calloc(write_max_map_entries, sizeof(*map));
if (map == NULL) {
gctl_error(req,
"Out of memory (need %zu bytes for allocation map)",
- map_size);
+ write_max_map_entries * sizeof(*map));
+ close(fd);
+ return;
}
-
- written = pwrite(fd, map, map_size, 0);
- free(map);
- if ((size_t)written != map_size) {
- if (verbose) {
- fprintf(stderr, "\nTried to write %zu, written %zd (%s)\n",
- map_size, written, strerror(errno));
+ for (size_t chunk = 0; chunk < total_chunks;
+ chunk += write_max_map_entries) {
+ size_t bytes_to_write, entries_to_write;
+
+ entries_to_write = total_chunks - chunk;
+ if (entries_to_write > write_max_map_entries)
+ entries_to_write = write_max_map_entries;
+ bytes_to_write = entries_to_write * sizeof(*map);
+ for (size_t off = 0; off < bytes_to_write; off += written) {
+ written = write(fd, ((char *)map) + off,
+ bytes_to_write - off);
+ if (written < 0) {
+ if (verbose) {
+ fprintf(stderr,
+ "\nError writing map at offset "
+ "%zu of %zu: %s\n",
+ chunk * sizeof(*map) + off,
+ map_size, strerror(errno));
+ }
+ gctl_error(req,
+ "Error writing out allocation map!");
+ free(map);
+ close(fd);
+ return;
+ }
}
- gctl_error(req, "Error writing out allocation map!");
- return;
}
+ free(map);
+ map = NULL;
close (fd);
if (verbose)