xref: /freebsd/usr.bin/mkimg/qcow.c (revision 40a8ac8f62b535d30349faf28cf47106b7041b83)
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/endian.h>
32 #include <sys/errno.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #include "image.h"
40 #include "format.h"
41 #include "mkimg.h"
42 
43 #undef	QCOW_SUPPORT_QCOW2
44 
45 /* Default cluster sizes. */
46 #define	QCOW1_CLSTR_LOG2SZ	12	/* 4KB */
47 #define	QCOW2_CLSTR_LOG2SZ	16	/* 64KB */
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_entries;
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 clstrsz, 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 		return (EDOOFUS);
104 	}
105 
106 	clstrsz = 1UL << clstr_log2sz;
107 	imagesz = round_clstr(imgsz * secsz);
108 
109 	if (verbose)
110 		fprintf(stderr, "QCOW: image size = %ju, cluster size = %ju\n",
111 		    (uintmax_t)imagesz, (uintmax_t)clstrsz);
112 
113 	return (image_set_size(imagesz / secsz));
114 }
115 
116 static int
117 qcow1_resize(lba_t imgsz)
118 {
119 
120 	return (qcow_resize(imgsz, QCOW_VERSION_1));
121 }
122 
123 #ifdef QCOW_SUPPORT_QCOW2
124 static int
125 qcow2_resize(lba_t imgsz)
126 {
127 
128 	return (qcow_resize(imgsz, QCOW_VERSION_2));
129 }
130 #endif
131 
132 static int
133 qcow_write(int fd, u_int version)
134 {
135 	struct qcow_header *hdr;
136 	uint64_t *l1tbl, *l2tbl;
137 	uint16_t *rctbl;
138 	uint64_t n, clstrsz, imagesz, nclstrs;
139 	uint64_t l1ofs, l2ofs, ofs, rcofs;
140 	lba_t blk, blkofs, blkcnt, imgsz;
141 	u_int l1idx, l2idx, l2clstrs;
142 	int error;
143 
144 	if (clstr_log2sz == 0)
145 		return (EDOOFUS);
146 
147 	clstrsz = 1UL << clstr_log2sz;
148 	blkcnt = clstrsz / secsz;
149 	imgsz = image_get_size();
150 	imagesz = imgsz * secsz;
151 	nclstrs = imagesz >> clstr_log2sz;
152 	l2clstrs = (nclstrs * 8 + clstrsz - 1) > clstr_log2sz;
153 
154 	l1ofs = clstrsz;
155 	rcofs = round_clstr(l1ofs + l2clstrs * 8);
156 
157 	hdr = calloc(1, clstrsz);
158 	if (hdr == NULL)
159 		return (errno);
160 
161 	be32enc(&hdr->magic, QCOW_MAGIC);
162 	be32enc(&hdr->version, version);
163 	be64enc(&hdr->disk_size, imagesz);
164 	switch (version) {
165 	case QCOW_VERSION_1:
166 		l2ofs = rcofs;	/* No reference counting. */
167 		hdr->u.v1.clstr_log2sz = clstr_log2sz;
168 		hdr->u.v1.l2_log2sz = clstr_log2sz - 3;
169 		be64enc(&hdr->u.v1.l1_offset, l1ofs);
170 		break;
171 	case QCOW_VERSION_2:
172 		l2ofs = round_clstr(rcofs + (nclstrs + l2clstrs) * 2);
173 		be32enc(&hdr->clstr_log2sz, clstr_log2sz);
174 		be32enc(&hdr->u.v2.l1_entries, l2clstrs);
175 		be64enc(&hdr->u.v2.l1_offset, l1ofs);
176 		be64enc(&hdr->u.v2.refcnt_offset, rcofs);
177 		be32enc(&hdr->u.v2.refcnt_entries, l2clstrs);
178 		break;
179 	default:
180 		return (EDOOFUS);
181 	}
182 
183 	l2tbl = l1tbl = NULL;
184 	rctbl = NULL;
185 
186 	l1tbl = calloc(1, (size_t)(rcofs - l1ofs));
187 	if (l1tbl == NULL) {
188 		error = ENOMEM;
189 		goto out;
190 	}
191 	if (l2ofs != rcofs) {
192 		rctbl = calloc(1, (size_t)(l2ofs - rcofs));
193 		if (rctbl == NULL) {
194 			error = ENOMEM;
195 			goto out;
196 		}
197 	}
198 
199 	ofs = l2ofs;
200 	for (n = 0; n < nclstrs; n++) {
201 		l1idx = n >> (clstr_log2sz - 3);
202 		if (l1tbl[l1idx] != 0UL)
203 			continue;
204 		blk = n * blkcnt;
205 		if (image_data(blk, blkcnt)) {
206 			be64enc(l1tbl + l1idx, ofs);
207 			ofs += clstrsz;
208 		}
209 	}
210 
211 	error = 0;
212 	if (!error && sparse_write(fd, hdr, clstrsz) < 0)
213 		error = errno;
214 	if (!error && sparse_write(fd, l1tbl, (size_t)(rcofs - l1ofs)) < 0)
215 		error = errno;
216 	/* XXX refcnt table. */
217 	if (error)
218 		goto out;
219 
220 	free(hdr);
221 	hdr = NULL;
222 	if (rctbl != NULL) {
223 		free(rctbl);
224 		rctbl = NULL;
225 	}
226 
227 	l2tbl = malloc(clstrsz);
228 	if (l2tbl == NULL) {
229 		error = ENOMEM;
230 		goto out;
231 	}
232 
233 	for (l1idx = 0; l1idx < l2clstrs; l1idx++) {
234 		if (l1tbl[l1idx] == 0)
235 			continue;
236 		memset(l2tbl, 0, clstrsz);
237 		blkofs = (lba_t)l1idx * (clstrsz * (clstrsz >> 3));
238 		for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) {
239 			blk = blkofs + (lba_t)l2idx * blkcnt;
240 			if (blk >= imgsz)
241 				break;
242 			if (image_data(blk, blkcnt)) {
243 				be64enc(l2tbl + l2idx, ofs);
244 				ofs += clstrsz;
245 			}
246 		}
247 		if (sparse_write(fd, l2tbl, clstrsz) < 0) {
248 			error = errno;
249 			goto out;
250 		}
251 	}
252 
253 	free(l2tbl);
254 	l2tbl = NULL;
255 	free(l1tbl);
256 	l1tbl = NULL;
257 
258 	error = 0;
259 	for (n = 0; n < nclstrs; n++) {
260 		blk = n * blkcnt;
261 		if (image_data(blk, blkcnt)) {
262 			error = image_copyout_region(fd, blk, blkcnt);
263 			if (error)
264 				break;
265 		}
266 	}
267 	if (!error)
268 		error = image_copyout_done(fd);
269 
270  out:
271 	if (l2tbl != NULL)
272 		free(l2tbl);
273 	if (rctbl != NULL)
274 		free(rctbl);
275 	if (l1tbl != NULL)
276 		free(l1tbl);
277 	if (hdr != NULL)
278 		free(hdr);
279 	return (error);
280 }
281 
282 static int
283 qcow1_write(int fd)
284 {
285 
286 	return (qcow_write(fd, QCOW_VERSION_1));
287 }
288 
289 #ifdef QCOW_SUPPORT_QCOW2
290 static int
291 qcow2_write(int fd)
292 {
293 
294 	return (qcow_write(fd, QCOW_VERSION_2));
295 }
296 #endif
297 
298 static struct mkimg_format qcow1_format = {
299 	.name = "qcow",
300 	.description = "QEMU Copy-On-Write, version 1",
301 	.resize = qcow1_resize,
302 	.write = qcow1_write,
303 };
304 FORMAT_DEFINE(qcow1_format);
305 
306 #ifdef QCOW_SUPPORT_QCOW2
307 static struct mkimg_format qcow2_format = {
308 	.name = "qcow2",
309 	.description = "QEMU Copy-On-Write, version 2",
310 	.resize = qcow2_resize,
311 	.write = qcow2_write,
312 };
313 FORMAT_DEFINE(qcow2_format);
314 #endif
315