xref: /freebsd/usr.bin/mkimg/qcow.c (revision 273c26a3c3bea87a241d6879abd4f991db180bf0)
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/types.h>
31 #include <sys/errno.h>
32 #include <assert.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #include "endian.h"
40 #include "image.h"
41 #include "format.h"
42 #include "mkimg.h"
43 
44 /* Default cluster sizes. */
45 #define	QCOW1_CLSTR_LOG2SZ	12	/* 4KB */
46 #define	QCOW2_CLSTR_LOG2SZ	16	/* 64KB */
47 
48 /* Flag bits in cluster offsets */
49 #define	QCOW_CLSTR_COMPRESSED	(1ULL << 62)
50 #define	QCOW_CLSTR_COPIED	(1ULL << 63)
51 
52 struct qcow_header {
53 	uint32_t	magic;
54 #define	QCOW_MAGIC		0x514649fb
55 	uint32_t	version;
56 #define	QCOW_VERSION_1		1
57 #define	QCOW_VERSION_2		2
58 	uint64_t	path_offset;
59 	uint32_t	path_length;
60 	uint32_t	clstr_log2sz;	/* v2 only */
61 	uint64_t	disk_size;
62 	union {
63 		struct {
64 			uint8_t		clstr_log2sz;
65 			uint8_t		l2_log2sz;
66 			uint16_t	_pad;
67 			uint32_t	encryption;
68 			uint64_t	l1_offset;
69 		} v1;
70 		struct {
71 			uint32_t	encryption;
72 			uint32_t	l1_entries;
73 			uint64_t	l1_offset;
74 			uint64_t	refcnt_offset;
75 			uint32_t	refcnt_clstrs;
76 			uint32_t	snapshot_count;
77 			uint64_t	snapshot_offset;
78 		} v2;
79 	} u;
80 };
81 
82 static u_int clstr_log2sz;
83 
84 static uint64_t
85 round_clstr(uint64_t ofs)
86 {
87 	uint64_t clstrsz;
88 
89 	clstrsz = 1UL << clstr_log2sz;
90 	return ((ofs + clstrsz - 1) & ~(clstrsz - 1));
91 }
92 
93 static int
94 qcow_resize(lba_t imgsz, u_int version)
95 {
96 	uint64_t imagesz;
97 
98 	switch (version) {
99 	case QCOW_VERSION_1:
100 		clstr_log2sz = QCOW1_CLSTR_LOG2SZ;
101 		break;
102 	case QCOW_VERSION_2:
103 		clstr_log2sz = QCOW2_CLSTR_LOG2SZ;
104 		break;
105 	default:
106 		assert(0);
107 	}
108 
109 	imagesz = round_clstr(imgsz * secsz);
110 
111 	if (verbose)
112 		fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n",
113 		    (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz));
114 
115 	return (image_set_size(imagesz / secsz));
116 }
117 
118 static int
119 qcow1_resize(lba_t imgsz)
120 {
121 
122 	return (qcow_resize(imgsz, QCOW_VERSION_1));
123 }
124 
125 static int
126 qcow2_resize(lba_t imgsz)
127 {
128 
129 	return (qcow_resize(imgsz, QCOW_VERSION_2));
130 }
131 
132 static int
133 qcow_write(int fd, u_int version)
134 {
135 	struct qcow_header *hdr;
136 	uint64_t *l1tbl, *l2tbl, *rctbl;
137 	uint16_t *rcblk;
138 	uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz;
139 	uint64_t clstr_rcblks, clstr_rctblsz;
140 	uint64_t n, imagesz, nclstrs, ofs, ofsflags;
141 	lba_t blk, blkofs, blk_imgsz;
142 	u_int l1clno, l2clno, rcclno;
143 	u_int blk_clstrsz, refcnt_clstrs;
144 	u_int clstrsz, l1idx, l2idx;
145 	int error;
146 
147 	assert(clstr_log2sz != 0);
148 
149 	clstrsz = 1U << clstr_log2sz;
150 	blk_clstrsz = clstrsz / secsz;
151 	blk_imgsz = image_get_size();
152 	imagesz = blk_imgsz * secsz;
153 	clstr_imgsz = imagesz >> clstr_log2sz;
154 	clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz;
155 	clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz;
156 	nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1;
157 	clstr_rcblks = clstr_rctblsz = 0;
158 	do {
159 		n = clstr_rcblks + clstr_rctblsz;
160 		clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
161 		clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
162 	} while (n < (clstr_rcblks + clstr_rctblsz));
163 
164 	/*
165 	 * We got all the sizes in clusters. Start the layout.
166 	 * 0 - header
167 	 * 1 - L1 table
168 	 * 2 - RC table (v2 only)
169 	 * 3 - L2 tables
170 	 * 4 - RC block (v2 only)
171 	 * 5 - data
172 	 */
173 
174 	l1clno = 1;
175 	rcclno = 0;
176 	rctbl = l2tbl = l1tbl = NULL;
177 	rcblk = NULL;
178 
179 	hdr = calloc(1, clstrsz);
180 	if (hdr == NULL)
181 		return (errno);
182 
183 	be32enc(&hdr->magic, QCOW_MAGIC);
184 	be32enc(&hdr->version, version);
185 	be64enc(&hdr->disk_size, imagesz);
186 	switch (version) {
187 	case QCOW_VERSION_1:
188 		ofsflags = 0;
189 		l2clno = l1clno + clstr_l1tblsz;
190 		hdr->u.v1.clstr_log2sz = clstr_log2sz;
191 		hdr->u.v1.l2_log2sz = clstr_log2sz - 3;
192 		be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno);
193 		break;
194 	case QCOW_VERSION_2:
195 		ofsflags = QCOW_CLSTR_COPIED;
196 		rcclno = l1clno + clstr_l1tblsz;
197 		l2clno = rcclno + clstr_rctblsz;
198 		be32enc(&hdr->clstr_log2sz, clstr_log2sz);
199 		be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls);
200 		be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno);
201 		be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno);
202 		refcnt_clstrs = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
203 		be32enc(&hdr->u.v2.refcnt_clstrs, refcnt_clstrs);
204 		break;
205 	default:
206 		assert(0);
207 	}
208 
209 	if (sparse_write(fd, hdr, clstrsz) < 0) {
210 		error = errno;
211 		goto out;
212 	}
213 
214 	free(hdr);
215 	hdr = NULL;
216 
217 	ofs = clstrsz * l2clno;
218 	nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz;
219 
220 	l1tbl = calloc(1, clstrsz * clstr_l1tblsz);
221 	if (l1tbl == NULL) {
222 		error = ENOMEM;
223 		goto out;
224 	}
225 
226 	for (n = 0; n < clstr_imgsz; n++) {
227 		blk = n * blk_clstrsz;
228 		if (image_data(blk, blk_clstrsz)) {
229 			nclstrs++;
230 			l1idx = n >> (clstr_log2sz - 3);
231 			if (l1tbl[l1idx] == 0) {
232 				be64enc(l1tbl + l1idx, ofs + ofsflags);
233 				ofs += clstrsz;
234 				nclstrs++;
235 			}
236 		}
237 	}
238 
239 	if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) {
240 		error = errno;
241 		goto out;
242 	}
243 
244 	clstr_rcblks = 0;
245 	do {
246 		n = clstr_rcblks;
247 		clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
248 	} while (n < clstr_rcblks);
249 
250 	if (rcclno > 0) {
251 		rctbl = calloc(1, clstrsz * clstr_rctblsz);
252 		if (rctbl == NULL) {
253 			error = ENOMEM;
254 			goto out;
255 		}
256 		for (n = 0; n < clstr_rcblks; n++) {
257 			be64enc(rctbl + n, ofs);
258 			ofs += clstrsz;
259 			nclstrs++;
260 		}
261 		if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) {
262 			error = errno;
263 			goto out;
264 		}
265 		free(rctbl);
266 		rctbl = NULL;
267 	}
268 
269 	l2tbl = malloc(clstrsz);
270 	if (l2tbl == NULL) {
271 		error = ENOMEM;
272 		goto out;
273 	}
274 
275 	for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) {
276 		if (l1tbl[l1idx] == 0)
277 			continue;
278 		memset(l2tbl, 0, clstrsz);
279 		blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3);
280 		for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) {
281 			blk = blkofs + (lba_t)l2idx * blk_clstrsz;
282 			if (blk >= blk_imgsz)
283 				break;
284 			if (image_data(blk, blk_clstrsz)) {
285 				be64enc(l2tbl + l2idx, ofs + ofsflags);
286 				ofs += clstrsz;
287 			}
288 		}
289 		if (sparse_write(fd, l2tbl, clstrsz) < 0) {
290 			error = errno;
291 			goto out;
292 		}
293 	}
294 
295 	free(l2tbl);
296 	l2tbl = NULL;
297 	free(l1tbl);
298 	l1tbl = NULL;
299 
300 	if (rcclno > 0) {
301 		rcblk = calloc(1, clstrsz * clstr_rcblks);
302 		if (rcblk == NULL) {
303 			error = ENOMEM;
304 			goto out;
305 		}
306 		for (n = 0; n < nclstrs; n++)
307 			be16enc(rcblk + n, 1);
308 		if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) {
309 			error = errno;
310 			goto out;
311 		}
312 		free(rcblk);
313 		rcblk = NULL;
314 	}
315 
316 	error = 0;
317 	for (n = 0; n < clstr_imgsz; n++) {
318 		blk = n * blk_clstrsz;
319 		if (image_data(blk, blk_clstrsz)) {
320 			error = image_copyout_region(fd, blk, blk_clstrsz);
321 			if (error)
322 				break;
323 		}
324 	}
325 	if (!error)
326 		error = image_copyout_done(fd);
327 
328  out:
329 	if (rcblk != NULL)
330 		free(rcblk);
331 	if (l2tbl != NULL)
332 		free(l2tbl);
333 	if (rctbl != NULL)
334 		free(rctbl);
335 	if (l1tbl != NULL)
336 		free(l1tbl);
337 	if (hdr != NULL)
338 		free(hdr);
339 	return (error);
340 }
341 
342 static int
343 qcow1_write(int fd)
344 {
345 
346 	return (qcow_write(fd, QCOW_VERSION_1));
347 }
348 
349 static int
350 qcow2_write(int fd)
351 {
352 
353 	return (qcow_write(fd, QCOW_VERSION_2));
354 }
355 
356 static struct mkimg_format qcow1_format = {
357 	.name = "qcow",
358 	.description = "QEMU Copy-On-Write, version 1",
359 	.resize = qcow1_resize,
360 	.write = qcow1_write,
361 };
362 FORMAT_DEFINE(qcow1_format);
363 
364 static struct mkimg_format qcow2_format = {
365 	.name = "qcow2",
366 	.description = "QEMU Copy-On-Write, version 2",
367 	.resize = qcow2_resize,
368 	.write = qcow2_write,
369 };
370 FORMAT_DEFINE(qcow2_format);
371