1 | /* block-qcow.c |
---|
2 | * |
---|
3 | * Asynchronous Qemu copy-on-write disk implementation. |
---|
4 | * Code based on the Qemu implementation |
---|
5 | * (see copyright notice below) |
---|
6 | * |
---|
7 | * (c) 2006 Andrew Warfield and Julian Chesterfield |
---|
8 | * |
---|
9 | */ |
---|
10 | |
---|
11 | /* |
---|
12 | * Block driver for the QCOW format |
---|
13 | * |
---|
14 | * Copyright (c) 2004 Fabrice Bellard |
---|
15 | * |
---|
16 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
---|
17 | * of this software and associated documentation files(the "Software"), to deal |
---|
18 | * in the Software without restriction, including without limitation the rights |
---|
19 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
---|
20 | * copies of the Software, and to permit persons to whom the Software is |
---|
21 | * furnished to do so, subject to the following conditions: |
---|
22 | */ |
---|
23 | |
---|
24 | #include <errno.h> |
---|
25 | #include <fcntl.h> |
---|
26 | #include <stdio.h> |
---|
27 | #include <stdlib.h> |
---|
28 | #include <unistd.h> |
---|
29 | #include <sys/statvfs.h> |
---|
30 | #include <sys/stat.h> |
---|
31 | #include <sys/ioctl.h> |
---|
32 | #include <linux/fs.h> |
---|
33 | #include <string.h> |
---|
34 | #include <zlib.h> |
---|
35 | #include <inttypes.h> |
---|
36 | #include <libaio.h> |
---|
37 | #include <openssl/md5.h> |
---|
38 | #include "bswap.h" |
---|
39 | #include "aes.h" |
---|
40 | #include "tapdisk.h" |
---|
41 | |
---|
42 | #if 1 |
---|
43 | #define ASSERT(_p) \ |
---|
44 | if ( !(_p) ) { DPRINTF("Assertion '%s' failed, line %d, file %s", #_p , \ |
---|
45 | __LINE__, __FILE__); *(int*)0=0; } |
---|
46 | #else |
---|
47 | #define ASSERT(_p) ((void)0) |
---|
48 | #endif |
---|
49 | |
---|
50 | #define ROUNDUP(l, s) \ |
---|
51 | ({ \ |
---|
52 | (uint64_t)( \ |
---|
53 | (l + (s - 1)) - ((l + (s - 1)) % s)); \ |
---|
54 | }) |
---|
55 | |
---|
56 | /******AIO DEFINES******/ |
---|
57 | #define REQUEST_ASYNC_FD 1 |
---|
58 | |
---|
59 | struct pending_aio { |
---|
60 | td_callback_t cb; |
---|
61 | int id; |
---|
62 | void *private; |
---|
63 | int nb_sectors; |
---|
64 | char *buf; |
---|
65 | uint64_t sector; |
---|
66 | }; |
---|
67 | |
---|
68 | #define IOCB_IDX(_s, _io) ((_io) - (_s)->iocb_list) |
---|
69 | |
---|
70 | #define ZERO_TEST(_b) (_b | 0x00) |
---|
71 | |
---|
72 | /**************************************************************/ |
---|
73 | /* QEMU COW block driver with compression and encryption support */ |
---|
74 | |
---|
75 | #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) |
---|
76 | #define XEN_MAGIC (('X' << 24) | ('E' << 16) | ('N' << 8) | 0xfb) |
---|
77 | #define QCOW_VERSION 1 |
---|
78 | |
---|
79 | #define QCOW_CRYPT_NONE 0x00 |
---|
80 | #define QCOW_CRYPT_AES 0x01 |
---|
81 | |
---|
82 | #define QCOW_OFLAG_COMPRESSED (1LL << 63) |
---|
83 | #define SPARSE_FILE 0x01 |
---|
84 | |
---|
85 | #ifndef O_BINARY |
---|
86 | #define O_BINARY 0 |
---|
87 | #endif |
---|
88 | |
---|
89 | typedef struct QCowHeader { |
---|
90 | uint32_t magic; |
---|
91 | uint32_t version; |
---|
92 | uint64_t backing_file_offset; |
---|
93 | uint32_t backing_file_size; |
---|
94 | uint32_t mtime; |
---|
95 | uint64_t size; /* in bytes */ |
---|
96 | uint8_t cluster_bits; |
---|
97 | uint8_t l2_bits; |
---|
98 | uint32_t crypt_method; |
---|
99 | uint64_t l1_table_offset; |
---|
100 | } QCowHeader; |
---|
101 | |
---|
102 | /*Extended header for Xen enhancements*/ |
---|
103 | typedef struct QCowHeader_ext { |
---|
104 | uint32_t xmagic; |
---|
105 | uint32_t cksum; |
---|
106 | uint32_t min_cluster_alloc; |
---|
107 | uint32_t flags; |
---|
108 | } QCowHeader_ext; |
---|
109 | |
---|
110 | #define L2_CACHE_SIZE 16 /*Fixed allocation in Qemu*/ |
---|
111 | |
---|
112 | struct tdqcow_state { |
---|
113 | int fd; /*Main Qcow file descriptor */ |
---|
114 | uint64_t fd_end; /*Store a local record of file length */ |
---|
115 | char *name; /*Record of the filename*/ |
---|
116 | uint32_t backing_file_size; |
---|
117 | uint64_t backing_file_offset; |
---|
118 | int encrypted; /*File contents are encrypted or plain*/ |
---|
119 | int cluster_bits; /*Determines length of cluster as |
---|
120 | *indicated by file hdr*/ |
---|
121 | int cluster_size; /*Length of cluster*/ |
---|
122 | int cluster_sectors; /*Number of sectors per cluster*/ |
---|
123 | int cluster_alloc; /*Blktap fix for allocating full |
---|
124 | *extents*/ |
---|
125 | int min_cluster_alloc; /*Blktap historical extent alloc*/ |
---|
126 | int sparse; /*Indicates whether to preserve sparseness*/ |
---|
127 | int l2_bits; /*Size of L2 table entry*/ |
---|
128 | int l2_size; /*Full table size*/ |
---|
129 | int l1_size; /*L1 table size*/ |
---|
130 | uint64_t cluster_offset_mask; |
---|
131 | uint64_t l1_table_offset; /*L1 table offset from beginning of |
---|
132 | *file*/ |
---|
133 | uint64_t *l1_table; /*L1 table entries*/ |
---|
134 | uint64_t *l2_cache; /*We maintain a cache of size |
---|
135 | *L2_CACHE_SIZE of most read entries*/ |
---|
136 | uint64_t l2_cache_offsets[L2_CACHE_SIZE]; /*L2 cache entries*/ |
---|
137 | uint32_t l2_cache_counts[L2_CACHE_SIZE]; /*Cache access record*/ |
---|
138 | uint8_t *cluster_cache; |
---|
139 | uint8_t *cluster_data; |
---|
140 | uint8_t *sector_lock; /*Locking bitmap for AIO reads/writes*/ |
---|
141 | uint64_t cluster_cache_offset; /**/ |
---|
142 | uint32_t crypt_method; /*current crypt method, 0 if no |
---|
143 | *key yet */ |
---|
144 | uint32_t crypt_method_header; /**/ |
---|
145 | AES_KEY aes_encrypt_key; /*AES key*/ |
---|
146 | AES_KEY aes_decrypt_key; /*AES key*/ |
---|
147 | /* libaio state */ |
---|
148 | io_context_t aio_ctx; |
---|
149 | int max_aio_reqs; |
---|
150 | struct iocb *iocb_list; |
---|
151 | struct iocb **iocb_free; |
---|
152 | struct pending_aio *pending_aio; |
---|
153 | int iocb_free_count; |
---|
154 | struct iocb **iocb_queue; |
---|
155 | int iocb_queued; |
---|
156 | int poll_fd; /* NB: we require aio_poll support */ |
---|
157 | struct io_event *aio_events; |
---|
158 | }; |
---|
159 | |
---|
160 | static int decompress_cluster(struct tdqcow_state *s, uint64_t cluster_offset); |
---|
161 | |
---|
162 | static void free_aio_state(struct disk_driver *dd) |
---|
163 | { |
---|
164 | struct tdqcow_state *s = (struct tdqcow_state *)dd->private; |
---|
165 | |
---|
166 | if (s->sector_lock) |
---|
167 | free(s->sector_lock); |
---|
168 | if (s->iocb_list) |
---|
169 | free(s->iocb_list); |
---|
170 | if (s->pending_aio) |
---|
171 | free(s->pending_aio); |
---|
172 | if (s->aio_events) |
---|
173 | free(s->aio_events); |
---|
174 | if (s->iocb_free) |
---|
175 | free(s->iocb_free); |
---|
176 | if (s->iocb_queue) |
---|
177 | free(s->iocb_queue); |
---|
178 | } |
---|
179 | |
---|
180 | static int init_aio_state(struct disk_driver *dd) |
---|
181 | { |
---|
182 | int i; |
---|
183 | struct td_state *bs = dd->td_state; |
---|
184 | struct tdqcow_state *s = (struct tdqcow_state *)dd->private; |
---|
185 | long ioidx; |
---|
186 | |
---|
187 | s->iocb_list = NULL; |
---|
188 | s->pending_aio = NULL; |
---|
189 | s->aio_events = NULL; |
---|
190 | s->iocb_free = NULL; |
---|
191 | s->iocb_queue = NULL; |
---|
192 | |
---|
193 | /*Initialize Locking bitmap*/ |
---|
194 | s->sector_lock = calloc(1, bs->size); |
---|
195 | |
---|
196 | if (!s->sector_lock) { |
---|
197 | DPRINTF("Failed to allocate sector lock\n"); |
---|
198 | goto fail; |
---|
199 | } |
---|
200 | |
---|
201 | /* A segment (i.e. a page) can span multiple clusters */ |
---|
202 | s->max_aio_reqs = ((getpagesize() / s->cluster_size) + 1) * |
---|
203 | MAX_SEGMENTS_PER_REQ * MAX_REQUESTS; |
---|
204 | |
---|
205 | /* Initialize AIO */ |
---|
206 | s->iocb_free_count = s->max_aio_reqs; |
---|
207 | s->iocb_queued = 0; |
---|
208 | |
---|
209 | if (!(s->iocb_list = malloc(sizeof(struct iocb) * s->max_aio_reqs)) || |
---|
210 | !(s->pending_aio = malloc(sizeof(struct pending_aio) * s->max_aio_reqs)) || |
---|
211 | !(s->aio_events = malloc(sizeof(struct io_event) * s->max_aio_reqs)) || |
---|
212 | !(s->iocb_free = malloc(sizeof(struct iocb *) * s->max_aio_reqs)) || |
---|
213 | !(s->iocb_queue = malloc(sizeof(struct iocb *) * s->max_aio_reqs))) { |
---|
214 | DPRINTF("Failed to allocate AIO structs (max_aio_reqs = %d)\n", |
---|
215 | s->max_aio_reqs); |
---|
216 | goto fail; |
---|
217 | } |
---|
218 | |
---|
219 | /*Signal kernel to create Poll FD for Asyc completion events*/ |
---|
220 | s->aio_ctx = (io_context_t) REQUEST_ASYNC_FD; |
---|
221 | s->poll_fd = io_setup(s->max_aio_reqs, &s->aio_ctx); |
---|
222 | |
---|
223 | if (s->poll_fd < 0) { |
---|
224 | if (s->poll_fd == -EAGAIN) { |
---|
225 | DPRINTF("Couldn't setup AIO context. If you are " |
---|
226 | "trying to concurrently use a large number " |
---|
227 | "of blktap-based disks, you may need to " |
---|
228 | "increase the system-wide aio request limit. " |
---|
229 | "(e.g. 'echo echo 1048576 > /proc/sys/fs/" |
---|
230 | "aio-max-nr')\n"); |
---|
231 | } else { |
---|
232 | DPRINTF("Couldn't get fd for AIO poll support. This " |
---|
233 | "is probably because your kernel does not " |
---|
234 | "have the aio-poll patch applied.\n"); |
---|
235 | } |
---|
236 | goto fail; |
---|
237 | } |
---|
238 | |
---|
239 | for (i=0;i<s->max_aio_reqs;i++) |
---|
240 | s->iocb_free[i] = &s->iocb_list[i]; |
---|
241 | |
---|
242 | DPRINTF("AIO state initialised\n"); |
---|
243 | |
---|
244 | return 0; |
---|
245 | |
---|
246 | fail: |
---|
247 | return -1; |
---|
248 | } |
---|
249 | |
---|
250 | static uint32_t gen_cksum(char *ptr, int len) |
---|
251 | { |
---|
252 | unsigned char *md; |
---|
253 | uint32_t ret; |
---|
254 | |
---|
255 | md = malloc(MD5_DIGEST_LENGTH); |
---|
256 | |
---|
257 | if(!md) return 0; |
---|
258 | |
---|
259 | if (MD5((unsigned char *)ptr, len, md) != md) { |
---|
260 | free(md); |
---|
261 | return 0; |
---|
262 | } |
---|
263 | |
---|
264 | memcpy(&ret, md, sizeof(uint32_t)); |
---|
265 | free(md); |
---|
266 | return ret; |
---|
267 | } |
---|
268 | |
---|
269 | static int get_filesize(char *filename, uint64_t *size, struct stat *st) |
---|
270 | { |
---|
271 | int fd; |
---|
272 | QCowHeader header; |
---|
273 | |
---|
274 | /*Set to the backing file size*/ |
---|
275 | fd = open(filename, O_RDONLY); |
---|
276 | if (fd < 0) |
---|
277 | return -1; |
---|
278 | if (read(fd, &header, sizeof(header)) < sizeof(header)) { |
---|
279 | close(fd); |
---|
280 | return -1; |
---|
281 | } |
---|
282 | close(fd); |
---|
283 | |
---|
284 | be32_to_cpus(&header.magic); |
---|
285 | be64_to_cpus(&header.size); |
---|
286 | if (header.magic == QCOW_MAGIC) { |
---|
287 | *size = header.size >> SECTOR_SHIFT; |
---|
288 | return 0; |
---|
289 | } |
---|
290 | |
---|
291 | if(S_ISBLK(st->st_mode)) { |
---|
292 | fd = open(filename, O_RDONLY); |
---|
293 | if (fd < 0) |
---|
294 | return -1; |
---|
295 | if (ioctl(fd,BLKGETSIZE,size)!=0) { |
---|
296 | printf("Unable to get Block device size\n"); |
---|
297 | close(fd); |
---|
298 | return -1; |
---|
299 | } |
---|
300 | close(fd); |
---|
301 | } else *size = (st->st_size >> SECTOR_SHIFT); |
---|
302 | return 0; |
---|
303 | } |
---|
304 | |
---|
305 | static int qcow_set_key(struct tdqcow_state *s, const char *key) |
---|
306 | { |
---|
307 | uint8_t keybuf[16]; |
---|
308 | int len, i; |
---|
309 | |
---|
310 | memset(keybuf, 0, 16); |
---|
311 | len = strlen(key); |
---|
312 | if (len > 16) |
---|
313 | len = 16; |
---|
314 | /* XXX: we could compress the chars to 7 bits to increase |
---|
315 | entropy */ |
---|
316 | for (i = 0; i < len; i++) { |
---|
317 | keybuf[i] = key[i]; |
---|
318 | } |
---|
319 | s->crypt_method = s->crypt_method_header; |
---|
320 | |
---|
321 | if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0) |
---|
322 | return -1; |
---|
323 | if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0) |
---|
324 | return -1; |
---|
325 | #if 0 |
---|
326 | /* test */ |
---|
327 | { |
---|
328 | uint8_t in[16]; |
---|
329 | uint8_t out[16]; |
---|
330 | uint8_t tmp[16]; |
---|
331 | for (i=0; i<16; i++) |
---|
332 | in[i] = i; |
---|
333 | AES_encrypt(in, tmp, &s->aes_encrypt_key); |
---|
334 | AES_decrypt(tmp, out, &s->aes_decrypt_key); |
---|
335 | for (i = 0; i < 16; i++) |
---|
336 | DPRINTF(" %02x", tmp[i]); |
---|
337 | DPRINTF("\n"); |
---|
338 | for (i = 0; i < 16; i++) |
---|
339 | DPRINTF(" %02x", out[i]); |
---|
340 | DPRINTF("\n"); |
---|
341 | } |
---|
342 | #endif |
---|
343 | return 0; |
---|
344 | } |
---|
345 | |
---|
346 | static int async_read(struct tdqcow_state *s, int size, |
---|
347 | uint64_t offset, char *buf, td_callback_t cb, |
---|
348 | int id, uint64_t sector, void *private) |
---|
349 | { |
---|
350 | struct iocb *io; |
---|
351 | struct pending_aio *pio; |
---|
352 | long ioidx; |
---|
353 | |
---|
354 | io = s->iocb_free[--s->iocb_free_count]; |
---|
355 | |
---|
356 | ioidx = IOCB_IDX(s, io); |
---|
357 | pio = &s->pending_aio[ioidx]; |
---|
358 | pio->cb = cb; |
---|
359 | pio->id = id; |
---|
360 | pio->private = private; |
---|
361 | pio->nb_sectors = size/512; |
---|
362 | pio->buf = buf; |
---|
363 | pio->sector = sector; |
---|
364 | |
---|
365 | io_prep_pread(io, s->fd, buf, size, offset); |
---|
366 | io->data = (void *)ioidx; |
---|
367 | |
---|
368 | s->iocb_queue[s->iocb_queued++] = io; |
---|
369 | |
---|
370 | return 1; |
---|
371 | } |
---|
372 | |
---|
373 | static int async_write(struct tdqcow_state *s, int size, |
---|
374 | uint64_t offset, char *buf, td_callback_t cb, |
---|
375 | int id, uint64_t sector, void *private) |
---|
376 | { |
---|
377 | struct iocb *io; |
---|
378 | struct pending_aio *pio; |
---|
379 | long ioidx; |
---|
380 | |
---|
381 | io = s->iocb_free[--s->iocb_free_count]; |
---|
382 | |
---|
383 | ioidx = IOCB_IDX(s, io); |
---|
384 | pio = &s->pending_aio[ioidx]; |
---|
385 | pio->cb = cb; |
---|
386 | pio->id = id; |
---|
387 | pio->private = private; |
---|
388 | pio->nb_sectors = size/512; |
---|
389 | pio->buf = buf; |
---|
390 | pio->sector = sector; |
---|
391 | |
---|
392 | io_prep_pwrite(io, s->fd, buf, size, offset); |
---|
393 | io->data = (void *)ioidx; |
---|
394 | |
---|
395 | s->iocb_queue[s->iocb_queued++] = io; |
---|
396 | |
---|
397 | return 1; |
---|
398 | } |
---|
399 | |
---|
400 | /*TODO: Fix sector span!*/ |
---|
401 | static int aio_can_lock(struct tdqcow_state *s, uint64_t sector) |
---|
402 | { |
---|
403 | return (s->sector_lock[sector] ? 0 : 1); |
---|
404 | } |
---|
405 | |
---|
406 | static int aio_lock(struct tdqcow_state *s, uint64_t sector) |
---|
407 | { |
---|
408 | return ++s->sector_lock[sector]; |
---|
409 | } |
---|
410 | |
---|
411 | static void aio_unlock(struct tdqcow_state *s, uint64_t sector) |
---|
412 | { |
---|
413 | if (!s->sector_lock[sector]) return; |
---|
414 | |
---|
415 | --s->sector_lock[sector]; |
---|
416 | return; |
---|
417 | } |
---|
418 | |
---|
419 | /* |
---|
420 | * The crypt function is compatible with the linux cryptoloop |
---|
421 | * algorithm for < 4 GB images. NOTE: out_buf == in_buf is |
---|
422 | * supported . |
---|
423 | */ |
---|
424 | static void encrypt_sectors(struct tdqcow_state *s, int64_t sector_num, |
---|
425 | uint8_t *out_buf, const uint8_t *in_buf, |
---|
426 | int nb_sectors, int enc, |
---|
427 | const AES_KEY *key) |
---|
428 | { |
---|
429 | union { |
---|
430 | uint64_t ll[2]; |
---|
431 | uint8_t b[16]; |
---|
432 | } ivec; |
---|
433 | int i; |
---|
434 | |
---|
435 | for (i = 0; i < nb_sectors; i++) { |
---|
436 | ivec.ll[0] = cpu_to_le64(sector_num); |
---|
437 | ivec.ll[1] = 0; |
---|
438 | AES_cbc_encrypt(in_buf, out_buf, 512, key, |
---|
439 | ivec.b, enc); |
---|
440 | sector_num++; |
---|
441 | in_buf += 512; |
---|
442 | out_buf += 512; |
---|
443 | } |
---|
444 | } |
---|
445 | |
---|
446 | static int qtruncate(int fd, off_t length, int sparse) |
---|
447 | { |
---|
448 | int ret, i; |
---|
449 | int current = 0, rem = 0; |
---|
450 | uint64_t sectors; |
---|
451 | struct stat st; |
---|
452 | char *buf; |
---|
453 | |
---|
454 | /* If length is greater than the current file len |
---|
455 | * we synchronously write zeroes to the end of the |
---|
456 | * file, otherwise we truncate the length down |
---|
457 | */ |
---|
458 | ret = fstat(fd, &st); |
---|
459 | if (ret == -1) |
---|
460 | return -1; |
---|
461 | if (S_ISBLK(st.st_mode)) |
---|
462 | return 0; |
---|
463 | |
---|
464 | sectors = (length + DEFAULT_SECTOR_SIZE - 1)/DEFAULT_SECTOR_SIZE; |
---|
465 | current = (st.st_size + DEFAULT_SECTOR_SIZE - 1)/DEFAULT_SECTOR_SIZE; |
---|
466 | rem = st.st_size % DEFAULT_SECTOR_SIZE; |
---|
467 | |
---|
468 | /* If we are extending this file, we write zeros to the end -- |
---|
469 | * this tries to ensure that the extents allocated wind up being |
---|
470 | * contiguous on disk. |
---|
471 | */ |
---|
472 | if(st.st_size < sectors * DEFAULT_SECTOR_SIZE) { |
---|
473 | /*We are extending the file*/ |
---|
474 | if ((ret = posix_memalign((void **)&buf, |
---|
475 | 512, DEFAULT_SECTOR_SIZE))) { |
---|
476 | DPRINTF("posix_memalign failed: %d\n", ret); |
---|
477 | return -1; |
---|
478 | } |
---|
479 | memset(buf, 0x00, DEFAULT_SECTOR_SIZE); |
---|
480 | if (lseek(fd, 0, SEEK_END)==-1) { |
---|
481 | DPRINTF("Lseek EOF failed (%d), internal error\n", |
---|
482 | errno); |
---|
483 | free(buf); |
---|
484 | return -1; |
---|
485 | } |
---|
486 | if (rem) { |
---|
487 | ret = write(fd, buf, rem); |
---|
488 | if (ret != rem) { |
---|
489 | DPRINTF("write failed: ret = %d, err = %s\n", |
---|
490 | ret, strerror(errno)); |
---|
491 | free(buf); |
---|
492 | return -1; |
---|
493 | } |
---|
494 | } |
---|
495 | for (i = current; i < sectors; i++ ) { |
---|
496 | ret = write(fd, buf, DEFAULT_SECTOR_SIZE); |
---|
497 | if (ret != DEFAULT_SECTOR_SIZE) { |
---|
498 | DPRINTF("write failed: ret = %d, err = %s\n", |
---|
499 | ret, strerror(errno)); |
---|
500 | free(buf); |
---|
501 | return -1; |
---|
502 | } |
---|
503 | } |
---|
504 | free(buf); |
---|
505 | } else if(sparse && (st.st_size > sectors * DEFAULT_SECTOR_SIZE)) |
---|
506 | if (ftruncate(fd, (off_t)sectors * DEFAULT_SECTOR_SIZE)==-1) { |
---|
507 | DPRINTF("Ftruncate failed (%s)\n", strerror(errno)); |
---|
508 | return -1; |
---|
509 | } |
---|
510 | return 0; |
---|
511 | } |
---|
512 | |
---|
513 | |
---|
514 | /* 'allocate' is: |
---|
515 | * |
---|
516 | * 0 to not allocate. |
---|
517 | * |
---|
518 | * 1 to allocate a normal cluster (for sector indexes 'n_start' to |
---|
519 | * 'n_end') |
---|
520 | * |
---|
521 | * 2 to allocate a compressed cluster of size |
---|
522 | * 'compressed_size'. 'compressed_size' must be > 0 and < |
---|
523 | * cluster_size |
---|
524 | * |
---|
525 | * return 0 if not allocated. |
---|
526 | */ |
---|
527 | static uint64_t get_cluster_offset(struct tdqcow_state *s, |
---|
528 | uint64_t offset, int allocate, |
---|
529 | int compressed_size, |
---|
530 | int n_start, int n_end) |
---|
531 | { |
---|
532 | int min_index, i, j, l1_index, l2_index, l2_sector, l1_sector; |
---|
533 | char *tmp_ptr, *tmp_ptr2, *l2_ptr, *l1_ptr; |
---|
534 | uint64_t l2_offset, *l2_table, cluster_offset, tmp; |
---|
535 | uint32_t min_count; |
---|
536 | int new_l2_table; |
---|
537 | |
---|
538 | /*Check L1 table for the extent offset*/ |
---|
539 | l1_index = offset >> (s->l2_bits + s->cluster_bits); |
---|
540 | l2_offset = s->l1_table[l1_index]; |
---|
541 | new_l2_table = 0; |
---|
542 | if (!l2_offset) { |
---|
543 | if (!allocate) |
---|
544 | return 0; |
---|
545 | /* |
---|
546 | * allocating a new l2 entry + extent |
---|
547 | * at the end of the file, we must also |
---|
548 | * update the L1 entry safely. |
---|
549 | */ |
---|
550 | l2_offset = s->fd_end; |
---|
551 | |
---|
552 | /* round to cluster size */ |
---|
553 | l2_offset = (l2_offset + s->cluster_size - 1) |
---|
554 | & ~(s->cluster_size - 1); |
---|
555 | |
---|
556 | /* update the L1 entry */ |
---|
557 | s->l1_table[l1_index] = l2_offset; |
---|
558 | tmp = cpu_to_be64(l2_offset); |
---|
559 | |
---|
560 | /*Truncate file for L2 table |
---|
561 | *(initialised to zero in case we crash)*/ |
---|
562 | if (qtruncate(s->fd, |
---|
563 | l2_offset + (s->l2_size * sizeof(uint64_t)), |
---|
564 | s->sparse) != 0) { |
---|
565 | DPRINTF("ERROR truncating file\n"); |
---|
566 | return 0; |
---|
567 | } |
---|
568 | s->fd_end = l2_offset + (s->l2_size * sizeof(uint64_t)); |
---|
569 | |
---|
570 | /*Update the L1 table entry on disk |
---|
571 | * (for O_DIRECT we write 4KByte blocks)*/ |
---|
572 | l1_sector = (l1_index * sizeof(uint64_t)) >> 12; |
---|
573 | l1_ptr = (char *)s->l1_table + (l1_sector << 12); |
---|
574 | |
---|
575 | if (posix_memalign((void **)&tmp_ptr, 4096, 4096) != 0) { |
---|
576 | DPRINTF("ERROR allocating memory for L1 table\n"); |
---|
577 | } |
---|
578 | memcpy(tmp_ptr, l1_ptr, 4096); |
---|
579 | |
---|
580 | /* |
---|
581 | * Issue non-asynchronous L1 write. |
---|
582 | * For safety, we must ensure that |
---|
583 | * entry is written before blocks. |
---|
584 | */ |
---|
585 | lseek(s->fd, s->l1_table_offset + (l1_sector << 12), SEEK_SET); |
---|
586 | if (write(s->fd, tmp_ptr, 4096) != 4096) { |
---|
587 | free(tmp_ptr); |
---|
588 | return 0; |
---|
589 | } |
---|
590 | free(tmp_ptr); |
---|
591 | |
---|
592 | new_l2_table = 1; |
---|
593 | goto cache_miss; |
---|
594 | } else if (s->min_cluster_alloc == s->l2_size) { |
---|
595 | /*Fast-track the request*/ |
---|
596 | cluster_offset = l2_offset + (s->l2_size * sizeof(uint64_t)); |
---|
597 | l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); |
---|
598 | return cluster_offset + (l2_index * s->cluster_size); |
---|
599 | } |
---|
600 | |
---|
601 | /*Check to see if L2 entry is already cached*/ |
---|
602 | for (i = 0; i < L2_CACHE_SIZE; i++) { |
---|
603 | if (l2_offset == s->l2_cache_offsets[i]) { |
---|
604 | /* increment the hit count */ |
---|
605 | if (++s->l2_cache_counts[i] == 0xffffffff) { |
---|
606 | for (j = 0; j < L2_CACHE_SIZE; j++) { |
---|
607 | s->l2_cache_counts[j] >>= 1; |
---|
608 | } |
---|
609 | } |
---|
610 | l2_table = s->l2_cache + (i << s->l2_bits); |
---|
611 | goto found; |
---|
612 | } |
---|
613 | } |
---|
614 | |
---|
615 | cache_miss: |
---|
616 | /* not found: load a new entry in the least used one */ |
---|
617 | min_index = 0; |
---|
618 | min_count = 0xffffffff; |
---|
619 | for (i = 0; i < L2_CACHE_SIZE; i++) { |
---|
620 | if (s->l2_cache_counts[i] < min_count) { |
---|
621 | min_count = s->l2_cache_counts[i]; |
---|
622 | min_index = i; |
---|
623 | } |
---|
624 | } |
---|
625 | l2_table = s->l2_cache + (min_index << s->l2_bits); |
---|
626 | |
---|
627 | /*If extent pre-allocated, read table from disk, |
---|
628 | *otherwise write new table to disk*/ |
---|
629 | if (new_l2_table) { |
---|
630 | /*Should we allocate the whole extent? Adjustable parameter.*/ |
---|
631 | if (s->cluster_alloc == s->l2_size) { |
---|
632 | cluster_offset = l2_offset + |
---|
633 | (s->l2_size * sizeof(uint64_t)); |
---|
634 | cluster_offset = (cluster_offset + s->cluster_size - 1) |
---|
635 | & ~(s->cluster_size - 1); |
---|
636 | if (qtruncate(s->fd, cluster_offset + |
---|
637 | (s->cluster_size * s->l2_size), |
---|
638 | s->sparse) != 0) { |
---|
639 | DPRINTF("ERROR truncating file\n"); |
---|
640 | return 0; |
---|
641 | } |
---|
642 | s->fd_end = cluster_offset + |
---|
643 | (s->cluster_size * s->l2_size); |
---|
644 | for (i = 0; i < s->l2_size; i++) { |
---|
645 | l2_table[i] = cpu_to_be64(cluster_offset + |
---|
646 | (i*s->cluster_size)); |
---|
647 | } |
---|
648 | } else memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); |
---|
649 | |
---|
650 | lseek(s->fd, l2_offset, SEEK_SET); |
---|
651 | if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != |
---|
652 | s->l2_size * sizeof(uint64_t)) |
---|
653 | return 0; |
---|
654 | } else { |
---|
655 | lseek(s->fd, l2_offset, SEEK_SET); |
---|
656 | if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != |
---|
657 | s->l2_size * sizeof(uint64_t)) |
---|
658 | return 0; |
---|
659 | } |
---|
660 | |
---|
661 | /*Update the cache entries*/ |
---|
662 | s->l2_cache_offsets[min_index] = l2_offset; |
---|
663 | s->l2_cache_counts[min_index] = 1; |
---|
664 | |
---|
665 | found: |
---|
666 | /*The extent is split into 's->l2_size' blocks of |
---|
667 | *size 's->cluster_size'*/ |
---|
668 | l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); |
---|
669 | cluster_offset = be64_to_cpu(l2_table[l2_index]); |
---|
670 | |
---|
671 | if (!cluster_offset || |
---|
672 | ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1) ) { |
---|
673 | if (!allocate) |
---|
674 | return 0; |
---|
675 | |
---|
676 | if ((cluster_offset & QCOW_OFLAG_COMPRESSED) && |
---|
677 | (n_end - n_start) < s->cluster_sectors) { |
---|
678 | /* cluster is already allocated but compressed, we must |
---|
679 | decompress it in the case it is not completely |
---|
680 | overwritten */ |
---|
681 | if (decompress_cluster(s, cluster_offset) < 0) |
---|
682 | return 0; |
---|
683 | cluster_offset = lseek(s->fd, s->fd_end, SEEK_SET); |
---|
684 | cluster_offset = (cluster_offset + s->cluster_size - 1) |
---|
685 | & ~(s->cluster_size - 1); |
---|
686 | /* write the cluster content - not asynchronous */ |
---|
687 | lseek(s->fd, cluster_offset, SEEK_SET); |
---|
688 | if (write(s->fd, s->cluster_cache, s->cluster_size) != |
---|
689 | s->cluster_size) |
---|
690 | return -1; |
---|
691 | } else { |
---|
692 | /* allocate a new cluster */ |
---|
693 | cluster_offset = lseek(s->fd, s->fd_end, SEEK_SET); |
---|
694 | if (allocate == 1) { |
---|
695 | /* round to cluster size */ |
---|
696 | cluster_offset = |
---|
697 | (cluster_offset + s->cluster_size - 1) |
---|
698 | & ~(s->cluster_size - 1); |
---|
699 | if (qtruncate(s->fd, cluster_offset + |
---|
700 | s->cluster_size, s->sparse)!=0) { |
---|
701 | DPRINTF("ERROR truncating file\n"); |
---|
702 | return 0; |
---|
703 | } |
---|
704 | s->fd_end = (cluster_offset + s->cluster_size); |
---|
705 | /* if encrypted, we must initialize the cluster |
---|
706 | content which won't be written */ |
---|
707 | if (s->crypt_method && |
---|
708 | (n_end - n_start) < s->cluster_sectors) { |
---|
709 | uint64_t start_sect; |
---|
710 | start_sect = (offset & |
---|
711 | ~(s->cluster_size - 1)) |
---|
712 | >> 9; |
---|
713 | memset(s->cluster_data + 512, |
---|
714 | 0xaa, 512); |
---|
715 | for (i = 0; i < s->cluster_sectors;i++) |
---|
716 | { |
---|
717 | if (i < n_start || i >= n_end) |
---|
718 | { |
---|
719 | encrypt_sectors(s, start_sect + i, |
---|
720 | s->cluster_data, |
---|
721 | s->cluster_data + 512, 1, 1, |
---|
722 | &s->aes_encrypt_key); |
---|
723 | lseek(s->fd, cluster_offset + i * 512, SEEK_SET); |
---|
724 | if (write(s->fd, s->cluster_data, 512) != 512) |
---|
725 | return -1; |
---|
726 | } |
---|
727 | } |
---|
728 | } |
---|
729 | } else { |
---|
730 | cluster_offset |= QCOW_OFLAG_COMPRESSED | |
---|
731 | (uint64_t)compressed_size |
---|
732 | << (63 - s->cluster_bits); |
---|
733 | } |
---|
734 | } |
---|
735 | /* update L2 table */ |
---|
736 | tmp = cpu_to_be64(cluster_offset); |
---|
737 | l2_table[l2_index] = tmp; |
---|
738 | |
---|
739 | /*For IO_DIRECT we write 4KByte blocks*/ |
---|
740 | l2_sector = (l2_index * sizeof(uint64_t)) >> 12; |
---|
741 | l2_ptr = (char *)l2_table + (l2_sector << 12); |
---|
742 | |
---|
743 | if (posix_memalign((void **)&tmp_ptr2, 4096, 4096) != 0) { |
---|
744 | DPRINTF("ERROR allocating memory for L1 table\n"); |
---|
745 | } |
---|
746 | memcpy(tmp_ptr2, l2_ptr, 4096); |
---|
747 | lseek(s->fd, l2_offset + (l2_sector << 12), SEEK_SET); |
---|
748 | write(s->fd, tmp_ptr2, 4096); |
---|
749 | free(tmp_ptr2); |
---|
750 | } |
---|
751 | return cluster_offset; |
---|
752 | } |
---|
753 | |
---|
754 | static void init_cluster_cache(struct disk_driver *dd) |
---|
755 | { |
---|
756 | struct td_state *bs = dd->td_state; |
---|
757 | struct tdqcow_state *s = (struct tdqcow_state *)dd->private; |
---|
758 | uint32_t count = 0; |
---|
759 | int i, cluster_entries; |
---|
760 | |
---|
761 | cluster_entries = s->cluster_size / 512; |
---|
762 | DPRINTF("Initialising Cluster cache, %d sectors per cluster (%d cluster size)\n", |
---|
763 | cluster_entries, s->cluster_size); |
---|
764 | |
---|
765 | for (i = 0; i < bs->size; i += cluster_entries) { |
---|
766 | if (get_cluster_offset(s, i << 9, 0, 0, 0, 1)) count++; |
---|
767 | if (count >= L2_CACHE_SIZE) return; |
---|
768 | } |
---|
769 | DPRINTF("Finished cluster initialisation, added %d entries\n", count); |
---|
770 | return; |
---|
771 | } |
---|
772 | |
---|
773 | static int qcow_is_allocated(struct tdqcow_state *s, int64_t sector_num, |
---|
774 | int nb_sectors, int *pnum) |
---|
775 | { |
---|
776 | int index_in_cluster, n; |
---|
777 | uint64_t cluster_offset; |
---|
778 | |
---|
779 | cluster_offset = get_cluster_offset(s, sector_num << 9, 0, 0, 0, 0); |
---|
780 | index_in_cluster = sector_num & (s->cluster_sectors - 1); |
---|
781 | n = s->cluster_sectors - index_in_cluster; |
---|
782 | if (n > nb_sectors) |
---|
783 | n = nb_sectors; |
---|
784 | *pnum = n; |
---|
785 | return (cluster_offset != 0); |
---|
786 | } |
---|
787 | |
---|
788 | static int decompress_buffer(uint8_t *out_buf, int out_buf_size, |
---|
789 | const uint8_t *buf, int buf_size) |
---|
790 | { |
---|
791 | z_stream strm1, *strm = &strm1; |
---|
792 | int ret, out_len; |
---|
793 | |
---|
794 | memset(strm, 0, sizeof(*strm)); |
---|
795 | |
---|
796 | strm->next_in = (uint8_t *)buf; |
---|
797 | strm->avail_in = buf_size; |
---|
798 | strm->next_out = out_buf; |
---|
799 | strm->avail_out = out_buf_size; |
---|
800 | |
---|
801 | ret = inflateInit2(strm, -12); |
---|
802 | if (ret != Z_OK) |
---|
803 | return -1; |
---|
804 | ret = inflate(strm, Z_FINISH); |
---|
805 | out_len = strm->next_out - out_buf; |
---|
806 | if ( (ret != Z_STREAM_END && ret != Z_BUF_ERROR) || |
---|
807 | (out_len != out_buf_size) ) { |
---|
808 | inflateEnd(strm); |
---|
809 | return -1; |
---|
810 | } |
---|
811 | inflateEnd(strm); |
---|
812 | return 0; |
---|
813 | } |
---|
814 | |
---|
815 | static int decompress_cluster(struct tdqcow_state *s, uint64_t cluster_offset) |
---|
816 | { |
---|
817 | int ret, csize; |
---|
818 | uint64_t coffset; |
---|
819 | |
---|
820 | coffset = cluster_offset & s->cluster_offset_mask; |
---|
821 | if (s->cluster_cache_offset != coffset) { |
---|
822 | csize = cluster_offset >> (63 - s->cluster_bits); |
---|
823 | csize &= (s->cluster_size - 1); |
---|
824 | lseek(s->fd, coffset, SEEK_SET); |
---|
825 | ret = read(s->fd, s->cluster_data, csize); |
---|
826 | if (ret != csize) |
---|
827 | return -1; |
---|
828 | if (decompress_buffer(s->cluster_cache, s->cluster_size, |
---|
829 | s->cluster_data, csize) < 0) { |
---|
830 | return -1; |
---|
831 | } |
---|
832 | s->cluster_cache_offset = coffset; |
---|
833 | } |
---|
834 | return 0; |
---|
835 | } |
---|
836 | |
---|
837 | static inline void init_fds(struct disk_driver *dd) |
---|
838 | { |
---|
839 | int i; |
---|
840 | struct tdqcow_state *s = (struct tdqcow_state *)dd->private; |
---|
841 | |
---|
842 | for(i = 0; i < MAX_IOFD; i++) |
---|
843 | dd->io_fd[i] = 0; |
---|
844 | |
---|
845 | dd->io_fd[0] = s->poll_fd; |
---|
846 | } |
---|
847 | |
---|
848 | /* Open the disk file and initialize qcow state. */ |
---|
849 | int tdqcow_open (struct disk_driver *dd, const char *name, td_flag_t flags) |
---|
850 | { |
---|
851 | int fd, len, i, shift, ret, size, l1_table_size, o_flags; |
---|
852 | struct td_state *bs = dd->td_state; |
---|
853 | struct tdqcow_state *s = (struct tdqcow_state *)dd->private; |
---|
854 | char *buf; |
---|
855 | QCowHeader *header; |
---|
856 | QCowHeader_ext *exthdr; |
---|
857 | uint32_t cksum; |
---|
858 | uint64_t final_cluster = 0; |
---|
859 | |
---|
860 | DPRINTF("QCOW: Opening %s\n",name); |
---|
861 | |
---|
862 | o_flags = O_DIRECT | O_LARGEFILE | |
---|
863 | ((flags == TD_RDONLY) ? O_RDONLY : O_RDWR); |
---|
864 | fd = open(name, o_flags); |
---|
865 | if (fd < 0) { |
---|
866 | DPRINTF("Unable to open %s (%d)\n",name,0 - errno); |
---|
867 | return -1; |
---|
868 | } |
---|
869 | |
---|
870 | s->fd = fd; |
---|
871 | asprintf(&s->name,"%s", name); |
---|
872 | |
---|
873 | ASSERT(sizeof(QCowHeader) + sizeof(QCowHeader_ext) < 512); |
---|
874 | |
---|
875 | ret = posix_memalign((void **)&buf, 512, 512); |
---|
876 | if (ret != 0) goto fail; |
---|
877 | |
---|
878 | if (read(fd, buf, 512) != 512) |
---|
879 | goto fail; |
---|
880 | |
---|
881 | header = (QCowHeader *)buf; |
---|
882 | be32_to_cpus(&header->magic); |
---|
883 | be32_to_cpus(&header->version); |
---|
884 | be64_to_cpus(&header->backing_file_offset); |
---|
885 | be32_to_cpus(&header->backing_file_size); |
---|
886 | be32_to_cpus(&header->mtime); |
---|
887 | be64_to_cpus(&header->size); |
---|
888 | be32_to_cpus(&header->crypt_method); |
---|
889 | be64_to_cpus(&header->l1_table_offset); |
---|
890 | |
---|
891 | if (header->magic != QCOW_MAGIC || header->version > QCOW_VERSION) |
---|
892 | goto fail; |
---|
893 | if (header->size <= 1 || header->cluster_bits < 9) |
---|
894 | goto fail; |
---|
895 | if (header->crypt_method > QCOW_CRYPT_AES) |
---|
896 | goto fail; |
---|
897 | s->crypt_method_header = header->crypt_method; |
---|
898 | if (s->crypt_method_header) |
---|
899 | s->encrypted = 1; |
---|
900 | s->cluster_bits = header->cluster_bits; |
---|
901 | s->cluster_size = 1 << s->cluster_bits; |
---|
902 | s->cluster_sectors = 1 << (s->cluster_bits - 9); |
---|
903 | s->l2_bits = header->l2_bits; |
---|
904 | s->l2_size = 1 << s->l2_bits; |
---|
905 | s->cluster_alloc = s->l2_size; |
---|
906 | bs->size = header->size / 512; |
---|
907 | s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1; |
---|
908 | s->backing_file_offset = header->backing_file_offset; |
---|
909 | s->backing_file_size = header->backing_file_size; |
---|
910 | |
---|
911 | /* read the level 1 table */ |
---|
912 | shift = s->cluster_bits + s->l2_bits; |
---|
913 | s->l1_size = (header->size + (1LL << shift) - 1) >> shift; |
---|
914 | |
---|
915 | s->l1_table_offset = header->l1_table_offset; |
---|
916 | |
---|
917 | /*allocate a 4Kbyte multiple of memory*/ |
---|
918 | l1_table_size = s->l1_size * sizeof(uint64_t); |
---|
919 | if (l1_table_size % 4096 > 0) { |
---|
920 | l1_table_size = ((l1_table_size >> 12) + 1) << 12; |
---|
921 | } |
---|
922 | ret = posix_memalign((void **)&s->l1_table, 4096, l1_table_size); |
---|
923 | if (ret != 0) goto fail; |
---|
924 | |
---|
925 | memset(s->l1_table, 0x00, l1_table_size); |
---|
926 | |
---|
927 | DPRINTF("L1 Table offset detected: %llu, size %d (%d)\n", |
---|
928 | (long long)s->l1_table_offset, |
---|
929 | (int) (s->l1_size * sizeof(uint64_t)), |
---|
930 | l1_table_size); |
---|
931 | |
---|
932 | lseek(fd, s->l1_table_offset, SEEK_SET); |
---|
933 | if (read(fd, s->l1_table, l1_table_size) != l1_table_size) |
---|
934 | goto fail; |
---|
935 | |
---|
936 | for(i = 0; i < s->l1_size; i++) { |
---|
937 | //be64_to_cpus(&s->l1_table[i]); |
---|
938 | //DPRINTF("L1[%d] => %llu\n", i, s->l1_table[i]); |
---|
939 | if (s->l1_table[i] > final_cluster) |
---|
940 | final_cluster = s->l1_table[i]; |
---|
941 | } |
---|
942 | |
---|
943 | /* alloc L2 cache */ |
---|
944 | size = s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t); |
---|
945 | ret = posix_memalign((void **)&s->l2_cache, 4096, size); |
---|
946 | if(ret != 0) goto fail; |
---|
947 | |
---|
948 | size = s->cluster_size; |
---|
949 | ret = posix_memalign((void **)&s->cluster_cache, 4096, size); |
---|
950 | if(ret != 0) goto fail; |
---|
951 | |
---|
952 | ret = posix_memalign((void **)&s->cluster_data, 4096, size); |
---|
953 | if(ret != 0) goto fail; |
---|
954 | s->cluster_cache_offset = -1; |
---|
955 | |
---|
956 | if (s->backing_file_offset != 0) |
---|
957 | s->cluster_alloc = 1; /*Cannot use pre-alloc*/ |
---|
958 | |
---|
959 | bs->sector_size = 512; |
---|
960 | bs->info = 0; |
---|
961 | |
---|
962 | /*Detect min_cluster_alloc*/ |
---|
963 | s->min_cluster_alloc = 1; /*Default*/ |
---|
964 | if (s->backing_file_offset == 0 && s->l1_table_offset % 4096 == 0) { |
---|
965 | /*We test to see if the xen magic # exists*/ |
---|
966 | exthdr = (QCowHeader_ext *)(buf + sizeof(QCowHeader)); |
---|
967 | be32_to_cpus(&exthdr->xmagic); |
---|
968 | if(exthdr->xmagic != XEN_MAGIC) |
---|
969 | goto end_xenhdr; |
---|
970 | |
---|
971 | /*Finally check the L1 table cksum*/ |
---|
972 | be32_to_cpus(&exthdr->cksum); |
---|
973 | cksum = gen_cksum((char *)s->l1_table, |
---|
974 | s->l1_size * sizeof(uint64_t)); |
---|
975 | if(exthdr->cksum != cksum) |
---|
976 | goto end_xenhdr; |
---|
977 | |
---|
978 | be32_to_cpus(&exthdr->min_cluster_alloc); |
---|
979 | be32_to_cpus(&exthdr->flags); |
---|
980 | s->sparse = (exthdr->flags & SPARSE_FILE); |
---|
981 | s->min_cluster_alloc = exthdr->min_cluster_alloc; |
---|
982 | } |
---|
983 | |
---|
984 | end_xenhdr: |
---|
985 | if (init_aio_state(dd)!=0) { |
---|
986 | DPRINTF("Unable to initialise AIO state\n"); |
---|
987 | free_aio_state(dd); |
---|
988 | goto fail; |
---|
989 | } |
---|
990 | init_fds(dd); |
---|
991 | |
---|
992 | if (!final_cluster) |
---|
993 | s->fd_end = s->l1_table_offset + l1_table_size; |
---|
994 | else { |
---|
995 | s->fd_end = lseek64(fd, 0, SEEK_END); |
---|
996 | if (s->fd_end == (off64_t)-1) |
---|
997 | goto fail; |
---|
998 | } |
---|
999 | |
---|
1000 | return 0; |
---|
1001 | |
---|
1002 | fail: |
---|
1003 | DPRINTF("QCOW Open failed\n"); |
---|
1004 | free_aio_state(dd); |
---|
1005 | free(s->l1_table); |
---|
1006 | free(s->l2_cache); |
---|
1007 | free(s->cluster_cache); |
---|
1008 | free(s->cluster_data); |
---|
1009 | close(fd); |
---|
1010 | return -1; |
---|
1011 | } |
---|
1012 | |
---|
1013 | int tdqcow_queue_read(struct disk_driver *dd, uint64_t sector, |
---|
1014 | int nb_sectors, char *buf, td_callback_t cb, |
---|
1015 | int id, void *private) |
---|
1016 | { |
---|
1017 | struct tdqcow_state *s = (struct tdqcow_state *)dd->private; |
---|
1018 | int ret = 0, index_in_cluster, n, i, rsp = 0; |
---|
1019 | uint64_t cluster_offset, sec, nr_secs; |
---|
1020 | |
---|
1021 | sec = sector; |
---|
1022 | nr_secs = nb_sectors; |
---|
1023 | |
---|
1024 | /*Check we can get a lock*/ |
---|
1025 | for (i = 0; i < nb_sectors; i++) |
---|
1026 | if (!aio_can_lock(s, sector + i)) |
---|
1027 | return cb(dd, -EBUSY, sector, nb_sectors, id, private); |
---|
1028 | |
---|
1029 | /*We store a local record of the request*/ |
---|
1030 | while (nb_sectors > 0) { |
---|
1031 | cluster_offset = |
---|
1032 | get_cluster_offset(s, sector << 9, 0, 0, 0, 0); |
---|
1033 | index_in_cluster = sector & (s->cluster_sectors - 1); |
---|
1034 | n = s->cluster_sectors - index_in_cluster; |
---|
1035 | if (n > nb_sectors) |
---|
1036 | n = nb_sectors; |
---|
1037 | |
---|
1038 | if (s->iocb_free_count == 0 || !aio_lock(s, sector)) |
---|
1039 | return cb(dd, -EBUSY, sector, nb_sectors, id, private); |
---|
1040 | |
---|
1041 | if(!cluster_offset) { |
---|
1042 | aio_unlock(s, sector); |
---|
1043 | ret = cb(dd, BLK_NOT_ALLOCATED, |
---|
1044 | sector, n, id, private); |
---|
1045 | if (ret == -EBUSY) { |
---|
1046 | /* mark remainder of request |
---|
1047 | * as busy and try again later */ |
---|
1048 | return cb(dd, -EBUSY, sector + n, |
---|
1049 | nb_sectors - n, id, private); |
---|
1050 | } else |
---|
1051 | rsp += ret; |
---|
1052 | } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { |
---|
1053 | aio_unlock(s, sector); |
---|
1054 | if (decompress_cluster(s, cluster_offset) < 0) { |
---|
1055 | rsp += cb(dd, -EIO, sector, |
---|
1056 | nb_sectors, id, private); |
---|
1057 | goto done; |
---|
1058 | } |
---|
1059 | memcpy(buf, s->cluster_cache + index_in_cluster * 512, |
---|
1060 | 512 * n); |
---|
1061 | rsp += cb(dd, 0, sector, n, id, private); |
---|
1062 | } else { |
---|
1063 | async_read(s, n * 512, |
---|
1064 | (cluster_offset + index_in_cluster * 512), |
---|
1065 | buf, cb, id, sector, private); |
---|
1066 | } |
---|
1067 | nb_sectors -= n; |
---|
1068 | sector += n; |
---|
1069 | buf += n * 512; |
---|
1070 | } |
---|
1071 | done: |
---|
1072 | return rsp; |
---|
1073 | } |
---|
1074 | |
---|
1075 | int tdqcow_queue_write(struct disk_driver *dd, uint64_t sector, |
---|
1076 | int nb_sectors, char *buf, td_callback_t cb, |
---|
1077 | int id, void *private) |
---|
1078 | { |
---|
1079 | struct tdqcow_state *s = (struct tdqcow_state *)dd->private; |
---|
1080 | int ret = 0, index_in_cluster, n, i; |
---|
1081 | uint64_t cluster_offset, sec, nr_secs; |
---|
1082 | |
---|
1083 | sec = sector; |
---|
1084 | nr_secs = nb_sectors; |
---|
1085 | |
---|
1086 | /*Check we can get a lock*/ |
---|
1087 | for (i = 0; i < nb_sectors; i++) |
---|
1088 | if (!aio_can_lock(s, sector + i)) |
---|
1089 | return cb(dd, -EBUSY, sector, nb_sectors, id, private); |
---|
1090 | |
---|
1091 | /*We store a local record of the request*/ |
---|
1092 | while (nb_sectors > 0) { |
---|
1093 | index_in_cluster = sector & (s->cluster_sectors - 1); |
---|
1094 | n = s->cluster_sectors - index_in_cluster; |
---|
1095 | if (n > nb_sectors) |
---|
1096 | n = nb_sectors; |
---|
1097 | |
---|
1098 | if (s->iocb_free_count == 0 || !aio_lock(s, sector)) |
---|
1099 | return cb(dd, -EBUSY, sector, nb_sectors, id, private); |
---|
1100 | |
---|
1101 | cluster_offset = get_cluster_offset(s, sector << 9, 1, 0, |
---|
1102 | index_in_cluster, |
---|
1103 | index_in_cluster+n); |
---|
1104 | if (!cluster_offset) { |
---|
1105 | DPRINTF("Ooops, no write cluster offset!\n"); |
---|
1106 | aio_unlock(s, sector); |
---|
1107 | return cb(dd, -EIO, sector, nb_sectors, id, private); |
---|
1108 | } |
---|
1109 | |
---|
1110 | if (s->crypt_method) { |
---|
1111 | encrypt_sectors(s, sector, s->cluster_data, |
---|
1112 | (unsigned char *)buf, n, 1, |
---|
1113 | &s->aes_encrypt_key); |
---|
1114 | async_write(s, n * 512, |
---|
1115 | (cluster_offset + index_in_cluster*512), |
---|
1116 | (char *)s->cluster_data, cb, id, sector, |
---|
1117 | private); |
---|
1118 | } else { |
---|
1119 | async_write(s, n * 512, |
---|
1120 | (cluster_offset + index_in_cluster*512), |
---|
1121 | buf, cb, id, sector, private); |
---|
1122 | } |
---|
1123 | |
---|
1124 | nb_sectors -= n; |
---|
1125 | sector += n; |
---|
1126 | buf += n * 512; |
---|
1127 | } |
---|
1128 | s->cluster_cache_offset = -1; /* disable compressed cache */ |
---|
1129 | |
---|
1130 | return 0; |
---|
1131 | } |
---|
1132 | |
---|
1133 | int tdqcow_submit(struct disk_driver *dd) |
---|
1134 | { |
---|
1135 | int ret; |
---|
1136 | struct tdqcow_state *prv = (struct tdqcow_state *)dd->private; |
---|
1137 | |
---|
1138 | if (!prv->iocb_queued) |
---|
1139 | return 0; |
---|
1140 | |
---|
1141 | ret = io_submit(prv->aio_ctx, prv->iocb_queued, prv->iocb_queue); |
---|
1142 | |
---|
1143 | /* XXX: TODO: Handle error conditions here. */ |
---|
1144 | |
---|
1145 | /* Success case: */ |
---|
1146 | prv->iocb_queued = 0; |
---|
1147 | |
---|
1148 | return 0; |
---|
1149 | } |
---|
1150 | |
---|
1151 | int tdqcow_close(struct disk_driver *dd) |
---|
1152 | { |
---|
1153 | struct tdqcow_state *s = (struct tdqcow_state *)dd->private; |
---|
1154 | uint32_t cksum, out; |
---|
1155 | int fd, offset; |
---|
1156 | |
---|
1157 | /*Update the hdr cksum*/ |
---|
1158 | if(s->min_cluster_alloc == s->l2_size) { |
---|
1159 | cksum = gen_cksum((char *)s->l1_table, s->l1_size * sizeof(uint64_t)); |
---|
1160 | printf("Writing cksum: %d",cksum); |
---|
1161 | fd = open(s->name, O_WRONLY | O_LARGEFILE); /*Open without O_DIRECT*/ |
---|
1162 | offset = sizeof(QCowHeader) + sizeof(uint32_t); |
---|
1163 | lseek(fd, offset, SEEK_SET); |
---|
1164 | out = cpu_to_be32(cksum); |
---|
1165 | write(fd, &out, sizeof(uint32_t)); |
---|
1166 | close(fd); |
---|
1167 | } |
---|
1168 | |
---|
1169 | io_destroy(s->aio_ctx); |
---|
1170 | free(s->name); |
---|
1171 | free(s->l1_table); |
---|
1172 | free(s->l2_cache); |
---|
1173 | free(s->cluster_cache); |
---|
1174 | free(s->cluster_data); |
---|
1175 | close(s->fd); |
---|
1176 | return 0; |
---|
1177 | } |
---|
1178 | |
---|
1179 | int tdqcow_do_callbacks(struct disk_driver *dd, int sid) |
---|
1180 | { |
---|
1181 | int ret, i, rsp = 0,*ptr; |
---|
1182 | struct io_event *ep; |
---|
1183 | struct tdqcow_state *prv = (struct tdqcow_state *)dd->private; |
---|
1184 | |
---|
1185 | if (sid > MAX_IOFD) return 1; |
---|
1186 | |
---|
1187 | /* Non-blocking test for completed io. */ |
---|
1188 | ret = io_getevents(prv->aio_ctx, 0, prv->max_aio_reqs, prv->aio_events, |
---|
1189 | NULL); |
---|
1190 | |
---|
1191 | for (ep = prv->aio_events, i = ret; i-- > 0; ep++) { |
---|
1192 | struct iocb *io = ep->obj; |
---|
1193 | struct pending_aio *pio; |
---|
1194 | |
---|
1195 | pio = &prv->pending_aio[(long)io->data]; |
---|
1196 | |
---|
1197 | aio_unlock(prv, pio->sector); |
---|
1198 | |
---|
1199 | if (prv->crypt_method) |
---|
1200 | encrypt_sectors(prv, pio->sector, |
---|
1201 | (unsigned char *)pio->buf, |
---|
1202 | (unsigned char *)pio->buf, |
---|
1203 | pio->nb_sectors, 0, |
---|
1204 | &prv->aes_decrypt_key); |
---|
1205 | |
---|
1206 | rsp += pio->cb(dd, ep->res == io->u.c.nbytes ? 0 : 1, |
---|
1207 | pio->sector, pio->nb_sectors, |
---|
1208 | pio->id, pio->private); |
---|
1209 | |
---|
1210 | prv->iocb_free[prv->iocb_free_count++] = io; |
---|
1211 | } |
---|
1212 | return rsp; |
---|
1213 | } |
---|
1214 | |
---|
1215 | int qcow_create(const char *filename, uint64_t total_size, |
---|
1216 | const char *backing_file, int sparse) |
---|
1217 | { |
---|
1218 | int fd, header_size, backing_filename_len, l1_size, i; |
---|
1219 | int shift, length, adjust, flags = 0, ret = 0; |
---|
1220 | QCowHeader header; |
---|
1221 | QCowHeader_ext exthdr; |
---|
1222 | char backing_filename[1024], *ptr; |
---|
1223 | uint64_t tmp, size, total_length; |
---|
1224 | struct stat st; |
---|
1225 | |
---|
1226 | DPRINTF("Qcow_create: size %llu\n",(long long unsigned)total_size); |
---|
1227 | |
---|
1228 | fd = open(filename, |
---|
1229 | O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, |
---|
1230 | 0644); |
---|
1231 | if (fd < 0) |
---|
1232 | return -1; |
---|
1233 | |
---|
1234 | memset(&header, 0, sizeof(header)); |
---|
1235 | header.magic = cpu_to_be32(QCOW_MAGIC); |
---|
1236 | header.version = cpu_to_be32(QCOW_VERSION); |
---|
1237 | |
---|
1238 | /*Create extended header fields*/ |
---|
1239 | exthdr.xmagic = cpu_to_be32(XEN_MAGIC); |
---|
1240 | |
---|
1241 | header_size = sizeof(header) + sizeof(QCowHeader_ext); |
---|
1242 | backing_filename_len = 0; |
---|
1243 | size = (total_size >> SECTOR_SHIFT); |
---|
1244 | if (backing_file) { |
---|
1245 | if (strcmp(backing_file, "fat:")) { |
---|
1246 | const char *p; |
---|
1247 | /* XXX: this is a hack: we do not attempt to |
---|
1248 | *check for URL like syntax */ |
---|
1249 | p = strchr(backing_file, ':'); |
---|
1250 | if (p && (p - backing_file) >= 2) { |
---|
1251 | /* URL like but exclude "c:" like filenames */ |
---|
1252 | strncpy(backing_filename, backing_file, |
---|
1253 | sizeof(backing_filename)); |
---|
1254 | } else { |
---|
1255 | realpath(backing_file, backing_filename); |
---|
1256 | if (stat(backing_filename, &st) != 0) { |
---|
1257 | return -1; |
---|
1258 | } |
---|
1259 | } |
---|
1260 | header.backing_file_offset = cpu_to_be64(header_size); |
---|
1261 | backing_filename_len = strlen(backing_filename); |
---|
1262 | header.backing_file_size = cpu_to_be32( |
---|
1263 | backing_filename_len); |
---|
1264 | header_size += backing_filename_len; |
---|
1265 | |
---|
1266 | /*Set to the backing file size*/ |
---|
1267 | if(get_filesize(backing_filename, &size, &st)) { |
---|
1268 | return -1; |
---|
1269 | } |
---|
1270 | DPRINTF("Backing file size detected: %lld sectors" |
---|
1271 | "(total %lld [%lld MB])\n", |
---|
1272 | (long long)size, |
---|
1273 | (long long)(size << SECTOR_SHIFT), |
---|
1274 | (long long)(size >> 11)); |
---|
1275 | } else { |
---|
1276 | backing_file = NULL; |
---|
1277 | DPRINTF("Setting file size: %lld (total %lld)\n", |
---|
1278 | (long long) total_size, |
---|
1279 | (long long) (total_size << SECTOR_SHIFT)); |
---|
1280 | } |
---|
1281 | header.mtime = cpu_to_be32(st.st_mtime); |
---|
1282 | header.cluster_bits = 9; /* 512 byte cluster to avoid copying |
---|
1283 | unmodifyed sectors */ |
---|
1284 | header.l2_bits = 12; /* 32 KB L2 tables */ |
---|
1285 | exthdr.min_cluster_alloc = cpu_to_be32(1); |
---|
1286 | } else { |
---|
1287 | DPRINTF("Setting file size: %lld sectors" |
---|
1288 | "(total %lld [%lld MB])\n", |
---|
1289 | (long long) size, |
---|
1290 | (long long) (size << SECTOR_SHIFT), |
---|
1291 | (long long) (size >> 11)); |
---|
1292 | header.cluster_bits = 12; /* 4 KB clusters */ |
---|
1293 | header.l2_bits = 9; /* 4 KB L2 tables */ |
---|
1294 | exthdr.min_cluster_alloc = cpu_to_be32(1 << 9); |
---|
1295 | } |
---|
1296 | /*Set the header size value*/ |
---|
1297 | header.size = cpu_to_be64(size * 512); |
---|
1298 | |
---|
1299 | header_size = (header_size + 7) & ~7; |
---|
1300 | if (header_size % 4096 > 0) { |
---|
1301 | header_size = ((header_size >> 12) + 1) << 12; |
---|
1302 | } |
---|
1303 | |
---|
1304 | shift = header.cluster_bits + header.l2_bits; |
---|
1305 | l1_size = ((size * 512) + (1LL << shift) - 1) >> shift; |
---|
1306 | |
---|
1307 | header.l1_table_offset = cpu_to_be64(header_size); |
---|
1308 | DPRINTF("L1 Table offset: %d, size %d\n", |
---|
1309 | header_size, |
---|
1310 | (int)(l1_size * sizeof(uint64_t))); |
---|
1311 | header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); |
---|
1312 | |
---|
1313 | ptr = calloc(1, l1_size * sizeof(uint64_t)); |
---|
1314 | exthdr.cksum = cpu_to_be32(gen_cksum(ptr, l1_size * sizeof(uint64_t))); |
---|
1315 | printf("Created cksum: %d\n",exthdr.cksum); |
---|
1316 | free(ptr); |
---|
1317 | |
---|
1318 | /*adjust file length to system page size boundary*/ |
---|
1319 | length = ROUNDUP(header_size + (l1_size * sizeof(uint64_t)), |
---|
1320 | getpagesize()); |
---|
1321 | if (qtruncate(fd, length, 0)!=0) { |
---|
1322 | DPRINTF("ERROR truncating file\n"); |
---|
1323 | return -1; |
---|
1324 | } |
---|
1325 | |
---|
1326 | if (sparse == 0) { |
---|
1327 | /*Filesize is length+l1_size*(1 << s->l2_bits)+(size*512)*/ |
---|
1328 | total_length = length + (l1_size * (1 << 9)) + (size * 512); |
---|
1329 | if (qtruncate(fd, total_length, 0)!=0) { |
---|
1330 | DPRINTF("ERROR truncating file\n"); |
---|
1331 | return -1; |
---|
1332 | } |
---|
1333 | printf("File truncated to length %"PRIu64"\n",total_length); |
---|
1334 | } else |
---|
1335 | flags = SPARSE_FILE; |
---|
1336 | |
---|
1337 | exthdr.flags = cpu_to_be32(flags); |
---|
1338 | |
---|
1339 | /* write all the data */ |
---|
1340 | lseek(fd, 0, SEEK_SET); |
---|
1341 | ret += write(fd, &header, sizeof(header)); |
---|
1342 | ret += write(fd, &exthdr, sizeof(exthdr)); |
---|
1343 | if (backing_file) |
---|
1344 | ret += write(fd, backing_filename, backing_filename_len); |
---|
1345 | |
---|
1346 | lseek(fd, header_size, SEEK_SET); |
---|
1347 | tmp = 0; |
---|
1348 | for (i = 0;i < l1_size; i++) { |
---|
1349 | ret += write(fd, &tmp, sizeof(tmp)); |
---|
1350 | } |
---|
1351 | |
---|
1352 | close(fd); |
---|
1353 | |
---|
1354 | return 0; |
---|
1355 | } |
---|
1356 | |
---|
1357 | int qcow_make_empty(struct tdqcow_state *s) |
---|
1358 | { |
---|
1359 | uint32_t l1_length = s->l1_size * sizeof(uint64_t); |
---|
1360 | |
---|
1361 | memset(s->l1_table, 0, l1_length); |
---|
1362 | lseek(s->fd, s->l1_table_offset, SEEK_SET); |
---|
1363 | if (write(s->fd, s->l1_table, l1_length) < 0) |
---|
1364 | return -1; |
---|
1365 | if (qtruncate(s->fd, s->l1_table_offset + l1_length, s->sparse)!=0) { |
---|
1366 | DPRINTF("ERROR truncating file\n"); |
---|
1367 | return -1; |
---|
1368 | } |
---|
1369 | |
---|
1370 | memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); |
---|
1371 | memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t)); |
---|
1372 | memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t)); |
---|
1373 | |
---|
1374 | return 0; |
---|
1375 | } |
---|
1376 | |
---|
1377 | int qcow_get_cluster_size(struct tdqcow_state *s) |
---|
1378 | { |
---|
1379 | return s->cluster_size; |
---|
1380 | } |
---|
1381 | |
---|
1382 | /* XXX: put compressed sectors first, then all the cluster aligned |
---|
1383 | tables to avoid losing bytes in alignment */ |
---|
1384 | int qcow_compress_cluster(struct tdqcow_state *s, int64_t sector_num, |
---|
1385 | const uint8_t *buf) |
---|
1386 | { |
---|
1387 | z_stream strm; |
---|
1388 | int ret, out_len; |
---|
1389 | uint8_t *out_buf; |
---|
1390 | uint64_t cluster_offset; |
---|
1391 | |
---|
1392 | out_buf = malloc(s->cluster_size + (s->cluster_size / 1000) + 128); |
---|
1393 | if (!out_buf) |
---|
1394 | return -1; |
---|
1395 | |
---|
1396 | /* best compression, small window, no zlib header */ |
---|
1397 | memset(&strm, 0, sizeof(strm)); |
---|
1398 | ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, |
---|
1399 | Z_DEFLATED, -12, |
---|
1400 | 9, Z_DEFAULT_STRATEGY); |
---|
1401 | if (ret != 0) { |
---|
1402 | free(out_buf); |
---|
1403 | return -1; |
---|
1404 | } |
---|
1405 | |
---|
1406 | strm.avail_in = s->cluster_size; |
---|
1407 | strm.next_in = (uint8_t *)buf; |
---|
1408 | strm.avail_out = s->cluster_size; |
---|
1409 | strm.next_out = out_buf; |
---|
1410 | |
---|
1411 | ret = deflate(&strm, Z_FINISH); |
---|
1412 | if (ret != Z_STREAM_END && ret != Z_OK) { |
---|
1413 | free(out_buf); |
---|
1414 | deflateEnd(&strm); |
---|
1415 | return -1; |
---|
1416 | } |
---|
1417 | out_len = strm.next_out - out_buf; |
---|
1418 | |
---|
1419 | deflateEnd(&strm); |
---|
1420 | |
---|
1421 | if (ret != Z_STREAM_END || out_len >= s->cluster_size) { |
---|
1422 | /* could not compress: write normal cluster */ |
---|
1423 | //tdqcow_queue_write(bs, sector_num, buf, s->cluster_sectors); |
---|
1424 | } else { |
---|
1425 | cluster_offset = get_cluster_offset(s, sector_num << 9, 2, |
---|
1426 | out_len, 0, 0); |
---|
1427 | cluster_offset &= s->cluster_offset_mask; |
---|
1428 | lseek(s->fd, cluster_offset, SEEK_SET); |
---|
1429 | if (write(s->fd, out_buf, out_len) != out_len) { |
---|
1430 | free(out_buf); |
---|
1431 | return -1; |
---|
1432 | } |
---|
1433 | } |
---|
1434 | |
---|
1435 | free(out_buf); |
---|
1436 | return 0; |
---|
1437 | } |
---|
1438 | |
---|
1439 | int tdqcow_get_parent_id(struct disk_driver *dd, struct disk_id *id) |
---|
1440 | { |
---|
1441 | off_t off; |
---|
1442 | char *buf, *filename; |
---|
1443 | int len, secs, err = -EINVAL; |
---|
1444 | struct tdqcow_state *child = (struct tdqcow_state *)dd->private; |
---|
1445 | |
---|
1446 | if (!child->backing_file_offset) |
---|
1447 | return TD_NO_PARENT; |
---|
1448 | |
---|
1449 | /* read the backing file name */ |
---|
1450 | len = child->backing_file_size; |
---|
1451 | off = child->backing_file_offset - (child->backing_file_offset % 512); |
---|
1452 | secs = (len + (child->backing_file_offset - off) + 511) >> 9; |
---|
1453 | |
---|
1454 | if (posix_memalign((void **)&buf, 512, secs << 9)) |
---|
1455 | return -1; |
---|
1456 | |
---|
1457 | if (lseek(child->fd, off, SEEK_SET) == (off_t)-1) |
---|
1458 | goto out; |
---|
1459 | |
---|
1460 | if (read(child->fd, buf, secs << 9) != secs << 9) |
---|
1461 | goto out; |
---|
1462 | filename = buf + (child->backing_file_offset - off); |
---|
1463 | filename[len] = '\0'; |
---|
1464 | |
---|
1465 | id->name = strdup(filename); |
---|
1466 | id->drivertype = DISK_TYPE_QCOW; |
---|
1467 | err = 0; |
---|
1468 | out: |
---|
1469 | free(buf); |
---|
1470 | return err; |
---|
1471 | } |
---|
1472 | |
---|
1473 | int tdqcow_validate_parent(struct disk_driver *child, |
---|
1474 | struct disk_driver *parent, td_flag_t flags) |
---|
1475 | { |
---|
1476 | struct stat stats; |
---|
1477 | uint64_t psize, csize; |
---|
1478 | struct tdqcow_state *c = (struct tdqcow_state *)child->private; |
---|
1479 | struct tdqcow_state *p = (struct tdqcow_state *)parent->private; |
---|
1480 | |
---|
1481 | if (stat(p->name, &stats)) |
---|
1482 | return -EINVAL; |
---|
1483 | if (get_filesize(p->name, &psize, &stats)) |
---|
1484 | return -EINVAL; |
---|
1485 | |
---|
1486 | if (stat(c->name, &stats)) |
---|
1487 | return -EINVAL; |
---|
1488 | if (get_filesize(c->name, &csize, &stats)) |
---|
1489 | return -EINVAL; |
---|
1490 | |
---|
1491 | if (csize != psize) |
---|
1492 | return -EINVAL; |
---|
1493 | |
---|
1494 | return 0; |
---|
1495 | } |
---|
1496 | |
---|
1497 | struct tap_disk tapdisk_qcow = { |
---|
1498 | .disk_type = "tapdisk_qcow", |
---|
1499 | .private_data_size = sizeof(struct tdqcow_state), |
---|
1500 | .td_open = tdqcow_open, |
---|
1501 | .td_queue_read = tdqcow_queue_read, |
---|
1502 | .td_queue_write = tdqcow_queue_write, |
---|
1503 | .td_submit = tdqcow_submit, |
---|
1504 | .td_close = tdqcow_close, |
---|
1505 | .td_do_callbacks = tdqcow_do_callbacks, |
---|
1506 | .td_get_parent_id = tdqcow_get_parent_id, |
---|
1507 | .td_validate_parent = tdqcow_validate_parent |
---|
1508 | }; |
---|