]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mkimg/qcow.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / usr.bin / mkimg / qcow.c
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);