ia64/xen-unstable

view tools/blktap2/drivers/block-vhd.c @ 19817:b7f73a7f3078

blktap2: portability fixes for NetBSD

- Use standard off_t and lseek() instead of non-portable off64_t and
lseek64()
- Use uuid API as documented in DCE 1.1 RPC specification
- Add NetBSD implementation for blk_getimagesize() and
blk_getsectorsize()
- Use blk_getimagesize() and blk_getsectorsize()
- Fix uuid header check

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 23 17:24:14 2009 +0100 (2009-06-23)
parents 1c627434605e
children 7750bae3d042
line source
1 /*
2 * Copyright (c) 2008, XenSource Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of XenSource Inc. nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * A note on write transactions:
29 * Writes that require updating the BAT or bitmaps cannot be signaled
30 * as complete until all updates have reached disk. Transactions are
31 * used to ensure proper ordering in these cases. The two types of
32 * transactions are as follows:
33 * - Bitmap updates only: data writes that require updates to the same
34 * bitmap are grouped in a transaction. Only after all data writes
35 * in a transaction complete does the bitmap write commence. Only
36 * after the bitmap write finishes are the data writes signalled as
37 * complete.
38 * - BAT and bitmap updates: data writes are grouped in transactions
39 * as above, but a special extra write is included in the transaction,
40 * which zeros out the newly allocated bitmap on disk. When the data
41 * writes and the zero-bitmap write complete, the BAT and bitmap writes
42 * are started in parallel. The transaction is completed only after both
43 * the BAT and bitmap writes successfully return.
44 */
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <sys/stat.h>
52 #include <sys/ioctl.h>
53 #include <string.h> /* for memset. */
54 #include <libaio.h>
55 #include <sys/mman.h>
57 #include "libvhd.h"
58 #include "tapdisk.h"
59 #include "tapdisk-driver.h"
60 #include "tapdisk-interface.h"
62 unsigned int SPB;
64 #define DEBUGGING 2
65 #define ASSERTING 1
66 #define MICROSOFT_COMPAT
68 #define VHD_BATMAP_MAX_RETRIES 10
70 #define __TRACE(s) \
71 do { \
72 DBG(TLOG_DBG, "%s: QUEUED: %" PRIu64 ", COMPLETED: %" \
73 PRIu64", RETURNED: %" PRIu64 ", DATA_ALLOCATED: " \
74 "%lu, BBLK: 0x%04x\n", \
75 s->vhd.file, s->queued, s->completed, s->returned, \
76 VHD_REQS_DATA - s->vreq_free_count, \
77 s->bat.pbw_blk); \
78 } while(0)
80 #define __ASSERT(_p) \
81 if (!(_p)) { \
82 DPRINTF("%s:%d: FAILED ASSERTION: '%s'\n", \
83 __FILE__, __LINE__, #_p); \
84 DBG(TLOG_WARN, "%s:%d: FAILED ASSERTION: '%s'\n", \
85 __FILE__, __LINE__, #_p); \
86 tlog_flush(); \
87 *(int*)0 = 0; \
88 }
90 #if (DEBUGGING == 1)
91 #define DBG(level, _f, _a...) DPRINTF(_f, ##_a)
92 #define ERR(err, _f, _a...) DPRINTF("ERROR: %d: " _f, err, ##_a)
93 #define TRACE(s) ((void)0)
94 #elif (DEBUGGING == 2)
95 #define DBG(level, _f, _a...) tlog_write(level, _f, ##_a)
96 #define ERR(err, _f, _a...) tlog_error(err, _f, ##_a)
97 #define TRACE(s) __TRACE(s)
98 #else
99 #define DBG(level, _f, _a...) ((void)0)
100 #define ERR(err, _f, _a...) ((void)0)
101 #define TRACE(s) ((void)0)
102 #endif
104 #if (ASSERTING == 1)
105 #define ASSERT(_p) __ASSERT(_p)
106 #else
107 #define ASSERT(_p) ((void)0)
108 #endif
110 /******VHD DEFINES******/
111 #define VHD_CACHE_SIZE 32
113 #define VHD_REQS_DATA TAPDISK_DATA_REQUESTS
114 #define VHD_REQS_META (VHD_CACHE_SIZE + 2)
115 #define VHD_REQS_TOTAL (VHD_REQS_DATA + VHD_REQS_META)
117 #define VHD_OP_BAT_WRITE 0
118 #define VHD_OP_DATA_READ 1
119 #define VHD_OP_DATA_WRITE 2
120 #define VHD_OP_BITMAP_READ 3
121 #define VHD_OP_BITMAP_WRITE 4
122 #define VHD_OP_ZERO_BM_WRITE 5
124 #define VHD_BM_BAT_LOCKED 0
125 #define VHD_BM_BAT_CLEAR 1
126 #define VHD_BM_BIT_CLEAR 2
127 #define VHD_BM_BIT_SET 3
128 #define VHD_BM_NOT_CACHED 4
129 #define VHD_BM_READ_PENDING 5
131 #define VHD_FLAG_OPEN_RDONLY 1
132 #define VHD_FLAG_OPEN_NO_CACHE 2
133 #define VHD_FLAG_OPEN_QUIET 4
134 #define VHD_FLAG_OPEN_STRICT 8
135 #define VHD_FLAG_OPEN_QUERY 16
136 #define VHD_FLAG_OPEN_PREALLOCATE 32
138 #define VHD_FLAG_BAT_LOCKED 1
139 #define VHD_FLAG_BAT_WRITE_STARTED 2
141 #define VHD_FLAG_BM_UPDATE_BAT 1
142 #define VHD_FLAG_BM_WRITE_PENDING 2
143 #define VHD_FLAG_BM_READ_PENDING 4
144 #define VHD_FLAG_BM_LOCKED 8
146 #define VHD_FLAG_REQ_UPDATE_BAT 1
147 #define VHD_FLAG_REQ_UPDATE_BITMAP 2
148 #define VHD_FLAG_REQ_QUEUED 4
149 #define VHD_FLAG_REQ_FINISHED 8
151 #define VHD_FLAG_TX_LIVE 1
152 #define VHD_FLAG_TX_UPDATE_BAT 2
154 typedef uint8_t vhd_flag_t;
156 struct vhd_state;
157 struct vhd_request;
159 struct vhd_req_list {
160 struct vhd_request *head;
161 struct vhd_request *tail;
162 };
164 struct vhd_transaction {
165 int error;
166 int closed;
167 int started;
168 int finished;
169 vhd_flag_t status;
170 struct vhd_req_list requests;
171 };
173 struct vhd_request {
174 int error;
175 uint8_t op;
176 vhd_flag_t flags;
177 td_request_t treq;
178 struct tiocb tiocb;
179 struct vhd_state *state;
180 struct vhd_request *next;
181 struct vhd_transaction *tx;
182 };
184 struct vhd_bat_state {
185 vhd_bat_t bat;
186 vhd_batmap_t batmap;
187 vhd_flag_t status;
188 uint32_t pbw_blk; /* blk num of pending write */
189 uint64_t pbw_offset; /* file offset of same */
190 struct vhd_request req; /* for writing bat table */
191 struct vhd_request zero_req; /* for initializing bitmaps */
192 char *bat_buf;
193 };
195 struct vhd_bitmap {
196 u32 blk;
197 u64 seqno; /* lru sequence number */
198 vhd_flag_t status;
200 char *map; /* map should only be modified
201 * in finish_bitmap_write */
202 char *shadow; /* in-memory bitmap changes are
203 * made to shadow and copied to
204 * map only after having been
205 * flushed to disk */
206 struct vhd_transaction tx; /* transaction data structure
207 * encapsulating data, bitmap,
208 * and bat writes */
209 struct vhd_req_list queue; /* data writes waiting for next
210 * transaction */
211 struct vhd_req_list waiting; /* pending requests that cannot
212 * be serviced until this bitmap
213 * is read from disk */
214 struct vhd_request req;
215 };
217 struct vhd_state {
218 vhd_flag_t flags;
220 /* VHD stuff */
221 vhd_context_t vhd;
222 u32 spp; /* sectors per page */
223 u32 spb; /* sectors per block */
224 u64 next_db; /* pointer to the next
225 * (unallocated) datablock */
227 struct vhd_bat_state bat;
229 u64 bm_lru; /* lru sequence number */
230 u32 bm_secs; /* size of bitmap, in sectors */
231 struct vhd_bitmap *bitmap[VHD_CACHE_SIZE];
233 int bm_free_count;
234 struct vhd_bitmap *bitmap_free[VHD_CACHE_SIZE];
235 struct vhd_bitmap bitmap_list[VHD_CACHE_SIZE];
237 int vreq_free_count;
238 struct vhd_request *vreq_free[VHD_REQS_DATA];
239 struct vhd_request vreq_list[VHD_REQS_DATA];
241 td_driver_t *driver;
243 uint64_t queued;
244 uint64_t completed;
245 uint64_t returned;
246 uint64_t reads;
247 uint64_t read_size;
248 uint64_t writes;
249 uint64_t write_size;
250 };
252 #define test_vhd_flag(word, flag) ((word) & (flag))
253 #define set_vhd_flag(word, flag) ((word) |= (flag))
254 #define clear_vhd_flag(word, flag) ((word) &= ~(flag))
256 #define bat_entry(s, blk) ((s)->bat.bat.bat[(blk)])
258 static void vhd_complete(void *, struct tiocb *, int);
259 static void finish_data_transaction(struct vhd_state *, struct vhd_bitmap *);
261 static struct vhd_state *_vhd_master;
262 static unsigned long _vhd_zsize;
263 static char *_vhd_zeros;
265 static int
266 vhd_initialize(struct vhd_state *s)
267 {
268 if (_vhd_zeros)
269 return 0;
271 _vhd_zsize = 2 * getpagesize();
272 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE))
273 _vhd_zsize += VHD_BLOCK_SIZE;
275 _vhd_zeros = mmap(0, _vhd_zsize, PROT_READ,
276 MAP_SHARED | MAP_ANON, -1, 0);
277 if (_vhd_zeros == MAP_FAILED) {
278 EPRINTF("vhd_initialize failed: %d\n", -errno);
279 _vhd_zeros = NULL;
280 _vhd_zsize = 0;
281 return -errno;
282 }
284 _vhd_master = s;
285 return 0;
286 }
288 static void
289 vhd_free(struct vhd_state *s)
290 {
291 if (_vhd_master != s || !_vhd_zeros)
292 return;
294 munmap(_vhd_zeros, _vhd_zsize);
295 _vhd_zsize = 0;
296 _vhd_zeros = NULL;
297 _vhd_master = NULL;
298 }
300 static char *
301 _get_vhd_zeros(const char *func, unsigned long size)
302 {
303 if (!_vhd_zeros || _vhd_zsize < size) {
304 EPRINTF("invalid zero request from %s: %lu, %lu, %p\n",
305 func, size, _vhd_zsize, _vhd_zeros);
306 ASSERT(0);
307 }
309 return _vhd_zeros;
310 }
312 #define vhd_zeros(size) _get_vhd_zeros(__func__, size)
314 static inline void
315 set_batmap(struct vhd_state *s, uint32_t blk)
316 {
317 if (s->bat.batmap.map) {
318 vhd_batmap_set(&s->vhd, &s->bat.batmap, blk);
319 DBG(TLOG_DBG, "block 0x%x completely full\n", blk);
320 }
321 }
323 static inline int
324 test_batmap(struct vhd_state *s, uint32_t blk)
325 {
326 if (!s->bat.batmap.map)
327 return 0;
328 return vhd_batmap_test(&s->vhd, &s->bat.batmap, blk);
329 }
331 static int
332 vhd_kill_footer(struct vhd_state *s)
333 {
334 int err;
335 off_t end;
336 char *zeros;
338 if (s->vhd.footer.type == HD_TYPE_FIXED)
339 return 0;
341 err = posix_memalign((void **)&zeros, 512, 512);
342 if (err)
343 return -err;
345 err = 1;
346 memset(zeros, 0xc7c7c7c7, 512);
348 if ((end = lseek(s->vhd.fd, 0, SEEK_END)) == -1)
349 goto fail;
351 if (lseek(s->vhd.fd, (end - 512), SEEK_SET) == -1)
352 goto fail;
354 if (write(s->vhd.fd, zeros, 512) != 512)
355 goto fail;
357 err = 0;
359 fail:
360 free(zeros);
361 if (err)
362 return (errno ? -errno : -EIO);
363 return 0;
364 }
366 static inline int
367 find_next_free_block(struct vhd_state *s)
368 {
369 int err;
370 off_t eom;
371 uint32_t i, entry;
373 err = vhd_end_of_headers(&s->vhd, &eom);
374 if (err)
375 return err;
377 s->next_db = secs_round_up(eom);
379 for (i = 0; i < s->bat.bat.entries; i++) {
380 entry = bat_entry(s, i);
381 if (entry != DD_BLK_UNUSED && entry >= s->next_db)
382 s->next_db = entry + s->spb + s->bm_secs;
383 }
385 return 0;
386 }
388 static void
389 vhd_free_bat(struct vhd_state *s)
390 {
391 free(s->bat.bat.bat);
392 free(s->bat.batmap.map);
393 free(s->bat.bat_buf);
394 memset(&s->bat, 0, sizeof(struct vhd_bat));
395 }
397 static int
398 vhd_initialize_bat(struct vhd_state *s)
399 {
400 int err, psize, batmap_required, i;
402 memset(&s->bat, 0, sizeof(struct vhd_bat));
404 psize = getpagesize();
406 err = vhd_read_bat(&s->vhd, &s->bat.bat);
407 if (err) {
408 EPRINTF("%s: reading bat: %d\n", s->vhd.file, err);
409 return err;
410 }
412 batmap_required = 1;
413 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_RDONLY)) {
414 batmap_required = 0;
415 } else {
416 err = find_next_free_block(s);
417 if (err)
418 goto fail;
419 }
421 if (vhd_has_batmap(&s->vhd)) {
422 for (i = 0; i < VHD_BATMAP_MAX_RETRIES; i++) {
423 err = vhd_read_batmap(&s->vhd, &s->bat.batmap);
424 if (err) {
425 EPRINTF("%s: reading batmap: %d\n",
426 s->vhd.file, err);
427 if (batmap_required)
428 goto fail;
429 } else {
430 break;
431 }
432 }
433 if (err)
434 EPRINTF("%s: ignoring non-critical batmap error\n",
435 s->vhd.file);
436 }
438 err = posix_memalign((void **)&s->bat.bat_buf,
439 VHD_SECTOR_SIZE, VHD_SECTOR_SIZE);
440 if (err) {
441 s->bat.bat_buf = NULL;
442 goto fail;
443 }
445 return 0;
447 fail:
448 vhd_free_bat(s);
449 return err;
450 }
452 static void
453 vhd_free_bitmap_cache(struct vhd_state *s)
454 {
455 int i;
456 struct vhd_bitmap *bm;
458 for (i = 0; i < VHD_CACHE_SIZE; i++) {
459 bm = s->bitmap_list + i;
460 free(bm->map);
461 free(bm->shadow);
462 s->bitmap_free[i] = NULL;
463 }
465 memset(s->bitmap_list, 0, sizeof(struct vhd_bitmap) * VHD_CACHE_SIZE);
466 }
468 static int
469 vhd_initialize_bitmap_cache(struct vhd_state *s)
470 {
471 int i, err, map_size;
472 struct vhd_bitmap *bm;
474 memset(s->bitmap_list, 0, sizeof(struct vhd_bitmap) * VHD_CACHE_SIZE);
476 s->bm_lru = 0;
477 map_size = vhd_sectors_to_bytes(s->bm_secs);
478 s->bm_free_count = VHD_CACHE_SIZE;
480 for (i = 0; i < VHD_CACHE_SIZE; i++) {
481 bm = s->bitmap_list + i;
483 err = posix_memalign((void **)&bm->map, 512, map_size);
484 if (err) {
485 bm->map = NULL;
486 goto fail;
487 }
489 err = posix_memalign((void **)&bm->shadow, 512, map_size);
490 if (err) {
491 bm->shadow = NULL;
492 goto fail;
493 }
495 memset(bm->map, 0, map_size);
496 memset(bm->shadow, 0, map_size);
497 s->bitmap_free[i] = bm;
498 }
500 return 0;
502 fail:
503 vhd_free_bitmap_cache(s);
504 return err;
505 }
507 static int
508 vhd_initialize_dynamic_disk(struct vhd_state *s)
509 {
510 int err;
512 err = vhd_get_header(&s->vhd);
513 if (err) {
514 if (!test_vhd_flag(s->flags, VHD_FLAG_OPEN_QUIET))
515 EPRINTF("Error reading VHD DD header.\n");
516 return err;
517 }
519 if (s->vhd.header.hdr_ver != 0x00010000) {
520 EPRINTF("unsupported header version! (0x%x)\n",
521 s->vhd.header.hdr_ver);
522 return -EINVAL;
523 }
525 s->spp = getpagesize() >> VHD_SECTOR_SHIFT;
526 s->spb = s->vhd.header.block_size >> VHD_SECTOR_SHIFT;
527 s->bm_secs = secs_round_up_no_zero(s->spb >> 3);
529 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_NO_CACHE))
530 return 0;
532 err = vhd_initialize_bat(s);
533 if (err)
534 return err;
536 err = vhd_initialize_bitmap_cache(s);
537 if (err) {
538 vhd_free_bat(s);
539 return err;
540 }
542 return 0;
543 }
545 static int
546 vhd_check_version(struct vhd_state *s)
547 {
548 if (strncmp(s->vhd.footer.crtr_app, "tap", 3))
549 return 0;
551 if (s->vhd.footer.crtr_ver > VHD_CURRENT_VERSION) {
552 if (!test_vhd_flag(s->flags, VHD_FLAG_OPEN_QUIET))
553 EPRINTF("WARNING: %s vhd creator version 0x%08x, "
554 "but only versions up to 0x%08x are "
555 "supported for IO\n", s->vhd.file,
556 s->vhd.footer.crtr_ver, VHD_CURRENT_VERSION);
558 return -EINVAL;
559 }
561 return 0;
562 }
564 static void
565 vhd_log_open(struct vhd_state *s)
566 {
567 char buf[5];
568 uint32_t i, allocated, full;
570 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_QUIET))
571 return;
573 snprintf(buf, sizeof(buf), "%s", s->vhd.footer.crtr_app);
574 if (!vhd_type_dynamic(&s->vhd)) {
575 DPRINTF("%s version: %s 0x%08x\n",
576 s->vhd.file, buf, s->vhd.footer.crtr_ver);
577 return;
578 }
580 allocated = 0;
581 full = 0;
583 for (i = 0; i < s->bat.bat.entries; i++) {
584 if (bat_entry(s, i) != DD_BLK_UNUSED)
585 allocated++;
586 if (test_batmap(s, i))
587 full++;
588 }
590 DPRINTF("%s version: %s 0x%08x, b: %u, a: %u, f: %u, n: %"PRIu64"\n",
591 s->vhd.file, buf, s->vhd.footer.crtr_ver, s->bat.bat.entries,
592 allocated, full, s->next_db);
593 }
595 static int
596 __vhd_open(td_driver_t *driver, const char *name, vhd_flag_t flags)
597 {
598 int i, o_flags, err;
599 struct vhd_state *s;
601 DBG(TLOG_INFO, "vhd_open: %s\n", name);
602 if (test_vhd_flag(flags, VHD_FLAG_OPEN_STRICT))
603 libvhd_set_log_level(1);
605 s = (struct vhd_state *)driver->data;
606 memset(s, 0, sizeof(struct vhd_state));
608 s->flags = flags;
609 s->driver = driver;
611 err = vhd_initialize(s);
612 if (err)
613 return err;
615 o_flags = ((test_vhd_flag(flags, VHD_FLAG_OPEN_RDONLY)) ?
616 VHD_OPEN_RDONLY : VHD_OPEN_RDWR);
618 err = vhd_open(&s->vhd, name, o_flags);
619 if (err) {
620 libvhd_set_log_level(1);
621 err = vhd_open(&s->vhd, name, o_flags);
622 if (err) {
623 EPRINTF("Unable to open [%s] (%d)!\n", name, err);
624 return err;
625 }
626 }
628 err = vhd_check_version(s);
629 if (err)
630 goto fail;
632 s->spb = s->spp = 1;
634 if (vhd_type_dynamic(&s->vhd)) {
635 err = vhd_initialize_dynamic_disk(s);
636 if (err)
637 goto fail;
638 }
640 vhd_log_open(s);
642 SPB = s->spb;
644 s->vreq_free_count = VHD_REQS_DATA;
645 for (i = 0; i < VHD_REQS_DATA; i++)
646 s->vreq_free[i] = s->vreq_list + i;
648 driver->info.size = s->vhd.footer.curr_size >> VHD_SECTOR_SHIFT;
649 driver->info.sector_size = VHD_SECTOR_SIZE;
650 driver->info.info = 0;
652 DBG(TLOG_INFO, "vhd_open: done (sz:%"PRIu64", sct:%lu, inf:%u)\n",
653 driver->info.size, driver->info.sector_size, driver->info.info);
655 if (test_vhd_flag(flags, VHD_FLAG_OPEN_STRICT) &&
656 !test_vhd_flag(flags, VHD_FLAG_OPEN_RDONLY)) {
657 err = vhd_kill_footer(s);
658 if (err) {
659 DPRINTF("ERROR killing footer: %d\n", err);
660 goto fail;
661 }
662 s->writes++;
663 }
665 return 0;
667 fail:
668 vhd_free_bat(s);
669 vhd_free_bitmap_cache(s);
670 vhd_close(&s->vhd);
671 vhd_free(s);
672 return err;
673 }
675 static int
676 _vhd_open(td_driver_t *driver, const char *name, td_flag_t flags)
677 {
678 vhd_flag_t vhd_flags = 0;
680 if (flags & TD_OPEN_RDONLY)
681 vhd_flags |= VHD_FLAG_OPEN_RDONLY;
682 if (flags & TD_OPEN_QUIET)
683 vhd_flags |= VHD_FLAG_OPEN_QUIET;
684 if (flags & TD_OPEN_STRICT)
685 vhd_flags |= VHD_FLAG_OPEN_STRICT;
686 if (flags & TD_OPEN_QUERY)
687 vhd_flags |= (VHD_FLAG_OPEN_QUERY |
688 VHD_FLAG_OPEN_QUIET |
689 VHD_FLAG_OPEN_RDONLY |
690 VHD_FLAG_OPEN_NO_CACHE);
692 /* pre-allocate for all but NFS and LVM storage */
693 if (driver->storage != TAPDISK_STORAGE_TYPE_NFS &&
694 driver->storage != TAPDISK_STORAGE_TYPE_LVM)
695 vhd_flags |= VHD_FLAG_OPEN_PREALLOCATE;
697 return __vhd_open(driver, name, vhd_flags);
698 }
700 static void
701 vhd_log_close(struct vhd_state *s)
702 {
703 uint32_t i, allocated, full;
705 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_QUIET))
706 return;
708 allocated = 0;
709 full = 0;
711 for (i = 0; i < s->bat.bat.entries; i++) {
712 if (bat_entry(s, i) != DD_BLK_UNUSED)
713 allocated++;
714 if (test_batmap(s, i))
715 full++;
716 }
718 DPRINTF("%s: b: %u, a: %u, f: %u, n: %"PRIu64"\n",
719 s->vhd.file, s->bat.bat.entries, allocated, full, s->next_db);
720 }
722 static int
723 _vhd_close(td_driver_t *driver)
724 {
725 int err;
726 struct vhd_state *s;
727 struct vhd_bitmap *bm;
729 DBG(TLOG_WARN, "vhd_close\n");
730 s = (struct vhd_state *)driver->data;
732 /* don't write footer if tapdisk is read-only */
733 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_RDONLY))
734 goto free;
736 /*
737 * write footer if:
738 * - we killed it on open (opened with strict)
739 * - we've written data since opening
740 */
741 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_STRICT) || s->writes) {
742 memcpy(&s->vhd.bat, &s->bat.bat, sizeof(vhd_bat_t));
743 err = vhd_write_footer(&s->vhd, &s->vhd.footer);
744 memset(&s->vhd.bat, 0, sizeof(vhd_bat_t));
746 if (err)
747 EPRINTF("writing %s footer: %d\n", s->vhd.file, err);
749 if (!vhd_has_batmap(&s->vhd))
750 goto free;
752 err = vhd_write_batmap(&s->vhd, &s->bat.batmap);
753 if (err)
754 EPRINTF("writing %s batmap: %d\n", s->vhd.file, err);
755 }
757 free:
758 vhd_log_close(s);
759 vhd_free_bat(s);
760 vhd_free_bitmap_cache(s);
761 vhd_close(&s->vhd);
762 vhd_free(s);
764 memset(s, 0, sizeof(struct vhd_state));
766 return 0;
767 }
769 int
770 vhd_validate_parent(td_driver_t *child_driver,
771 td_driver_t *parent_driver, td_flag_t flags)
772 {
773 uint32_t status;
774 struct stat stats;
775 struct vhd_state *child = (struct vhd_state *)child_driver->data;
776 struct vhd_state *parent;
778 if (parent_driver->type != DISK_TYPE_VHD) {
779 if (child_driver->type != DISK_TYPE_VHD)
780 return -EINVAL;
781 if (child->vhd.footer.type != HD_TYPE_DIFF)
782 return -EINVAL;
783 if (!vhd_parent_raw(&child->vhd))
784 return -EINVAL;
785 return 0;
786 }
788 parent = (struct vhd_state *)parent_driver->data;
790 /*
791 * This check removed because of cases like:
792 * - parent VHD marked as 'hidden'
793 * - parent VHD modified during coalesce
794 */
795 /*
796 if (stat(parent->vhd.file, &stats)) {
797 DPRINTF("ERROR stating parent file %s\n", parent->vhd.file);
798 return -errno;
799 }
801 if (child->hdr.prt_ts != vhd_time(stats.st_mtime)) {
802 DPRINTF("ERROR: parent file has been modified since "
803 "snapshot. Child image no longer valid.\n");
804 return -EINVAL;
805 }
806 */
808 if (uuid_compare(child->vhd.header.prt_uuid, parent->vhd.footer.uuid)) {
809 DPRINTF("ERROR: %s: %s, %s: parent uuid has changed since "
810 "snapshot. Child image no longer valid.\n",
811 __func__, child->vhd.file, parent->vhd.file);
812 return -EINVAL;
813 }
815 /* TODO: compare sizes */
817 return 0;
818 }
820 int
821 vhd_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
822 {
823 int err;
824 char *parent;
825 struct vhd_state *s;
827 DBG(TLOG_DBG, "\n");
828 memset(id, 0, sizeof(td_disk_id_t));
830 s = (struct vhd_state *)driver->data;
832 if (s->vhd.footer.type != HD_TYPE_DIFF)
833 return TD_NO_PARENT;
835 err = vhd_parent_locator_get(&s->vhd, &parent);
836 if (err)
837 return err;
839 id->name = parent;
840 id->drivertype = DISK_TYPE_VHD;
841 if (vhd_parent_raw(&s->vhd)) {
842 DPRINTF("VHD: parent is raw\n");
843 id->drivertype = DISK_TYPE_AIO;
844 }
845 return 0;
846 }
848 static inline void
849 clear_req_list(struct vhd_req_list *list)
850 {
851 list->head = list->tail = NULL;
852 }
854 static inline void
855 add_to_tail(struct vhd_req_list *list, struct vhd_request *e)
856 {
857 if (!list->head)
858 list->head = list->tail = e;
859 else
860 list->tail = list->tail->next = e;
861 }
863 static inline int
864 remove_from_req_list(struct vhd_req_list *list, struct vhd_request *e)
865 {
866 struct vhd_request *i = list->head;
868 if (list->head == e) {
869 if (list->tail == e)
870 clear_req_list(list);
871 else
872 list->head = list->head->next;
873 return 0;
874 }
876 while (i->next) {
877 if (i->next == e) {
878 if (list->tail == e) {
879 i->next = NULL;
880 list->tail = i;
881 } else
882 i->next = i->next->next;
883 return 0;
884 }
885 i = i->next;
886 }
888 return -EINVAL;
889 }
891 static inline void
892 init_vhd_request(struct vhd_state *s, struct vhd_request *req)
893 {
894 memset(req, 0, sizeof(struct vhd_request));
895 req->state = s;
896 }
898 static inline void
899 init_tx(struct vhd_transaction *tx)
900 {
901 memset(tx, 0, sizeof(struct vhd_transaction));
902 }
904 static inline void
905 add_to_transaction(struct vhd_transaction *tx, struct vhd_request *r)
906 {
907 ASSERT(!tx->closed);
909 r->tx = tx;
910 tx->started++;
911 add_to_tail(&tx->requests, r);
912 set_vhd_flag(tx->status, VHD_FLAG_TX_LIVE);
914 DBG(TLOG_DBG, "blk: 0x%04"PRIx64", lsec: 0x%08"PRIx64", tx: %p, "
915 "started: %d, finished: %d, status: %u\n",
916 r->treq.sec / SPB, r->treq.sec, tx,
917 tx->started, tx->finished, tx->status);
918 }
920 static inline int
921 transaction_completed(struct vhd_transaction *tx)
922 {
923 return (tx->started == tx->finished);
924 }
926 static inline void
927 init_bat(struct vhd_state *s)
928 {
929 s->bat.req.tx = NULL;
930 s->bat.req.next = NULL;
931 s->bat.req.error = 0;
932 s->bat.pbw_blk = 0;
933 s->bat.pbw_offset = 0;
934 s->bat.status = 0;
935 }
937 static inline void
938 lock_bat(struct vhd_state *s)
939 {
940 set_vhd_flag(s->bat.status, VHD_FLAG_BAT_LOCKED);
941 }
943 static inline void
944 unlock_bat(struct vhd_state *s)
945 {
946 clear_vhd_flag(s->bat.status, VHD_FLAG_BAT_LOCKED);
947 }
949 static inline int
950 bat_locked(struct vhd_state *s)
951 {
952 return test_vhd_flag(s->bat.status, VHD_FLAG_BAT_LOCKED);
953 }
955 static inline void
956 init_vhd_bitmap(struct vhd_state *s, struct vhd_bitmap *bm)
957 {
958 bm->blk = 0;
959 bm->seqno = 0;
960 bm->status = 0;
961 init_tx(&bm->tx);
962 clear_req_list(&bm->queue);
963 clear_req_list(&bm->waiting);
964 memset(bm->map, 0, vhd_sectors_to_bytes(s->bm_secs));
965 memset(bm->shadow, 0, vhd_sectors_to_bytes(s->bm_secs));
966 init_vhd_request(s, &bm->req);
967 }
969 static inline struct vhd_bitmap *
970 get_bitmap(struct vhd_state *s, uint32_t block)
971 {
972 int i;
973 struct vhd_bitmap *bm;
975 for (i = 0; i < VHD_CACHE_SIZE; i++) {
976 bm = s->bitmap[i];
977 if (bm && bm->blk == block)
978 return bm;
979 }
981 return NULL;
982 }
984 static inline void
985 lock_bitmap(struct vhd_bitmap *bm)
986 {
987 set_vhd_flag(bm->status, VHD_FLAG_BM_LOCKED);
988 }
990 static inline void
991 unlock_bitmap(struct vhd_bitmap *bm)
992 {
993 clear_vhd_flag(bm->status, VHD_FLAG_BM_LOCKED);
994 }
996 static inline int
997 bitmap_locked(struct vhd_bitmap *bm)
998 {
999 return test_vhd_flag(bm->status, VHD_FLAG_BM_LOCKED);
1002 static inline int
1003 bitmap_valid(struct vhd_bitmap *bm)
1005 return !test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING);
1008 static inline int
1009 bitmap_in_use(struct vhd_bitmap *bm)
1011 return (test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING) ||
1012 test_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING) ||
1013 test_vhd_flag(bm->tx.status, VHD_FLAG_TX_UPDATE_BAT) ||
1014 bm->waiting.head || bm->tx.requests.head || bm->queue.head);
1017 static inline int
1018 bitmap_full(struct vhd_state *s, struct vhd_bitmap *bm)
1020 int i, n;
1022 n = s->spb >> 3;
1023 for (i = 0; i < n; i++)
1024 if (bm->map[i] != (char)0xFF)
1025 return 0;
1027 DBG(TLOG_DBG, "bitmap 0x%04x full\n", bm->blk);
1028 return 1;
1031 static struct vhd_bitmap *
1032 remove_lru_bitmap(struct vhd_state *s)
1034 int i, idx = 0;
1035 u64 seq = s->bm_lru;
1036 struct vhd_bitmap *bm, *lru = NULL;
1038 for (i = 0; i < VHD_CACHE_SIZE; i++) {
1039 bm = s->bitmap[i];
1040 if (bm && bm->seqno < seq && !bitmap_locked(bm)) {
1041 idx = i;
1042 lru = bm;
1043 seq = lru->seqno;
1047 if (lru) {
1048 s->bitmap[idx] = NULL;
1049 ASSERT(!bitmap_in_use(lru));
1052 return lru;
1055 static int
1056 alloc_vhd_bitmap(struct vhd_state *s, struct vhd_bitmap **bitmap, uint32_t blk)
1058 struct vhd_bitmap *bm;
1060 *bitmap = NULL;
1062 if (s->bm_free_count > 0) {
1063 bm = s->bitmap_free[--s->bm_free_count];
1064 } else {
1065 bm = remove_lru_bitmap(s);
1066 if (!bm)
1067 return -EBUSY;
1070 init_vhd_bitmap(s, bm);
1071 bm->blk = blk;
1072 *bitmap = bm;
1074 return 0;
1077 static inline uint64_t
1078 __bitmap_lru_seqno(struct vhd_state *s)
1080 int i;
1081 struct vhd_bitmap *bm;
1083 if (s->bm_lru == 0xffffffff) {
1084 s->bm_lru = 0;
1085 for (i = 0; i < VHD_CACHE_SIZE; i++) {
1086 bm = s->bitmap[i];
1087 if (bm) {
1088 bm->seqno >>= 1;
1089 if (bm->seqno > s->bm_lru)
1090 s->bm_lru = bm->seqno;
1095 return ++s->bm_lru;
1098 static inline void
1099 touch_bitmap(struct vhd_state *s, struct vhd_bitmap *bm)
1101 bm->seqno = __bitmap_lru_seqno(s);
1104 static inline void
1105 install_bitmap(struct vhd_state *s, struct vhd_bitmap *bm)
1107 int i;
1108 for (i = 0; i < VHD_CACHE_SIZE; i++) {
1109 if (!s->bitmap[i]) {
1110 touch_bitmap(s, bm);
1111 s->bitmap[i] = bm;
1112 return;
1116 ASSERT(0);
1119 static inline void
1120 free_vhd_bitmap(struct vhd_state *s, struct vhd_bitmap *bm)
1122 int i;
1124 for (i = 0; i < VHD_CACHE_SIZE; i++)
1125 if (s->bitmap[i] == bm)
1126 break;
1128 ASSERT(!bitmap_locked(bm));
1129 ASSERT(!bitmap_in_use(bm));
1130 ASSERT(i < VHD_CACHE_SIZE);
1132 s->bitmap[i] = NULL;
1133 s->bitmap_free[s->bm_free_count++] = bm;
1136 static int
1137 read_bitmap_cache(struct vhd_state *s, uint64_t sector, uint8_t op)
1139 u32 blk, sec;
1140 struct vhd_bitmap *bm;
1142 /* in fixed disks, every block is present */
1143 if (s->vhd.footer.type == HD_TYPE_FIXED)
1144 return VHD_BM_BIT_SET;
1146 blk = sector / s->spb;
1147 sec = sector % s->spb;
1149 if (blk > s->vhd.header.max_bat_size) {
1150 DPRINTF("ERROR: sec %"PRIu64" out of range, op = %d\n",
1151 sector, op);
1152 return -EINVAL;
1155 if (bat_entry(s, blk) == DD_BLK_UNUSED) {
1156 if (op == VHD_OP_DATA_WRITE &&
1157 s->bat.pbw_blk != blk && bat_locked(s))
1158 return VHD_BM_BAT_LOCKED;
1160 return VHD_BM_BAT_CLEAR;
1163 if (test_batmap(s, blk)) {
1164 DBG(TLOG_DBG, "batmap set for 0x%04x\n", blk);
1165 return VHD_BM_BIT_SET;
1168 bm = get_bitmap(s, blk);
1169 if (!bm)
1170 return VHD_BM_NOT_CACHED;
1172 /* bump lru count */
1173 touch_bitmap(s, bm);
1175 if (test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING))
1176 return VHD_BM_READ_PENDING;
1178 return ((vhd_bitmap_test(&s->vhd, bm->map, sec)) ?
1179 VHD_BM_BIT_SET : VHD_BM_BIT_CLEAR);
1182 static int
1183 read_bitmap_cache_span(struct vhd_state *s,
1184 uint64_t sector, int nr_secs, int value)
1186 int ret;
1187 u32 blk, sec;
1188 struct vhd_bitmap *bm;
1190 /* in fixed disks, every block is present */
1191 if (s->vhd.footer.type == HD_TYPE_FIXED)
1192 return nr_secs;
1194 sec = sector % s->spb;
1195 blk = sector / s->spb;
1197 if (test_batmap(s, blk))
1198 return MIN(nr_secs, s->spb - sec);
1200 bm = get_bitmap(s, blk);
1202 ASSERT(bm && bitmap_valid(bm));
1204 for (ret = 0; sec < s->spb && ret < nr_secs; sec++, ret++)
1205 if (vhd_bitmap_test(&s->vhd, bm->map, sec) != value)
1206 break;
1208 return ret;
1211 static inline struct vhd_request *
1212 alloc_vhd_request(struct vhd_state *s)
1214 struct vhd_request *req = NULL;
1216 if (s->vreq_free_count > 0) {
1217 req = s->vreq_free[--s->vreq_free_count];
1218 ASSERT(req->treq.secs == 0);
1219 init_vhd_request(s, req);
1220 return req;
1223 return NULL;
1226 static inline void
1227 free_vhd_request(struct vhd_state *s, struct vhd_request *req)
1229 memset(req, 0, sizeof(struct vhd_request));
1230 s->vreq_free[s->vreq_free_count++] = req;
1233 static inline void
1234 aio_read(struct vhd_state *s, struct vhd_request *req, uint64_t offset)
1236 struct tiocb *tiocb = &req->tiocb;
1238 td_prep_read(tiocb, s->vhd.fd, req->treq.buf,
1239 vhd_sectors_to_bytes(req->treq.secs),
1240 offset, vhd_complete, req);
1241 td_queue_tiocb(s->driver, tiocb);
1243 s->queued++;
1244 s->reads++;
1245 s->read_size += req->treq.secs;
1246 TRACE(s);
1249 static inline void
1250 aio_write(struct vhd_state *s, struct vhd_request *req, uint64_t offset)
1252 struct tiocb *tiocb = &req->tiocb;
1254 td_prep_write(tiocb, s->vhd.fd, req->treq.buf,
1255 vhd_sectors_to_bytes(req->treq.secs),
1256 offset, vhd_complete, req);
1257 td_queue_tiocb(s->driver, tiocb);
1259 s->queued++;
1260 s->writes++;
1261 s->write_size += req->treq.secs;
1262 TRACE(s);
1265 static inline uint64_t
1266 reserve_new_block(struct vhd_state *s, uint32_t blk)
1268 int gap = 0;
1270 ASSERT(!test_vhd_flag(s->bat.status, VHD_FLAG_BAT_WRITE_STARTED));
1272 /* data region of segment should begin on page boundary */
1273 if ((s->next_db + s->bm_secs) % s->spp)
1274 gap = (s->spp - ((s->next_db + s->bm_secs) % s->spp));
1276 s->bat.pbw_blk = blk;
1277 s->bat.pbw_offset = s->next_db + gap;
1279 return s->next_db;
1282 static int
1283 schedule_bat_write(struct vhd_state *s)
1285 int i;
1286 u32 blk;
1287 char *buf;
1288 u64 offset;
1289 struct vhd_request *req;
1291 ASSERT(bat_locked(s));
1293 req = &s->bat.req;
1294 buf = s->bat.bat_buf;
1295 blk = s->bat.pbw_blk;
1297 init_vhd_request(s, req);
1298 memcpy(buf, &bat_entry(s, blk - (blk % 128)), 512);
1300 ((u32 *)buf)[blk % 128] = s->bat.pbw_offset;
1302 for (i = 0; i < 128; i++)
1303 BE32_OUT(&((u32 *)buf)[i]);
1305 offset = s->vhd.header.table_offset + (blk - (blk % 128)) * 4;
1306 req->treq.secs = 1;
1307 req->treq.buf = buf;
1308 req->op = VHD_OP_BAT_WRITE;
1309 req->next = NULL;
1311 aio_write(s, req, offset);
1312 set_vhd_flag(s->bat.status, VHD_FLAG_BAT_WRITE_STARTED);
1314 DBG(TLOG_DBG, "blk: 0x%04x, pbwo: 0x%08"PRIx64", "
1315 "table_offset: 0x%08"PRIx64"\n", blk, s->bat.pbw_offset, offset);
1317 return 0;
1320 static void
1321 schedule_zero_bm_write(struct vhd_state *s,
1322 struct vhd_bitmap *bm, uint64_t lb_end)
1324 uint64_t offset;
1325 struct vhd_request *req = &s->bat.zero_req;
1327 init_vhd_request(s, req);
1329 offset = vhd_sectors_to_bytes(lb_end);
1330 req->op = VHD_OP_ZERO_BM_WRITE;
1331 req->treq.sec = s->bat.pbw_blk * s->spb;
1332 req->treq.secs = (s->bat.pbw_offset - lb_end) + s->bm_secs;
1333 req->treq.buf = vhd_zeros(vhd_sectors_to_bytes(req->treq.secs));
1334 req->next = NULL;
1336 DBG(TLOG_DBG, "blk: 0x%04x, writing zero bitmap at 0x%08"PRIx64"\n",
1337 s->bat.pbw_blk, offset);
1339 lock_bitmap(bm);
1340 add_to_transaction(&bm->tx, req);
1341 aio_write(s, req, offset);
1344 static int
1345 update_bat(struct vhd_state *s, uint32_t blk)
1347 int err;
1348 uint64_t lb_end;
1349 struct vhd_bitmap *bm;
1351 ASSERT(bat_entry(s, blk) == DD_BLK_UNUSED);
1353 if (bat_locked(s)) {
1354 ASSERT(s->bat.pbw_blk == blk);
1355 return 0;
1358 /* empty bitmap could already be in
1359 * cache if earlier bat update failed */
1360 bm = get_bitmap(s, blk);
1361 if (!bm) {
1362 /* install empty bitmap in cache */
1363 err = alloc_vhd_bitmap(s, &bm, blk);
1364 if (err)
1365 return err;
1367 install_bitmap(s, bm);
1370 lock_bat(s);
1371 lb_end = reserve_new_block(s, blk);
1372 schedule_zero_bm_write(s, bm, lb_end);
1373 set_vhd_flag(bm->tx.status, VHD_FLAG_TX_UPDATE_BAT);
1375 return 0;
1378 static int
1379 allocate_block(struct vhd_state *s, uint32_t blk)
1381 char *zeros;
1382 int err, gap;
1383 uint64_t offset, size;
1384 struct vhd_bitmap *bm;
1386 ASSERT(bat_entry(s, blk) == DD_BLK_UNUSED);
1388 if (bat_locked(s)) {
1389 ASSERT(s->bat.pbw_blk == blk);
1390 if (s->bat.req.error)
1391 return -EBUSY;
1392 return 0;
1395 gap = 0;
1396 s->bat.pbw_blk = blk;
1397 offset = vhd_sectors_to_bytes(s->next_db);
1399 /* data region of segment should begin on page boundary */
1400 if ((s->next_db + s->bm_secs) % s->spp) {
1401 gap = (s->spp - ((s->next_db + s->bm_secs) % s->spp));
1402 s->next_db += gap;
1405 s->bat.pbw_offset = s->next_db;
1407 DBG(TLOG_DBG, "blk: 0x%04x, pbwo: 0x%08"PRIx64"\n",
1408 blk, s->bat.pbw_offset);
1410 if (lseek(s->vhd.fd, offset, SEEK_SET) == (off_t)-1) {
1411 ERR(errno, "lseek failed\n");
1412 return -errno;
1415 size = vhd_sectors_to_bytes(s->spb + s->bm_secs + gap);
1416 err = write(s->vhd.fd, vhd_zeros(size), size);
1417 if (err != size) {
1418 err = (err == -1 ? -errno : -EIO);
1419 ERR(err, "write failed");
1420 return err;
1423 /* empty bitmap could already be in
1424 * cache if earlier bat update failed */
1425 bm = get_bitmap(s, blk);
1426 if (!bm) {
1427 /* install empty bitmap in cache */
1428 err = alloc_vhd_bitmap(s, &bm, blk);
1429 if (err)
1430 return err;
1432 install_bitmap(s, bm);
1435 lock_bat(s);
1436 lock_bitmap(bm);
1437 schedule_bat_write(s);
1438 add_to_transaction(&bm->tx, &s->bat.req);
1440 return 0;
1443 static int
1444 schedule_data_read(struct vhd_state *s, td_request_t treq, vhd_flag_t flags)
1446 u64 offset;
1447 u32 blk = 0, sec = 0;
1448 struct vhd_bitmap *bm;
1449 struct vhd_request *req;
1451 if (s->vhd.footer.type == HD_TYPE_FIXED) {
1452 offset = vhd_sectors_to_bytes(treq.sec);
1453 goto make_request;
1456 blk = treq.sec / s->spb;
1457 sec = treq.sec % s->spb;
1458 bm = get_bitmap(s, blk);
1459 offset = bat_entry(s, blk);
1461 ASSERT(offset != DD_BLK_UNUSED);
1462 ASSERT(test_batmap(s, blk) || (bm && bitmap_valid(bm)));
1464 offset += s->bm_secs + sec;
1465 offset = vhd_sectors_to_bytes(offset);
1467 make_request:
1468 req = alloc_vhd_request(s);
1469 if (!req)
1470 return -EBUSY;
1472 req->treq = treq;
1473 req->flags = flags;
1474 req->op = VHD_OP_DATA_READ;
1475 req->next = NULL;
1477 aio_read(s, req, offset);
1479 DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", blk: 0x%04x, sec: 0x%04x, "
1480 "nr_secs: 0x%04x, offset: 0x%08"PRIx64", flags: 0x%08x, buf: %p\n",
1481 s->vhd.file, treq.sec, blk, sec, treq.secs, offset, req->flags,
1482 treq.buf);
1484 return 0;
1487 static int
1488 schedule_data_write(struct vhd_state *s, td_request_t treq, vhd_flag_t flags)
1490 int err;
1491 u64 offset;
1492 u32 blk = 0, sec = 0;
1493 struct vhd_bitmap *bm = NULL;
1494 struct vhd_request *req;
1496 if (s->vhd.footer.type == HD_TYPE_FIXED) {
1497 offset = vhd_sectors_to_bytes(treq.sec);
1498 goto make_request;
1501 blk = treq.sec / s->spb;
1502 sec = treq.sec % s->spb;
1503 offset = bat_entry(s, blk);
1505 if (test_vhd_flag(flags, VHD_FLAG_REQ_UPDATE_BAT)) {
1506 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE))
1507 err = allocate_block(s, blk);
1508 else
1509 err = update_bat(s, blk);
1511 if (err)
1512 return err;
1514 offset = s->bat.pbw_offset;
1517 offset += s->bm_secs + sec;
1518 offset = vhd_sectors_to_bytes(offset);
1520 make_request:
1521 req = alloc_vhd_request(s);
1522 if (!req)
1523 return -EBUSY;
1525 req->treq = treq;
1526 req->flags = flags;
1527 req->op = VHD_OP_DATA_WRITE;
1528 req->next = NULL;
1530 if (test_vhd_flag(flags, VHD_FLAG_REQ_UPDATE_BITMAP)) {
1531 bm = get_bitmap(s, blk);
1532 ASSERT(bm && bitmap_valid(bm));
1533 lock_bitmap(bm);
1535 if (bm->tx.closed) {
1536 add_to_tail(&bm->queue, req);
1537 set_vhd_flag(req->flags, VHD_FLAG_REQ_QUEUED);
1538 } else
1539 add_to_transaction(&bm->tx, req);
1542 aio_write(s, req, offset);
1544 DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", blk: 0x%04x, sec: 0x%04x, "
1545 "nr_secs: 0x%04x, offset: 0x%08"PRIx64", flags: 0x%08x\n",
1546 s->vhd.file, treq.sec, blk, sec, treq.secs, offset, req->flags);
1548 return 0;
1551 static int
1552 schedule_bitmap_read(struct vhd_state *s, uint32_t blk)
1554 int err;
1555 u64 offset;
1556 struct vhd_bitmap *bm;
1557 struct vhd_request *req = NULL;
1559 ASSERT(vhd_type_dynamic(&s->vhd));
1561 offset = bat_entry(s, blk);
1563 ASSERT(offset != DD_BLK_UNUSED);
1564 ASSERT(!get_bitmap(s, blk));
1566 offset = vhd_sectors_to_bytes(offset);
1568 err = alloc_vhd_bitmap(s, &bm, blk);
1569 if (err)
1570 return err;
1572 req = &bm->req;
1573 init_vhd_request(s, req);
1575 req->treq.sec = blk * s->spb;
1576 req->treq.secs = s->bm_secs;
1577 req->treq.buf = bm->map;
1578 req->treq.cb = NULL;
1579 req->op = VHD_OP_BITMAP_READ;
1580 req->next = NULL;
1582 aio_read(s, req, offset);
1583 lock_bitmap(bm);
1584 install_bitmap(s, bm);
1585 set_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING);
1587 DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", blk: 0x%04x, nr_secs: 0x%04x, "
1588 "offset: 0x%08"PRIx64"\n", s->vhd.file, req->treq.sec, blk,
1589 req->treq.secs, offset);
1591 return 0;
1594 static void
1595 schedule_bitmap_write(struct vhd_state *s, uint32_t blk)
1597 u64 offset;
1598 struct vhd_bitmap *bm;
1599 struct vhd_request *req;
1601 bm = get_bitmap(s, blk);
1602 offset = bat_entry(s, blk);
1604 ASSERT(vhd_type_dynamic(&s->vhd));
1605 ASSERT(bm && bitmap_valid(bm) &&
1606 !test_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING));
1608 if (offset == DD_BLK_UNUSED) {
1609 ASSERT(bat_locked(s) && s->bat.pbw_blk == blk);
1610 offset = s->bat.pbw_offset;
1613 offset = vhd_sectors_to_bytes(offset);
1615 req = &bm->req;
1616 init_vhd_request(s, req);
1618 req->treq.sec = blk * s->spb;
1619 req->treq.secs = s->bm_secs;
1620 req->treq.buf = bm->shadow;
1621 req->treq.cb = NULL;
1622 req->op = VHD_OP_BITMAP_WRITE;
1623 req->next = NULL;
1625 aio_write(s, req, offset);
1626 lock_bitmap(bm);
1627 touch_bitmap(s, bm); /* bump lru count */
1628 set_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING);
1630 DBG(TLOG_DBG, "%s: blk: 0x%04x, sec: 0x%08"PRIx64", nr_secs: 0x%04x, "
1631 "offset: 0x%"PRIx64"\n", s->vhd.file, blk, req->treq.sec,
1632 req->treq.secs, offset);
1635 /*
1636 * queued requests will be submitted once the bitmap
1637 * describing them is read and the requests are validated.
1638 */
1639 static int
1640 __vhd_queue_request(struct vhd_state *s, uint8_t op, td_request_t treq)
1642 u32 blk;
1643 struct vhd_bitmap *bm;
1644 struct vhd_request *req;
1646 ASSERT(vhd_type_dynamic(&s->vhd));
1648 blk = treq.sec / s->spb;
1649 bm = get_bitmap(s, blk);
1651 ASSERT(bm && test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING));
1653 req = alloc_vhd_request(s);
1654 if (!req)
1655 return -EBUSY;
1657 req->treq = treq;
1658 req->op = op;
1659 req->next = NULL;
1661 add_to_tail(&bm->waiting, req);
1662 lock_bitmap(bm);
1664 DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", blk: 0x%04x nr_secs: 0x%04x, "
1665 "op: %u\n", s->vhd.file, treq.sec, blk, treq.secs, op);
1667 TRACE(s);
1668 return 0;
1671 static void
1672 vhd_queue_read(td_driver_t *driver, td_request_t treq)
1674 struct vhd_state *s = (struct vhd_state *)driver->data;
1676 DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", secs: 0x%04x (seg: %d)\n",
1677 s->vhd.file, treq.sec, treq.secs, treq.sidx);
1679 while (treq.secs) {
1680 int err;
1681 td_request_t clone;
1683 err = 0;
1684 clone = treq;
1686 switch (read_bitmap_cache(s, clone.sec, VHD_OP_DATA_READ)) {
1687 case -EINVAL:
1688 err = -EINVAL;
1689 goto fail;
1691 case VHD_BM_BAT_CLEAR:
1692 clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
1693 td_forward_request(clone);
1694 break;
1696 case VHD_BM_BIT_CLEAR:
1697 clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 0);
1698 td_forward_request(clone);
1699 break;
1701 case VHD_BM_BIT_SET:
1702 clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 1);
1703 err = schedule_data_read(s, clone, 0);
1704 if (err)
1705 goto fail;
1706 break;
1708 case VHD_BM_NOT_CACHED:
1709 err = schedule_bitmap_read(s, clone.sec / s->spb);
1710 if (err)
1711 goto fail;
1713 clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
1714 err = __vhd_queue_request(s, VHD_OP_DATA_READ, clone);
1715 if (err)
1716 goto fail;
1717 break;
1719 case VHD_BM_READ_PENDING:
1720 clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
1721 err = __vhd_queue_request(s, VHD_OP_DATA_READ, clone);
1722 if (err)
1723 goto fail;
1724 break;
1726 case VHD_BM_BAT_LOCKED:
1727 default:
1728 ASSERT(0);
1729 break;
1732 treq.sec += clone.secs;
1733 treq.secs -= clone.secs;
1734 treq.buf += vhd_sectors_to_bytes(clone.secs);
1735 continue;
1737 fail:
1738 clone.secs = treq.secs;
1739 td_complete_request(clone, err);
1740 break;
1744 static void
1745 vhd_queue_write(td_driver_t *driver, td_request_t treq)
1747 struct vhd_state *s = (struct vhd_state *)driver->data;
1749 DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", secs: 0x%04x, (seg: %d)\n",
1750 s->vhd.file, treq.sec, treq.secs, treq.sidx);
1752 while (treq.secs) {
1753 int err;
1754 uint8_t flags;
1755 td_request_t clone;
1757 err = 0;
1758 flags = 0;
1759 clone = treq;
1761 switch (read_bitmap_cache(s, clone.sec, VHD_OP_DATA_WRITE)) {
1762 case -EINVAL:
1763 err = -EINVAL;
1764 goto fail;
1766 case VHD_BM_BAT_LOCKED:
1767 err = -EBUSY;
1768 clone.blocked = 1;
1769 goto fail;
1771 case VHD_BM_BAT_CLEAR:
1772 flags = (VHD_FLAG_REQ_UPDATE_BAT |
1773 VHD_FLAG_REQ_UPDATE_BITMAP);
1774 clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
1775 err = schedule_data_write(s, clone, flags);
1776 if (err)
1777 goto fail;
1778 break;
1780 case VHD_BM_BIT_CLEAR:
1781 flags = VHD_FLAG_REQ_UPDATE_BITMAP;
1782 clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 0);
1783 err = schedule_data_write(s, clone, flags);
1784 if (err)
1785 goto fail;
1786 break;
1788 case VHD_BM_BIT_SET:
1789 clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 1);
1790 err = schedule_data_write(s, clone, 0);
1791 if (err)
1792 goto fail;
1793 break;
1795 case VHD_BM_NOT_CACHED:
1796 clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
1797 err = schedule_bitmap_read(s, clone.sec / s->spb);
1798 if (err)
1799 goto fail;
1801 err = __vhd_queue_request(s, VHD_OP_DATA_WRITE, clone);
1802 if (err)
1803 goto fail;
1804 break;
1806 case VHD_BM_READ_PENDING:
1807 clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
1808 err = __vhd_queue_request(s, VHD_OP_DATA_WRITE, clone);
1809 if (err)
1810 goto fail;
1811 break;
1813 default:
1814 ASSERT(0);
1815 break;
1818 treq.sec += clone.secs;
1819 treq.secs -= clone.secs;
1820 treq.buf += vhd_sectors_to_bytes(clone.secs);
1821 continue;
1823 fail:
1824 clone.secs = treq.secs;
1825 td_complete_request(clone, err);
1826 break;
1830 static inline void
1831 signal_completion(struct vhd_request *list, int error)
1833 struct vhd_state *s;
1834 struct vhd_request *r, *next;
1836 if (!list)
1837 return;
1839 r = list;
1840 s = list->state;
1842 while (r) {
1843 int err;
1845 err = (error ? error : r->error);
1846 next = r->next;
1847 td_complete_request(r->treq, err);
1848 DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x%04"PRIx64", "
1849 "err: %d\n", r->treq.sec, r->treq.sec / s->spb, err);
1850 free_vhd_request(s, r);
1851 r = next;
1853 s->returned++;
1854 TRACE(s);
1858 static void
1859 start_new_bitmap_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
1861 int i, error = 0;
1862 struct vhd_transaction *tx;
1863 struct vhd_request *r, *next;
1865 if (!bm->queue.head)
1866 return;
1868 DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
1870 r = bm->queue.head;
1871 tx = &bm->tx;
1872 clear_req_list(&bm->queue);
1874 if (r && bat_entry(s, bm->blk) == DD_BLK_UNUSED)
1875 tx->error = -EIO;
1877 while (r) {
1878 next = r->next;
1879 r->next = NULL;
1880 clear_vhd_flag(r->flags, VHD_FLAG_REQ_QUEUED);
1882 add_to_transaction(tx, r);
1883 if (test_vhd_flag(r->flags, VHD_FLAG_REQ_FINISHED)) {
1884 tx->finished++;
1885 if (!r->error) {
1886 u32 sec = r->treq.sec % s->spb;
1887 for (i = 0; i < r->treq.secs; i++)
1888 vhd_bitmap_set(&s->vhd,
1889 bm->shadow, sec + i);
1892 r = next;
1895 /* perhaps all the queued writes already completed? */
1896 if (tx->started && transaction_completed(tx))
1897 finish_data_transaction(s, bm);
1900 static void
1901 finish_bat_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
1903 struct vhd_transaction *tx = &bm->tx;
1905 if (!bat_locked(s))
1906 return;
1908 if (s->bat.pbw_blk != bm->blk)
1909 return;
1911 if (!s->bat.req.error)
1912 goto release;
1914 if (!test_vhd_flag(tx->status, VHD_FLAG_TX_LIVE))
1915 goto release;
1917 tx->closed = 1;
1918 return;
1920 release:
1921 DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
1922 unlock_bat(s);
1923 init_bat(s);
1926 static void
1927 finish_bitmap_transaction(struct vhd_state *s,
1928 struct vhd_bitmap *bm, int error)
1930 int map_size;
1931 struct vhd_transaction *tx = &bm->tx;
1933 DBG(TLOG_DBG, "blk: 0x%04x, err: %d\n", bm->blk, error);
1934 tx->error = (tx->error ? tx->error : error);
1935 map_size = vhd_sectors_to_bytes(s->bm_secs);
1937 if (!test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE)) {
1938 if (test_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT)) {
1939 /* still waiting for bat write */
1940 ASSERT(bm->blk == s->bat.pbw_blk);
1941 ASSERT(test_vhd_flag(s->bat.status,
1942 VHD_FLAG_BAT_WRITE_STARTED));
1943 s->bat.req.tx = tx;
1944 return;
1948 if (tx->error) {
1949 /* undo changes to shadow */
1950 memcpy(bm->shadow, bm->map, map_size);
1951 } else {
1952 /* complete atomic write */
1953 memcpy(bm->map, bm->shadow, map_size);
1954 if (!test_batmap(s, bm->blk) && bitmap_full(s, bm))
1955 set_batmap(s, bm->blk);
1958 /* transaction done; signal completions */
1959 signal_completion(tx->requests.head, tx->error);
1960 init_tx(tx);
1961 start_new_bitmap_transaction(s, bm);
1963 if (!bitmap_in_use(bm))
1964 unlock_bitmap(bm);
1966 finish_bat_transaction(s, bm);
1969 static void
1970 finish_data_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
1972 struct vhd_transaction *tx = &bm->tx;
1974 DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
1976 tx->closed = 1;
1978 if (!tx->error)
1979 return schedule_bitmap_write(s, bm->blk);
1981 return finish_bitmap_transaction(s, bm, 0);
1984 static void
1985 finish_bat_write(struct vhd_request *req)
1987 struct vhd_bitmap *bm;
1988 struct vhd_transaction *tx;
1989 struct vhd_state *s = req->state;
1991 s->returned++;
1992 TRACE(s);
1994 bm = get_bitmap(s, s->bat.pbw_blk);
1996 DBG(TLOG_DBG, "blk 0x%04x, pbwo: 0x%08"PRIx64", err %d\n",
1997 s->bat.pbw_blk, s->bat.pbw_offset, req->error);
1998 ASSERT(bm && bitmap_valid(bm));
1999 ASSERT(bat_locked(s) &&
2000 test_vhd_flag(s->bat.status, VHD_FLAG_BAT_WRITE_STARTED));
2002 tx = &bm->tx;
2003 ASSERT(test_vhd_flag(tx->status, VHD_FLAG_TX_LIVE));
2005 if (!req->error) {
2006 bat_entry(s, s->bat.pbw_blk) = s->bat.pbw_offset;
2007 s->next_db = s->bat.pbw_offset + s->spb + s->bm_secs;
2008 } else
2009 tx->error = req->error;
2011 if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE)) {
2012 tx->finished++;
2013 remove_from_req_list(&tx->requests, req);
2014 if (transaction_completed(tx))
2015 finish_data_transaction(s, bm);
2016 } else {
2017 clear_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT);
2018 if (s->bat.req.tx)
2019 finish_bitmap_transaction(s, bm, req->error);
2022 finish_bat_transaction(s, bm);
2025 static void
2026 finish_zero_bm_write(struct vhd_request *req)
2028 u32 blk;
2029 struct vhd_bitmap *bm;
2030 struct vhd_transaction *tx = req->tx;
2031 struct vhd_state *s = req->state;
2033 s->returned++;
2034 TRACE(s);
2036 blk = req->treq.sec / s->spb;
2037 bm = get_bitmap(s, blk);
2039 DBG(TLOG_DBG, "blk: 0x%04x\n", blk);
2040 ASSERT(bat_locked(s));
2041 ASSERT(s->bat.pbw_blk == blk);
2042 ASSERT(bm && bitmap_valid(bm) && bitmap_locked(bm));
2044 tx->finished++;
2045 remove_from_req_list(&tx->requests, req);
2047 if (req->error) {
2048 unlock_bat(s);
2049 init_bat(s);
2050 tx->error = req->error;
2051 clear_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT);
2052 } else
2053 schedule_bat_write(s);
2055 if (transaction_completed(tx))
2056 finish_data_transaction(s, bm);
2059 static void
2060 finish_bitmap_read(struct vhd_request *req)
2062 u32 blk;
2063 struct vhd_bitmap *bm;
2064 struct vhd_request *r, *next;
2065 struct vhd_state *s = req->state;
2067 s->returned++;
2068 TRACE(s);
2070 blk = req->treq.sec / s->spb;
2071 bm = get_bitmap(s, blk);
2073 DBG(TLOG_DBG, "blk: 0x%04x\n", blk);
2074 ASSERT(bm && test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING));
2076 r = bm->waiting.head;
2077 clear_req_list(&bm->waiting);
2078 clear_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING);
2080 if (!req->error) {
2081 memcpy(bm->shadow, bm->map, vhd_sectors_to_bytes(s->bm_secs));
2083 while (r) {
2084 struct vhd_request tmp;
2086 tmp = *r;
2087 next = r->next;
2088 free_vhd_request(s, r);
2090 ASSERT(tmp.op == VHD_OP_DATA_READ ||
2091 tmp.op == VHD_OP_DATA_WRITE);
2093 if (tmp.op == VHD_OP_DATA_READ)
2094 vhd_queue_read(s->driver, tmp.treq);
2095 else if (tmp.op == VHD_OP_DATA_WRITE)
2096 vhd_queue_write(s->driver, tmp.treq);
2098 r = next;
2100 } else {
2101 int err = req->error;
2102 unlock_bitmap(bm);
2103 free_vhd_bitmap(s, bm);
2104 return signal_completion(r, err);
2107 if (!bitmap_in_use(bm))
2108 unlock_bitmap(bm);
2111 static void
2112 finish_bitmap_write(struct vhd_request *req)
2114 u32 blk;
2115 struct vhd_bitmap *bm;
2116 struct vhd_transaction *tx;
2117 struct vhd_state *s = req->state;
2119 s->returned++;
2120 TRACE(s);
2122 blk = req->treq.sec / s->spb;
2123 bm = get_bitmap(s, blk);
2124 tx = &bm->tx;
2126 DBG(TLOG_DBG, "blk: 0x%04x, started: %d, finished: %d\n",
2127 blk, tx->started, tx->finished);
2128 ASSERT(tx->closed);
2129 ASSERT(bm && bitmap_valid(bm));
2130 ASSERT(test_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING));
2132 clear_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING);
2134 finish_bitmap_transaction(s, bm, req->error);
2137 static void
2138 finish_data_read(struct vhd_request *req)
2140 struct vhd_state *s = req->state;
2142 DBG(TLOG_DBG, "lsec 0x%08"PRIx64", blk: 0x%04"PRIx64"\n",
2143 req->treq.sec, req->treq.sec / s->spb);
2144 signal_completion(req, 0);
2147 static void
2148 finish_data_write(struct vhd_request *req)
2150 int i;
2151 struct vhd_transaction *tx = req->tx;
2152 struct vhd_state *s = (struct vhd_state *)req->state;
2154 set_vhd_flag(req->flags, VHD_FLAG_REQ_FINISHED);
2156 if (tx) {
2157 u32 blk, sec;
2158 struct vhd_bitmap *bm;
2160 blk = req->treq.sec / s->spb;
2161 sec = req->treq.sec % s->spb;
2162 bm = get_bitmap(s, blk);
2164 ASSERT(bm && bitmap_valid(bm) && bitmap_locked(bm));
2166 tx->finished++;
2168 DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x04%"PRIx64", "
2169 "tx->started: %d, tx->finished: %d\n", req->treq.sec,
2170 req->treq.sec / s->spb, tx->started, tx->finished);
2172 if (!req->error)
2173 for (i = 0; i < req->treq.secs; i++)
2174 vhd_bitmap_set(&s->vhd, bm->shadow, sec + i);
2176 if (transaction_completed(tx))
2177 finish_data_transaction(s, bm);
2179 } else if (!test_vhd_flag(req->flags, VHD_FLAG_REQ_QUEUED)) {
2180 ASSERT(!req->next);
2181 DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x%04"PRIx64"\n",
2182 req->treq.sec, req->treq.sec / s->spb);
2183 signal_completion(req, 0);
2187 void
2188 vhd_complete(void *arg, struct tiocb *tiocb, int err)
2190 struct vhd_request *req = (struct vhd_request *)arg;
2191 struct vhd_state *s = req->state;
2192 struct iocb *io = &tiocb->iocb;
2194 s->completed++;
2195 TRACE(s);
2197 req->error = err;
2199 if (req->error)
2200 ERR(req->error, "%s: op: %u, lsec: %"PRIu64", secs: %u, "
2201 "nbytes: %lu, blk: %"PRIu64", blk_offset: %u",
2202 s->vhd.file, req->op, req->treq.sec, req->treq.secs,
2203 io->u.c.nbytes, req->treq.sec / s->spb,
2204 bat_entry(s, req->treq.sec / s->spb));
2206 switch (req->op) {
2207 case VHD_OP_DATA_READ:
2208 finish_data_read(req);
2209 break;
2211 case VHD_OP_DATA_WRITE:
2212 finish_data_write(req);
2213 break;
2215 case VHD_OP_BITMAP_READ:
2216 finish_bitmap_read(req);
2217 break;
2219 case VHD_OP_BITMAP_WRITE:
2220 finish_bitmap_write(req);
2221 break;
2223 case VHD_OP_ZERO_BM_WRITE:
2224 finish_zero_bm_write(req);
2225 break;
2227 case VHD_OP_BAT_WRITE:
2228 finish_bat_write(req);
2229 break;
2231 default:
2232 ASSERT(0);
2233 break;
2237 void
2238 vhd_debug(td_driver_t *driver)
2240 int i;
2241 struct vhd_state *s = (struct vhd_state *)driver->data;
2243 DBG(TLOG_WARN, "%s: QUEUED: 0x%08"PRIx64", COMPLETED: 0x%08"PRIx64", "
2244 "RETURNED: 0x%08"PRIx64"\n", s->vhd.file, s->queued, s->completed,
2245 s->returned);
2246 DBG(TLOG_WARN, "WRITES: 0x%08"PRIx64", AVG_WRITE_SIZE: %f\n",
2247 s->writes, (s->writes ? ((float)s->write_size / s->writes) : 0.0));
2248 DBG(TLOG_WARN, "READS: 0x%08"PRIx64", AVG_READ_SIZE: %f\n",
2249 s->reads, (s->reads ? ((float)s->read_size / s->reads) : 0.0));
2251 DBG(TLOG_WARN, "ALLOCATED REQUESTS: (%lu total)\n", VHD_REQS_DATA);
2252 for (i = 0; i < VHD_REQS_DATA; i++) {
2253 struct vhd_request *r = &s->vreq_list[i];
2254 td_request_t *t = &r->treq;
2255 if (t->secs)
2256 DBG(TLOG_WARN, "%d: id: 0x%04"PRIx64", err: %d, op: %d,"
2257 " lsec: 0x%08"PRIx64", flags: %d, this: %p, "
2258 "next: %p, tx: %p\n", i, t->id, r->error, r->op,
2259 t->sec, r->flags, r, r->next, r->tx);
2262 DBG(TLOG_WARN, "BITMAP CACHE:\n");
2263 for (i = 0; i < VHD_CACHE_SIZE; i++) {
2264 int qnum = 0, wnum = 0, rnum = 0;
2265 struct vhd_bitmap *bm = s->bitmap[i];
2266 struct vhd_transaction *tx;
2267 struct vhd_request *r;
2269 if (!bm)
2270 continue;
2272 tx = &bm->tx;
2273 r = bm->queue.head;
2274 while (r) {
2275 qnum++;
2276 r = r->next;
2279 r = bm->waiting.head;
2280 while (r) {
2281 wnum++;
2282 r = r->next;
2285 r = tx->requests.head;
2286 while (r) {
2287 rnum++;
2288 r = r->next;
2291 DBG(TLOG_WARN, "%d: blk: 0x%04x, status: 0x%08x, q: %p, qnum: %d, w: %p, "
2292 "wnum: %d, locked: %d, in use: %d, tx: %p, tx_error: %d, "
2293 "started: %d, finished: %d, status: %u, reqs: %p, nreqs: %d\n",
2294 i, bm->blk, bm->status, bm->queue.head, qnum, bm->waiting.head,
2295 wnum, bitmap_locked(bm), bitmap_in_use(bm), tx, tx->error,
2296 tx->started, tx->finished, tx->status, tx->requests.head, rnum);
2299 DBG(TLOG_WARN, "BAT: status: 0x%08x, pbw_blk: 0x%04x, "
2300 "pbw_off: 0x%08"PRIx64", tx: %p\n", s->bat.status, s->bat.pbw_blk,
2301 s->bat.pbw_offset, s->bat.req.tx);
2303 /*
2304 for (i = 0; i < s->hdr.max_bat_size; i++)
2305 DPRINTF("%d: %u\n", i, s->bat.bat[i]);
2306 */
2309 struct tap_disk tapdisk_vhd = {
2310 .disk_type = "tapdisk_vhd",
2311 .flags = 0,
2312 .private_data_size = sizeof(struct vhd_state),
2313 .td_open = _vhd_open,
2314 .td_close = _vhd_close,
2315 .td_queue_read = vhd_queue_read,
2316 .td_queue_write = vhd_queue_write,
2317 .td_get_parent_id = vhd_get_parent_id,
2318 .td_validate_parent = vhd_validate_parent,
2319 .td_debug = vhd_debug,
2320 };