Date: Tue, 30 Sep 2014 23:16:03 +0000 (UTC) From: Marcel Moolenaar <marcel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r272335 - user/marcel/mkimg Message-ID: <201409302316.s8UNG3rb082311@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: marcel Date: Tue Sep 30 23:16:03 2014 New Revision: 272335 URL: http://svnweb.freebsd.org/changeset/base/272335 Log: Implement image_write(): For every sector in the buffer, find the chunk that contains it and break it up (if it's not already a memory chunk) so that we have have a new chunk for every sector being written. We don't write to chunks for type file, because we may not be able to write and we don't want to clobber partition data. We don't try to combine adjacent chunks of type memory into a single one. It doesn't seem to have any significant upsides other than reducing syscall overhead. The downsides includes "excessive" copying and memory fragmantation. Without any kind of benchmarking, simplicity wins. Modified: user/marcel/mkimg/image.c Modified: user/marcel/mkimg/image.c ============================================================================== --- user/marcel/mkimg/image.c Tue Sep 30 23:01:11 2014 (r272334) +++ user/marcel/mkimg/image.c Tue Sep 30 23:16:03 2014 (r272335) @@ -73,6 +73,22 @@ static off_t image_swap_size; static lba_t image_size; +static int +is_empty_sector(void *buf) +{ + uint64_t *p = buf; + size_t n, max; + + assert(((uintptr_t)p & 3) == 0); + + max = secsz / sizeof(uint64_t); + for (n = 0; n < max; n++) { + if (p[n] != 0UL) + return (0); + } + return (1); +} + /* * Swap file handlng. */ @@ -102,11 +118,11 @@ image_swap_alloc(size_t size) */ static void -image_chunk_dump(void) +image_chunk_dump(int count) { struct chunk *ch; - fprintf(stderr, "%u chunks:\n", image_nchunks); + fprintf(stderr, "Dump %d: %u chunks:\n", count, image_nchunks); STAILQ_FOREACH(ch, &image_chunks, ch_list) { fprintf(stderr, "\tblk=%jd, sz=%zu, type=%u", (intmax_t)ch->ch_block, ch->ch_size, ch->ch_type); @@ -127,6 +143,25 @@ image_chunk_dump(void) } } +static struct chunk * +image_chunk_find(lba_t blk) +{ + static struct chunk *last = NULL; + struct chunk *ch; + + ch = (last != NULL && last->ch_block <= blk) + ? last : STAILQ_FIRST(&image_chunks); + while (ch != NULL) { + if (ch->ch_block <= blk && + (lba_t)(ch->ch_block + (ch->ch_size / secsz)) > blk) { + last = ch; + break; + } + ch = STAILQ_NEXT(ch, ch_list); + } + return (ch); +} + static size_t image_chunk_grow(struct chunk *ch, size_t sz) { @@ -144,6 +179,50 @@ image_chunk_grow(struct chunk *ch, size_ return (sz - dsz); } +static struct chunk * +image_chunk_memory(struct chunk *ch, lba_t blk) +{ + struct chunk *new; + void *ptr; + + ptr = calloc(1, secsz); + if (ptr == NULL) + return (NULL); + + if (ch->ch_block < blk) { + new = malloc(sizeof(*new)); + if (new == NULL) { + free(ptr); + return (NULL); + } + memcpy(new, ch, sizeof(*new)); + ch->ch_size = (blk - ch->ch_block) * secsz; + new->ch_block = blk; + new->ch_size -= ch->ch_size; + STAILQ_INSERT_AFTER(&image_chunks, ch, new, ch_list); + image_nchunks++; + ch = new; + } + + if (ch->ch_size > secsz) { + new = malloc(sizeof(*new)); + if (new == NULL) { + free(ptr); + return (NULL); + } + memcpy(new, ch, sizeof(*new)); + ch->ch_size = secsz; + new->ch_block++; + new->ch_size -= secsz; + STAILQ_INSERT_AFTER(&image_chunks, ch, new, ch_list); + image_nchunks++; + } + + ch->ch_type = CH_TYPE_MEMORY; + ch->ch_u.mem.ptr = ptr; + return (ch); +} + static int image_chunk_skipto(lba_t to) { @@ -215,24 +294,18 @@ image_chunk_append(lba_t blk, size_t sz, static int image_chunk_copyin(lba_t blk, void *buf, size_t sz, off_t ofs, int fd) { - uint64_t *p = buf; - size_t n; + uint8_t *p = buf; int error; - assert(((uintptr_t)p & 3) == 0); - error = 0; sz = (sz + secsz - 1) & ~(secsz - 1); while (!error && sz > 0) { - n = 0; - while (n < (secsz >> 3) && p[n] == 0) - n++; - if (n == (secsz >> 3)) + if (is_empty_sector(p)) error = image_chunk_skipto(blk + 1); else error = image_chunk_append(blk, secsz, ofs, fd); blk++; - p += (secsz >> 3); + p += secsz; sz -= secsz; ofs += secsz; } @@ -522,12 +595,9 @@ image_data(lba_t blk, lba_t size) lba_t image_get_size(void) { - static int once = 0; + static int count = 0; - if (once == 0) { - once++; - image_chunk_dump(); - } + image_chunk_dump(count++); return (image_size); } @@ -545,13 +615,28 @@ image_set_size(lba_t blk) int image_write(lba_t blk, void *buf, ssize_t len) { + struct chunk *ch; - blk *= secsz; - if (lseek(image_swap_fd, blk, SEEK_SET) != blk) - return (errno); - len *= secsz; - if (sparse_write(image_swap_fd, buf, len) != len) - return (errno); + while (len > 0) { + if (!is_empty_sector(buf)) { + ch = image_chunk_find(blk); + if (ch == NULL) + return (ENXIO); + /* We may not be able to write to files. */ + if (ch->ch_type == CH_TYPE_FILE) + return (EINVAL); + if (ch->ch_type == CH_TYPE_ZEROES) { + ch = image_chunk_memory(ch, blk); + if (ch == NULL) + return (ENOMEM); + } + assert(ch->ch_type == CH_TYPE_MEMORY); + memcpy(ch->ch_u.mem.ptr, buf, secsz); + } + blk++; + buf = (char *)buf + secsz; + len--; + } return (0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409302316.s8UNG3rb082311>