1210284Sjmallett/*- 2215990Sjmallett * Copyright (c) 2014 Marcel Moolenaar 3215990Sjmallett * All rights reserved. 4210284Sjmallett * 5210284Sjmallett * Redistribution and use in source and binary forms, with or without 6215990Sjmallett * modification, are permitted provided that the following conditions 7215990Sjmallett * are met: 8215990Sjmallett * 1. Redistributions of source code must retain the above copyright 9210284Sjmallett * notice, this list of conditions and the following disclaimer. 10215990Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer in the 12210284Sjmallett * documentation and/or other materials provided with the distribution. 13215990Sjmallett * 14215990Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15215990Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16215990Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17215990Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18215990Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19215990Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20215990Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21215990Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22215990Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23215990Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24215990Sjmallett * SUCH DAMAGE. 25215990Sjmallett */ 26215990Sjmallett 27215990Sjmallett#include <sys/cdefs.h> 28215990Sjmallett#include <sys/errno.h> 29215990Sjmallett#include <assert.h> 30215990Sjmallett#include <stdio.h> 31215990Sjmallett#include <stdlib.h> 32215990Sjmallett#include <string.h> 33215990Sjmallett 34215990Sjmallett#include "endian.h" 35215990Sjmallett#include "image.h" 36215990Sjmallett#include "format.h" 37215990Sjmallett#include "mkimg.h" 38210284Sjmallett 39210284Sjmallett/* Default cluster sizes. */ 40210284Sjmallett#define QCOW1_CLSTR_LOG2SZ 12 /* 4KB */ 41210284Sjmallett#define QCOW2_CLSTR_LOG2SZ 16 /* 64KB */ 42210284Sjmallett 43210284Sjmallett/* Flag bits in cluster offsets */ 44210284Sjmallett#define QCOW_CLSTR_COMPRESSED (1ULL << 62) 45215990Sjmallett#define QCOW_CLSTR_COPIED (1ULL << 63) 46210284Sjmallett 47210284Sjmallettstruct qcow_header { 48210284Sjmallett uint32_t magic; 49210284Sjmallett#define QCOW_MAGIC 0x514649fb 50210284Sjmallett uint32_t version; 51210284Sjmallett#define QCOW_VERSION_1 1 52210284Sjmallett#define QCOW_VERSION_2 2 53210284Sjmallett uint64_t path_offset; 54215990Sjmallett uint32_t path_length; 55210284Sjmallett uint32_t clstr_log2sz; /* v2 only */ 56210284Sjmallett uint64_t disk_size; 57210284Sjmallett union { 58210284Sjmallett struct { 59210284Sjmallett uint8_t clstr_log2sz; 60210284Sjmallett uint8_t l2_log2sz; 61210284Sjmallett uint16_t _pad; 62210284Sjmallett uint32_t encryption; 63210284Sjmallett uint64_t l1_offset; 64210284Sjmallett } v1; 65210284Sjmallett struct { 66210284Sjmallett uint32_t encryption; 67210284Sjmallett uint32_t l1_entries; 68210284Sjmallett uint64_t l1_offset; 69210284Sjmallett uint64_t refcnt_offset; 70210284Sjmallett uint32_t refcnt_clstrs; 71210284Sjmallett uint32_t snapshot_count; 72210284Sjmallett uint64_t snapshot_offset; 73210284Sjmallett } v2; 74210284Sjmallett } u; 75210284Sjmallett}; 76210284Sjmallett 77210284Sjmallettstatic u_int clstr_log2sz; 78210284Sjmallett 79210284Sjmallettstatic uint64_t 80210284Sjmallettround_clstr(uint64_t ofs) 81210284Sjmallett{ 82210284Sjmallett uint64_t clstrsz; 83210284Sjmallett 84210284Sjmallett clstrsz = 1UL << clstr_log2sz; 85210284Sjmallett return ((ofs + clstrsz - 1) & ~(clstrsz - 1)); 86210284Sjmallett} 87210284Sjmallett 88210284Sjmallettstatic int 89210284Sjmallettqcow_resize(lba_t imgsz, u_int version) 90210284Sjmallett{ 91210284Sjmallett uint64_t imagesz; 92210284Sjmallett 93210284Sjmallett switch (version) { 94210284Sjmallett case QCOW_VERSION_1: 95210284Sjmallett clstr_log2sz = QCOW1_CLSTR_LOG2SZ; 96210284Sjmallett break; 97210284Sjmallett case QCOW_VERSION_2: 98 clstr_log2sz = QCOW2_CLSTR_LOG2SZ; 99 break; 100 default: 101 assert(0); 102 } 103 104 imagesz = round_clstr(imgsz * secsz); 105 106 if (verbose) 107 fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n", 108 (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz)); 109 110 return (image_set_size(imagesz / secsz)); 111} 112 113static int 114qcow1_resize(lba_t imgsz) 115{ 116 117 return (qcow_resize(imgsz, QCOW_VERSION_1)); 118} 119 120static int 121qcow2_resize(lba_t imgsz) 122{ 123 124 return (qcow_resize(imgsz, QCOW_VERSION_2)); 125} 126 127static int 128qcow_write(int fd, u_int version) 129{ 130 struct qcow_header *hdr; 131 uint64_t *l1tbl, *l2tbl, *rctbl; 132 uint16_t *rcblk; 133 uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz; 134 uint64_t clstr_rcblks, clstr_rctblsz; 135 uint64_t n, imagesz, nclstrs, ofs, ofsflags; 136 lba_t blk, blkofs, blk_imgsz; 137 u_int l1clno, l2clno, rcclno; 138 u_int blk_clstrsz, refcnt_clstrs; 139 u_int clstrsz, l1idx, l2idx; 140 int error; 141 142 assert(clstr_log2sz != 0); 143 144 clstrsz = 1U << clstr_log2sz; 145 blk_clstrsz = clstrsz / secsz; 146 blk_imgsz = image_get_size(); 147 imagesz = blk_imgsz * secsz; 148 clstr_imgsz = imagesz >> clstr_log2sz; 149 clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz; 150 clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz; 151 nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1; 152 clstr_rcblks = clstr_rctblsz = 0; 153 do { 154 n = clstr_rcblks + clstr_rctblsz; 155 clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz; 156 clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz; 157 } while (n < (clstr_rcblks + clstr_rctblsz)); 158 159 /* 160 * We got all the sizes in clusters. Start the layout. 161 * 0 - header 162 * 1 - L1 table 163 * 2 - RC table (v2 only) 164 * 3 - L2 tables 165 * 4 - RC block (v2 only) 166 * 5 - data 167 */ 168 169 l1clno = 1; 170 rcclno = 0; 171 rctbl = l2tbl = l1tbl = NULL; 172 rcblk = NULL; 173 174 hdr = calloc(1, clstrsz); 175 if (hdr == NULL) 176 return (errno); 177 178 be32enc(&hdr->magic, QCOW_MAGIC); 179 be32enc(&hdr->version, version); 180 be64enc(&hdr->disk_size, imagesz); 181 switch (version) { 182 case QCOW_VERSION_1: 183 ofsflags = 0; 184 l2clno = l1clno + clstr_l1tblsz; 185 hdr->u.v1.clstr_log2sz = clstr_log2sz; 186 hdr->u.v1.l2_log2sz = clstr_log2sz - 3; 187 be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno); 188 break; 189 case QCOW_VERSION_2: 190 ofsflags = QCOW_CLSTR_COPIED; 191 rcclno = l1clno + clstr_l1tblsz; 192 l2clno = rcclno + clstr_rctblsz; 193 be32enc(&hdr->clstr_log2sz, clstr_log2sz); 194 be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls); 195 be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno); 196 be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno); 197 refcnt_clstrs = round_clstr(clstr_rcblks * 8) >> clstr_log2sz; 198 be32enc(&hdr->u.v2.refcnt_clstrs, refcnt_clstrs); 199 break; 200 default: 201 assert(0); 202 } 203 204 if (sparse_write(fd, hdr, clstrsz) < 0) { 205 error = errno; 206 goto out; 207 } 208 209 free(hdr); 210 hdr = NULL; 211 212 ofs = clstrsz * l2clno; 213 nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz; 214 215 l1tbl = calloc(clstr_l1tblsz, clstrsz); 216 if (l1tbl == NULL) { 217 error = ENOMEM; 218 goto out; 219 } 220 221 for (n = 0; n < clstr_imgsz; n++) { 222 blk = n * blk_clstrsz; 223 if (image_data(blk, blk_clstrsz)) { 224 nclstrs++; 225 l1idx = n >> (clstr_log2sz - 3); 226 if (l1tbl[l1idx] == 0) { 227 be64enc(l1tbl + l1idx, ofs + ofsflags); 228 ofs += clstrsz; 229 nclstrs++; 230 } 231 } 232 } 233 234 if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) { 235 error = errno; 236 goto out; 237 } 238 239 clstr_rcblks = 0; 240 do { 241 n = clstr_rcblks; 242 clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz; 243 } while (n < clstr_rcblks); 244 245 if (rcclno > 0) { 246 rctbl = calloc(clstr_rctblsz, clstrsz); 247 if (rctbl == NULL) { 248 error = ENOMEM; 249 goto out; 250 } 251 for (n = 0; n < clstr_rcblks; n++) { 252 be64enc(rctbl + n, ofs); 253 ofs += clstrsz; 254 nclstrs++; 255 } 256 if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) { 257 error = errno; 258 goto out; 259 } 260 free(rctbl); 261 rctbl = NULL; 262 } 263 264 l2tbl = malloc(clstrsz); 265 if (l2tbl == NULL) { 266 error = ENOMEM; 267 goto out; 268 } 269 270 for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) { 271 if (l1tbl[l1idx] == 0) 272 continue; 273 memset(l2tbl, 0, clstrsz); 274 blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3); 275 for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) { 276 blk = blkofs + (lba_t)l2idx * blk_clstrsz; 277 if (blk >= blk_imgsz) 278 break; 279 if (image_data(blk, blk_clstrsz)) { 280 be64enc(l2tbl + l2idx, ofs + ofsflags); 281 ofs += clstrsz; 282 } 283 } 284 if (sparse_write(fd, l2tbl, clstrsz) < 0) { 285 error = errno; 286 goto out; 287 } 288 } 289 290 free(l2tbl); 291 l2tbl = NULL; 292 free(l1tbl); 293 l1tbl = NULL; 294 295 if (rcclno > 0) { 296 rcblk = calloc(clstr_rcblks, clstrsz); 297 if (rcblk == NULL) { 298 error = ENOMEM; 299 goto out; 300 } 301 for (n = 0; n < nclstrs; n++) 302 be16enc(rcblk + n, 1); 303 if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) { 304 error = errno; 305 goto out; 306 } 307 free(rcblk); 308 rcblk = NULL; 309 } 310 311 error = 0; 312 for (n = 0; n < clstr_imgsz; n++) { 313 blk = n * blk_clstrsz; 314 if (image_data(blk, blk_clstrsz)) { 315 error = image_copyout_region(fd, blk, blk_clstrsz); 316 if (error) 317 break; 318 } 319 } 320 if (!error) 321 error = image_copyout_done(fd); 322 323 out: 324 if (rcblk != NULL) 325 free(rcblk); 326 if (l2tbl != NULL) 327 free(l2tbl); 328 if (rctbl != NULL) 329 free(rctbl); 330 if (l1tbl != NULL) 331 free(l1tbl); 332 if (hdr != NULL) 333 free(hdr); 334 return (error); 335} 336 337static int 338qcow1_write(int fd) 339{ 340 341 return (qcow_write(fd, QCOW_VERSION_1)); 342} 343 344static int 345qcow2_write(int fd) 346{ 347 348 return (qcow_write(fd, QCOW_VERSION_2)); 349} 350 351static struct mkimg_format qcow1_format = { 352 .name = "qcow", 353 .description = "QEMU Copy-On-Write, version 1", 354 .resize = qcow1_resize, 355 .write = qcow1_write, 356}; 357FORMAT_DEFINE(qcow1_format); 358 359static struct mkimg_format qcow2_format = { 360 .name = "qcow2", 361 .description = "QEMU Copy-On-Write, version 2", 362 .resize = qcow2_resize, 363 .write = qcow2_write, 364}; 365FORMAT_DEFINE(qcow2_format); 366