qcow.c revision 272773
1271965Smarcel/*- 2271965Smarcel * Copyright (c) 2014 Marcel Moolenaar 3271965Smarcel * All rights reserved. 4271965Smarcel * 5271965Smarcel * Redistribution and use in source and binary forms, with or without 6271965Smarcel * modification, are permitted provided that the following conditions 7271965Smarcel * are met: 8271965Smarcel * 1. Redistributions of source code must retain the above copyright 9271965Smarcel * notice, this list of conditions and the following disclaimer. 10271965Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11271965Smarcel * notice, this list of conditions and the following disclaimer in the 12271965Smarcel * documentation and/or other materials provided with the distribution. 13271965Smarcel * 14271965Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15271965Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16271965Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17271965Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18271965Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19271965Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20271965Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21271965Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22271965Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23271965Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24271965Smarcel * SUCH DAMAGE. 25271965Smarcel */ 26271965Smarcel 27271965Smarcel#include <sys/cdefs.h> 28271965Smarcel__FBSDID("$FreeBSD: stable/10/usr.bin/mkimg/qcow.c 272773 2014-10-08 22:01:35Z marcel $"); 29271965Smarcel 30271965Smarcel#include <sys/types.h> 31271965Smarcel#include <sys/endian.h> 32271965Smarcel#include <sys/errno.h> 33271965Smarcel#include <stdint.h> 34271965Smarcel#include <stdio.h> 35271965Smarcel#include <stdlib.h> 36271965Smarcel#include <string.h> 37271965Smarcel#include <unistd.h> 38271965Smarcel 39271965Smarcel#include "image.h" 40271965Smarcel#include "format.h" 41271965Smarcel#include "mkimg.h" 42271965Smarcel 43271965Smarcel/* Default cluster sizes. */ 44271965Smarcel#define QCOW1_CLSTR_LOG2SZ 12 /* 4KB */ 45271965Smarcel#define QCOW2_CLSTR_LOG2SZ 16 /* 64KB */ 46271965Smarcel 47272773Smarcel/* Flag bits in cluster offsets */ 48272773Smarcel#define QCOW_CLSTR_COMPRESSED (1ULL << 62) 49272773Smarcel#define QCOW_CLSTR_COPIED (1ULL << 63) 50272773Smarcel 51271965Smarcelstruct qcow_header { 52271965Smarcel uint32_t magic; 53271965Smarcel#define QCOW_MAGIC 0x514649fb 54271965Smarcel uint32_t version; 55271965Smarcel#define QCOW_VERSION_1 1 56271965Smarcel#define QCOW_VERSION_2 2 57271965Smarcel uint64_t path_offset; 58271965Smarcel uint32_t path_length; 59271965Smarcel uint32_t clstr_log2sz; /* v2 only */ 60271965Smarcel uint64_t disk_size; 61271965Smarcel union { 62271965Smarcel struct { 63271965Smarcel uint8_t clstr_log2sz; 64271965Smarcel uint8_t l2_log2sz; 65271965Smarcel uint16_t _pad; 66271965Smarcel uint32_t encryption; 67271965Smarcel uint64_t l1_offset; 68271965Smarcel } v1; 69271965Smarcel struct { 70271965Smarcel uint32_t encryption; 71271965Smarcel uint32_t l1_entries; 72271965Smarcel uint64_t l1_offset; 73271965Smarcel uint64_t refcnt_offset; 74271965Smarcel uint32_t refcnt_entries; 75271965Smarcel uint32_t snapshot_count; 76271965Smarcel uint64_t snapshot_offset; 77271965Smarcel } v2; 78271965Smarcel } u; 79271965Smarcel}; 80271965Smarcel 81271965Smarcelstatic u_int clstr_log2sz; 82271965Smarcel 83271965Smarcelstatic uint64_t 84271965Smarcelround_clstr(uint64_t ofs) 85271965Smarcel{ 86271965Smarcel uint64_t clstrsz; 87271965Smarcel 88271965Smarcel clstrsz = 1UL << clstr_log2sz; 89271965Smarcel return ((ofs + clstrsz - 1) & ~(clstrsz - 1)); 90271965Smarcel} 91271965Smarcel 92271965Smarcelstatic int 93271965Smarcelqcow_resize(lba_t imgsz, u_int version) 94271965Smarcel{ 95272773Smarcel uint64_t imagesz; 96271965Smarcel 97271965Smarcel switch (version) { 98271965Smarcel case QCOW_VERSION_1: 99271965Smarcel clstr_log2sz = QCOW1_CLSTR_LOG2SZ; 100271965Smarcel break; 101271965Smarcel case QCOW_VERSION_2: 102271965Smarcel clstr_log2sz = QCOW2_CLSTR_LOG2SZ; 103271965Smarcel break; 104271965Smarcel default: 105271965Smarcel return (EDOOFUS); 106271965Smarcel } 107271965Smarcel 108271965Smarcel imagesz = round_clstr(imgsz * secsz); 109271965Smarcel 110271965Smarcel if (verbose) 111272773Smarcel fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n", 112272773Smarcel (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz)); 113271965Smarcel 114271965Smarcel return (image_set_size(imagesz / secsz)); 115271965Smarcel} 116271965Smarcel 117271965Smarcelstatic int 118271965Smarcelqcow1_resize(lba_t imgsz) 119271965Smarcel{ 120271965Smarcel 121271965Smarcel return (qcow_resize(imgsz, QCOW_VERSION_1)); 122271965Smarcel} 123271965Smarcel 124271965Smarcelstatic int 125271965Smarcelqcow2_resize(lba_t imgsz) 126271965Smarcel{ 127271965Smarcel 128271965Smarcel return (qcow_resize(imgsz, QCOW_VERSION_2)); 129271965Smarcel} 130271965Smarcel 131271965Smarcelstatic int 132271965Smarcelqcow_write(int fd, u_int version) 133271965Smarcel{ 134271965Smarcel struct qcow_header *hdr; 135272773Smarcel uint64_t *l1tbl, *l2tbl, *rctbl; 136272773Smarcel uint16_t *rcblk; 137272773Smarcel uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz; 138272773Smarcel uint64_t clstr_rcblks, clstr_rctblsz; 139272773Smarcel uint64_t n, imagesz, nclstrs, ofs, ofsflags; 140272773Smarcel lba_t blk, blkofs, blk_imgsz; 141272773Smarcel u_int l1clno, l2clno, rcclno; 142272773Smarcel u_int blk_clstrsz; 143272773Smarcel u_int clstrsz, l1idx, l2idx; 144271965Smarcel int error; 145271965Smarcel 146271965Smarcel if (clstr_log2sz == 0) 147271965Smarcel return (EDOOFUS); 148271965Smarcel 149272773Smarcel clstrsz = 1U << clstr_log2sz; 150272773Smarcel blk_clstrsz = clstrsz / secsz; 151272773Smarcel blk_imgsz = image_get_size(); 152272773Smarcel imagesz = blk_imgsz * secsz; 153272773Smarcel clstr_imgsz = imagesz >> clstr_log2sz; 154272773Smarcel clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz; 155272773Smarcel clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz; 156272773Smarcel nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1; 157272773Smarcel clstr_rcblks = clstr_rctblsz = 0; 158272773Smarcel do { 159272773Smarcel n = clstr_rcblks + clstr_rctblsz; 160272773Smarcel clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz; 161272773Smarcel clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz; 162272773Smarcel } while (n < (clstr_rcblks + clstr_rctblsz)); 163271965Smarcel 164272773Smarcel /* 165272773Smarcel * We got all the sizes in clusters. Start the layout. 166272773Smarcel * 0 - header 167272773Smarcel * 1 - L1 table 168272773Smarcel * 2 - RC table (v2 only) 169272773Smarcel * 3 - L2 tables 170272773Smarcel * 4 - RC block (v2 only) 171272773Smarcel * 5 - data 172272773Smarcel */ 173271965Smarcel 174272773Smarcel l1clno = 1; 175272773Smarcel rcclno = 0; 176272773Smarcel rctbl = l2tbl = l1tbl = NULL; 177272773Smarcel rcblk = NULL; 178272773Smarcel 179271965Smarcel hdr = calloc(1, clstrsz); 180271965Smarcel if (hdr == NULL) 181271965Smarcel return (errno); 182271965Smarcel 183271965Smarcel be32enc(&hdr->magic, QCOW_MAGIC); 184271965Smarcel be32enc(&hdr->version, version); 185271965Smarcel be64enc(&hdr->disk_size, imagesz); 186271965Smarcel switch (version) { 187271965Smarcel case QCOW_VERSION_1: 188272773Smarcel ofsflags = 0; 189272773Smarcel l2clno = l1clno + clstr_l1tblsz; 190271965Smarcel hdr->u.v1.clstr_log2sz = clstr_log2sz; 191271965Smarcel hdr->u.v1.l2_log2sz = clstr_log2sz - 3; 192272773Smarcel be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno); 193271965Smarcel break; 194271965Smarcel case QCOW_VERSION_2: 195272773Smarcel ofsflags = QCOW_CLSTR_COPIED; 196272773Smarcel rcclno = l1clno + clstr_l1tblsz; 197272773Smarcel l2clno = rcclno + clstr_rctblsz; 198271965Smarcel be32enc(&hdr->clstr_log2sz, clstr_log2sz); 199272773Smarcel be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls); 200272773Smarcel be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno); 201272773Smarcel be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno); 202272773Smarcel be32enc(&hdr->u.v2.refcnt_entries, clstr_rcblks); 203271965Smarcel break; 204271965Smarcel default: 205271965Smarcel return (EDOOFUS); 206271965Smarcel } 207271965Smarcel 208272773Smarcel if (sparse_write(fd, hdr, clstrsz) < 0) { 209272773Smarcel error = errno; 210272773Smarcel goto out; 211272773Smarcel } 212271965Smarcel 213272773Smarcel free(hdr); 214272773Smarcel hdr = NULL; 215272773Smarcel 216272773Smarcel ofs = clstrsz * l2clno; 217272773Smarcel nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz; 218272773Smarcel 219272773Smarcel l1tbl = calloc(1, clstrsz * clstr_l1tblsz); 220271965Smarcel if (l1tbl == NULL) { 221271965Smarcel error = ENOMEM; 222271965Smarcel goto out; 223271965Smarcel } 224271965Smarcel 225272773Smarcel for (n = 0; n < clstr_imgsz; n++) { 226272773Smarcel blk = n * blk_clstrsz; 227272773Smarcel if (image_data(blk, blk_clstrsz)) { 228272773Smarcel nclstrs++; 229272773Smarcel l1idx = n >> (clstr_log2sz - 3); 230272773Smarcel if (l1tbl[l1idx] == 0) { 231272773Smarcel be64enc(l1tbl + l1idx, ofs + ofsflags); 232272773Smarcel ofs += clstrsz; 233272773Smarcel nclstrs++; 234272773Smarcel } 235271965Smarcel } 236271965Smarcel } 237271965Smarcel 238272773Smarcel if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) { 239271965Smarcel error = errno; 240271965Smarcel goto out; 241272773Smarcel } 242271965Smarcel 243272773Smarcel clstr_rcblks = 0; 244272773Smarcel do { 245272773Smarcel n = clstr_rcblks; 246272773Smarcel clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz; 247272773Smarcel } while (n < clstr_rcblks); 248272773Smarcel 249272773Smarcel if (rcclno > 0) { 250272773Smarcel rctbl = calloc(1, clstrsz * clstr_rctblsz); 251272773Smarcel if (rctbl == NULL) { 252272773Smarcel error = ENOMEM; 253272773Smarcel goto out; 254272773Smarcel } 255272773Smarcel for (n = 0; n < clstr_rcblks; n++) { 256272773Smarcel be64enc(rctbl + n, ofs); 257272773Smarcel ofs += clstrsz; 258272773Smarcel nclstrs++; 259272773Smarcel } 260272773Smarcel if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) { 261272773Smarcel error = errno; 262272773Smarcel goto out; 263272773Smarcel } 264271965Smarcel free(rctbl); 265271965Smarcel rctbl = NULL; 266271965Smarcel } 267271965Smarcel 268271965Smarcel l2tbl = malloc(clstrsz); 269271965Smarcel if (l2tbl == NULL) { 270271965Smarcel error = ENOMEM; 271271965Smarcel goto out; 272271965Smarcel } 273271965Smarcel 274272773Smarcel for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) { 275271965Smarcel if (l1tbl[l1idx] == 0) 276271965Smarcel continue; 277271965Smarcel memset(l2tbl, 0, clstrsz); 278272773Smarcel blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3); 279271965Smarcel for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) { 280272773Smarcel blk = blkofs + (lba_t)l2idx * blk_clstrsz; 281272773Smarcel if (blk >= blk_imgsz) 282271965Smarcel break; 283272773Smarcel if (image_data(blk, blk_clstrsz)) { 284272773Smarcel be64enc(l2tbl + l2idx, ofs + ofsflags); 285271965Smarcel ofs += clstrsz; 286271965Smarcel } 287271965Smarcel } 288271965Smarcel if (sparse_write(fd, l2tbl, clstrsz) < 0) { 289271965Smarcel error = errno; 290271965Smarcel goto out; 291271965Smarcel } 292271965Smarcel } 293271965Smarcel 294271965Smarcel free(l2tbl); 295271965Smarcel l2tbl = NULL; 296271965Smarcel free(l1tbl); 297271965Smarcel l1tbl = NULL; 298271965Smarcel 299272773Smarcel if (rcclno > 0) { 300272773Smarcel rcblk = calloc(1, clstrsz * clstr_rcblks); 301272773Smarcel if (rcblk == NULL) { 302272773Smarcel error = ENOMEM; 303272773Smarcel goto out; 304272773Smarcel } 305272773Smarcel for (n = 0; n < nclstrs; n++) 306272773Smarcel be16enc(rcblk + n, 1); 307272773Smarcel if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) { 308272773Smarcel error = errno; 309272773Smarcel goto out; 310272773Smarcel } 311272773Smarcel free(rcblk); 312272773Smarcel rcblk = NULL; 313272773Smarcel } 314272773Smarcel 315271965Smarcel error = 0; 316272773Smarcel for (n = 0; n < clstr_imgsz; n++) { 317272773Smarcel blk = n * blk_clstrsz; 318272773Smarcel if (image_data(blk, blk_clstrsz)) { 319272773Smarcel error = image_copyout_region(fd, blk, blk_clstrsz); 320271965Smarcel if (error) 321271965Smarcel break; 322271965Smarcel } 323271965Smarcel } 324271965Smarcel if (!error) 325271965Smarcel error = image_copyout_done(fd); 326271965Smarcel 327271965Smarcel out: 328272773Smarcel if (rcblk != NULL) 329272773Smarcel free(rcblk); 330271965Smarcel if (l2tbl != NULL) 331271965Smarcel free(l2tbl); 332271965Smarcel if (rctbl != NULL) 333271965Smarcel free(rctbl); 334271965Smarcel if (l1tbl != NULL) 335271965Smarcel free(l1tbl); 336271965Smarcel if (hdr != NULL) 337271965Smarcel free(hdr); 338271965Smarcel return (error); 339271965Smarcel} 340271965Smarcel 341271965Smarcelstatic int 342271965Smarcelqcow1_write(int fd) 343271965Smarcel{ 344271965Smarcel 345271965Smarcel return (qcow_write(fd, QCOW_VERSION_1)); 346271965Smarcel} 347271965Smarcel 348271965Smarcelstatic int 349271965Smarcelqcow2_write(int fd) 350271965Smarcel{ 351271965Smarcel 352271965Smarcel return (qcow_write(fd, QCOW_VERSION_2)); 353271965Smarcel} 354271965Smarcel 355271965Smarcelstatic struct mkimg_format qcow1_format = { 356271965Smarcel .name = "qcow", 357271965Smarcel .description = "QEMU Copy-On-Write, version 1", 358271965Smarcel .resize = qcow1_resize, 359271965Smarcel .write = qcow1_write, 360271965Smarcel}; 361271965SmarcelFORMAT_DEFINE(qcow1_format); 362271965Smarcel 363271965Smarcelstatic struct mkimg_format qcow2_format = { 364271965Smarcel .name = "qcow2", 365271965Smarcel .description = "QEMU Copy-On-Write, version 2", 366271965Smarcel .resize = qcow2_resize, 367271965Smarcel .write = qcow2_write, 368271965Smarcel}; 369271965SmarcelFORMAT_DEFINE(qcow2_format); 370