svn commit: r272773 - stable/10/usr.bin/mkimg
Marcel Moolenaar
marcel at FreeBSD.org
Wed Oct 8 22:01:37 UTC 2014
Author: marcel
Date: Wed Oct 8 22:01:35 2014
New Revision: 272773
URL: https://svnweb.freebsd.org/changeset/base/272773
Log:
MFC 271965, 272072, 272086: Add QCOW v1 & v2 support
Requested by: gjb
Relnotes: yes
Added:
stable/10/usr.bin/mkimg/qcow.c
- copied, changed from r271965, head/usr.bin/mkimg/qcow.c
Modified:
stable/10/usr.bin/mkimg/Makefile
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/usr.bin/mkimg/Makefile
==============================================================================
--- stable/10/usr.bin/mkimg/Makefile Wed Oct 8 21:56:00 2014 (r272772)
+++ stable/10/usr.bin/mkimg/Makefile Wed Oct 8 22:01:35 2014 (r272773)
@@ -8,6 +8,7 @@ CFLAGS+=-DSPARSE_WRITE
# List of formats to support
SRCS+= \
+ qcow.c \
raw.c \
vhd.c \
vmdk.c
Copied and modified: stable/10/usr.bin/mkimg/qcow.c (from r271965, head/usr.bin/mkimg/qcow.c)
==============================================================================
--- head/usr.bin/mkimg/qcow.c Mon Sep 22 15:05:28 2014 (r271965, copy source)
+++ stable/10/usr.bin/mkimg/qcow.c Wed Oct 8 22:01:35 2014 (r272773)
@@ -40,12 +40,14 @@ __FBSDID("$FreeBSD$");
#include "format.h"
#include "mkimg.h"
-#undef QCOW_SUPPORT_QCOW2
-
/* Default cluster sizes. */
#define QCOW1_CLSTR_LOG2SZ 12 /* 4KB */
#define QCOW2_CLSTR_LOG2SZ 16 /* 64KB */
+/* Flag bits in cluster offsets */
+#define QCOW_CLSTR_COMPRESSED (1ULL << 62)
+#define QCOW_CLSTR_COPIED (1ULL << 63)
+
struct qcow_header {
uint32_t magic;
#define QCOW_MAGIC 0x514649fb
@@ -90,7 +92,7 @@ round_clstr(uint64_t ofs)
static int
qcow_resize(lba_t imgsz, u_int version)
{
- uint64_t clstrsz, imagesz;
+ uint64_t imagesz;
switch (version) {
case QCOW_VERSION_1:
@@ -103,12 +105,11 @@ qcow_resize(lba_t imgsz, u_int version)
return (EDOOFUS);
}
- clstrsz = 1UL << clstr_log2sz;
imagesz = round_clstr(imgsz * secsz);
if (verbose)
- fprintf(stderr, "QCOW: image size = %ju, cluster size = %ju\n",
- (uintmax_t)imagesz, (uintmax_t)clstrsz);
+ fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n",
+ (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz));
return (image_set_size(imagesz / secsz));
}
@@ -120,39 +121,60 @@ qcow1_resize(lba_t imgsz)
return (qcow_resize(imgsz, QCOW_VERSION_1));
}
-#ifdef QCOW_SUPPORT_QCOW2
static int
qcow2_resize(lba_t imgsz)
{
return (qcow_resize(imgsz, QCOW_VERSION_2));
}
-#endif
static int
qcow_write(int fd, u_int version)
{
struct qcow_header *hdr;
- uint64_t *l1tbl, *l2tbl;
- uint16_t *rctbl;
- uint64_t n, clstrsz, imagesz, nclstrs;
- uint64_t l1ofs, l2ofs, ofs, rcofs;
- lba_t blk, blkofs, blkcnt, imgsz;
- u_int l1idx, l2idx, l2clstrs;
+ uint64_t *l1tbl, *l2tbl, *rctbl;
+ uint16_t *rcblk;
+ uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz;
+ uint64_t clstr_rcblks, clstr_rctblsz;
+ uint64_t n, imagesz, nclstrs, ofs, ofsflags;
+ lba_t blk, blkofs, blk_imgsz;
+ u_int l1clno, l2clno, rcclno;
+ u_int blk_clstrsz;
+ u_int clstrsz, l1idx, l2idx;
int error;
if (clstr_log2sz == 0)
return (EDOOFUS);
- clstrsz = 1UL << clstr_log2sz;
- blkcnt = clstrsz / secsz;
- imgsz = image_get_size();
- imagesz = imgsz * secsz;
- nclstrs = imagesz >> clstr_log2sz;
- l2clstrs = (nclstrs * 8 + clstrsz - 1) > clstr_log2sz;
-
- l1ofs = clstrsz;
- rcofs = round_clstr(l1ofs + l2clstrs * 8);
+ clstrsz = 1U << clstr_log2sz;
+ blk_clstrsz = clstrsz / secsz;
+ blk_imgsz = image_get_size();
+ imagesz = blk_imgsz * secsz;
+ clstr_imgsz = imagesz >> clstr_log2sz;
+ clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz;
+ clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz;
+ nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1;
+ clstr_rcblks = clstr_rctblsz = 0;
+ do {
+ n = clstr_rcblks + clstr_rctblsz;
+ clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
+ clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
+ } while (n < (clstr_rcblks + clstr_rctblsz));
+
+ /*
+ * We got all the sizes in clusters. Start the layout.
+ * 0 - header
+ * 1 - L1 table
+ * 2 - RC table (v2 only)
+ * 3 - L2 tables
+ * 4 - RC block (v2 only)
+ * 5 - data
+ */
+
+ l1clno = 1;
+ rcclno = 0;
+ rctbl = l2tbl = l1tbl = NULL;
+ rcblk = NULL;
hdr = calloc(1, clstrsz);
if (hdr == NULL)
@@ -163,63 +185,82 @@ qcow_write(int fd, u_int version)
be64enc(&hdr->disk_size, imagesz);
switch (version) {
case QCOW_VERSION_1:
- l2ofs = rcofs; /* No reference counting. */
+ ofsflags = 0;
+ l2clno = l1clno + clstr_l1tblsz;
hdr->u.v1.clstr_log2sz = clstr_log2sz;
hdr->u.v1.l2_log2sz = clstr_log2sz - 3;
- be64enc(&hdr->u.v1.l1_offset, l1ofs);
+ be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno);
break;
case QCOW_VERSION_2:
- l2ofs = round_clstr(rcofs + (nclstrs + l2clstrs) * 2);
+ ofsflags = QCOW_CLSTR_COPIED;
+ rcclno = l1clno + clstr_l1tblsz;
+ l2clno = rcclno + clstr_rctblsz;
be32enc(&hdr->clstr_log2sz, clstr_log2sz);
- be32enc(&hdr->u.v2.l1_entries, l2clstrs);
- be64enc(&hdr->u.v2.l1_offset, l1ofs);
- be64enc(&hdr->u.v2.refcnt_offset, rcofs);
- be32enc(&hdr->u.v2.refcnt_entries, l2clstrs);
+ be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls);
+ be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno);
+ be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno);
+ be32enc(&hdr->u.v2.refcnt_entries, clstr_rcblks);
break;
default:
return (EDOOFUS);
}
- l2tbl = l1tbl = NULL;
- rctbl = NULL;
+ if (sparse_write(fd, hdr, clstrsz) < 0) {
+ error = errno;
+ goto out;
+ }
+
+ free(hdr);
+ hdr = NULL;
+
+ ofs = clstrsz * l2clno;
+ nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz;
- l1tbl = calloc(1, (size_t)(rcofs - l1ofs));
+ l1tbl = calloc(1, clstrsz * clstr_l1tblsz);
if (l1tbl == NULL) {
error = ENOMEM;
goto out;
}
- if (l2ofs != rcofs) {
- rctbl = calloc(1, (size_t)(l2ofs - rcofs));
- if (rctbl == NULL) {
- error = ENOMEM;
- goto out;
- }
- }
- ofs = l2ofs;
- for (n = 0; n < nclstrs; n++) {
- l1idx = n >> (clstr_log2sz - 3);
- if (l1tbl[l1idx] != 0UL)
- continue;
- blk = n * blkcnt;
- if (image_data(blk, blkcnt)) {
- be64enc(l1tbl + l1idx, ofs);
- ofs += clstrsz;
+ for (n = 0; n < clstr_imgsz; n++) {
+ blk = n * blk_clstrsz;
+ if (image_data(blk, blk_clstrsz)) {
+ nclstrs++;
+ l1idx = n >> (clstr_log2sz - 3);
+ if (l1tbl[l1idx] == 0) {
+ be64enc(l1tbl + l1idx, ofs + ofsflags);
+ ofs += clstrsz;
+ nclstrs++;
+ }
}
}
- error = 0;
- if (!error && sparse_write(fd, hdr, clstrsz) < 0)
- error = errno;
- if (!error && sparse_write(fd, l1tbl, (size_t)(rcofs - l1ofs)) < 0)
+ if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) {
error = errno;
- /* XXX refcnt table. */
- if (error)
goto out;
+ }
- free(hdr);
- hdr = NULL;
- if (rctbl != NULL) {
+ clstr_rcblks = 0;
+ do {
+ n = clstr_rcblks;
+ clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
+ } while (n < clstr_rcblks);
+
+ if (rcclno > 0) {
+ rctbl = calloc(1, clstrsz * clstr_rctblsz);
+ if (rctbl == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ for (n = 0; n < clstr_rcblks; n++) {
+ be64enc(rctbl + n, ofs);
+ ofs += clstrsz;
+ nclstrs++;
+ }
+ if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) {
+ error = errno;
+ goto out;
+ }
free(rctbl);
rctbl = NULL;
}
@@ -230,17 +271,17 @@ qcow_write(int fd, u_int version)
goto out;
}
- for (l1idx = 0; l1idx < l2clstrs; l1idx++) {
+ for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) {
if (l1tbl[l1idx] == 0)
continue;
memset(l2tbl, 0, clstrsz);
- blkofs = (lba_t)l1idx * (clstrsz * (clstrsz >> 3));
+ blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3);
for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) {
- blk = blkofs + (lba_t)l2idx * blkcnt;
- if (blk >= imgsz)
+ blk = blkofs + (lba_t)l2idx * blk_clstrsz;
+ if (blk >= blk_imgsz)
break;
- if (image_data(blk, blkcnt)) {
- be64enc(l2tbl + l2idx, ofs);
+ if (image_data(blk, blk_clstrsz)) {
+ be64enc(l2tbl + l2idx, ofs + ofsflags);
ofs += clstrsz;
}
}
@@ -255,11 +296,27 @@ qcow_write(int fd, u_int version)
free(l1tbl);
l1tbl = NULL;
+ if (rcclno > 0) {
+ rcblk = calloc(1, clstrsz * clstr_rcblks);
+ if (rcblk == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ for (n = 0; n < nclstrs; n++)
+ be16enc(rcblk + n, 1);
+ if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) {
+ error = errno;
+ goto out;
+ }
+ free(rcblk);
+ rcblk = NULL;
+ }
+
error = 0;
- for (n = 0; n < nclstrs; n++) {
- blk = n * blkcnt;
- if (image_data(blk, blkcnt)) {
- error = image_copyout_region(fd, blk, blkcnt);
+ for (n = 0; n < clstr_imgsz; n++) {
+ blk = n * blk_clstrsz;
+ if (image_data(blk, blk_clstrsz)) {
+ error = image_copyout_region(fd, blk, blk_clstrsz);
if (error)
break;
}
@@ -268,6 +325,8 @@ qcow_write(int fd, u_int version)
error = image_copyout_done(fd);
out:
+ if (rcblk != NULL)
+ free(rcblk);
if (l2tbl != NULL)
free(l2tbl);
if (rctbl != NULL)
@@ -286,14 +345,12 @@ qcow1_write(int fd)
return (qcow_write(fd, QCOW_VERSION_1));
}
-#ifdef QCOW_SUPPORT_QCOW2
static int
qcow2_write(int fd)
{
return (qcow_write(fd, QCOW_VERSION_2));
}
-#endif
static struct mkimg_format qcow1_format = {
.name = "qcow",
@@ -303,7 +360,6 @@ static struct mkimg_format qcow1_format
};
FORMAT_DEFINE(qcow1_format);
-#ifdef QCOW_SUPPORT_QCOW2
static struct mkimg_format qcow2_format = {
.name = "qcow2",
.description = "QEMU Copy-On-Write, version 2",
@@ -311,4 +367,3 @@ static struct mkimg_format qcow2_format
.write = qcow2_write,
};
FORMAT_DEFINE(qcow2_format);
-#endif
More information about the svn-src-stable
mailing list