Author: marcel
Date: Wed Oct 1 21:03:17 2014
New Revision: 272384
URL: https://svnweb.freebsd.org/changeset/base/272384
Log:
Improve performance of mking(1) by keeping a list of chunks in memory,
that keeps track of a particular region of the image. In particular the
image_data() function needs to return to the caller whether a region
contains data or is all zeroes. This required reading the region from
the temporary file and comparing the bytes. When image_data() is used
multiple times for the same region, this will get painful fast.
With a chunk describing a region of the image, we now also have a way
to refer to the image provided on the command line. This means we don't
need to copy the image into a temporary file. We just keep track of the
file descriptor and offset within the source file on a per-chunk basis.
For streams (pipes, sockets, fifos, etc) we now use the temporary file
as a swap file. We read from the input file and create a chunk of type
zeroes for each sequence of zeroes that's a multiple of the sector
size. Otherwise, we allocte from the swap file, mmap(2) it, read into
the mmap(2)'d memory and create a chunk representing data.
For regular files, we use SEEK_HOLE and SEEK_DATA to handle sparse files
eficiently and create a chunk of type zeroes for holes and a chunk of
type data for data regions. For data regions, we still compare the bytes
we read to handle differences between a file system's block size and our
sector size.
After reading all files, image_write() is used by schemes to scribble in
the reserved sectors. Since this never amounts to much, keep this data
in memory in chunks of exactly 1 sector.
The output image is created by looking using the chunk list to find the
data and write it out to the output file. For chunks of type zeroes
we prefer to seek, but fall back to writing zeroes to handle pipes.
For chunks of type file and memoty we simply write.
The net effect of this is that for reasonably large images the execution
time drops from 1-2 minutes to 10-20 seconds. A typical speedup is about
5 to 8 times, depending on partition sizes, output format whether in
input files are sparse or not.
Bump version to 20141001.
Modified:
head/usr.bin/mkimg/Makefile
head/usr.bin/mkimg/image.c
Directory Properties:
head/usr.bin/mkimg/ (props changed)
Modified: head/usr.bin/mkimg/Makefile
==
--- head/usr.bin/mkimg/Makefile Wed Oct 1 20:52:08 2014(r272383)
+++ head/usr.bin/mkimg/Makefile Wed Oct 1 21:03:17 2014(r272384)
@@ -6,7 +6,7 @@ PROG= mkimg
SRCS= format.c image.c mkimg.c scheme.c
MAN= mkimg.1
-MKIMG_VERSION=20140927
+MKIMG_VERSION=20141001
CFLAGS+=-DMKIMG_VERSION=${MKIMG_VERSION}
CFLAGS+=-DSPARSE_WRITE
Modified: head/usr.bin/mkimg/image.c
==
--- head/usr.bin/mkimg/image.c Wed Oct 1 20:52:08 2014(r272383)
+++ head/usr.bin/mkimg/image.c Wed Oct 1 21:03:17 2014(r272384)
@@ -27,71 +27,462 @@
#include sys/cdefs.h
__FBSDID($FreeBSD$);
+#include sys/mman.h
+#include sys/queue.h
+#include sys/stat.h
#include sys/types.h
#include assert.h
#include errno.h
#include limits.h
#include paths.h
+#include stdint.h
#include stdio.h
#include stdlib.h
+#include string.h
#include unistd.h
#include image.h
#include mkimg.h
-#defineBUFFER_SIZE (1024*1024)
+struct chunk {
+ STAILQ_ENTRY(chunk) ch_list;
+ size_t ch_size;/* Size of chunk in bytes. */
+ lba_t ch_block; /* Block address in image. */
+ union {
+ struct {
+ off_t ofs;/* Offset in backing file. */
+ int fd; /* FD of backing file. */
+ } file;
+ struct {
+ void*ptr; /* Pointer to data in memory */
+ } mem;
+ } ch_u;
+ u_int ch_type;
+#defineCH_TYPE_ZEROES 0 /* Chunk is a gap (no data). */
+#defineCH_TYPE_FILE1 /* File-backed chunk. */
+#defineCH_TYPE_MEMORY 2 /* Memory-backed chunk */
+};
+
+static STAILQ_HEAD(chunk_head, chunk) image_chunks;
+static u_int image_nchunks;
+
+static char image_swap_file[PATH_MAX];
+static int image_swap_fd = -1;
+static u_int image_swap_pgsz;
+static off_t image_swap_size;
-static char image_tmpfile[PATH_MAX];
-static int image_fd = -1;
static lba_t image_size;
-static void
-cleanup(void)
+static int
+is_empty_sector(void *buf)
{
+ uint64_t *p = buf;
+ size_t n, max;
+
+ assert(((uintptr_t)p 3) == 0);
- if (image_fd != -1)
- close(image_fd);
- unlink(image_tmpfile);
+ max = secsz / sizeof(uint64_t);
+ for (n = 0; n max; n++) {
+ if