xref: /freebsd/usr.bin/mkimg/qcow.c (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
1 /*-
2  * Copyright (c) 2014 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/errno.h>
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "endian.h"
37 #include "image.h"
38 #include "format.h"
39 #include "mkimg.h"
40 
41 /* Default cluster sizes. */
42 #define	QCOW1_CLSTR_LOG2SZ	12	/* 4KB */
43 #define	QCOW2_CLSTR_LOG2SZ	16	/* 64KB */
44 
45 /* Flag bits in cluster offsets */
46 #define	QCOW_CLSTR_COMPRESSED	(1ULL << 62)
47 #define	QCOW_CLSTR_COPIED	(1ULL << 63)
48 
49 struct qcow_header {
50 	uint32_t	magic;
51 #define	QCOW_MAGIC		0x514649fb
52 	uint32_t	version;
53 #define	QCOW_VERSION_1		1
54 #define	QCOW_VERSION_2		2
55 	uint64_t	path_offset;
56 	uint32_t	path_length;
57 	uint32_t	clstr_log2sz;	/* v2 only */
58 	uint64_t	disk_size;
59 	union {
60 		struct {
61 			uint8_t		clstr_log2sz;
62 			uint8_t		l2_log2sz;
63 			uint16_t	_pad;
64 			uint32_t	encryption;
65 			uint64_t	l1_offset;
66 		} v1;
67 		struct {
68 			uint32_t	encryption;
69 			uint32_t	l1_entries;
70 			uint64_t	l1_offset;
71 			uint64_t	refcnt_offset;
72 			uint32_t	refcnt_clstrs;
73 			uint32_t	snapshot_count;
74 			uint64_t	snapshot_offset;
75 		} v2;
76 	} u;
77 };
78 
79 static u_int clstr_log2sz;
80 
81 static uint64_t
82 round_clstr(uint64_t ofs)
83 {
84 	uint64_t clstrsz;
85 
86 	clstrsz = 1UL << clstr_log2sz;
87 	return ((ofs + clstrsz - 1) & ~(clstrsz - 1));
88 }
89 
90 static int
91 qcow_resize(lba_t imgsz, u_int version)
92 {
93 	uint64_t imagesz;
94 
95 	switch (version) {
96 	case QCOW_VERSION_1:
97 		clstr_log2sz = QCOW1_CLSTR_LOG2SZ;
98 		break;
99 	case QCOW_VERSION_2:
100 		clstr_log2sz = QCOW2_CLSTR_LOG2SZ;
101 		break;
102 	default:
103 		assert(0);
104 	}
105 
106 	imagesz = round_clstr(imgsz * secsz);
107 
108 	if (verbose)
109 		fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n",
110 		    (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz));
111 
112 	return (image_set_size(imagesz / secsz));
113 }
114 
115 static int
116 qcow1_resize(lba_t imgsz)
117 {
118 
119 	return (qcow_resize(imgsz, QCOW_VERSION_1));
120 }
121 
122 static int
123 qcow2_resize(lba_t imgsz)
124 {
125 
126 	return (qcow_resize(imgsz, QCOW_VERSION_2));
127 }
128 
129 static int
130 qcow_write(int fd, u_int version)
131 {
132 	struct qcow_header *hdr;
133 	uint64_t *l1tbl, *l2tbl, *rctbl;
134 	uint16_t *rcblk;
135 	uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz;
136 	uint64_t clstr_rcblks, clstr_rctblsz;
137 	uint64_t n, imagesz, nclstrs, ofs, ofsflags;
138 	lba_t blk, blkofs, blk_imgsz;
139 	u_int l1clno, l2clno, rcclno;
140 	u_int blk_clstrsz, refcnt_clstrs;
141 	u_int clstrsz, l1idx, l2idx;
142 	int error;
143 
144 	assert(clstr_log2sz != 0);
145 
146 	clstrsz = 1U << clstr_log2sz;
147 	blk_clstrsz = clstrsz / secsz;
148 	blk_imgsz = image_get_size();
149 	imagesz = blk_imgsz * secsz;
150 	clstr_imgsz = imagesz >> clstr_log2sz;
151 	clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz;
152 	clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz;
153 	nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1;
154 	clstr_rcblks = clstr_rctblsz = 0;
155 	do {
156 		n = clstr_rcblks + clstr_rctblsz;
157 		clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
158 		clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
159 	} while (n < (clstr_rcblks + clstr_rctblsz));
160 
161 	/*
162 	 * We got all the sizes in clusters. Start the layout.
163 	 * 0 - header
164 	 * 1 - L1 table
165 	 * 2 - RC table (v2 only)
166 	 * 3 - L2 tables
167 	 * 4 - RC block (v2 only)
168 	 * 5 - data
169 	 */
170 
171 	l1clno = 1;
172 	rcclno = 0;
173 	rctbl = l2tbl = l1tbl = NULL;
174 	rcblk = NULL;
175 
176 	hdr = calloc(1, clstrsz);
177 	if (hdr == NULL)
178 		return (errno);
179 
180 	be32enc(&hdr->magic, QCOW_MAGIC);
181 	be32enc(&hdr->version, version);
182 	be64enc(&hdr->disk_size, imagesz);
183 	switch (version) {
184 	case QCOW_VERSION_1:
185 		ofsflags = 0;
186 		l2clno = l1clno + clstr_l1tblsz;
187 		hdr->u.v1.clstr_log2sz = clstr_log2sz;
188 		hdr->u.v1.l2_log2sz = clstr_log2sz - 3;
189 		be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno);
190 		break;
191 	case QCOW_VERSION_2:
192 		ofsflags = QCOW_CLSTR_COPIED;
193 		rcclno = l1clno + clstr_l1tblsz;
194 		l2clno = rcclno + clstr_rctblsz;
195 		be32enc(&hdr->clstr_log2sz, clstr_log2sz);
196 		be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls);
197 		be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno);
198 		be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno);
199 		refcnt_clstrs = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
200 		be32enc(&hdr->u.v2.refcnt_clstrs, refcnt_clstrs);
201 		break;
202 	default:
203 		assert(0);
204 	}
205 
206 	if (sparse_write(fd, hdr, clstrsz) < 0) {
207 		error = errno;
208 		goto out;
209 	}
210 
211 	free(hdr);
212 	hdr = NULL;
213 
214 	ofs = clstrsz * l2clno;
215 	nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz;
216 
217 	l1tbl = calloc(clstr_l1tblsz, clstrsz);
218 	if (l1tbl == NULL) {
219 		error = ENOMEM;
220 		goto out;
221 	}
222 
223 	for (n = 0; n < clstr_imgsz; n++) {
224 		blk = n * blk_clstrsz;
225 		if (image_data(blk, blk_clstrsz)) {
226 			nclstrs++;
227 			l1idx = n >> (clstr_log2sz - 3);
228 			if (l1tbl[l1idx] == 0) {
229 				be64enc(l1tbl + l1idx, ofs + ofsflags);
230 				ofs += clstrsz;
231 				nclstrs++;
232 			}
233 		}
234 	}
235 
236 	if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) {
237 		error = errno;
238 		goto out;
239 	}
240 
241 	clstr_rcblks = 0;
242 	do {
243 		n = clstr_rcblks;
244 		clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
245 	} while (n < clstr_rcblks);
246 
247 	if (rcclno > 0) {
248 		rctbl = calloc(clstr_rctblsz, clstrsz);
249 		if (rctbl == NULL) {
250 			error = ENOMEM;
251 			goto out;
252 		}
253 		for (n = 0; n < clstr_rcblks; n++) {
254 			be64enc(rctbl + n, ofs);
255 			ofs += clstrsz;
256 			nclstrs++;
257 		}
258 		if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) {
259 			error = errno;
260 			goto out;
261 		}
262 		free(rctbl);
263 		rctbl = NULL;
264 	}
265 
266 	l2tbl = malloc(clstrsz);
267 	if (l2tbl == NULL) {
268 		error = ENOMEM;
269 		goto out;
270 	}
271 
272 	for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) {
273 		if (l1tbl[l1idx] == 0)
274 			continue;
275 		memset(l2tbl, 0, clstrsz);
276 		blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3);
277 		for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) {
278 			blk = blkofs + (lba_t)l2idx * blk_clstrsz;
279 			if (blk >= blk_imgsz)
280 				break;
281 			if (image_data(blk, blk_clstrsz)) {
282 				be64enc(l2tbl + l2idx, ofs + ofsflags);
283 				ofs += clstrsz;
284 			}
285 		}
286 		if (sparse_write(fd, l2tbl, clstrsz) < 0) {
287 			error = errno;
288 			goto out;
289 		}
290 	}
291 
292 	free(l2tbl);
293 	l2tbl = NULL;
294 	free(l1tbl);
295 	l1tbl = NULL;
296 
297 	if (rcclno > 0) {
298 		rcblk = calloc(clstr_rcblks, clstrsz);
299 		if (rcblk == NULL) {
300 			error = ENOMEM;
301 			goto out;
302 		}
303 		for (n = 0; n < nclstrs; n++)
304 			be16enc(rcblk + n, 1);
305 		if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) {
306 			error = errno;
307 			goto out;
308 		}
309 		free(rcblk);
310 		rcblk = NULL;
311 	}
312 
313 	error = 0;
314 	for (n = 0; n < clstr_imgsz; n++) {
315 		blk = n * blk_clstrsz;
316 		if (image_data(blk, blk_clstrsz)) {
317 			error = image_copyout_region(fd, blk, blk_clstrsz);
318 			if (error)
319 				break;
320 		}
321 	}
322 	if (!error)
323 		error = image_copyout_done(fd);
324 
325  out:
326 	if (rcblk != NULL)
327 		free(rcblk);
328 	if (l2tbl != NULL)
329 		free(l2tbl);
330 	if (rctbl != NULL)
331 		free(rctbl);
332 	if (l1tbl != NULL)
333 		free(l1tbl);
334 	if (hdr != NULL)
335 		free(hdr);
336 	return (error);
337 }
338 
339 static int
340 qcow1_write(int fd)
341 {
342 
343 	return (qcow_write(fd, QCOW_VERSION_1));
344 }
345 
346 static int
347 qcow2_write(int fd)
348 {
349 
350 	return (qcow_write(fd, QCOW_VERSION_2));
351 }
352 
353 static struct mkimg_format qcow1_format = {
354 	.name = "qcow",
355 	.description = "QEMU Copy-On-Write, version 1",
356 	.resize = qcow1_resize,
357 	.write = qcow1_write,
358 };
359 FORMAT_DEFINE(qcow1_format);
360 
361 static struct mkimg_format qcow2_format = {
362 	.name = "qcow2",
363 	.description = "QEMU Copy-On-Write, version 2",
364 	.resize = qcow2_resize,
365 	.write = qcow2_write,
366 };
367 FORMAT_DEFINE(qcow2_format);
368