From owner-svn-src-user@FreeBSD.ORG Tue Sep 30 23:16:03 2014 Return-Path: <owner-svn-src-user@FreeBSD.ORG> Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id CEB03803; Tue, 30 Sep 2014 23:16:03 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id AF90625A; Tue, 30 Sep 2014 23:16:03 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s8UNG3Bp082312; Tue, 30 Sep 2014 23:16:03 GMT (envelope-from marcel@FreeBSD.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s8UNG3rb082311; Tue, 30 Sep 2014 23:16:03 GMT (envelope-from marcel@FreeBSD.org) Message-Id: <201409302316.s8UNG3rb082311@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: marcel set sender to marcel@FreeBSD.org using -f From: Marcel Moolenaar <marcel@FreeBSD.org> Date: Tue, 30 Sep 2014 23:16:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r272335 - user/marcel/mkimg X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" <svn-src-user.freebsd.org> List-Unsubscribe: <http://lists.freebsd.org/mailman/options/svn-src-user>, <mailto:svn-src-user-request@freebsd.org?subject=unsubscribe> List-Archive: <http://lists.freebsd.org/pipermail/svn-src-user/> List-Post: <mailto:svn-src-user@freebsd.org> List-Help: <mailto:svn-src-user-request@freebsd.org?subject=help> List-Subscribe: <http://lists.freebsd.org/mailman/listinfo/svn-src-user>, <mailto:svn-src-user-request@freebsd.org?subject=subscribe> X-List-Received-Date: Tue, 30 Sep 2014 23:16:03 -0000 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); }