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