Skip site navigation (1)Skip section navigation (2)
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>