qcow.c revision 271965
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: head/usr.bin/mkimg/qcow.c 271965 2014-09-22 15:05:28Z 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#undef QCOW_SUPPORT_QCOW2 44271965Smarcel 45271965Smarcel/* Default cluster sizes. */ 46271965Smarcel#define QCOW1_CLSTR_LOG2SZ 12 /* 4KB */ 47271965Smarcel#define QCOW2_CLSTR_LOG2SZ 16 /* 64KB */ 48271965Smarcel 49271965Smarcelstruct qcow_header { 50271965Smarcel uint32_t magic; 51271965Smarcel#define QCOW_MAGIC 0x514649fb 52271965Smarcel uint32_t version; 53271965Smarcel#define QCOW_VERSION_1 1 54271965Smarcel#define QCOW_VERSION_2 2 55271965Smarcel uint64_t path_offset; 56271965Smarcel uint32_t path_length; 57271965Smarcel uint32_t clstr_log2sz; /* v2 only */ 58271965Smarcel uint64_t disk_size; 59271965Smarcel union { 60271965Smarcel struct { 61271965Smarcel uint8_t clstr_log2sz; 62271965Smarcel uint8_t l2_log2sz; 63271965Smarcel uint16_t _pad; 64271965Smarcel uint32_t encryption; 65271965Smarcel uint64_t l1_offset; 66271965Smarcel } v1; 67271965Smarcel struct { 68271965Smarcel uint32_t encryption; 69271965Smarcel uint32_t l1_entries; 70271965Smarcel uint64_t l1_offset; 71271965Smarcel uint64_t refcnt_offset; 72271965Smarcel uint32_t refcnt_entries; 73271965Smarcel uint32_t snapshot_count; 74271965Smarcel uint64_t snapshot_offset; 75271965Smarcel } v2; 76271965Smarcel } u; 77271965Smarcel}; 78271965Smarcel 79271965Smarcelstatic u_int clstr_log2sz; 80271965Smarcel 81271965Smarcelstatic uint64_t 82271965Smarcelround_clstr(uint64_t ofs) 83271965Smarcel{ 84271965Smarcel uint64_t clstrsz; 85271965Smarcel 86271965Smarcel clstrsz = 1UL << clstr_log2sz; 87271965Smarcel return ((ofs + clstrsz - 1) & ~(clstrsz - 1)); 88271965Smarcel} 89271965Smarcel 90271965Smarcelstatic int 91271965Smarcelqcow_resize(lba_t imgsz, u_int version) 92271965Smarcel{ 93271965Smarcel uint64_t clstrsz, imagesz; 94271965Smarcel 95271965Smarcel switch (version) { 96271965Smarcel case QCOW_VERSION_1: 97271965Smarcel clstr_log2sz = QCOW1_CLSTR_LOG2SZ; 98271965Smarcel break; 99271965Smarcel case QCOW_VERSION_2: 100271965Smarcel clstr_log2sz = QCOW2_CLSTR_LOG2SZ; 101271965Smarcel break; 102271965Smarcel default: 103271965Smarcel return (EDOOFUS); 104271965Smarcel } 105271965Smarcel 106271965Smarcel clstrsz = 1UL << clstr_log2sz; 107271965Smarcel imagesz = round_clstr(imgsz * secsz); 108271965Smarcel 109271965Smarcel if (verbose) 110271965Smarcel fprintf(stderr, "QCOW: image size = %ju, cluster size = %ju\n", 111271965Smarcel (uintmax_t)imagesz, (uintmax_t)clstrsz); 112271965Smarcel 113271965Smarcel return (image_set_size(imagesz / secsz)); 114271965Smarcel} 115271965Smarcel 116271965Smarcelstatic int 117271965Smarcelqcow1_resize(lba_t imgsz) 118271965Smarcel{ 119271965Smarcel 120271965Smarcel return (qcow_resize(imgsz, QCOW_VERSION_1)); 121271965Smarcel} 122271965Smarcel 123271965Smarcel#ifdef QCOW_SUPPORT_QCOW2 124271965Smarcelstatic int 125271965Smarcelqcow2_resize(lba_t imgsz) 126271965Smarcel{ 127271965Smarcel 128271965Smarcel return (qcow_resize(imgsz, QCOW_VERSION_2)); 129271965Smarcel} 130271965Smarcel#endif 131271965Smarcel 132271965Smarcelstatic int 133271965Smarcelqcow_write(int fd, u_int version) 134271965Smarcel{ 135271965Smarcel struct qcow_header *hdr; 136271965Smarcel uint64_t *l1tbl, *l2tbl; 137271965Smarcel uint16_t *rctbl; 138271965Smarcel uint64_t n, clstrsz, imagesz, nclstrs; 139271965Smarcel uint64_t l1ofs, l2ofs, ofs, rcofs; 140271965Smarcel lba_t blk, blkofs, blkcnt, imgsz; 141271965Smarcel u_int l1idx, l2idx, l2clstrs; 142271965Smarcel int error; 143271965Smarcel 144271965Smarcel if (clstr_log2sz == 0) 145271965Smarcel return (EDOOFUS); 146271965Smarcel 147271965Smarcel clstrsz = 1UL << clstr_log2sz; 148271965Smarcel blkcnt = clstrsz / secsz; 149271965Smarcel imgsz = image_get_size(); 150271965Smarcel imagesz = imgsz * secsz; 151271965Smarcel nclstrs = imagesz >> clstr_log2sz; 152271965Smarcel l2clstrs = (nclstrs * 8 + clstrsz - 1) > clstr_log2sz; 153271965Smarcel 154271965Smarcel l1ofs = clstrsz; 155271965Smarcel rcofs = round_clstr(l1ofs + l2clstrs * 8); 156271965Smarcel 157271965Smarcel hdr = calloc(1, clstrsz); 158271965Smarcel if (hdr == NULL) 159271965Smarcel return (errno); 160271965Smarcel 161271965Smarcel be32enc(&hdr->magic, QCOW_MAGIC); 162271965Smarcel be32enc(&hdr->version, version); 163271965Smarcel be64enc(&hdr->disk_size, imagesz); 164271965Smarcel switch (version) { 165271965Smarcel case QCOW_VERSION_1: 166271965Smarcel l2ofs = rcofs; /* No reference counting. */ 167271965Smarcel hdr->u.v1.clstr_log2sz = clstr_log2sz; 168271965Smarcel hdr->u.v1.l2_log2sz = clstr_log2sz - 3; 169271965Smarcel be64enc(&hdr->u.v1.l1_offset, l1ofs); 170271965Smarcel break; 171271965Smarcel case QCOW_VERSION_2: 172271965Smarcel l2ofs = round_clstr(rcofs + (nclstrs + l2clstrs) * 2); 173271965Smarcel be32enc(&hdr->clstr_log2sz, clstr_log2sz); 174271965Smarcel be32enc(&hdr->u.v2.l1_entries, l2clstrs); 175271965Smarcel be64enc(&hdr->u.v2.l1_offset, l1ofs); 176271965Smarcel be64enc(&hdr->u.v2.refcnt_offset, rcofs); 177271965Smarcel be32enc(&hdr->u.v2.refcnt_entries, l2clstrs); 178271965Smarcel break; 179271965Smarcel default: 180271965Smarcel return (EDOOFUS); 181271965Smarcel } 182271965Smarcel 183271965Smarcel l2tbl = l1tbl = NULL; 184271965Smarcel rctbl = NULL; 185271965Smarcel 186271965Smarcel l1tbl = calloc(1, (size_t)(rcofs - l1ofs)); 187271965Smarcel if (l1tbl == NULL) { 188271965Smarcel error = ENOMEM; 189271965Smarcel goto out; 190271965Smarcel } 191271965Smarcel if (l2ofs != rcofs) { 192271965Smarcel rctbl = calloc(1, (size_t)(l2ofs - rcofs)); 193271965Smarcel if (rctbl == NULL) { 194271965Smarcel error = ENOMEM; 195271965Smarcel goto out; 196271965Smarcel } 197271965Smarcel } 198271965Smarcel 199271965Smarcel ofs = l2ofs; 200271965Smarcel for (n = 0; n < nclstrs; n++) { 201271965Smarcel l1idx = n >> (clstr_log2sz - 3); 202271965Smarcel if (l1tbl[l1idx] != 0UL) 203271965Smarcel continue; 204271965Smarcel blk = n * blkcnt; 205271965Smarcel if (image_data(blk, blkcnt)) { 206271965Smarcel be64enc(l1tbl + l1idx, ofs); 207271965Smarcel ofs += clstrsz; 208271965Smarcel } 209271965Smarcel } 210271965Smarcel 211271965Smarcel error = 0; 212271965Smarcel if (!error && sparse_write(fd, hdr, clstrsz) < 0) 213271965Smarcel error = errno; 214271965Smarcel if (!error && sparse_write(fd, l1tbl, (size_t)(rcofs - l1ofs)) < 0) 215271965Smarcel error = errno; 216271965Smarcel /* XXX refcnt table. */ 217271965Smarcel if (error) 218271965Smarcel goto out; 219271965Smarcel 220271965Smarcel free(hdr); 221271965Smarcel hdr = NULL; 222271965Smarcel if (rctbl != NULL) { 223271965Smarcel free(rctbl); 224271965Smarcel rctbl = NULL; 225271965Smarcel } 226271965Smarcel 227271965Smarcel l2tbl = malloc(clstrsz); 228271965Smarcel if (l2tbl == NULL) { 229271965Smarcel error = ENOMEM; 230271965Smarcel goto out; 231271965Smarcel } 232271965Smarcel 233271965Smarcel for (l1idx = 0; l1idx < l2clstrs; l1idx++) { 234271965Smarcel if (l1tbl[l1idx] == 0) 235271965Smarcel continue; 236271965Smarcel memset(l2tbl, 0, clstrsz); 237271965Smarcel blkofs = (lba_t)l1idx * (clstrsz * (clstrsz >> 3)); 238271965Smarcel for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) { 239271965Smarcel blk = blkofs + (lba_t)l2idx * blkcnt; 240271965Smarcel if (blk >= imgsz) 241271965Smarcel break; 242271965Smarcel if (image_data(blk, blkcnt)) { 243271965Smarcel be64enc(l2tbl + l2idx, ofs); 244271965Smarcel ofs += clstrsz; 245271965Smarcel } 246271965Smarcel } 247271965Smarcel if (sparse_write(fd, l2tbl, clstrsz) < 0) { 248271965Smarcel error = errno; 249271965Smarcel goto out; 250271965Smarcel } 251271965Smarcel } 252271965Smarcel 253271965Smarcel free(l2tbl); 254271965Smarcel l2tbl = NULL; 255271965Smarcel free(l1tbl); 256271965Smarcel l1tbl = NULL; 257271965Smarcel 258271965Smarcel error = 0; 259271965Smarcel for (n = 0; n < nclstrs; n++) { 260271965Smarcel blk = n * blkcnt; 261271965Smarcel if (image_data(blk, blkcnt)) { 262271965Smarcel error = image_copyout_region(fd, blk, blkcnt); 263271965Smarcel if (error) 264271965Smarcel break; 265271965Smarcel } 266271965Smarcel } 267271965Smarcel if (!error) 268271965Smarcel error = image_copyout_done(fd); 269271965Smarcel 270271965Smarcel out: 271271965Smarcel if (l2tbl != NULL) 272271965Smarcel free(l2tbl); 273271965Smarcel if (rctbl != NULL) 274271965Smarcel free(rctbl); 275271965Smarcel if (l1tbl != NULL) 276271965Smarcel free(l1tbl); 277271965Smarcel if (hdr != NULL) 278271965Smarcel free(hdr); 279271965Smarcel return (error); 280271965Smarcel} 281271965Smarcel 282271965Smarcelstatic int 283271965Smarcelqcow1_write(int fd) 284271965Smarcel{ 285271965Smarcel 286271965Smarcel return (qcow_write(fd, QCOW_VERSION_1)); 287271965Smarcel} 288271965Smarcel 289271965Smarcel#ifdef QCOW_SUPPORT_QCOW2 290271965Smarcelstatic int 291271965Smarcelqcow2_write(int fd) 292271965Smarcel{ 293271965Smarcel 294271965Smarcel return (qcow_write(fd, QCOW_VERSION_2)); 295271965Smarcel} 296271965Smarcel#endif 297271965Smarcel 298271965Smarcelstatic struct mkimg_format qcow1_format = { 299271965Smarcel .name = "qcow", 300271965Smarcel .description = "QEMU Copy-On-Write, version 1", 301271965Smarcel .resize = qcow1_resize, 302271965Smarcel .write = qcow1_write, 303271965Smarcel}; 304271965SmarcelFORMAT_DEFINE(qcow1_format); 305271965Smarcel 306271965Smarcel#ifdef QCOW_SUPPORT_QCOW2 307271965Smarcelstatic struct mkimg_format qcow2_format = { 308271965Smarcel .name = "qcow2", 309271965Smarcel .description = "QEMU Copy-On-Write, version 2", 310271965Smarcel .resize = qcow2_resize, 311271965Smarcel .write = qcow2_write, 312271965Smarcel}; 313271965SmarcelFORMAT_DEFINE(qcow2_format); 314271965Smarcel#endif 315