From owner-svn-src-stable-10@FreeBSD.ORG Wed Oct 8 22:01:37 2014 Return-Path: Delivered-To: svn-src-stable-10@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 168DD570; Wed, 8 Oct 2014 22:01:37 +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 021223D7; Wed, 8 Oct 2014 22:01:37 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s98M1aiZ040775; Wed, 8 Oct 2014 22:01:36 GMT (envelope-from marcel@FreeBSD.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s98M1a80040773; Wed, 8 Oct 2014 22:01:36 GMT (envelope-from marcel@FreeBSD.org) Message-Id: <201410082201.s98M1a80040773@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: marcel set sender to marcel@FreeBSD.org using -f From: Marcel Moolenaar Date: Wed, 8 Oct 2014 22:01:36 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r272773 - stable/10/usr.bin/mkimg X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Oct 2014 22:01:37 -0000 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