git: a2fda816eb05 - main - virstor: write large maps in chunks during label
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 11 Jun 2024 00:42:05 UTC
The branch main has been updated by rlibby:
URL: https://cgit.FreeBSD.org/src/commit/?id=a2fda816eb054d5873be223ef2461741dfcc253c
commit a2fda816eb054d5873be223ef2461741dfcc253c
Author: Ryan Libby <rlibby@FreeBSD.org>
AuthorDate: 2024-06-11 00:36:20 +0000
Commit: Ryan Libby <rlibby@FreeBSD.org>
CommitDate: 2024-06-11 00:36:20 +0000
virstor: write large maps in chunks during label
During the initial label of a virstor device, write out the allocation
map in chunks if it is large (> 1 MB) in order to avoid large mallocs.
Even though the kernel virstor geom may still do a large malloc to
represent the allocation map, this may still be useful to avoid a
ulimit.
Reviewed by: markj
Sponsored by: Dell EMC Isilon
Differential Revision: https://reviews.freebsd.org/D45517
---
lib/geom/virstor/geom_virstor.c | 59 ++++++++++++++++++++++++++++++-----------
1 file changed, 43 insertions(+), 16 deletions(-)
diff --git a/lib/geom/virstor/geom_virstor.c b/lib/geom/virstor/geom_virstor.c
index 131ece0107c7..6a7dfb27fe43 100644
--- a/lib/geom/virstor/geom_virstor.c
+++ b/lib/geom/virstor/geom_virstor.c
@@ -157,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;
@@ -325,28 +324,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)