Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : /*
32 : : * block-vhd.c: asynchronous vhd implementation.
33 : : *
34 : : * A note on write transactions:
35 : : * Writes that require updating the BAT or bitmaps cannot be signaled
36 : : * as complete until all updates have reached disk. Transactions are
37 : : * used to ensure proper ordering in these cases. The two types of
38 : : * transactions are as follows:
39 : : * - Bitmap updates only: data writes that require updates to the same
40 : : * bitmap are grouped in a transaction. Only after all data writes
41 : : * in a transaction complete does the bitmap write commence. Only
42 : : * after the bitmap write finishes are the data writes signalled as
43 : : * complete.
44 : : * - BAT and bitmap updates: data writes are grouped in transactions
45 : : * as above, but a special extra write is included in the transaction,
46 : : * which zeros out the newly allocated bitmap on disk. When the data
47 : : * writes and the zero-bitmap write complete, the BAT and bitmap writes
48 : : * are started in parallel. The transaction is completed only after both
49 : : * the BAT and bitmap writes successfully return.
50 : : */
51 : :
52 : : #ifdef HAVE_CONFIG_H
53 : : #include "config.h"
54 : : #endif
55 : :
56 : : #include <errno.h>
57 : : #include <fcntl.h>
58 : : #include <stdio.h>
59 : : #include <stdlib.h>
60 : : #include <unistd.h>
61 : : #include <sys/stat.h>
62 : : #include <sys/ioctl.h>
63 : : #include <uuid/uuid.h> /* For whatever reason, Linux packages this in */
64 : : /* e2fsprogs-devel. */
65 : : #include <string.h> /* for memset. */
66 : : #include <libaio.h>
67 : : #include <sys/mman.h>
68 : : #include <limits.h>
69 : : #include <dlfcn.h>
70 : :
71 : : #include "debug.h"
72 : : #include "libvhd.h"
73 : : #include "tapdisk.h"
74 : : #include "tapdisk-driver.h"
75 : : #include "tapdisk-interface.h"
76 : : #include "tapdisk-disktype.h"
77 : : #include "tapdisk-storage.h"
78 : : #include "block-crypto.h"
79 : :
80 : : unsigned int SPB;
81 : :
82 : : #define DEBUGGING 2
83 : : #define MICROSOFT_COMPAT
84 : :
85 : : #define VHD_BATMAP_MAX_RETRIES 10
86 : :
87 : : #define __TRACE(s) \
88 : : do { \
89 : : DBG(TLOG_DBG, "%s: QUEUED: %" PRIu64 ", COMPLETED: %" \
90 : : PRIu64", RETURNED: %" PRIu64 ", DATA_ALLOCATED: " \
91 : : "%u, BBLK: 0x%04x\n", \
92 : : s->vhd.file, s->queued, s->completed, s->returned, \
93 : : VHD_REQS_DATA - s->vreq_free_count, \
94 : : s->bat.pbw_blk); \
95 : : } while(0)
96 : :
97 : : #if (DEBUGGING == 1)
98 : : #define DBG(level, _f, _a...) DPRINTF(_f, ##_a)
99 : : #define ERR(_s, err, _f, _a...) DPRINTF("ERROR: %d: " _f, err, ##_a)
100 : : #define TRACE(s) ((void)0)
101 : : #elif (DEBUGGING == 2)
102 : : #define DBG(level, _f, _a...) tlog_write(level, _f, ##_a)
103 : : #define ERR(_s, _err, _f, _a...) tlog_drv_error((_s)->driver, _err, _f, ##_a)
104 : : #define TRACE(s) __TRACE(s)
105 : : #else
106 : : #define DBG(level, _f, _a...) ((void)0)
107 : : #define ERR(_s, err, _f, _a...) ((void)0)
108 : : #define TRACE(s) ((void)0)
109 : : #endif
110 : :
111 : : /******VHD DEFINES******/
112 : : #define VHD_CACHE_SIZE 32
113 : :
114 : : #define VHD_REQS_DATA TAPDISK_DATA_REQUESTS
115 : : #define VHD_REQS_META (VHD_CACHE_SIZE + 2)
116 : : #define VHD_REQS_TOTAL (VHD_REQS_DATA + VHD_REQS_META)
117 : :
118 : : #define VHD_OP_BAT_WRITE 0
119 : : #define VHD_OP_DATA_READ 1
120 : : #define VHD_OP_DATA_WRITE 2
121 : : #define VHD_OP_BITMAP_READ 3
122 : : #define VHD_OP_BITMAP_WRITE 4
123 : : #define VHD_OP_ZERO_BM_WRITE 5
124 : : #define VHD_OP_REDUNDANT_BM_WRITE 6
125 : : #define VHD_OP_BLOCK_STATUS 7
126 : :
127 : : #define VHD_BM_BAT_LOCKED 0
128 : : #define VHD_BM_BAT_CLEAR 1
129 : : #define VHD_BM_BIT_CLEAR 2
130 : : #define VHD_BM_BIT_SET 3
131 : : #define VHD_BM_NOT_CACHED 4
132 : : #define VHD_BM_READ_PENDING 5
133 : :
134 : : #define VHD_FLAG_OPEN_RDONLY 1
135 : : #define VHD_FLAG_OPEN_NO_CACHE 2
136 : : #define VHD_FLAG_OPEN_QUIET 4
137 : : #define VHD_FLAG_OPEN_STRICT 8
138 : : #define VHD_FLAG_OPEN_QUERY 16
139 : : #define VHD_FLAG_OPEN_PREALLOCATE 32
140 : : #define VHD_FLAG_OPEN_NO_O_DIRECT 64
141 : : #define VHD_FLAG_OPEN_LOCAL_CACHE 128
142 : :
143 : : #define VHD_FLAG_BAT_LOCKED 1
144 : : #define VHD_FLAG_BAT_WRITE_STARTED 2
145 : :
146 : : #define VHD_FLAG_BM_UPDATE_BAT 1
147 : : #define VHD_FLAG_BM_WRITE_PENDING 2
148 : : #define VHD_FLAG_BM_READ_PENDING 4
149 : : #define VHD_FLAG_BM_LOCKED 8
150 : :
151 : : #define VHD_FLAG_REQ_UPDATE_BAT 1
152 : : #define VHD_FLAG_REQ_UPDATE_BITMAP 2
153 : : #define VHD_FLAG_REQ_QUEUED 4
154 : : #define VHD_FLAG_REQ_FINISHED 8
155 : :
156 : : #define VHD_FLAG_TX_LIVE 1
157 : : #define VHD_FLAG_TX_UPDATE_BAT 2
158 : :
159 : : typedef uint8_t vhd_flag_t;
160 : :
161 : : struct vhd_state;
162 : : struct vhd_request;
163 : :
164 : : struct vhd_req_list {
165 : : struct vhd_request *head;
166 : : struct vhd_request *tail;
167 : : };
168 : :
169 : : struct vhd_transaction {
170 : : int error;
171 : : int closed;
172 : : int started;
173 : : int finished;
174 : : vhd_flag_t status;
175 : : struct vhd_req_list requests;
176 : : };
177 : :
178 : : struct vhd_request {
179 : : int error;
180 : : uint8_t op;
181 : : vhd_flag_t flags;
182 : : td_request_t treq;
183 : : char *orig_buf;
184 : : struct tiocb tiocb;
185 : : struct vhd_state *state;
186 : : struct vhd_request *next;
187 : : struct vhd_transaction *tx;
188 : : };
189 : :
190 : : struct vhd_bat_state {
191 : : vhd_bat_t bat;
192 : : vhd_batmap_t batmap;
193 : : vhd_flag_t status;
194 : : uint32_t pbw_blk; /* blk num of pending write */
195 : : uint64_t pbw_offset; /* file offset of same */
196 : : struct vhd_request req; /* for writing bat table */
197 : : struct vhd_request zero_req; /* for initializing bitmaps */
198 : : char *bat_buf;
199 : : };
200 : :
201 : : struct vhd_bitmap {
202 : : uint32_t blk;
203 : : uint64_t seqno; /* lru sequence number */
204 : : vhd_flag_t status;
205 : :
206 : : char *map; /* map should only be modified
207 : : * in finish_bitmap_write */
208 : : char *shadow; /* in-memory bitmap changes are
209 : : * made to shadow and copied to
210 : : * map only after having been
211 : : * flushed to disk */
212 : : struct vhd_transaction tx; /* transaction data structure
213 : : * encapsulating data, bitmap,
214 : : * and bat writes */
215 : : struct vhd_req_list queue; /* data writes waiting for next
216 : : * transaction */
217 : : struct vhd_req_list waiting; /* pending requests that cannot
218 : : * be serviced until this bitmap
219 : : * is read from disk */
220 : : struct vhd_request req;
221 : : };
222 : :
223 : : struct vhd_state {
224 : : vhd_flag_t flags;
225 : :
226 : : /* VHD stuff */
227 : : vhd_context_t vhd;
228 : : uint32_t spp; /* sectors per page */
229 : : uint32_t spb; /* sectors per block */
230 : : uint64_t first_db; /* pointer to datablock 0 */
231 : :
232 : : /**
233 : : * Pointer to the next (unallocated) datablock. If greater than UINT_MAX,
234 : : * there are no more blocks available.
235 : : */
236 : : uint64_t next_db;
237 : :
238 : : struct vhd_bat_state bat;
239 : :
240 : : uint64_t bm_lru; /* lru sequence number */
241 : : uint32_t bm_secs; /* size of bitmap, in sectors */
242 : : struct vhd_bitmap *bitmap[VHD_CACHE_SIZE];
243 : :
244 : : int bm_free_count;
245 : : struct vhd_bitmap *bitmap_free[VHD_CACHE_SIZE];
246 : : struct vhd_bitmap bitmap_list[VHD_CACHE_SIZE];
247 : :
248 : : int vreq_free_count;
249 : : struct vhd_request *vreq_free[VHD_REQS_DATA];
250 : : struct vhd_request vreq_list[VHD_REQS_DATA];
251 : :
252 : : /* for redundant bitmap writes */
253 : : int padbm_size;
254 : : char *padbm_buf;
255 : : long int debug_skipped_redundant_writes;
256 : : long int debug_done_redundant_writes;
257 : :
258 : : td_driver_t *driver;
259 : :
260 : : uint64_t queued;
261 : : uint64_t completed;
262 : : uint64_t returned;
263 : : uint64_t reads;
264 : : uint64_t read_size;
265 : : uint64_t writes;
266 : : uint64_t write_size;
267 : : };
268 : :
269 : : /* Define access functions for VHD encryption */
270 : : struct crypto_interface
271 : : {
272 : : int (*vhd_open_crypto)(
273 : : vhd_context_t *, const uint8_t *, size_t,
274 : : const char *);
275 : : void (*vhd_close_crypto)(vhd_context_t *);
276 : : void (*vhd_crypto_encrypt)(
277 : : vhd_context_t *, td_request_t *, char *);
278 : : void (*vhd_crypto_decrypt)(vhd_context_t *, td_request_t *);
279 : : };
280 : :
281 : : static struct crypto_interface *crypto_interface = NULL;
282 : : static void *crypto_handle;
283 : :
284 : : #define test_vhd_flag(word, flag) ((word) & (flag))
285 : : #define set_vhd_flag(word, flag) ((word) |= (flag))
286 : : #define clear_vhd_flag(word, flag) ((word) &= ~(flag))
287 : :
288 : : #define bat_entry(s, blk) ((s)->bat.bat.bat[(blk)])
289 : :
290 : : static void vhd_complete(void *, struct tiocb *, int);
291 : : static void finish_data_transaction(struct vhd_state *, struct vhd_bitmap *);
292 : :
293 : : static struct vhd_state *_vhd_master;
294 : : static unsigned long _vhd_zsize;
295 : : static char *_vhd_zeros = NULL;
296 : : int _dev_zero = -1;
297 : :
298 : : static int
299 : 0 : vhd_initialize(struct vhd_state *s)
300 : : {
301 : : int err;
302 : :
303 [ # # ]: 0 : if (_vhd_zeros)
304 : : return 0;
305 : :
306 : 0 : _vhd_zsize = 2 * getpagesize();
307 [ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE))
308 : 0 : _vhd_zsize += VHD_BLOCK_SIZE;
309 : :
310 : 0 : _dev_zero = open("/dev/zero", O_RDONLY);
311 [ # # ]: 0 : if (unlikely(_dev_zero == -1)) {
312 : 0 : err = errno;
313 : 0 : EPRINTF("failed to open /dev/zero: %s\n", strerror(err));
314 : 0 : return -err;
315 : : }
316 : :
317 : 0 : _vhd_zeros = mmap(NULL, _vhd_zsize, PROT_READ,
318 : : MAP_SHARED, _dev_zero, 0);
319 [ # # ]: 0 : if (_vhd_zeros == MAP_FAILED) {
320 : : int _err;
321 : 0 : err = errno;
322 : 0 : EPRINTF("vhd_initialize failed: %s\n", strerror(err));
323 : 0 : _vhd_zeros = NULL;
324 : 0 : _vhd_zsize = 0;
325 : 0 : _err = close(_dev_zero);
326 [ # # ]: 0 : if (unlikely(_err == -1))
327 : 0 : EPRINTF("failed to close /dev/zero: %s (error ignored)\n",
328 : : strerror(errno));
329 : : else
330 : 0 : _dev_zero = -1;
331 : :
332 : 0 : return -err;
333 : : }
334 : :
335 : 0 : _vhd_master = s;
336 : 0 : return 0;
337 : : }
338 : :
339 : : static void
340 : 0 : vhd_free(struct vhd_state *s)
341 : : {
342 : 0 : free(s->padbm_buf);
343 : :
344 [ # # ][ # # ]: 0 : if (_vhd_master != s || !_vhd_zeros)
345 : 0 : return;
346 : :
347 : 0 : munmap(_vhd_zeros, _vhd_zsize);
348 : 0 : _vhd_zsize = 0;
349 : 0 : _vhd_zeros = NULL;
350 : 0 : _vhd_master = NULL;
351 [ # # ]: 0 : if (_dev_zero != -1) {
352 : 0 : int _err = close(_dev_zero);
353 [ # # ]: 0 : if (unlikely(_err == -1))
354 : 0 : EPRINTF("failed to close /dev/zero: %s (error ignored)\n",
355 : : strerror(errno));
356 : : else
357 : 0 : _dev_zero = -1;
358 : : }
359 : : }
360 : :
361 : : static char *
362 : 0 : _get_vhd_zeros(const char *func, unsigned long size)
363 : : {
364 [ # # ][ # # ]: 0 : if (!_vhd_zeros || _vhd_zsize < size) {
365 : 0 : EPRINTF("invalid zero request from %s: %lu, %lu, %p\n",
366 : : func, size, _vhd_zsize, _vhd_zeros);
367 : 0 : ASSERT(0);
368 : : }
369 : :
370 : 0 : return _vhd_zeros;
371 : : }
372 : :
373 : : #define vhd_zeros(size) _get_vhd_zeros(__func__, size)
374 : :
375 : : static inline void
376 : 0 : set_batmap(struct vhd_state *s, uint32_t blk)
377 : : {
378 [ # # ]: 0 : if (s->bat.batmap.map) {
379 : 0 : vhd_batmap_set(&s->vhd, &s->bat.batmap, blk);
380 : 0 : DBG(TLOG_DBG, "block 0x%x completely full\n", blk);
381 : : }
382 : 0 : }
383 : :
384 : : static inline int
385 : : test_batmap(struct vhd_state *s, uint32_t blk)
386 : : {
387 [ # # ][ # # ]: 0 : if (!s->bat.batmap.map)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
388 : : return 0;
389 : 0 : return vhd_batmap_test(&s->vhd, &s->bat.batmap, blk);
390 : : }
391 : :
392 : : static int
393 : 0 : vhd_kill_footer(struct vhd_state *s)
394 : : {
395 : : int err;
396 : : off64_t end;
397 : : void *zeros;
398 : :
399 [ # # ]: 0 : if (s->vhd.footer.type == HD_TYPE_FIXED)
400 : 0 : return 0;
401 : :
402 : 0 : err = posix_memalign(&zeros, 512, 512);
403 [ # # ]: 0 : if (err)
404 : 0 : return -err;
405 : :
406 : 0 : err = 1;
407 : 0 : memset(zeros, 0xc7, 512);
408 : :
409 [ # # ]: 0 : if ((end = lseek64(s->vhd.fd, 0, SEEK_END)) == -1)
410 : : goto fail;
411 : :
412 [ # # ]: 0 : if (lseek64(s->vhd.fd, (end - 512), SEEK_SET) == -1)
413 : : goto fail;
414 : :
415 [ # # ]: 0 : if (write(s->vhd.fd, zeros, 512) != 512)
416 : : goto fail;
417 : :
418 : 0 : err = 0;
419 : :
420 : : fail:
421 : 0 : free(zeros);
422 [ # # ]: 0 : if (err)
423 [ # # ]: 0 : return (errno ? -errno : -EIO);
424 : : return 0;
425 : : }
426 : :
427 : : static inline int
428 : 0 : find_next_free_block(struct vhd_state *s)
429 : : {
430 : : int err;
431 : : off64_t eom;
432 : : uint32_t i, entry;
433 : :
434 : 0 : err = vhd_end_of_headers(&s->vhd, &eom);
435 [ # # ]: 0 : if (err)
436 : 0 : return err;
437 : :
438 : 0 : s->next_db = secs_round_up(eom);
439 : 0 : s->first_db = s->next_db;
440 [ # # ]: 0 : if ((s->first_db + s->bm_secs) % s->spp)
441 : 0 : s->first_db += (s->spp - ((s->first_db + s->bm_secs) % s->spp));
442 : :
443 [ # # ]: 0 : for (i = 0; i < s->bat.bat.entries; i++) {
444 : 0 : entry = bat_entry(s, i);
445 [ # # ][ # # ]: 0 : if (entry != DD_BLK_UNUSED && entry >= s->next_db)
446 : 0 : s->next_db = (uint64_t)entry + (uint64_t)s->spb
447 : 0 : + (uint64_t)s->bm_secs;
448 [ # # ]: 0 : if (s->next_db > UINT_MAX)
449 : : break;
450 : : }
451 : :
452 : : return 0;
453 : : }
454 : :
455 : : static void
456 : 0 : vhd_free_bat(struct vhd_state *s)
457 : : {
458 : 0 : free(s->bat.bat.bat);
459 : 0 : free(s->bat.batmap.map);
460 : 0 : free(s->bat.bat_buf);
461 : 0 : memset(&s->bat, 0, sizeof(struct vhd_bat));
462 : 0 : }
463 : :
464 : : static int
465 : 0 : vhd_initialize_bat(struct vhd_state *s)
466 : : {
467 : : int err, batmap_required, i;
468 : : void *buf;
469 : :
470 : 0 : memset(&s->bat, 0, sizeof(struct vhd_bat));
471 : :
472 : 0 : err = vhd_read_bat(&s->vhd, &s->bat.bat);
473 [ # # ]: 0 : if (err) {
474 : 0 : EPRINTF("%s: reading bat: %d\n", s->vhd.file, err);
475 : 0 : return err;
476 : : }
477 : :
478 : 0 : batmap_required = 1;
479 [ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_RDONLY)) {
480 : : batmap_required = 0;
481 : : } else {
482 : 0 : err = find_next_free_block(s);
483 [ # # ]: 0 : if (err)
484 : : goto fail;
485 : : }
486 : :
487 [ # # ]: 0 : if (vhd_has_batmap(&s->vhd)) {
488 [ # # ]: 0 : for (i = 0; i < VHD_BATMAP_MAX_RETRIES; i++) {
489 : 0 : err = vhd_read_batmap(&s->vhd, &s->bat.batmap);
490 [ # # ]: 0 : if (err) {
491 : 0 : EPRINTF("%s: reading batmap: %d\n",
492 : : s->vhd.file, err);
493 [ # # ]: 0 : if (batmap_required)
494 : : goto fail;
495 : : } else {
496 : : break;
497 : : }
498 : : }
499 [ # # ]: 0 : if (err)
500 : 0 : EPRINTF("%s: ignoring non-critical batmap error\n",
501 : : s->vhd.file);
502 : : }
503 : :
504 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, VHD_SECTOR_SIZE);
505 [ # # ]: 0 : if (err)
506 : : goto fail;
507 : :
508 : 0 : s->bat.bat_buf = buf;
509 : :
510 : 0 : return 0;
511 : :
512 : : fail:
513 : 0 : vhd_free_bat(s);
514 : 0 : return err;
515 : : }
516 : :
517 : : static void
518 : 0 : vhd_free_bitmap_cache(struct vhd_state *s)
519 : : {
520 : : int i;
521 : : struct vhd_bitmap *bm;
522 : :
523 [ # # ]: 0 : for (i = 0; i < VHD_CACHE_SIZE; i++) {
524 : 0 : bm = s->bitmap_list + i;
525 : 0 : free(bm->map);
526 : 0 : free(bm->shadow);
527 : 0 : s->bitmap_free[i] = NULL;
528 : : }
529 : :
530 : 0 : memset(s->bitmap_list, 0, sizeof(struct vhd_bitmap) * VHD_CACHE_SIZE);
531 : 0 : }
532 : :
533 : : static int
534 : 0 : vhd_initialize_bitmap_cache(struct vhd_state *s)
535 : : {
536 : : int i, err, map_size;
537 : : struct vhd_bitmap *bm;
538 : : void *map, *shadow;
539 : :
540 : 0 : memset(s->bitmap_list, 0, sizeof(struct vhd_bitmap) * VHD_CACHE_SIZE);
541 : :
542 : 0 : s->bm_lru = 0;
543 : 0 : map_size = vhd_sectors_to_bytes(s->bm_secs);
544 : 0 : s->bm_free_count = VHD_CACHE_SIZE;
545 : :
546 [ # # ]: 0 : for (i = 0; i < VHD_CACHE_SIZE; i++) {
547 : 0 : bm = s->bitmap_list + i;
548 : :
549 : 0 : err = posix_memalign(&map, 512, map_size);
550 [ # # ]: 0 : if (err)
551 : : goto fail;
552 : :
553 : 0 : bm->map = map;
554 : :
555 : 0 : err = posix_memalign(&shadow, 512, map_size);
556 [ # # ]: 0 : if (err)
557 : : goto fail;
558 : :
559 : 0 : bm->shadow = shadow;
560 : :
561 : 0 : memset(bm->map, 0, map_size);
562 : 0 : memset(bm->shadow, 0, map_size);
563 : 0 : s->bitmap_free[i] = bm;
564 : : }
565 : :
566 : 0 : return 0;
567 : :
568 : : fail:
569 : 0 : vhd_free_bitmap_cache(s);
570 : 0 : return err;
571 : : }
572 : :
573 : : static int
574 : 0 : vhd_initialize_dynamic_disk(struct vhd_state *s)
575 : : {
576 : : uint32_t bm_size;
577 : : void *buf;
578 : : int err;
579 : :
580 : 0 : err = vhd_get_header(&s->vhd);
581 [ # # ]: 0 : if (err) {
582 [ # # ]: 0 : if (!test_vhd_flag(s->flags, VHD_FLAG_OPEN_QUIET))
583 : : EPRINTF("Error reading VHD DD header.\n");
584 : 0 : return err;
585 : : }
586 : :
587 [ # # ]: 0 : if (s->vhd.header.hdr_ver != 0x00010000) {
588 : 0 : EPRINTF("unsupported header version! (0x%x)\n",
589 : : s->vhd.header.hdr_ver);
590 : : return -EINVAL;
591 : : }
592 : :
593 : 0 : s->spp = getpagesize() >> VHD_SECTOR_SHIFT;
594 : 0 : s->spb = s->vhd.header.block_size >> VHD_SECTOR_SHIFT;
595 : 0 : s->bm_secs = secs_round_up_no_zero(s->spb >> 3);
596 : :
597 : 0 : s->padbm_size = (s->bm_secs / getpagesize()) * getpagesize();
598 [ # # ]: 0 : if (s->bm_secs % getpagesize())
599 : 0 : s->padbm_size += getpagesize();
600 : :
601 : 0 : err = posix_memalign(&buf, 512, s->padbm_size);
602 [ # # ]: 0 : if (err)
603 : 0 : return -err;
604 : :
605 : 0 : s->padbm_buf = buf;
606 : 0 : bm_size = s->bm_secs << VHD_SECTOR_SHIFT;
607 : 0 : memset(s->padbm_buf, 0, s->padbm_size - bm_size);
608 : 0 : memset(s->padbm_buf + (s->padbm_size - bm_size), ~0, bm_size);
609 : 0 : s->debug_skipped_redundant_writes = 0;
610 : 0 : s->debug_done_redundant_writes = 0;
611 : :
612 [ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_NO_CACHE))
613 : : return 0;
614 : :
615 : 0 : err = vhd_initialize_bat(s);
616 [ # # ]: 0 : if (err)
617 : : return err;
618 : :
619 : 0 : err = vhd_initialize_bitmap_cache(s);
620 [ # # ]: 0 : if (err) {
621 : 0 : vhd_free_bat(s);
622 : 0 : return err;
623 : : }
624 : :
625 : : return 0;
626 : : }
627 : :
628 : : static int
629 : 0 : vhd_check_version(struct vhd_state *s)
630 : : {
631 [ # # ]: 0 : if (strncmp(s->vhd.footer.crtr_app, "tap", 3))
632 : : return 0;
633 : :
634 [ # # ]: 0 : if (s->vhd.footer.crtr_ver > VHD_CURRENT_VERSION) {
635 [ # # ]: 0 : if (!test_vhd_flag(s->flags, VHD_FLAG_OPEN_QUIET))
636 : 0 : EPRINTF("WARNING: %s vhd creator version 0x%08x, "
637 : : "but only versions up to 0x%08x are "
638 : : "supported for IO\n", s->vhd.file,
639 : : s->vhd.footer.crtr_ver, VHD_CURRENT_VERSION);
640 : :
641 : : return -EINVAL;
642 : : }
643 : :
644 : : return 0;
645 : : }
646 : :
647 : : static void
648 : 0 : vhd_log_open(struct vhd_state *s)
649 : : {
650 : : char buf[5];
651 : : uint32_t i, allocated, full;
652 : :
653 [ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_QUIET))
654 : 0 : return;
655 : :
656 : 0 : snprintf(buf, sizeof(buf), "%s", s->vhd.footer.crtr_app);
657 [ # # ]: 0 : if (!vhd_type_dynamic(&s->vhd)) {
658 : 0 : DPRINTF("%s version: %s 0x%08x\n",
659 : : s->vhd.file, buf, s->vhd.footer.crtr_ver);
660 : : return;
661 : : }
662 : :
663 : : allocated = 0;
664 : : full = 0;
665 : :
666 [ # # ]: 0 : for (i = 0; i < s->bat.bat.entries; i++) {
667 [ # # ]: 0 : if (bat_entry(s, i) != DD_BLK_UNUSED)
668 : 0 : allocated++;
669 [ # # ]: 0 : if (test_batmap(s, i))
670 : 0 : full++;
671 : : }
672 : :
673 : 0 : DPRINTF("%s version: %s 0x%08x, b: %u, a: %u, f: %u, n: %"PRIu64"\n",
674 : : s->vhd.file, buf, s->vhd.footer.crtr_ver, s->bat.bat.entries,
675 : : allocated, full, s->next_db);
676 : : }
677 : :
678 : 0 : static int dummy_open_crypto(
679 : : vhd_context_t *vhd, const uint8_t *key, size_t key_bytes,
680 : : const char *name)
681 : : {
682 [ # # ]: 0 : if (key) {
683 : : EPRINTF("Encryption requested with no support library\n");
684 : 0 : return -EINVAL;
685 : : }
686 : :
687 : : return 0;
688 : : }
689 : :
690 : 0 : void dummy_close_crypto(vhd_context_t *vhd)
691 : : {
692 : :
693 : 0 : }
694 : :
695 : : static int
696 : 0 : __load_crypto(struct td_vbd_encryption *encryption)
697 : : {
698 : 0 : crypto_interface = malloc(sizeof(struct crypto_interface));
699 [ # # ]: 0 : if (!crypto_interface) {
700 : : EPRINTF("Failed to allocate memory\n");
701 : 0 : return -ENOMEM;
702 : : }
703 : :
704 [ # # ]: 0 : if (encryption->encryption_key == NULL) {
705 : 0 : crypto_interface->vhd_open_crypto = dummy_open_crypto;
706 : 0 : crypto_interface->vhd_close_crypto = dummy_close_crypto;
707 : 0 : crypto_interface->vhd_crypto_encrypt = NULL;
708 : 0 : crypto_interface->vhd_crypto_decrypt = NULL;
709 : : } else {
710 : 0 : dlerror();
711 : 0 : crypto_handle = dlopen(LIBBLOCKCRYPTO_NAME, RTLD_LAZY);
712 [ # # ]: 0 : if (crypto_handle == NULL) {
713 : 0 : EPRINTF("Failed to load crypto library. %s\n",
714 : : dlerror());
715 : 0 : return -EINVAL;
716 : : }
717 : :
718 : 0 : dlerror();
719 : 0 : crypto_interface->vhd_open_crypto =
720 : 0 : (int (*)(vhd_context_t *, const uint8_t *, size_t,
721 : : const char *))
722 : 0 : dlsym (crypto_handle, "vhd_open_crypto");
723 : 0 : crypto_interface->vhd_close_crypto =
724 : 0 : (void (*)(vhd_context_t *))
725 : 0 : dlsym(crypto_handle, "vhd_close_crypto");
726 : 0 : crypto_interface->vhd_crypto_encrypt =
727 : 0 : (void (*)(vhd_context_t *, td_request_t *,
728 : : char *))
729 : 0 : dlsym(crypto_handle, "vhd_crypto_encrypt");
730 : 0 : crypto_interface->vhd_crypto_decrypt =
731 : 0 : (void (*)(vhd_context_t *, td_request_t *))
732 : 0 : dlsym(crypto_handle, "vhd_crypto_decrypt");
733 : :
734 [ # # ][ # # ]: 0 : if (!crypto_interface->vhd_open_crypto ||
735 [ # # ]: 0 : !crypto_interface->vhd_close_crypto ||
736 [ # # ]: 0 : !crypto_interface->vhd_crypto_encrypt ||
737 : 0 : !crypto_interface->vhd_crypto_decrypt) {
738 : 0 : EPRINTF("Failed to load crypto routines from dynamic library. %s\n",
739 : : dlerror());
740 : 0 : return -EINVAL;
741 : : }
742 : : DPRINTF("Loaded cryptography library\n");
743 : : }
744 : :
745 : : return 0;
746 : : }
747 : :
748 : 0 : void vhd_atexit(void)
749 : : {
750 [ # # ]: 0 : if (crypto_interface) {
751 : 0 : free(crypto_interface);
752 : 0 : crypto_interface = NULL;
753 : : }
754 : 0 : }
755 : :
756 : : static void
757 : 0 : __vhd_free_crypto(vhd_context_t *vhd)
758 : : {
759 [ # # ]: 0 : if (crypto_interface) {
760 : 0 : crypto_interface->vhd_close_crypto(vhd);
761 : 0 : atexit(vhd_atexit);
762 : : }
763 : 0 : }
764 : :
765 : : static int
766 : 0 : __load_and_open_crypto(vhd_context_t *vhd, struct td_vbd_encryption *encryption,
767 : : const char *name)
768 : : {
769 : 0 : int ret = 0;
770 : :
771 [ # # ]: 0 : if (!crypto_interface) {
772 : 0 : ret = __load_crypto(encryption);
773 [ # # ]: 0 : if (ret)
774 : : return ret;
775 : : }
776 : :
777 : 0 : return crypto_interface->vhd_open_crypto(
778 : 0 : vhd, encryption->encryption_key, encryption->key_size, name);
779 : : }
780 : :
781 : : static int
782 : 0 : __vhd_open(td_driver_t *driver, const char *name,
783 : : struct td_vbd_encryption *encryption, vhd_flag_t flags)
784 : : {
785 : : int i, o_flags, err;
786 : 0 : struct vhd_state *s;
787 : :
788 : 0 : DBG(TLOG_INFO, "vhd_open: %s\n", name);
789 [ # # ]: 0 : if (test_vhd_flag(flags, VHD_FLAG_OPEN_STRICT))
790 : 0 : libvhd_set_log_level(1);
791 : :
792 : 0 : s = (struct vhd_state *)driver->data;
793 : : memset(s, 0, sizeof(struct vhd_state));
794 : :
795 : 0 : s->flags = flags;
796 : 0 : s->driver = driver;
797 : :
798 : 0 : err = vhd_initialize(s);
799 [ # # ]: 0 : if (err)
800 : : return err;
801 : :
802 : 0 : o_flags = ((test_vhd_flag(flags, VHD_FLAG_OPEN_RDONLY)) ?
803 [ # # ]: 0 : VHD_OPEN_RDONLY : VHD_OPEN_RDWR);
804 [ # # ][ # # ]: 0 : if ((test_vhd_flag(flags, VHD_FLAG_OPEN_RDONLY) ||
805 [ # # ]: 0 : test_vhd_flag(flags, VHD_FLAG_OPEN_LOCAL_CACHE)) &&
806 : 0 : test_vhd_flag(flags, VHD_FLAG_OPEN_NO_O_DIRECT))
807 : 0 : set_vhd_flag(o_flags, VHD_OPEN_CACHED);
808 : :
809 [ # # ]: 0 : if (test_vhd_flag(flags, VHD_FLAG_OPEN_STRICT))
810 : 0 : set_vhd_flag(o_flags, VHD_OPEN_STRICT);
811 : :
812 : 0 : err = vhd_open(&s->vhd, name, o_flags);
813 [ # # ]: 0 : if (err) {
814 : 0 : libvhd_set_log_level(1);
815 : 0 : err = vhd_open(&s->vhd, name, o_flags);
816 [ # # ]: 0 : if (err) {
817 : : EPRINTF("Unable to open [%s] (%d)!\n", name, err);
818 : 0 : return err;
819 : : }
820 : : }
821 : :
822 : 0 : err = vhd_check_version(s);
823 [ # # ]: 0 : if (err)
824 : : goto fail;
825 : :
826 : 0 : s->spb = s->spp = 1;
827 : :
828 [ # # ]: 0 : if (vhd_type_dynamic(&s->vhd)) {
829 : 0 : err = vhd_initialize_dynamic_disk(s);
830 [ # # ]: 0 : if (err)
831 : : goto fail;
832 : : }
833 : :
834 : 0 : vhd_log_open(s);
835 : :
836 : 0 : SPB = s->spb;
837 : :
838 : 0 : s->vreq_free_count = VHD_REQS_DATA;
839 [ # # ]: 0 : for (i = 0; i < VHD_REQS_DATA; i++)
840 : 0 : s->vreq_free[i] = s->vreq_list + i;
841 : :
842 : 0 : driver->info.size = s->vhd.footer.curr_size >> VHD_SECTOR_SHIFT;
843 : 0 : driver->info.sector_size = VHD_SECTOR_SIZE;
844 : 0 : driver->info.info = 0;
845 : :
846 : 0 : DBG(TLOG_INFO, "vhd_open: done (sz:%"PRIu64", sct:%lu, inf:%u)\n",
847 : : driver->info.size, driver->info.sector_size, driver->info.info);
848 : :
849 : 0 : err = __load_and_open_crypto(&s->vhd, encryption, name);
850 [ # # ]: 0 : if (err) {
851 : : DPRINTF("failed to init crypto: %d\n", err);
852 : : goto fail;
853 : : }
854 : :
855 [ # # ]: 0 : if (test_vhd_flag(flags, VHD_FLAG_OPEN_STRICT) &&
856 : : !test_vhd_flag(flags, VHD_FLAG_OPEN_RDONLY)) {
857 : 0 : err = vhd_kill_footer(s);
858 [ # # ]: 0 : if (err) {
859 : : DPRINTF("ERROR killing footer: %d\n", err);
860 : : goto fail;
861 : : }
862 : 0 : s->writes++;
863 : : }
864 : :
865 : : return 0;
866 : :
867 : : fail:
868 : 0 : vhd_free_bat(s);
869 : 0 : vhd_free_bitmap_cache(s);
870 : 0 : __vhd_free_crypto(&s->vhd);
871 : 0 : vhd_close(&s->vhd);
872 : 0 : vhd_free(s);
873 : 0 : return err;
874 : : }
875 : :
876 : : static int
877 : 0 : _vhd_open(td_driver_t *driver, const char *name,
878 : : struct td_vbd_encryption *encryption, td_flag_t flags)
879 : : {
880 : 0 : vhd_flag_t vhd_flags = 0;
881 : :
882 [ # # ]: 0 : if (flags & TD_OPEN_RDONLY)
883 : 0 : vhd_flags |= VHD_FLAG_OPEN_RDONLY;
884 [ # # ]: 0 : if (flags & TD_OPEN_NO_O_DIRECT)
885 : 0 : vhd_flags |= VHD_FLAG_OPEN_NO_O_DIRECT;
886 [ # # ]: 0 : if (flags & TD_OPEN_QUIET)
887 : 0 : vhd_flags |= VHD_FLAG_OPEN_QUIET;
888 [ # # ]: 0 : if (flags & TD_OPEN_STRICT)
889 : 0 : vhd_flags |= VHD_FLAG_OPEN_STRICT;
890 [ # # ]: 0 : if (flags & TD_OPEN_QUERY)
891 : 0 : vhd_flags |= (VHD_FLAG_OPEN_QUERY |
892 : : VHD_FLAG_OPEN_QUIET |
893 : : VHD_FLAG_OPEN_RDONLY |
894 : : VHD_FLAG_OPEN_NO_CACHE);
895 [ # # ]: 0 : if (flags & TD_OPEN_LOCAL_CACHE)
896 : 0 : vhd_flags |= VHD_FLAG_OPEN_LOCAL_CACHE;
897 : :
898 : : /* pre-allocate for all but NFS and LVM storage */
899 : 0 : driver->storage = tapdisk_storage_type(name);
900 : :
901 [ # # ]: 0 : if (driver->storage != TAPDISK_STORAGE_TYPE_NFS &&
902 : : driver->storage != TAPDISK_STORAGE_TYPE_LVM)
903 : 0 : vhd_flags |= VHD_FLAG_OPEN_PREALLOCATE;
904 : :
905 : 0 : return __vhd_open(driver, name, encryption, vhd_flags);
906 : : }
907 : :
908 : : static void
909 : 0 : vhd_log_close(struct vhd_state *s)
910 : : {
911 : : uint32_t i, allocated, full;
912 : :
913 [ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_QUIET))
914 : 0 : return;
915 : :
916 : : allocated = 0;
917 : : full = 0;
918 : :
919 [ # # ]: 0 : for (i = 0; i < s->bat.bat.entries; i++) {
920 [ # # ]: 0 : if (bat_entry(s, i) != DD_BLK_UNUSED)
921 : 0 : allocated++;
922 [ # # ]: 0 : if (test_batmap(s, i))
923 : 0 : full++;
924 : : }
925 : :
926 : 0 : DPRINTF("%s: b: %u, a: %u, f: %u, n: %"PRIu64"\n",
927 : : s->vhd.file, s->bat.bat.entries, allocated, full, s->next_db);
928 : : }
929 : :
930 : : static int
931 : 0 : _vhd_close(td_driver_t *driver)
932 : : {
933 : : int err;
934 : : struct vhd_state *s;
935 : :
936 : 0 : DBG(TLOG_WARN, "vhd_close\n");
937 : 0 : s = (struct vhd_state *)driver->data;
938 : :
939 : 0 : DPRINTF("gaps written/skipped: %ld/%ld\n",
940 : : s->debug_done_redundant_writes,
941 : : s->debug_skipped_redundant_writes);
942 : :
943 : : /* don't write footer if tapdisk is read-only */
944 [ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_RDONLY))
945 : : goto free;
946 : :
947 : : /*
948 : : * write footer if:
949 : : * - we killed it on open (opened with strict)
950 : : * - we've written data since opening
951 : : */
952 [ # # ][ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_STRICT) || s->writes) {
953 : 0 : memcpy(&s->vhd.bat, &s->bat.bat, sizeof(vhd_bat_t));
954 : 0 : err = vhd_write_footer(&s->vhd, &s->vhd.footer);
955 : 0 : memset(&s->vhd.bat, 0, sizeof(vhd_bat_t));
956 : :
957 [ # # ]: 0 : if (err)
958 : 0 : EPRINTF("writing %s footer: %d\n", s->vhd.file, err);
959 : :
960 [ # # ]: 0 : if (!vhd_has_batmap(&s->vhd))
961 : : goto free;
962 : :
963 : 0 : err = vhd_write_batmap(&s->vhd, &s->bat.batmap);
964 [ # # ]: 0 : if (err)
965 : 0 : EPRINTF("writing %s batmap: %d\n", s->vhd.file, err);
966 : : }
967 : :
968 : : free:
969 : 0 : vhd_log_close(s);
970 : 0 : vhd_free_bat(s);
971 : 0 : vhd_free_bitmap_cache(s);
972 : 0 : __vhd_free_crypto(&s->vhd);
973 : 0 : vhd_close(&s->vhd);
974 : 0 : vhd_free(s);
975 : :
976 : : memset(s, 0, sizeof(struct vhd_state));
977 : :
978 : 0 : return 0;
979 : : }
980 : :
981 : : int
982 : 0 : vhd_validate_parent(td_driver_t *child_driver,
983 : : td_driver_t *parent_driver, td_flag_t flags)
984 : : {
985 : 0 : struct vhd_state *child = (struct vhd_state *)child_driver->data;
986 : : struct vhd_state *parent;
987 : :
988 : 0 : DPRINTF("vhd_validate_parent. ptype %d, ctype %d",
989 : : parent_driver->type, child_driver->type);
990 [ # # ]: 0 : if (parent_driver->type != DISK_TYPE_VHD)
991 : : {
992 [ # # ]: 0 : if (child_driver->type != DISK_TYPE_VHD)
993 : : return -EINVAL;
994 [ # # ]: 0 : if (child->vhd.footer.type != HD_TYPE_DIFF)
995 : : return -EINVAL;
996 [ # # ][ # # ]: 0 : if (!vhd_parent_raw(&child->vhd) &&
997 [ # # ]: 0 : !(parent_driver->type == DISK_TYPE_LCACHE ||
998 : : parent_driver->type == DISK_TYPE_AIO ||
999 : : parent_driver->type == DISK_TYPE_NBD))
1000 : : return -EINVAL;
1001 : 0 : return 0;
1002 : : }
1003 : :
1004 : 0 : parent = (struct vhd_state *)parent_driver->data;
1005 : :
1006 : : /*
1007 : : * This check removed because of cases like:
1008 : : * - parent VHD marked as 'hidden'
1009 : : * - parent VHD modified during coalesce
1010 : : */
1011 : : /*
1012 : : if (stat(parent->vhd.file, &stats)) {
1013 : : DPRINTF("ERROR stating parent file %s\n", parent->vhd.file);
1014 : : return -errno;
1015 : : }
1016 : :
1017 : : if (child->hdr.prt_ts != vhd_time(stats.st_mtime)) {
1018 : : DPRINTF("ERROR: parent file has been modified since "
1019 : : "snapshot. Child image no longer valid.\n");
1020 : : return -EINVAL;
1021 : : }
1022 : : */
1023 : :
1024 [ # # ]: 0 : if (uuid_compare(child->vhd.header.prt_uuid, parent->vhd.footer.uuid)) {
1025 : 0 : DPRINTF("ERROR: %s: %s, %s: parent uuid has changed since "
1026 : : "snapshot. Child image no longer valid.\n",
1027 : : __func__, child->vhd.file, parent->vhd.file);
1028 : 0 : return -EINVAL;
1029 : : }
1030 : :
1031 : : /* TODO: compare sizes */
1032 : :
1033 : : return 0;
1034 : : }
1035 : :
1036 : : int
1037 : 0 : vhd_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
1038 : : {
1039 : : int err;
1040 : : char *parent;
1041 : : struct vhd_state *s;
1042 : : int flags;
1043 : :
1044 : 0 : DBG(TLOG_DBG, "\n");
1045 : 0 : flags = id->flags;
1046 : : memset(id, 0, sizeof(td_disk_id_t));
1047 : :
1048 : 0 : s = (struct vhd_state *)driver->data;
1049 : :
1050 [ # # ]: 0 : if (s->vhd.footer.type != HD_TYPE_DIFF)
1051 : 0 : return TD_NO_PARENT;
1052 : :
1053 : 0 : err = vhd_parent_locator_get(&s->vhd, &parent);
1054 [ # # ]: 0 : if (err)
1055 : : return err;
1056 : :
1057 : 0 : id->name = parent;
1058 [ # # ]: 0 : id->type = vhd_parent_raw(&s->vhd) ? DISK_TYPE_AIO : DISK_TYPE_VHD;
1059 : 0 : id->flags = flags|TD_OPEN_SHAREABLE|TD_OPEN_RDONLY;
1060 : :
1061 : 0 : return 0;
1062 : : }
1063 : :
1064 : : static inline void
1065 : : clear_req_list(struct vhd_req_list *list)
1066 : : {
1067 : 0 : list->head = list->tail = NULL;
1068 : : }
1069 : :
1070 : : static inline void
1071 : : add_to_tail(struct vhd_req_list *list, struct vhd_request *e)
1072 : : {
1073 [ # # ][ # # ]: 0 : if (!list->head)
[ # # ]
1074 : 0 : list->head = list->tail = e;
1075 : : else
1076 : 0 : list->tail = list->tail->next = e;
1077 : : }
1078 : :
1079 : : static inline int
1080 : 0 : remove_from_req_list(struct vhd_req_list *list, struct vhd_request *e)
1081 : : {
1082 : 0 : struct vhd_request *i = list->head;
1083 : :
1084 [ # # ]: 0 : if (list->head == e) {
1085 [ # # ]: 0 : if (list->tail == e)
1086 : : clear_req_list(list);
1087 : : else
1088 : 0 : list->head = list->head->next;
1089 : : return 0;
1090 : : }
1091 : :
1092 [ # # ]: 0 : while (i->next) {
1093 [ # # ]: 0 : if (i->next == e) {
1094 [ # # ]: 0 : if (list->tail == e) {
1095 : 0 : i->next = NULL;
1096 : 0 : list->tail = i;
1097 : : } else
1098 : 0 : i->next = i->next->next;
1099 : : return 0;
1100 : : }
1101 : : i = i->next;
1102 : : }
1103 : :
1104 : : return -EINVAL;
1105 : : }
1106 : :
1107 : : static inline void
1108 : : init_vhd_request(struct vhd_state *s, struct vhd_request *req)
1109 : : {
1110 : : memset(req, 0, sizeof(struct vhd_request));
1111 : 0 : req->state = s;
1112 : : }
1113 : :
1114 : : static inline void
1115 : : init_tx(struct vhd_transaction *tx)
1116 : : {
1117 : : memset(tx, 0, sizeof(struct vhd_transaction));
1118 : : }
1119 : :
1120 : : static inline void
1121 : 0 : add_to_transaction(struct vhd_transaction *tx, struct vhd_request *r)
1122 : : {
1123 [ # # ]: 0 : ASSERT(!tx->closed);
1124 : :
1125 : 0 : r->tx = tx;
1126 : 0 : tx->started++;
1127 : 0 : add_to_tail(&tx->requests, r);
1128 : 0 : set_vhd_flag(tx->status, VHD_FLAG_TX_LIVE);
1129 : :
1130 : 0 : DBG(TLOG_DBG, "blk: 0x%04"PRIx64", lsec: 0x%08"PRIx64", tx: %p, "
1131 : : "started: %d, finished: %d, status: %u\n",
1132 : : r->treq.sec / SPB, r->treq.sec, tx,
1133 : : tx->started, tx->finished, tx->status);
1134 : 0 : }
1135 : :
1136 : : static inline int
1137 : 0 : transaction_completed(struct vhd_transaction *tx)
1138 : : {
1139 : 0 : return (tx->started == tx->finished);
1140 : : }
1141 : :
1142 : : static inline void
1143 : : init_bat(struct vhd_state *s)
1144 : : {
1145 : 0 : s->bat.req.tx = NULL;
1146 : 0 : s->bat.req.next = NULL;
1147 : 0 : s->bat.req.error = 0;
1148 : 0 : s->bat.pbw_blk = 0;
1149 : 0 : s->bat.pbw_offset = 0;
1150 : 0 : s->bat.status = 0;
1151 : : }
1152 : :
1153 : : static inline void
1154 : 0 : lock_bat(struct vhd_state *s)
1155 : : {
1156 : 0 : set_vhd_flag(s->bat.status, VHD_FLAG_BAT_LOCKED);
1157 : 0 : }
1158 : :
1159 : : static inline void
1160 : 0 : unlock_bat(struct vhd_state *s)
1161 : : {
1162 : 0 : clear_vhd_flag(s->bat.status, VHD_FLAG_BAT_LOCKED);
1163 : 0 : }
1164 : :
1165 : : static inline int
1166 : 0 : bat_locked(struct vhd_state *s)
1167 : : {
1168 : 0 : return test_vhd_flag(s->bat.status, VHD_FLAG_BAT_LOCKED);
1169 : : }
1170 : :
1171 : : static inline void
1172 : 0 : init_vhd_bitmap(struct vhd_state *s, struct vhd_bitmap *bm)
1173 : : {
1174 : 0 : bm->blk = 0;
1175 : 0 : bm->seqno = 0;
1176 : 0 : bm->status = 0;
1177 : 0 : init_tx(&bm->tx);
1178 : 0 : clear_req_list(&bm->queue);
1179 : 0 : clear_req_list(&bm->waiting);
1180 : 0 : memset(bm->map, 0, vhd_sectors_to_bytes(s->bm_secs));
1181 : 0 : memset(bm->shadow, 0, vhd_sectors_to_bytes(s->bm_secs));
1182 : 0 : init_vhd_request(s, &bm->req);
1183 : 0 : }
1184 : :
1185 : : static inline struct vhd_bitmap *
1186 : : get_bitmap(struct vhd_state *s, uint32_t block)
1187 : : {
1188 : : int i;
1189 : : struct vhd_bitmap *bm;
1190 : :
1191 [ # # ][ # # ]: 0 : for (i = 0; i < VHD_CACHE_SIZE; i++) {
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1192 : 0 : bm = s->bitmap[i];
1193 [ # # ][ # # ]: 0 : if (bm && bm->blk == block)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1194 : : return bm;
1195 : : }
1196 : :
1197 : : return NULL;
1198 : : }
1199 : :
1200 : : static inline void
1201 : 0 : lock_bitmap(struct vhd_bitmap *bm)
1202 : : {
1203 : 0 : set_vhd_flag(bm->status, VHD_FLAG_BM_LOCKED);
1204 : 0 : }
1205 : :
1206 : : static inline void
1207 : 0 : unlock_bitmap(struct vhd_bitmap *bm)
1208 : : {
1209 : 0 : clear_vhd_flag(bm->status, VHD_FLAG_BM_LOCKED);
1210 : 0 : }
1211 : :
1212 : : static inline int
1213 : 0 : bitmap_locked(struct vhd_bitmap *bm)
1214 : : {
1215 : 0 : return test_vhd_flag(bm->status, VHD_FLAG_BM_LOCKED);
1216 : : }
1217 : :
1218 : : static inline int
1219 : 0 : bitmap_valid(struct vhd_bitmap *bm)
1220 : : {
1221 : 0 : return !test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING);
1222 : : }
1223 : :
1224 : : static inline int
1225 : 0 : bitmap_in_use(struct vhd_bitmap *bm)
1226 : : {
1227 : 0 : return (test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING) ||
1228 [ # # ]: 0 : test_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING) ||
1229 [ # # ]: 0 : test_vhd_flag(bm->tx.status, VHD_FLAG_TX_UPDATE_BAT) ||
1230 [ # # ][ # # ]: 0 : bm->waiting.head || bm->tx.requests.head || bm->queue.head);
[ # # ]
1231 : : }
1232 : :
1233 : : static inline int
1234 : 0 : bitmap_full(struct vhd_state *s, struct vhd_bitmap *bm)
1235 : : {
1236 : : int i, n;
1237 : :
1238 : 0 : n = s->spb >> 3;
1239 [ # # ]: 0 : for (i = 0; i < n; i++)
1240 [ # # ]: 0 : if (bm->map[i] != (char)0xFF)
1241 : : return 0;
1242 : :
1243 : 0 : DBG(TLOG_DBG, "bitmap 0x%04x full\n", bm->blk);
1244 : 0 : return 1;
1245 : : }
1246 : :
1247 : : static struct vhd_bitmap *
1248 : 0 : remove_lru_bitmap(struct vhd_state *s)
1249 : : {
1250 : 0 : int i, idx = 0;
1251 : 0 : uint64_t seq = s->bm_lru;
1252 : 0 : struct vhd_bitmap *bm, *lru = NULL;
1253 : :
1254 [ # # ]: 0 : for (i = 0; i < VHD_CACHE_SIZE; i++) {
1255 : 0 : bm = s->bitmap[i];
1256 [ # # ][ # # ]: 0 : if (bm && bm->seqno < seq && !bitmap_locked(bm)) {
[ # # ]
1257 : 0 : idx = i;
1258 : 0 : lru = bm;
1259 : 0 : seq = lru->seqno;
1260 : : }
1261 : : }
1262 : :
1263 [ # # ]: 0 : if (lru) {
1264 : 0 : s->bitmap[idx] = NULL;
1265 [ # # ]: 0 : ASSERT(!bitmap_in_use(lru));
1266 : : }
1267 : :
1268 : 0 : return lru;
1269 : : }
1270 : :
1271 : : static int
1272 : 0 : alloc_vhd_bitmap(struct vhd_state *s, struct vhd_bitmap **bitmap, uint32_t blk)
1273 : : {
1274 : : struct vhd_bitmap *bm;
1275 : :
1276 : 0 : *bitmap = NULL;
1277 : :
1278 [ # # ]: 0 : if (s->bm_free_count > 0) {
1279 : 0 : bm = s->bitmap_free[--s->bm_free_count];
1280 : : } else {
1281 : 0 : bm = remove_lru_bitmap(s);
1282 [ # # ]: 0 : if (!bm)
1283 : : return -EBUSY;
1284 : : }
1285 : :
1286 : 0 : init_vhd_bitmap(s, bm);
1287 : 0 : bm->blk = blk;
1288 : 0 : *bitmap = bm;
1289 : :
1290 : 0 : return 0;
1291 : : }
1292 : :
1293 : : static inline uint64_t
1294 : 0 : __bitmap_lru_seqno(struct vhd_state *s)
1295 : : {
1296 : : int i;
1297 : : struct vhd_bitmap *bm;
1298 : :
1299 [ # # ]: 0 : if (s->bm_lru == 0xffffffff) {
1300 : 0 : s->bm_lru = 0;
1301 [ # # ]: 0 : for (i = 0; i < VHD_CACHE_SIZE; i++) {
1302 : 0 : bm = s->bitmap[i];
1303 [ # # ]: 0 : if (bm) {
1304 : 0 : bm->seqno >>= 1;
1305 [ # # ]: 0 : if (bm->seqno > s->bm_lru)
1306 : 0 : s->bm_lru = bm->seqno;
1307 : : }
1308 : : }
1309 : : }
1310 : :
1311 : 0 : return ++s->bm_lru;
1312 : : }
1313 : :
1314 : : static inline void
1315 : 0 : touch_bitmap(struct vhd_state *s, struct vhd_bitmap *bm)
1316 : : {
1317 : 0 : bm->seqno = __bitmap_lru_seqno(s);
1318 : 0 : }
1319 : :
1320 : : static inline void
1321 : 0 : install_bitmap(struct vhd_state *s, struct vhd_bitmap *bm)
1322 : : {
1323 : : int i;
1324 [ # # ]: 0 : for (i = 0; i < VHD_CACHE_SIZE; i++) {
1325 [ # # ]: 0 : if (!s->bitmap[i]) {
1326 : 0 : touch_bitmap(s, bm);
1327 : 0 : s->bitmap[i] = bm;
1328 : 0 : return;
1329 : : }
1330 : : }
1331 : :
1332 : 0 : ASSERT(0);
1333 : : }
1334 : :
1335 : : static inline void
1336 : 0 : free_vhd_bitmap(struct vhd_state *s, struct vhd_bitmap *bm)
1337 : : {
1338 : : int i;
1339 : :
1340 [ # # ]: 0 : for (i = 0; i < VHD_CACHE_SIZE; i++)
1341 [ # # ]: 0 : if (s->bitmap[i] == bm)
1342 : : break;
1343 : :
1344 [ # # ]: 0 : ASSERT(!bitmap_locked(bm));
1345 [ # # ]: 0 : ASSERT(!bitmap_in_use(bm));
1346 [ # # ]: 0 : ASSERT(i < VHD_CACHE_SIZE);
1347 : :
1348 : 0 : s->bitmap[i] = NULL;
1349 : 0 : s->bitmap_free[s->bm_free_count++] = bm;
1350 : 0 : }
1351 : :
1352 : : static int
1353 : 0 : read_bitmap_cache(struct vhd_state *s, uint64_t sector, uint8_t op)
1354 : : {
1355 : : uint32_t blk, sec;
1356 : : struct vhd_bitmap *bm;
1357 : :
1358 : : /* in fixed disks, every block is present */
1359 [ # # ]: 0 : if (s->vhd.footer.type == HD_TYPE_FIXED)
1360 : : return VHD_BM_BIT_SET;
1361 : :
1362 : : /* the extent the logical sector falls in */
1363 : 0 : blk = sector / s->spb;
1364 : :
1365 : : /* offset within the extent the logical sector is located */
1366 : 0 : sec = sector % s->spb;
1367 : :
1368 [ # # ]: 0 : if (blk > s->vhd.header.max_bat_size) {
1369 : 0 : DPRINTF("ERROR: sec %"PRIu64" out of range, op = %d\n",
1370 : : sector, op);
1371 : 0 : return -EINVAL;
1372 : : }
1373 : :
1374 [ # # ]: 0 : if (bat_entry(s, blk) == DD_BLK_UNUSED) {
1375 [ # # ][ # # ]: 0 : if (op == VHD_OP_DATA_WRITE &&
1376 [ # # ]: 0 : s->bat.pbw_blk != blk && bat_locked(s))
1377 : : return VHD_BM_BAT_LOCKED;
1378 : :
1379 : 0 : return VHD_BM_BAT_CLEAR;
1380 : : }
1381 : :
1382 [ # # ]: 0 : if (test_batmap(s, blk)) {
1383 : 0 : DBG(TLOG_DBG, "batmap set for 0x%04x\n", blk);
1384 : 0 : return VHD_BM_BIT_SET;
1385 : : }
1386 : :
1387 : 0 : bm = get_bitmap(s, blk);
1388 [ # # ]: 0 : if (!bm)
1389 : : return VHD_BM_NOT_CACHED;
1390 : :
1391 : : /* bump lru count */
1392 : 0 : touch_bitmap(s, bm);
1393 : :
1394 [ # # ]: 0 : if (test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING))
1395 : : return VHD_BM_READ_PENDING;
1396 : :
1397 : 0 : return ((vhd_bitmap_test(&s->vhd, bm->map, sec)) ?
1398 [ # # ]: 0 : VHD_BM_BIT_SET : VHD_BM_BIT_CLEAR);
1399 : : }
1400 : :
1401 : : static int
1402 : 0 : read_bitmap_cache_span(struct vhd_state *s,
1403 : : uint64_t sector, int nr_secs, int value)
1404 : : {
1405 : : int ret;
1406 : : uint32_t blk, sec;
1407 : 0 : struct vhd_bitmap *bm;
1408 : :
1409 : : /* in fixed disks, every block is present */
1410 [ # # ]: 0 : if (s->vhd.footer.type == HD_TYPE_FIXED)
1411 : : return nr_secs;
1412 : :
1413 : 0 : sec = sector % s->spb;
1414 : 0 : blk = sector / s->spb;
1415 : :
1416 [ # # ]: 0 : if (test_batmap(s, blk))
1417 : 0 : return MIN(nr_secs, s->spb - sec);
1418 : :
1419 : 0 : bm = get_bitmap(s, blk);
1420 : :
1421 [ # # ][ # # ]: 0 : ASSERT(bm && bitmap_valid(bm));
1422 : :
1423 [ # # ][ # # ]: 0 : for (ret = 0; sec < s->spb && ret < nr_secs; sec++, ret++)
1424 [ # # ]: 0 : if (vhd_bitmap_test(&s->vhd, bm->map, sec) != value)
1425 : : break;
1426 : :
1427 : 0 : return ret;
1428 : : }
1429 : :
1430 : : static inline struct vhd_request *
1431 : 0 : alloc_vhd_request(struct vhd_state *s)
1432 : : {
1433 : 0 : struct vhd_request *req = NULL;
1434 : :
1435 [ # # ]: 0 : if (s->vreq_free_count > 0) {
1436 : 0 : req = s->vreq_free[--s->vreq_free_count];
1437 [ # # ]: 0 : ASSERT(req->treq.secs == 0);
1438 : : init_vhd_request(s, req);
1439 : 0 : return req;
1440 : : }
1441 : :
1442 : : return NULL;
1443 : : }
1444 : :
1445 : : static inline void
1446 : : free_vhd_request(struct vhd_state *s, struct vhd_request *req)
1447 : : {
1448 : : memset(req, 0, sizeof(struct vhd_request));
1449 : 0 : s->vreq_free[s->vreq_free_count++] = req;
1450 : : }
1451 : :
1452 : : static inline void
1453 : 0 : do_aio_read(struct vhd_state *s, struct vhd_request *req, uint64_t offset)
1454 : : {
1455 : 0 : struct tiocb *tiocb = &req->tiocb;
1456 : :
1457 : 0 : td_prep_read(s->driver, tiocb, s->vhd.fd, req->treq.buf,
1458 : 0 : vhd_sectors_to_bytes(req->treq.secs),
1459 : : offset, vhd_complete, req);
1460 : 0 : td_queue_tiocb(s->driver, tiocb);
1461 : :
1462 : 0 : s->queued++;
1463 : 0 : s->reads++;
1464 : 0 : s->read_size += req->treq.secs;
1465 : 0 : TRACE(s);
1466 : 0 : }
1467 : :
1468 : : static inline void
1469 : 0 : do_aio_write(struct vhd_state *s, struct vhd_request *req, uint64_t offset)
1470 : : {
1471 : 0 : struct tiocb *tiocb = &req->tiocb;
1472 : :
1473 : 0 : td_prep_write(s->driver, tiocb, s->vhd.fd, req->treq.buf,
1474 : 0 : vhd_sectors_to_bytes(req->treq.secs),
1475 : : offset, vhd_complete, req);
1476 : 0 : td_queue_tiocb(s->driver, tiocb);
1477 : :
1478 : 0 : s->queued++;
1479 : 0 : s->writes++;
1480 : 0 : s->write_size += req->treq.secs;
1481 : 0 : TRACE(s);
1482 : 0 : }
1483 : :
1484 : : /**
1485 : : * Reserves a new extent.
1486 : : *
1487 : : * @returns a 64-bit unsigned integer where the error code is stored in the
1488 : : * upper 32 bits and the reserved block number is stored in the lower 32 bits.
1489 : : * If an error is returned (the upper 32 bits are not zero), the lower 32 bits
1490 : : * are undefined.
1491 : : */
1492 : : static inline uint64_t
1493 : 0 : reserve_new_block(struct vhd_state *s, uint32_t blk)
1494 : : {
1495 : 0 : int gap = 0;
1496 : :
1497 [ # # ]: 0 : ASSERT(!test_vhd_flag(s->bat.status, VHD_FLAG_BAT_WRITE_STARTED));
1498 : :
1499 : : /* data region of segment should begin on page boundary */
1500 [ # # ]: 0 : if ((s->next_db + s->bm_secs) % s->spp)
1501 : 0 : gap = (s->spp - ((s->next_db + s->bm_secs) % s->spp));
1502 : :
1503 [ # # ]: 0 : if (s->next_db + gap > UINT_MAX)
1504 : : return (uint64_t)ENOSPC << 32;
1505 : :
1506 : 0 : s->bat.pbw_blk = blk;
1507 : 0 : s->bat.pbw_offset = s->next_db + gap;
1508 : :
1509 : 0 : return s->next_db;
1510 : : }
1511 : :
1512 : : static int
1513 : 0 : schedule_bat_write(struct vhd_state *s)
1514 : : {
1515 : : int i;
1516 : : uint32_t blk;
1517 : : char *buf;
1518 : : uint64_t offset;
1519 : : struct vhd_request *req;
1520 : :
1521 [ # # ]: 0 : ASSERT(bat_locked(s));
1522 : :
1523 : 0 : req = &s->bat.req;
1524 : 0 : buf = s->bat.bat_buf;
1525 : 0 : blk = s->bat.pbw_blk;
1526 : :
1527 : : init_vhd_request(s, req);
1528 : 0 : memcpy(buf, &bat_entry(s, blk - (blk % 128)), 512);
1529 : :
1530 : 0 : ((uint32_t *)buf)[blk % 128] = s->bat.pbw_offset;
1531 : :
1532 [ # # ]: 0 : for (i = 0; i < 128; i++)
1533 : 0 : BE32_OUT(&((uint32_t *)buf)[i]);
1534 : :
1535 : 0 : offset = s->vhd.header.table_offset + ((uint64_t)blk - (blk % 128)) * 4;
1536 : 0 : req->treq.secs = 1;
1537 : 0 : req->treq.buf = buf;
1538 : 0 : req->op = VHD_OP_BAT_WRITE;
1539 : 0 : req->next = NULL;
1540 : :
1541 : 0 : do_aio_write(s, req, offset);
1542 : 0 : set_vhd_flag(s->bat.status, VHD_FLAG_BAT_WRITE_STARTED);
1543 : :
1544 : 0 : DBG(TLOG_DBG, "blk: 0x%04x, pbwo: 0x%08"PRIx64", "
1545 : : "table_offset: 0x%08"PRIx64"\n", blk, s->bat.pbw_offset, offset);
1546 : :
1547 : 0 : return 0;
1548 : : }
1549 : :
1550 : : static void
1551 : 0 : schedule_zero_bm_write(struct vhd_state *s,
1552 : : struct vhd_bitmap *bm, uint64_t lb_end)
1553 : : {
1554 : : uint64_t offset;
1555 : 0 : struct vhd_request *req = &s->bat.zero_req;
1556 : :
1557 : : init_vhd_request(s, req);
1558 : :
1559 : 0 : offset = vhd_sectors_to_bytes(lb_end);
1560 : 0 : req->op = VHD_OP_ZERO_BM_WRITE;
1561 : 0 : req->treq.sec = (td_sector_t)s->bat.pbw_blk * s->spb;
1562 : 0 : req->treq.secs = (s->bat.pbw_offset - lb_end) + s->bm_secs;
1563 : 0 : req->treq.buf = vhd_zeros(vhd_sectors_to_bytes(req->treq.secs));
1564 : 0 : req->next = NULL;
1565 : :
1566 : 0 : DBG(TLOG_DBG, "blk: 0x%04x, writing zero bitmap at 0x%08"PRIx64"\n",
1567 : : s->bat.pbw_blk, offset);
1568 : :
1569 : 0 : lock_bitmap(bm);
1570 : 0 : add_to_transaction(&bm->tx, req);
1571 : 0 : do_aio_write(s, req, offset);
1572 : 0 : }
1573 : :
1574 : : /* This is a performance optimization. When writing sequentially into full
1575 : : * blocks, skipping (up-to-date) bitmaps causes an approx. 25% reduction in
1576 : : * throughput. To prevent skipping, we issue redundant writes into the (padded)
1577 : : * bitmap area just to make all writes sequential. This will help VHDs on raw
1578 : : * block devices, while the FS-based VHDs shouldn't suffer much.
1579 : : *
1580 : : * Note that it only makes sense to perform this reduntant bitmap write if the
1581 : : * block is completely full (i.e. the batmap entry is set). If the block is not
1582 : : * completely full then one of the following two things will be true:
1583 : : * 1. we'll either be allocating new sectors in this block and writing its
1584 : : * bitmap transactionally, which will be slow anyways; or
1585 : : * 2. the IO will be skipping over the unallocated sectors again, so the
1586 : : * pattern will not be sequential anyways
1587 : : * In either case a redundant bitmap write becomes pointless. This fact
1588 : : * simplifies the implementation of redundant writes: since we know the bitmap
1589 : : * cannot be updated by anyone else, we don't have to worry about transactions
1590 : : * or potential write conflicts.
1591 : : * */
1592 : : static void
1593 : 0 : schedule_redundant_bm_write(struct vhd_state *s, uint32_t blk)
1594 : : {
1595 : : uint64_t offset;
1596 : : struct vhd_request *req;
1597 : :
1598 [ # # ]: 0 : ASSERT(s->vhd.footer.type != HD_TYPE_FIXED);
1599 [ # # ]: 0 : ASSERT(test_batmap(s, blk));
1600 : :
1601 : 0 : req = alloc_vhd_request(s);
1602 [ # # ]: 0 : if (!req)
1603 : 0 : return;
1604 : :
1605 : 0 : req->treq.buf = s->padbm_buf;
1606 : :
1607 : 0 : offset = bat_entry(s, blk);
1608 [ # # ]: 0 : ASSERT(offset != DD_BLK_UNUSED);
1609 : 0 : offset <<= VHD_SECTOR_SHIFT;
1610 : 0 : offset -= s->padbm_size - ((uint64_t)s->bm_secs << VHD_SECTOR_SHIFT);
1611 : :
1612 : 0 : req->op = VHD_OP_REDUNDANT_BM_WRITE;
1613 : 0 : req->treq.sec = (td_sector_t)blk * s->spb;
1614 : 0 : req->treq.secs = s->padbm_size >> VHD_SECTOR_SHIFT;
1615 : 0 : req->next = NULL;
1616 : :
1617 : 0 : DBG(TLOG_DBG, "blk: %u, writing redundant bitmap at %" PRIu64 "\n",
1618 : : blk, offset);
1619 : :
1620 : 0 : do_aio_write(s, req, offset);
1621 : : }
1622 : :
1623 : : static int
1624 : 0 : update_bat(struct vhd_state *s, uint32_t blk)
1625 : : {
1626 : : int err;
1627 : : uint64_t lb_end;
1628 : : struct vhd_bitmap *bm;
1629 : :
1630 [ # # ]: 0 : ASSERT(bat_entry(s, blk) == DD_BLK_UNUSED);
1631 : :
1632 [ # # ]: 0 : if (bat_locked(s)) {
1633 [ # # ]: 0 : ASSERT(s->bat.pbw_blk == blk);
1634 : 0 : return 0;
1635 : : }
1636 : :
1637 : : /* empty bitmap could already be in
1638 : : * cache if earlier bat update failed */
1639 : 0 : bm = get_bitmap(s, blk);
1640 [ # # ]: 0 : if (!bm) {
1641 : : /* install empty bitmap in cache */
1642 : 0 : err = alloc_vhd_bitmap(s, &bm, blk);
1643 [ # # ]: 0 : if (err)
1644 : : return err;
1645 : :
1646 : 0 : install_bitmap(s, bm);
1647 : : }
1648 : :
1649 : 0 : lock_bat(s);
1650 : 0 : lb_end = reserve_new_block(s, blk);
1651 [ # # ]: 0 : if (lb_end >> 32) {
1652 : 0 : unlock_bat(s);
1653 : 0 : return -(lb_end >> 32);
1654 : : }
1655 : 0 : schedule_zero_bm_write(s, bm, lb_end);
1656 : 0 : set_vhd_flag(bm->tx.status, VHD_FLAG_TX_UPDATE_BAT);
1657 : :
1658 : 0 : return 0;
1659 : : }
1660 : :
1661 : : static int
1662 : 0 : allocate_block(struct vhd_state *s, uint32_t blk)
1663 : : {
1664 : : int err, gap;
1665 : : uint64_t offset, size;
1666 : : struct vhd_bitmap *bm;
1667 : : ssize_t count;
1668 : : uint64_t next_db;
1669 : :
1670 [ # # ]: 0 : ASSERT(bat_entry(s, blk) == DD_BLK_UNUSED);
1671 : :
1672 [ # # ]: 0 : if (bat_locked(s)) {
1673 [ # # ]: 0 : ASSERT(s->bat.pbw_blk == blk);
1674 [ # # ]: 0 : if (s->bat.req.error)
1675 : 0 : return -EBUSY;
1676 : 0 : return 0;
1677 : : }
1678 : :
1679 : 0 : gap = 0;
1680 : 0 : offset = vhd_sectors_to_bytes(s->next_db);
1681 : 0 : next_db = s->next_db;
1682 : :
1683 : : /* data region of segment should begin on page boundary */
1684 [ # # ]: 0 : if ((next_db + s->bm_secs) % s->spp) {
1685 : 0 : gap = (s->spp - ((next_db + s->bm_secs) % s->spp));
1686 : 0 : next_db += gap;
1687 : : }
1688 : :
1689 [ # # ]: 0 : if (next_db > UINT_MAX)
1690 : : return -ENOSPC;
1691 : :
1692 : 0 : s->next_db = next_db;
1693 : :
1694 : 0 : s->bat.pbw_blk = blk;
1695 : 0 : s->bat.pbw_offset = s->next_db;
1696 : :
1697 : 0 : DBG(TLOG_DBG, "blk: 0x%04x, pbwo: 0x%08"PRIx64"\n",
1698 : : blk, s->bat.pbw_offset);
1699 : :
1700 [ # # ]: 0 : if (lseek(s->vhd.fd, offset, SEEK_SET) == (off_t)-1) {
1701 [ # # ]: 0 : ERR(s, -errno, "lseek failed\n");
1702 : 0 : return -errno;
1703 : : }
1704 : :
1705 : 0 : size = vhd_sectors_to_bytes(s->spb + s->bm_secs + gap);
1706 : 0 : count = write(s->vhd.fd, vhd_zeros(size), size);
1707 [ # # ]: 0 : if (count != size) {
1708 [ # # ]: 0 : err = count < 0 ? -errno : -ENOSPC;
1709 [ # # ]: 0 : ERR(s, -errno,
1710 : : "write failed (%zd, offset %"PRIu64")\n", count, offset);
1711 : 0 : return err;
1712 : : }
1713 : :
1714 : : /* empty bitmap could already be in
1715 : : * cache if earlier bat update failed */
1716 : 0 : bm = get_bitmap(s, blk);
1717 [ # # ]: 0 : if (!bm) {
1718 : : /* install empty bitmap in cache */
1719 : 0 : err = alloc_vhd_bitmap(s, &bm, blk);
1720 [ # # ]: 0 : if (err)
1721 : : return err;
1722 : :
1723 : 0 : install_bitmap(s, bm);
1724 : : }
1725 : :
1726 : 0 : lock_bat(s);
1727 : 0 : lock_bitmap(bm);
1728 : 0 : schedule_bat_write(s);
1729 : 0 : add_to_transaction(&bm->tx, &s->bat.req);
1730 : :
1731 : : return 0;
1732 : : }
1733 : :
1734 : : static int
1735 : 0 : schedule_data_read(struct vhd_state *s, td_request_t treq, vhd_flag_t flags)
1736 : : {
1737 : : uint64_t offset;
1738 : 0 : uint32_t blk = 0, sec = 0;
1739 : 0 : struct vhd_bitmap *bm;
1740 : : struct vhd_request *req;
1741 : :
1742 [ # # ]: 0 : if (s->vhd.footer.type == HD_TYPE_FIXED) {
1743 : 0 : offset = vhd_sectors_to_bytes(treq.sec);
1744 : 0 : goto make_request;
1745 : : }
1746 : :
1747 : 0 : blk = treq.sec / s->spb;
1748 : 0 : sec = treq.sec % s->spb;
1749 : 0 : bm = get_bitmap(s, blk);
1750 : 0 : offset = bat_entry(s, blk);
1751 : :
1752 [ # # ]: 0 : ASSERT(offset != DD_BLK_UNUSED);
1753 [ # # ][ # # ]: 0 : ASSERT(test_batmap(s, blk) || (bm && bitmap_valid(bm)));
[ # # ]
1754 : :
1755 : 0 : offset += s->bm_secs + sec;
1756 : 0 : offset = vhd_sectors_to_bytes(offset);
1757 : :
1758 : : make_request:
1759 : 0 : req = alloc_vhd_request(s);
1760 [ # # ]: 0 : if (!req)
1761 : : return -EBUSY;
1762 : :
1763 : 0 : req->treq = treq;
1764 : 0 : req->flags = flags;
1765 : 0 : req->op = VHD_OP_DATA_READ;
1766 : 0 : req->next = NULL;
1767 : :
1768 : 0 : do_aio_read(s, req, offset);
1769 : :
1770 : 0 : DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", blk: 0x%04x, sec: 0x%04x, "
1771 : : "nr_secs: 0x%04x, offset: 0x%08"PRIx64", flags: 0x%08x, buf: %p\n",
1772 : : s->vhd.file, treq.sec, blk, sec, treq.secs, offset, req->flags,
1773 : : treq.buf);
1774 : :
1775 : 0 : return 0;
1776 : : }
1777 : :
1778 : : static bool
1779 : 0 : vhd_is_encrypted(struct vhd_state *s)
1780 : : {
1781 : 0 : return s->vhd.xts_tfm != NULL;
1782 : : }
1783 : :
1784 : : static int
1785 : 0 : schedule_data_write(struct vhd_state *s, td_request_t treq, vhd_flag_t flags)
1786 : : {
1787 : : int err;
1788 : : uint64_t offset;
1789 : 0 : uint32_t blk = 0, sec = 0;
1790 : 0 : struct vhd_bitmap *bm = NULL;
1791 : 0 : struct vhd_request *req = NULL;
1792 : 0 : char *crypto_buf = NULL;
1793 : :
1794 [ # # ]: 0 : if (vhd_is_encrypted(s)) {
1795 : 0 : err = posix_memalign((void **)&crypto_buf, VHD_SECTOR_SIZE,
1796 : 0 : (size_t)treq.secs * VHD_SECTOR_SIZE);
1797 [ # # ]: 0 : if (err)
1798 : 0 : return -EBUSY;
1799 : : }
1800 : 0 : req = alloc_vhd_request(s);
1801 [ # # ]: 0 : if (!req) {
1802 : : err = -EBUSY;
1803 : : goto fail;
1804 : : }
1805 : :
1806 [ # # ]: 0 : if (s->vhd.footer.type == HD_TYPE_FIXED) {
1807 : 0 : offset = vhd_sectors_to_bytes(treq.sec);
1808 : : } else {
1809 : 0 : blk = treq.sec / s->spb;
1810 [ # # ]: 0 : ASSERT(blk < s->bat.bat.entries);
1811 : 0 : sec = treq.sec % s->spb;
1812 : 0 : offset = bat_entry(s, blk);
1813 : :
1814 [ # # ]: 0 : if (test_vhd_flag(flags, VHD_FLAG_REQ_UPDATE_BAT)) {
1815 [ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE))
1816 : 0 : err = allocate_block(s, blk);
1817 : : else
1818 : 0 : err = update_bat(s, blk);
1819 : :
1820 [ # # ]: 0 : if (err) {
1821 : : goto fail;
1822 : : }
1823 : :
1824 : 0 : offset = s->bat.pbw_offset;
1825 : : }
1826 : :
1827 : 0 : offset += s->bm_secs + sec;
1828 : 0 : offset = vhd_sectors_to_bytes(offset);
1829 : :
1830 : : /* Make sure we're not about to overwrite the header */
1831 [ # # ]: 0 : ASSERT(offset >= 1536);
1832 : : }
1833 : :
1834 : 0 : req->treq = treq;
1835 : 0 : req->flags = flags;
1836 : 0 : req->op = VHD_OP_DATA_WRITE;
1837 : 0 : req->next = NULL;
1838 : :
1839 [ # # ]: 0 : if (vhd_is_encrypted(s)) {
1840 : 0 : req->orig_buf = req->treq.buf;
1841 : 0 : req->treq.buf = crypto_buf;
1842 : 0 : crypto_interface->vhd_crypto_encrypt(
1843 : : &s->vhd, &req->treq, req->orig_buf);
1844 : : }
1845 : :
1846 [ # # ]: 0 : if (test_vhd_flag(flags, VHD_FLAG_REQ_UPDATE_BITMAP)) {
1847 : 0 : bm = get_bitmap(s, blk);
1848 [ # # ][ # # ]: 0 : ASSERT(bm && bitmap_valid(bm));
1849 : 0 : lock_bitmap(bm);
1850 : :
1851 [ # # ]: 0 : if (bm->tx.closed) {
1852 : 0 : add_to_tail(&bm->queue, req);
1853 : 0 : set_vhd_flag(req->flags, VHD_FLAG_REQ_QUEUED);
1854 : : } else
1855 : 0 : add_to_transaction(&bm->tx, req);
1856 [ # # ][ # # ]: 0 : } else if (sec == 0 && /* first sector inside data block */
1857 [ # # ]: 0 : s->vhd.footer.type != HD_TYPE_FIXED &&
1858 [ # # ]: 0 : bat_entry(s, blk) != s->first_db &&
1859 : : test_batmap(s, blk))
1860 : 0 : schedule_redundant_bm_write(s, blk);
1861 : :
1862 : 0 : do_aio_write(s, req, offset);
1863 : :
1864 : 0 : DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", blk: 0x%04x, sec: 0x%04x, "
1865 : : "nr_secs: 0x%04x, offset: 0x%08"PRIx64", flags: 0x%08x\n",
1866 : : s->vhd.file, treq.sec, blk, sec, treq.secs, offset, req->flags);
1867 : :
1868 : : return 0;
1869 : : fail:
1870 [ # # ]: 0 : if (crypto_buf)
1871 : 0 : free(crypto_buf);
1872 : :
1873 [ # # ]: 0 : if (req)
1874 : : free_vhd_request(s, req);
1875 : :
1876 : 0 : return err;
1877 : : }
1878 : :
1879 : : static int
1880 : 0 : schedule_bitmap_read(struct vhd_state *s, uint32_t blk)
1881 : : {
1882 : : int err;
1883 : : uint64_t offset;
1884 : : struct vhd_bitmap *bm;
1885 : 0 : struct vhd_request *req = NULL;
1886 : :
1887 [ # # ]: 0 : ASSERT(vhd_type_dynamic(&s->vhd));
1888 : :
1889 : 0 : offset = bat_entry(s, blk);
1890 : :
1891 [ # # ]: 0 : ASSERT(offset != DD_BLK_UNUSED);
1892 [ # # ]: 0 : ASSERT(!get_bitmap(s, blk));
1893 : :
1894 : 0 : offset = vhd_sectors_to_bytes(offset);
1895 : :
1896 : 0 : err = alloc_vhd_bitmap(s, &bm, blk);
1897 [ # # ]: 0 : if (err)
1898 : 0 : return err;
1899 : :
1900 : 0 : req = &bm->req;
1901 : : init_vhd_request(s, req);
1902 : :
1903 : 0 : req->treq.sec = (td_sector_t)blk * s->spb;
1904 : 0 : req->treq.secs = s->bm_secs;
1905 : 0 : req->treq.buf = bm->map;
1906 : 0 : req->treq.cb = NULL;
1907 : 0 : req->op = VHD_OP_BITMAP_READ;
1908 : 0 : req->next = NULL;
1909 : :
1910 : 0 : do_aio_read(s, req, offset);
1911 : 0 : lock_bitmap(bm);
1912 : 0 : install_bitmap(s, bm);
1913 : 0 : set_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING);
1914 : :
1915 : 0 : DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", blk: 0x%04x, nr_secs: 0x%04x, "
1916 : : "offset: 0x%08"PRIx64"\n", s->vhd.file, req->treq.sec, blk,
1917 : : req->treq.secs, offset);
1918 : :
1919 : : return 0;
1920 : : }
1921 : :
1922 : : static bool
1923 : 0 : schedule_bitmap_write(struct vhd_state *s, uint32_t blk)
1924 : : {
1925 : : uint64_t offset;
1926 : 0 : struct vhd_bitmap *bm;
1927 : : struct vhd_request *req;
1928 : :
1929 : 0 : bm = get_bitmap(s, blk);
1930 : 0 : offset = bat_entry(s, blk);
1931 : :
1932 [ # # ]: 0 : ASSERT(vhd_type_dynamic(&s->vhd));
1933 [ # # ][ # # ]: 0 : ASSERT(bm && bitmap_valid(bm) &&
[ # # ]
1934 : : !test_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING));
1935 : :
1936 [ # # ]: 0 : if (memcmp(bm->map, bm->shadow, vhd_sectors_to_bytes(s->bm_secs)) == 0) {
1937 : : /* Bitmap unchanged */
1938 : : return true;
1939 : : }
1940 : :
1941 [ # # ]: 0 : if (offset == DD_BLK_UNUSED) {
1942 [ # # ][ # # ]: 0 : ASSERT(bat_locked(s) && s->bat.pbw_blk == blk);
1943 : 0 : offset = s->bat.pbw_offset;
1944 : : }
1945 : :
1946 : 0 : offset = vhd_sectors_to_bytes(offset);
1947 : :
1948 : 0 : req = &bm->req;
1949 : : init_vhd_request(s, req);
1950 : :
1951 : 0 : req->treq.sec = (td_sector_t)blk * s->spb;
1952 : 0 : req->treq.secs = s->bm_secs;
1953 : 0 : req->treq.buf = bm->shadow;
1954 : 0 : req->treq.cb = NULL;
1955 : 0 : req->op = VHD_OP_BITMAP_WRITE;
1956 : 0 : req->next = NULL;
1957 : :
1958 : 0 : do_aio_write(s, req, offset);
1959 : 0 : lock_bitmap(bm);
1960 : 0 : touch_bitmap(s, bm); /* bump lru count */
1961 : 0 : set_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING);
1962 : :
1963 : 0 : DBG(TLOG_DBG, "%s: blk: 0x%04x, sec: 0x%08"PRIx64", nr_secs: 0x%04x, "
1964 : : "offset: 0x%"PRIx64"\n", s->vhd.file, blk, req->treq.sec,
1965 : : req->treq.secs, offset);
1966 : 0 : return false;
1967 : : }
1968 : :
1969 : : /*
1970 : : * queued requests will be submitted once the bitmap
1971 : : * describing them is read and the requests are validated.
1972 : : */
1973 : : static int
1974 : 0 : __vhd_queue_request(struct vhd_state *s, uint8_t op, td_request_t treq)
1975 : : {
1976 : : uint32_t blk;
1977 : : struct vhd_bitmap *bm;
1978 : : struct vhd_request *req;
1979 : :
1980 [ # # ]: 0 : ASSERT(vhd_type_dynamic(&s->vhd));
1981 : :
1982 : 0 : blk = treq.sec / s->spb;
1983 : 0 : bm = get_bitmap(s, blk);
1984 : :
1985 [ # # ][ # # ]: 0 : ASSERT(bm && test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING));
1986 : :
1987 : 0 : req = alloc_vhd_request(s);
1988 [ # # ]: 0 : if (!req)
1989 : : return -EBUSY;
1990 : :
1991 : 0 : req->treq = treq;
1992 : 0 : req->op = op;
1993 : 0 : req->next = NULL;
1994 : :
1995 : 0 : add_to_tail(&bm->waiting, req);
1996 : 0 : lock_bitmap(bm);
1997 : :
1998 : 0 : DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", blk: 0x%04x nr_secs: 0x%04x, "
1999 : : "op: %u\n", s->vhd.file, treq.sec, blk, treq.secs, op);
2000 : :
2001 : 0 : TRACE(s);
2002 : 0 : return 0;
2003 : : }
2004 : :
2005 : : static void
2006 : 0 : vhd_queue_block_status(td_driver_t *driver, td_request_t treq)
2007 : : {
2008 : 0 : struct vhd_state *s = (struct vhd_state *)driver->data;
2009 : :
2010 : 0 : DBG(TLOG_DBG, "block status: %s: lsec: 0x%08"PRIx64", secs: 0x%04x (seg: %d)\n",
2011 : : s->vhd.file, treq.sec, treq.secs, treq.sidx);
2012 : :
2013 [ # # ]: 0 : while (treq.secs) {
2014 : : int err;
2015 : : td_request_t clone;
2016 : :
2017 : 0 : err = 0;
2018 : 0 : clone = treq;
2019 : :
2020 [ # # # # : 0 : switch (read_bitmap_cache(s, clone.sec, VHD_OP_BLOCK_STATUS)) {
# # # ]
2021 : : case -EINVAL:
2022 : : err = -EINVAL;
2023 : : goto fail;
2024 : :
2025 : : case VHD_BM_BAT_CLEAR:
2026 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2027 : 0 : td_forward_request(clone);
2028 : : break;
2029 : :
2030 : : case VHD_BM_BIT_CLEAR:
2031 : 0 : clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 0);
2032 : 0 : td_forward_request(clone);
2033 : : break;
2034 : :
2035 : : case VHD_BM_BIT_SET:
2036 : 0 : clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 1);
2037 : 0 : clone.status = TD_BLOCK_STATE_NONE;
2038 : 0 : td_complete_request(clone, 0);
2039 : : break;
2040 : :
2041 : : case VHD_BM_NOT_CACHED:
2042 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2043 : 0 : clone.status = TD_BLOCK_STATE_NONE;
2044 : 0 : td_complete_request(clone, 0);
2045 : : break;
2046 : :
2047 : : case VHD_BM_READ_PENDING:
2048 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2049 : 0 : err = __vhd_queue_request(s, VHD_OP_BLOCK_STATUS, clone);
2050 [ # # ]: 0 : if (err)
2051 : : goto fail;
2052 : : break;
2053 : :
2054 : : case VHD_BM_BAT_LOCKED:
2055 : : default:
2056 : 0 : ASSERT(0);
2057 : : break;
2058 : : }
2059 : :
2060 : 0 : treq.sec += clone.secs;
2061 : 0 : treq.secs -= clone.secs;
2062 : 0 : treq.buf += vhd_sectors_to_bytes(clone.secs);
2063 : 0 : continue;
2064 : :
2065 : : fail:
2066 : 0 : clone.secs = treq.secs;
2067 : 0 : td_complete_request(clone, err);
2068 : 0 : break;
2069 : : }
2070 : 0 : }
2071 : :
2072 : : static void
2073 : 0 : vhd_queue_read(td_driver_t *driver, td_request_t treq)
2074 : : {
2075 : 0 : struct vhd_state *s = (struct vhd_state *)driver->data;
2076 : :
2077 : 0 : DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", secs: 0x%04x (seg: %d)\n",
2078 : : s->vhd.file, treq.sec, treq.secs, treq.sidx);
2079 : :
2080 [ # # ]: 0 : while (treq.secs) {
2081 : : int err;
2082 : : td_request_t clone;
2083 : :
2084 : 0 : err = 0;
2085 : 0 : clone = treq;
2086 : :
2087 [ # # # # : 0 : switch (read_bitmap_cache(s, clone.sec, VHD_OP_DATA_READ)) {
# # # ]
2088 : : case -EINVAL:
2089 : : err = -EINVAL;
2090 : : goto fail;
2091 : :
2092 : : case VHD_BM_BAT_CLEAR:
2093 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2094 : 0 : td_forward_request(clone);
2095 : : break;
2096 : :
2097 : : case VHD_BM_BIT_CLEAR:
2098 : 0 : clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 0);
2099 : 0 : td_forward_request(clone);
2100 : : break;
2101 : :
2102 : : case VHD_BM_BIT_SET:
2103 : 0 : clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 1);
2104 : 0 : err = schedule_data_read(s, clone, 0);
2105 [ # # ]: 0 : if (err)
2106 : : goto fail;
2107 : : break;
2108 : :
2109 : : case VHD_BM_NOT_CACHED:
2110 : 0 : err = schedule_bitmap_read(s, clone.sec / s->spb);
2111 [ # # ]: 0 : if (err)
2112 : : goto fail;
2113 : :
2114 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2115 : 0 : err = __vhd_queue_request(s, VHD_OP_DATA_READ, clone);
2116 [ # # ]: 0 : if (err)
2117 : : goto fail;
2118 : : break;
2119 : :
2120 : : case VHD_BM_READ_PENDING:
2121 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2122 : 0 : err = __vhd_queue_request(s, VHD_OP_DATA_READ, clone);
2123 [ # # ]: 0 : if (err)
2124 : : goto fail;
2125 : : break;
2126 : :
2127 : : case VHD_BM_BAT_LOCKED:
2128 : : default:
2129 : 0 : ASSERT(0);
2130 : : break;
2131 : : }
2132 : :
2133 : 0 : treq.sec += clone.secs;
2134 : 0 : treq.secs -= clone.secs;
2135 : 0 : treq.buf += vhd_sectors_to_bytes(clone.secs);
2136 : 0 : continue;
2137 : :
2138 : : fail:
2139 : 0 : clone.secs = treq.secs;
2140 : 0 : td_complete_request(clone, err);
2141 : 0 : break;
2142 : : }
2143 : 0 : }
2144 : :
2145 : : static void
2146 : 0 : vhd_queue_write(td_driver_t *driver, td_request_t treq)
2147 : : {
2148 : 0 : struct vhd_state *s = (struct vhd_state *)driver->data;
2149 : :
2150 : 0 : DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", secs: 0x%04x, (seg: %d)\n",
2151 : : s->vhd.file, treq.sec, treq.secs, treq.sidx);
2152 : :
2153 [ # # ]: 0 : while (treq.secs) {
2154 : : int err;
2155 : : uint8_t flags;
2156 : : td_request_t clone;
2157 : :
2158 : 0 : err = 0;
2159 : 0 : flags = 0;
2160 : 0 : clone = treq;
2161 : :
2162 [ # # # # : 0 : switch (read_bitmap_cache(s, clone.sec, VHD_OP_DATA_WRITE)) {
# # # # ]
2163 : : case -EINVAL:
2164 : : err = -EINVAL;
2165 : : goto fail;
2166 : :
2167 : : case VHD_BM_BAT_LOCKED:
2168 : 0 : err = -EBUSY;
2169 : 0 : goto fail;
2170 : :
2171 : : case VHD_BM_BAT_CLEAR:
2172 : 0 : flags = (VHD_FLAG_REQ_UPDATE_BAT |
2173 : : VHD_FLAG_REQ_UPDATE_BITMAP);
2174 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2175 : 0 : err = schedule_data_write(s, clone, flags);
2176 [ # # ]: 0 : if (err)
2177 : : goto fail;
2178 : : break;
2179 : :
2180 : : case VHD_BM_BIT_CLEAR:
2181 : 0 : flags = VHD_FLAG_REQ_UPDATE_BITMAP;
2182 : 0 : clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 0);
2183 : 0 : err = schedule_data_write(s, clone, flags);
2184 [ # # ]: 0 : if (err)
2185 : : goto fail;
2186 : : break;
2187 : :
2188 : : case VHD_BM_BIT_SET:
2189 : 0 : clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 1);
2190 : 0 : err = schedule_data_write(s, clone, 0);
2191 [ # # ]: 0 : if (err)
2192 : : goto fail;
2193 : : break;
2194 : :
2195 : : case VHD_BM_NOT_CACHED:
2196 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2197 : 0 : err = schedule_bitmap_read(s, clone.sec / s->spb);
2198 [ # # ]: 0 : if (err)
2199 : : goto fail;
2200 : :
2201 : 0 : err = __vhd_queue_request(s, VHD_OP_DATA_WRITE, clone);
2202 [ # # ]: 0 : if (err)
2203 : : goto fail;
2204 : : break;
2205 : :
2206 : : case VHD_BM_READ_PENDING:
2207 : 0 : clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
2208 : 0 : err = __vhd_queue_request(s, VHD_OP_DATA_WRITE, clone);
2209 [ # # ]: 0 : if (err)
2210 : : goto fail;
2211 : : break;
2212 : :
2213 : : default:
2214 : 0 : ASSERT(0);
2215 : : break;
2216 : : }
2217 : :
2218 : 0 : treq.sec += clone.secs;
2219 : 0 : treq.secs -= clone.secs;
2220 : 0 : treq.buf += vhd_sectors_to_bytes(clone.secs);
2221 : 0 : continue;
2222 : :
2223 : : fail:
2224 : 0 : clone.secs = treq.secs;
2225 : 0 : td_complete_request(clone, err);
2226 : 0 : break;
2227 : : }
2228 : 0 : }
2229 : :
2230 : : static inline void
2231 : 0 : signal_completion(struct vhd_request *list, int error)
2232 : : {
2233 : 0 : struct vhd_state *s;
2234 : : struct vhd_request *r, *next;
2235 : :
2236 [ # # ]: 0 : if (!list)
2237 : 0 : return;
2238 : :
2239 : 0 : r = list;
2240 : 0 : s = list->state;
2241 : :
2242 [ # # ]: 0 : while (r) {
2243 : : int err;
2244 : :
2245 [ # # ]: 0 : err = (error ? error : r->error);
2246 : 0 : next = r->next;
2247 [ # # ]: 0 : if (vhd_is_encrypted(s)) {
2248 [ # # # ]: 0 : switch (r->op) {
2249 : : case VHD_OP_DATA_READ:
2250 : 0 : crypto_interface->vhd_crypto_decrypt(
2251 : : &s->vhd, &r->treq);
2252 : 0 : break;
2253 : : case VHD_OP_DATA_WRITE:
2254 : 0 : free(r->treq.buf);
2255 : 0 : r->treq.buf = r->orig_buf;
2256 : 0 : break;
2257 : : }
2258 : : }
2259 : 0 : td_complete_request(r->treq, err);
2260 : 0 : DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x%04"PRIx64", "
2261 : : "err: %d\n", r->treq.sec, r->treq.sec / s->spb, err);
2262 : : free_vhd_request(s, r);
2263 : 0 : r = next;
2264 : :
2265 : 0 : s->returned++;
2266 : 0 : TRACE(s);
2267 : : }
2268 : : }
2269 : :
2270 : : static void
2271 : 0 : start_new_bitmap_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
2272 : : {
2273 : 0 : struct vhd_transaction *tx;
2274 : : struct vhd_request *r, *next;
2275 : : int i;
2276 : :
2277 [ # # ]: 0 : if (!bm->queue.head)
2278 : 0 : return;
2279 : :
2280 : 0 : DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
2281 : :
2282 : 0 : r = bm->queue.head;
2283 : 0 : tx = &bm->tx;
2284 : 0 : clear_req_list(&bm->queue);
2285 : :
2286 [ # # ][ # # ]: 0 : if (r && bat_entry(s, bm->blk) == DD_BLK_UNUSED)
2287 : 0 : tx->error = -EIO;
2288 : :
2289 [ # # ]: 0 : while (r) {
2290 : 0 : next = r->next;
2291 : 0 : r->next = NULL;
2292 : 0 : clear_vhd_flag(r->flags, VHD_FLAG_REQ_QUEUED);
2293 : :
2294 : 0 : add_to_transaction(tx, r);
2295 [ # # ]: 0 : if (test_vhd_flag(r->flags, VHD_FLAG_REQ_FINISHED)) {
2296 : 0 : tx->finished++;
2297 [ # # ]: 0 : if (!r->error) {
2298 : 0 : uint32_t sec = r->treq.sec % s->spb;
2299 [ # # ]: 0 : for (i = 0; i < r->treq.secs; i++)
2300 : 0 : vhd_bitmap_set(&s->vhd,
2301 : : bm->shadow, sec + i);
2302 : : }
2303 : : }
2304 : 0 : r = next;
2305 : : }
2306 : :
2307 : : /* perhaps all the queued writes already completed? */
2308 [ # # ][ # # ]: 0 : if (tx->started && transaction_completed(tx))
2309 : 0 : finish_data_transaction(s, bm);
2310 : : }
2311 : :
2312 : : static void
2313 : 0 : finish_bat_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
2314 : : {
2315 : 0 : struct vhd_transaction *tx = &bm->tx;
2316 : :
2317 [ # # ]: 0 : if (!bat_locked(s))
2318 : : return;
2319 : :
2320 [ # # ]: 0 : if (s->bat.pbw_blk != bm->blk)
2321 : : return;
2322 : :
2323 [ # # ]: 0 : if (!s->bat.req.error)
2324 : : goto release;
2325 : :
2326 [ # # ]: 0 : if (!test_vhd_flag(tx->status, VHD_FLAG_TX_LIVE))
2327 : : goto release;
2328 : :
2329 : 0 : tx->closed = 1;
2330 : 0 : return;
2331 : :
2332 : : release:
2333 : 0 : DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
2334 : 0 : unlock_bat(s);
2335 : : init_bat(s);
2336 : : }
2337 : :
2338 : : static void
2339 : 0 : finish_bitmap_transaction(struct vhd_state *s,
2340 : 0 : struct vhd_bitmap *bm, int error)
2341 : : {
2342 : : int map_size;
2343 : 0 : struct vhd_transaction *tx = &bm->tx;
2344 : :
2345 : 0 : DBG(TLOG_DBG, "blk: 0x%04x, err: %d\n", bm->blk, error);
2346 [ # # ]: 0 : tx->error = (tx->error ? tx->error : error);
2347 : 0 : map_size = vhd_sectors_to_bytes(s->bm_secs);
2348 : :
2349 [ # # ]: 0 : if (!test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE)) {
2350 [ # # ]: 0 : if (test_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT)) {
2351 : : /* still waiting for bat write */
2352 [ # # ]: 0 : ASSERT(bm->blk == s->bat.pbw_blk);
2353 [ # # ]: 0 : ASSERT(test_vhd_flag(s->bat.status,
2354 : : VHD_FLAG_BAT_WRITE_STARTED));
2355 : 0 : s->bat.req.tx = tx;
2356 : 0 : return;
2357 : : }
2358 : : }
2359 : :
2360 [ # # ]: 0 : if (tx->error) {
2361 : : /* undo changes to shadow */
2362 : 0 : memcpy(bm->shadow, bm->map, map_size);
2363 : : } else {
2364 : : /* complete atomic write */
2365 : 0 : memcpy(bm->map, bm->shadow, map_size);
2366 [ # # ][ # # ]: 0 : if (!test_batmap(s, bm->blk) && bitmap_full(s, bm))
2367 : 0 : set_batmap(s, bm->blk);
2368 : : }
2369 : :
2370 : : /* transaction done; signal completions */
2371 : 0 : signal_completion(tx->requests.head, tx->error);
2372 : : init_tx(tx);
2373 : 0 : start_new_bitmap_transaction(s, bm);
2374 : :
2375 [ # # ]: 0 : if (!bitmap_in_use(bm))
2376 : 0 : unlock_bitmap(bm);
2377 : :
2378 : 0 : finish_bat_transaction(s, bm);
2379 : : }
2380 : :
2381 : : static void
2382 : 0 : finish_data_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
2383 : : {
2384 : 0 : struct vhd_transaction *tx = &bm->tx;
2385 : 0 : bool finish_transaction = true;
2386 : :
2387 : 0 : DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
2388 : :
2389 : 0 : tx->closed = 1;
2390 : :
2391 [ # # ]: 0 : if (!tx->error)
2392 : 0 : finish_transaction = schedule_bitmap_write(s, bm->blk);
2393 : :
2394 [ # # ]: 0 : if (finish_transaction) {
2395 : 0 : return finish_bitmap_transaction(s, bm, 0);
2396 : : }
2397 : : }
2398 : :
2399 : : static void
2400 : 0 : finish_bat_write(struct vhd_request *req)
2401 : : {
2402 : 0 : struct vhd_bitmap *bm;
2403 : 0 : struct vhd_transaction *tx;
2404 : 0 : struct vhd_state *s = req->state;
2405 : :
2406 : 0 : s->returned++;
2407 : 0 : TRACE(s);
2408 : :
2409 : 0 : bm = get_bitmap(s, s->bat.pbw_blk);
2410 : :
2411 : 0 : DBG(TLOG_DBG, "blk 0x%04x, pbwo: 0x%08"PRIx64", err %d\n",
2412 : : s->bat.pbw_blk, s->bat.pbw_offset, req->error);
2413 [ # # ][ # # ]: 0 : ASSERT(bm && bitmap_valid(bm));
2414 [ # # ][ # # ]: 0 : ASSERT(bat_locked(s) &&
2415 : : test_vhd_flag(s->bat.status, VHD_FLAG_BAT_WRITE_STARTED));
2416 : :
2417 : 0 : tx = &bm->tx;
2418 [ # # ]: 0 : ASSERT(test_vhd_flag(tx->status, VHD_FLAG_TX_LIVE));
2419 : :
2420 [ # # ]: 0 : if (!req->error) {
2421 : 0 : bat_entry(s, s->bat.pbw_blk) = s->bat.pbw_offset;
2422 : 0 : s->next_db = s->bat.pbw_offset + s->spb + s->bm_secs;
2423 : : } else
2424 : 0 : tx->error = req->error;
2425 : :
2426 [ # # ]: 0 : if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE)) {
2427 : 0 : tx->finished++;
2428 : 0 : remove_from_req_list(&tx->requests, req);
2429 [ # # ]: 0 : if (transaction_completed(tx))
2430 : 0 : finish_data_transaction(s, bm);
2431 : : } else {
2432 : 0 : clear_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT);
2433 [ # # ]: 0 : if (s->bat.req.tx)
2434 : 0 : finish_bitmap_transaction(s, bm, req->error);
2435 : : }
2436 : :
2437 : 0 : finish_bat_transaction(s, bm);
2438 : 0 : }
2439 : :
2440 : : static void
2441 : 0 : finish_zero_bm_write(struct vhd_request *req)
2442 : : {
2443 : : uint32_t blk;
2444 : 0 : struct vhd_bitmap *bm;
2445 : 0 : struct vhd_transaction *tx = req->tx;
2446 : 0 : struct vhd_state *s = req->state;
2447 : :
2448 : 0 : s->returned++;
2449 : 0 : TRACE(s);
2450 : :
2451 : 0 : blk = req->treq.sec / s->spb;
2452 : 0 : bm = get_bitmap(s, blk);
2453 : :
2454 : 0 : DBG(TLOG_DBG, "blk: 0x%04x\n", blk);
2455 [ # # ]: 0 : ASSERT(bat_locked(s));
2456 [ # # ]: 0 : ASSERT(s->bat.pbw_blk == blk);
2457 [ # # ][ # # ]: 0 : ASSERT(bm && bitmap_valid(bm) && bitmap_locked(bm));
[ # # ]
2458 : :
2459 : 0 : tx->finished++;
2460 : 0 : remove_from_req_list(&tx->requests, req);
2461 : :
2462 [ # # ]: 0 : if (req->error) {
2463 : 0 : unlock_bat(s);
2464 : : init_bat(s);
2465 : 0 : tx->error = req->error;
2466 : 0 : clear_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT);
2467 : : } else
2468 : 0 : schedule_bat_write(s);
2469 : :
2470 [ # # ]: 0 : if (transaction_completed(tx))
2471 : 0 : finish_data_transaction(s, bm);
2472 : 0 : }
2473 : :
2474 : : static int
2475 : 0 : finish_redundant_bm_write(struct vhd_request *req)
2476 : : {
2477 : : /* uint32_t blk; */
2478 : 0 : struct vhd_state *s = (struct vhd_state *) req->state;
2479 : :
2480 : 0 : s->returned++;
2481 : 0 : TRACE(s);
2482 : : /* blk = req->treq.sec / s->spb;
2483 : : DBG(TLOG_DBG, "blk: %u\n", blk); */
2484 : :
2485 [ # # ]: 0 : if (req->error) {
2486 [ # # ]: 0 : ERR(s, req->error, "lsec: 0x%08"PRIx64, req->treq.sec);
2487 : : }
2488 : : free_vhd_request(s, req);
2489 : 0 : s->debug_done_redundant_writes++;
2490 : 0 : return 0;
2491 : : }
2492 : :
2493 : :
2494 : : static void
2495 : 0 : finish_bitmap_read(struct vhd_request *req)
2496 : : {
2497 : : uint32_t blk;
2498 : : struct vhd_bitmap *bm;
2499 : : struct vhd_request *r, *next;
2500 : 0 : struct vhd_state *s = req->state;
2501 : :
2502 : 0 : s->returned++;
2503 : 0 : TRACE(s);
2504 : :
2505 : 0 : blk = req->treq.sec / s->spb;
2506 : 0 : bm = get_bitmap(s, blk);
2507 : :
2508 : 0 : DBG(TLOG_DBG, "blk: 0x%04x\n", blk);
2509 [ # # ][ # # ]: 0 : ASSERT(bm && test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING));
2510 : :
2511 : 0 : r = bm->waiting.head;
2512 : 0 : clear_req_list(&bm->waiting);
2513 : 0 : clear_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING);
2514 : :
2515 [ # # ]: 0 : if (!req->error) {
2516 : 0 : memcpy(bm->shadow, bm->map, vhd_sectors_to_bytes(s->bm_secs));
2517 : :
2518 [ # # ]: 0 : while (r) {
2519 : : struct vhd_request tmp;
2520 : :
2521 : 0 : tmp = *r;
2522 : 0 : next = r->next;
2523 : : free_vhd_request(s, r);
2524 : :
2525 [ # # ]: 0 : ASSERT(tmp.op == VHD_OP_DATA_READ ||
2526 : : tmp.op == VHD_OP_DATA_WRITE);
2527 : :
2528 [ # # ]: 0 : if (tmp.op == VHD_OP_DATA_READ)
2529 : 0 : vhd_queue_read(s->driver, tmp.treq);
2530 [ # # ]: 0 : else if (tmp.op == VHD_OP_DATA_WRITE)
2531 : 0 : vhd_queue_write(s->driver, tmp.treq);
2532 : :
2533 : 0 : r = next;
2534 : : }
2535 : : } else {
2536 : 0 : int err = req->error;
2537 : 0 : unlock_bitmap(bm);
2538 : 0 : free_vhd_bitmap(s, bm);
2539 : 0 : return signal_completion(r, err);
2540 : : }
2541 : :
2542 [ # # ]: 0 : if (!bitmap_in_use(bm))
2543 : 0 : unlock_bitmap(bm);
2544 : : }
2545 : :
2546 : : static void
2547 : 0 : finish_bitmap_write(struct vhd_request *req)
2548 : : {
2549 : : uint32_t blk;
2550 : 0 : struct vhd_bitmap *bm;
2551 : : struct vhd_transaction *tx;
2552 : 0 : struct vhd_state *s = req->state;
2553 : :
2554 : 0 : s->returned++;
2555 : 0 : TRACE(s);
2556 : :
2557 : 0 : blk = req->treq.sec / s->spb;
2558 : 0 : bm = get_bitmap(s, blk);
2559 : 0 : tx = &bm->tx;
2560 : :
2561 : 0 : DBG(TLOG_DBG, "blk: 0x%04x, started: %d, finished: %d\n",
2562 : : blk, tx->started, tx->finished);
2563 [ # # ]: 0 : ASSERT(tx->closed);
2564 [ # # ][ # # ]: 0 : ASSERT(bm && bitmap_valid(bm));
2565 [ # # ]: 0 : ASSERT(test_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING));
2566 : :
2567 : 0 : clear_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING);
2568 : :
2569 : 0 : finish_bitmap_transaction(s, bm, req->error);
2570 : 0 : }
2571 : :
2572 : : static void
2573 : 0 : finish_data_read(struct vhd_request *req)
2574 : : {
2575 : 0 : struct vhd_state *s = req->state;
2576 : :
2577 : 0 : DBG(TLOG_DBG, "lsec 0x%08"PRIx64", blk: 0x%04"PRIx64"\n",
2578 : : req->treq.sec, req->treq.sec / s->spb);
2579 : 0 : signal_completion(req, 0);
2580 : 0 : }
2581 : :
2582 : : static void
2583 : 0 : finish_data_write(struct vhd_request *req)
2584 : : {
2585 : : int i;
2586 : 0 : struct vhd_transaction *tx = req->tx;
2587 : 0 : struct vhd_state *s = (struct vhd_state *)req->state;
2588 : :
2589 : 0 : set_vhd_flag(req->flags, VHD_FLAG_REQ_FINISHED);
2590 : :
2591 [ # # ]: 0 : if (tx) {
2592 : : uint32_t blk, sec;
2593 : 0 : struct vhd_bitmap *bm;
2594 : :
2595 : 0 : blk = req->treq.sec / s->spb;
2596 : 0 : sec = req->treq.sec % s->spb;
2597 : 0 : bm = get_bitmap(s, blk);
2598 : :
2599 [ # # ][ # # ]: 0 : ASSERT(bm && bitmap_valid(bm) && bitmap_locked(bm));
[ # # ]
2600 : :
2601 : 0 : tx->finished++;
2602 : :
2603 : 0 : DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x04%"PRIx64", "
2604 : : "tx->started: %d, tx->finished: %d\n", req->treq.sec,
2605 : : req->treq.sec / s->spb, tx->started, tx->finished);
2606 : :
2607 [ # # ]: 0 : if (!req->error)
2608 [ # # ]: 0 : for (i = 0; i < req->treq.secs; i++)
2609 : 0 : vhd_bitmap_set(&s->vhd, bm->shadow, sec + i);
2610 : :
2611 [ # # ]: 0 : if (transaction_completed(tx))
2612 : 0 : finish_data_transaction(s, bm);
2613 : :
2614 [ # # ]: 0 : } else if (!test_vhd_flag(req->flags, VHD_FLAG_REQ_QUEUED)) {
2615 [ # # ]: 0 : ASSERT(!req->next);
2616 : 0 : DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x%04"PRIx64"\n",
2617 : : req->treq.sec, req->treq.sec / s->spb);
2618 : 0 : signal_completion(req, 0);
2619 : : }
2620 : 0 : }
2621 : :
2622 : : void
2623 : 0 : vhd_complete(void *arg, struct tiocb *tiocb, int err)
2624 : : {
2625 : 0 : struct vhd_request *req = (struct vhd_request *)arg;
2626 : 0 : struct vhd_state *s = req->state;
2627 : :
2628 : 0 : s->completed++;
2629 : 0 : TRACE(s);
2630 : :
2631 : 0 : req->error = err;
2632 : :
2633 [ # # ]: 0 : if (req->error)
2634 [ # # ]: 0 : ERR(s, req->error, "%s: op: %u, lsec: %"PRIu64", secs: %u, "
2635 : : "blk: %"PRIu64", blk_offset: %u",
2636 : : s->vhd.file, req->op, req->treq.sec, req->treq.secs,
2637 : : req->treq.sec / s->spb,
2638 : : bat_entry(s, req->treq.sec / s->spb));
2639 : :
2640 [ # # # # : 0 : switch (req->op) {
# # # # ]
2641 : : case VHD_OP_DATA_READ:
2642 : 0 : finish_data_read(req);
2643 : 0 : break;
2644 : :
2645 : : case VHD_OP_DATA_WRITE:
2646 : 0 : finish_data_write(req);
2647 : 0 : break;
2648 : :
2649 : : case VHD_OP_BITMAP_READ:
2650 : 0 : finish_bitmap_read(req);
2651 : 0 : break;
2652 : :
2653 : : case VHD_OP_BITMAP_WRITE:
2654 : 0 : finish_bitmap_write(req);
2655 : 0 : break;
2656 : :
2657 : : case VHD_OP_ZERO_BM_WRITE:
2658 : 0 : finish_zero_bm_write(req);
2659 : 0 : break;
2660 : :
2661 : : case VHD_OP_REDUNDANT_BM_WRITE:
2662 : 0 : finish_redundant_bm_write(req);
2663 : 0 : break;
2664 : :
2665 : : case VHD_OP_BAT_WRITE:
2666 : 0 : finish_bat_write(req);
2667 : 0 : break;
2668 : :
2669 : : default:
2670 : 0 : ASSERT(0);
2671 : : break;
2672 : : }
2673 : 0 : }
2674 : :
2675 : : void
2676 : 0 : vhd_debug(td_driver_t *driver)
2677 : : {
2678 : : int i;
2679 : 0 : struct vhd_state *s = (struct vhd_state *)driver->data;
2680 : :
2681 : 0 : DBG(TLOG_WARN, "%s: QUEUED: 0x%08"PRIx64", COMPLETED: 0x%08"PRIx64", "
2682 : : "RETURNED: 0x%08"PRIx64"\n", s->vhd.file, s->queued, s->completed,
2683 : : s->returned);
2684 [ # # ]: 0 : DBG(TLOG_WARN, "WRITES: 0x%08"PRIx64", AVG_WRITE_SIZE: %f\n",
2685 : : s->writes, (s->writes ? ((float)s->write_size / s->writes) : 0.0));
2686 [ # # ]: 0 : DBG(TLOG_WARN, "READS: 0x%08"PRIx64", AVG_READ_SIZE: %f\n",
2687 : : s->reads, (s->reads ? ((float)s->read_size / s->reads) : 0.0));
2688 : :
2689 : 0 : DBG(TLOG_WARN, "ALLOCATED REQUESTS: (%u total)\n", VHD_REQS_DATA);
2690 [ # # ]: 0 : for (i = 0; i < VHD_REQS_DATA; i++) {
2691 : 0 : struct vhd_request *r = &s->vreq_list[i];
2692 : 0 : td_request_t *t = &r->treq;
2693 [ # # ]: 0 : const char *vname = t->vreq ? t->vreq->name: NULL;
2694 [ # # ]: 0 : if (t->secs)
2695 : 0 : DBG(TLOG_WARN, "%d: vreq: %s.%d, err: %d, op: %d,"
2696 : : " lsec: 0x%08"PRIx64", flags: %d, this: %p, "
2697 : : "next: %p, tx: %p\n", i, vname, t->sidx, r->error, r->op,
2698 : : t->sec, r->flags, r, r->next, r->tx);
2699 : : }
2700 : :
2701 : 0 : DBG(TLOG_WARN, "BITMAP CACHE:\n");
2702 [ # # ]: 0 : for (i = 0; i < VHD_CACHE_SIZE; i++) {
2703 : 0 : int qnum = 0, wnum = 0, rnum = 0;
2704 : 0 : struct vhd_bitmap *bm = s->bitmap[i];
2705 : : struct vhd_transaction *tx;
2706 : : struct vhd_request *r;
2707 : :
2708 [ # # ]: 0 : if (!bm)
2709 : 0 : continue;
2710 : :
2711 : 0 : tx = &bm->tx;
2712 : 0 : r = bm->queue.head;
2713 [ # # ]: 0 : while (r) {
2714 : 0 : qnum++;
2715 : 0 : r = r->next;
2716 : : }
2717 : :
2718 : 0 : r = bm->waiting.head;
2719 [ # # ]: 0 : while (r) {
2720 : 0 : wnum++;
2721 : 0 : r = r->next;
2722 : : }
2723 : :
2724 : 0 : r = tx->requests.head;
2725 [ # # ]: 0 : while (r) {
2726 : 0 : rnum++;
2727 : 0 : r = r->next;
2728 : : }
2729 : :
2730 : 0 : DBG(TLOG_WARN, "%d: blk: 0x%04x, status: 0x%08x, q: %p, qnum: %d, w: %p, "
2731 : : "wnum: %d, locked: %d, in use: %d, tx: %p, tx_error: %d, "
2732 : : "started: %d, finished: %d, status: %u, reqs: %p, nreqs: %d\n",
2733 : : i, bm->blk, bm->status, bm->queue.head, qnum, bm->waiting.head,
2734 : : wnum, bitmap_locked(bm), bitmap_in_use(bm), tx, tx->error,
2735 : : tx->started, tx->finished, tx->status, tx->requests.head, rnum);
2736 : : }
2737 : :
2738 : 0 : DBG(TLOG_WARN, "BAT: status: 0x%08x, pbw_blk: 0x%04x, "
2739 : : "pbw_off: 0x%08"PRIx64", tx: %p\n", s->bat.status, s->bat.pbw_blk,
2740 : : s->bat.pbw_offset, s->bat.req.tx);
2741 : :
2742 : : /*
2743 : : for (i = 0; i < s->hdr.max_bat_size; i++)
2744 : : DPRINTF("%d: %u\n", i, s->bat.bat[i]);
2745 : : */
2746 : 0 : }
2747 : :
2748 : : struct tap_disk tapdisk_vhd = {
2749 : : .disk_type = "tapdisk_vhd",
2750 : : .flags = 0,
2751 : : .private_data_size = sizeof(struct vhd_state),
2752 : : .td_open = _vhd_open,
2753 : : .td_close = _vhd_close,
2754 : : .td_queue_read = vhd_queue_read,
2755 : : .td_queue_block_status
2756 : : = vhd_queue_block_status,
2757 : : .td_queue_write = vhd_queue_write,
2758 : : .td_get_parent_id = vhd_get_parent_id,
2759 : : .td_validate_parent = vhd_validate_parent,
2760 : : .td_debug = vhd_debug,
2761 : : };
|