This patch imports the VHD driver from blktap2, with all changes coming from
blktap2.5.
Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com>
diff --git a/tools/blktap3/drivers/Makefile b/tools/blktap3/drivers/Makefile
--- a/tools/blktap3/drivers/Makefile
+++ b/tools/blktap3/drivers/Makefile
@@ -95,6 +95,7 @@ LIBSRING := sring/libsring.a
#MISC-OBJS-y := atomicio.o
BLK-OBJS-y := block-aio.o
+BLK-OBJS-y += block-vhd.o
# FIXME The following exist in blktap2 but not in blktap2.5.
#BLK-OBJS-y += aes.o
#BLK-OBJS-y += md5.o
diff --git a/tools/blktap2/drivers/block-vhd.c
b/tools/blktap3/drivers/block-vhd.c
copy from tools/blktap2/drivers/block-vhd.c
copy to tools/blktap3/drivers/block-vhd.c
--- a/tools/blktap2/drivers/block-vhd.c
+++ b/tools/blktap3/drivers/block-vhd.c
@@ -1,5 +1,8 @@
-/*
- * Copyright (c) 2008, XenSource Inc.
+/*
+ *
+ * Copyright (c) 2007, XenSource Inc.
+ * Copyright (c) 2010, Citrix Systems, Inc.
+ *
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,6 +27,10 @@
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * block-vhd.c: asynchronous vhd implementation.
*
* A note on write transactions:
* Writes that require updating the BAT or bitmaps cannot be signaled
@@ -50,6 +57,8 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <uuid/uuid.h> /* For whatever reason, Linux packages this in */
+ /* e2fsprogs-devel. */
#include <string.h> /* for memset. */
#include <libaio.h>
#include <sys/mman.h>
@@ -59,6 +68,7 @@
#include "tapdisk-driver.h"
#include "tapdisk-interface.h"
#include "tapdisk-disktype.h"
+#include "tapdisk-storage.h"
unsigned int SPB;
@@ -72,7 +82,7 @@ unsigned int SPB;
do { \
DBG(TLOG_DBG, "%s: QUEUED: %" PRIu64 ", COMPLETED: %" \
PRIu64", RETURNED: %" PRIu64 ", DATA_ALLOCATED: " \
- "%lu, BBLK: 0x%04x\n", \
+ "%u, BBLK: 0x%04x\n", \
s->vhd.file, s->queued, s->completed, s->returned, \
VHD_REQS_DATA - s->vreq_free_count, \
s->bat.pbw_blk); \
@@ -84,21 +94,20 @@ unsigned int SPB;
__FILE__, __LINE__, #_p); \
DBG(TLOG_WARN, "%s:%d: FAILED ASSERTION: ''%s''\n",
\
__FILE__, __LINE__, #_p); \
- tlog_flush(); \
- *(int*)0 = 0; \
+ td_panic(); \
}
#if (DEBUGGING == 1)
#define DBG(level, _f, _a...) DPRINTF(_f, ##_a)
- #define ERR(err, _f, _a...) DPRINTF("ERROR: %d: " _f, err,
##_a)
+ #define ERR(_s, err, _f, _a...) DPRINTF("ERROR: %d: " _f, err,
##_a)
#define TRACE(s) ((void)0)
#elif (DEBUGGING == 2)
#define DBG(level, _f, _a...) tlog_write(level, _f, ##_a)
- #define ERR(err, _f, _a...) tlog_error(err, _f, ##_a)
+ #define ERR(_s, _err, _f, _a...) tlog_drv_error((_s)->driver, _err, _f,
##_a)
#define TRACE(s) __TRACE(s)
#else
#define DBG(level, _f, _a...) ((void)0)
- #define ERR(err, _f, _a...) ((void)0)
+ #define ERR(_s, err, _f, _a...) ((void)0)
#define TRACE(s) ((void)0)
#endif
@@ -121,6 +130,7 @@ unsigned int SPB;
#define VHD_OP_BITMAP_READ 3
#define VHD_OP_BITMAP_WRITE 4
#define VHD_OP_ZERO_BM_WRITE 5
+#define VHD_OP_REDUNDANT_BM_WRITE 6
#define VHD_BM_BAT_LOCKED 0
#define VHD_BM_BAT_CLEAR 1
@@ -194,8 +204,8 @@ struct vhd_bat_state {
};
struct vhd_bitmap {
- u32 blk;
- u64 seqno; /* lru sequence number */
+ uint32_t blk;
+ uint64_t seqno; /* lru sequence number */
vhd_flag_t status;
char *map; /* map should only be modified
@@ -220,15 +230,16 @@ struct vhd_state {
/* VHD stuff */
vhd_context_t vhd;
- u32 spp; /* sectors per page */
- u32 spb; /* sectors per block */
- u64 next_db; /* pointer to the next
+ uint32_t spp; /* sectors per page */
+ uint32_t spb; /* sectors per block */
+ uint64_t first_db; /* pointer to datablock 0 */
+ uint64_t next_db; /* pointer to the next
* (unallocated) datablock */
struct vhd_bat_state bat;
- u64 bm_lru; /* lru sequence number */
- u32 bm_secs; /* size of bitmap, in sectors */
+ uint64_t bm_lru; /* lru sequence number */
+ uint32_t bm_secs; /* size of bitmap, in sectors */
struct vhd_bitmap *bitmap[VHD_CACHE_SIZE];
int bm_free_count;
@@ -239,6 +250,12 @@ struct vhd_state {
struct vhd_request *vreq_free[VHD_REQS_DATA];
struct vhd_request vreq_list[VHD_REQS_DATA];
+ /* for redundant bitmap writes */
+ int padbm_size;
+ char *padbm_buf;
+ long int debug_skipped_redundant_writes;
+ long int debug_done_redundant_writes;
+
td_driver_t *driver;
uint64_t queued;
@@ -274,7 +291,7 @@ vhd_initialize(struct vhd_state *s)
_vhd_zsize += VHD_BLOCK_SIZE;
_vhd_zeros = mmap(0, _vhd_zsize, PROT_READ,
- MAP_SHARED | MAP_ANON, -1, 0);
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (_vhd_zeros == MAP_FAILED) {
EPRINTF("vhd_initialize failed: %d\n", -errno);
_vhd_zeros = NULL;
@@ -292,6 +309,7 @@ vhd_free(struct vhd_state *s)
if (_vhd_master != s || !_vhd_zeros)
return;
+ free(s->padbm_buf);
munmap(_vhd_zeros, _vhd_zsize);
_vhd_zsize = 0;
_vhd_zeros = NULL;
@@ -333,23 +351,23 @@ static int
vhd_kill_footer(struct vhd_state *s)
{
int err;
- off_t end;
- char *zeros;
+ off64_t end;
+ void *zeros;
if (s->vhd.footer.type == HD_TYPE_FIXED)
return 0;
- err = posix_memalign((void **)&zeros, 512, 512);
+ err = posix_memalign(&zeros, 512, 512);
if (err)
return -err;
err = 1;
memset(zeros, 0xc7c7c7c7, 512);
- if ((end = lseek(s->vhd.fd, 0, SEEK_END)) == -1)
+ if ((end = lseek64(s->vhd.fd, 0, SEEK_END)) == -1)
goto fail;
- if (lseek(s->vhd.fd, (end - 512), SEEK_SET) == -1)
+ if (lseek64(s->vhd.fd, (end - 512), SEEK_SET) == -1)
goto fail;
if (write(s->vhd.fd, zeros, 512) != 512)
@@ -368,7 +386,7 @@ static inline int
find_next_free_block(struct vhd_state *s)
{
int err;
- off_t eom;
+ off64_t eom;
uint32_t i, entry;
err = vhd_end_of_headers(&s->vhd, &eom);
@@ -376,6 +394,9 @@ find_next_free_block(struct vhd_state *s
return err;
s->next_db = secs_round_up(eom);
+ s->first_db = s->next_db;
+ if ((s->first_db + s->bm_secs) % s->spp)
+ s->first_db += (s->spp - ((s->first_db + s->bm_secs) %
s->spp));
for (i = 0; i < s->bat.bat.entries; i++) {
entry = bat_entry(s, i);
@@ -398,12 +419,11 @@ vhd_free_bat(struct vhd_state *s)
static int
vhd_initialize_bat(struct vhd_state *s)
{
- int err, psize, batmap_required, i;
+ int err, batmap_required, i;
+ void *buf;
memset(&s->bat, 0, sizeof(struct vhd_bat));
- psize = getpagesize();
-
err = vhd_read_bat(&s->vhd, &s->bat.bat);
if (err) {
EPRINTF("%s: reading bat: %d\n", s->vhd.file, err);
@@ -436,12 +456,11 @@ vhd_initialize_bat(struct vhd_state *s)
s->vhd.file);
}
- err = posix_memalign((void **)&s->bat.bat_buf,
- VHD_SECTOR_SIZE, VHD_SECTOR_SIZE);
- if (err) {
- s->bat.bat_buf = NULL;
+ err = posix_memalign(&buf, VHD_SECTOR_SIZE, VHD_SECTOR_SIZE);
+ if (err)
goto fail;
- }
+
+ s->bat.bat_buf = buf;
return 0;
@@ -471,6 +490,7 @@ vhd_initialize_bitmap_cache(struct vhd_s
{
int i, err, map_size;
struct vhd_bitmap *bm;
+ void *map, *shadow;
memset(s->bitmap_list, 0, sizeof(struct vhd_bitmap) * VHD_CACHE_SIZE);
@@ -481,17 +501,17 @@ vhd_initialize_bitmap_cache(struct vhd_s
for (i = 0; i < VHD_CACHE_SIZE; i++) {
bm = s->bitmap_list + i;
- err = posix_memalign((void **)&bm->map, 512, map_size);
- if (err) {
- bm->map = NULL;
+ err = posix_memalign(&map, 512, map_size);
+ if (err)
goto fail;
- }
-
- err = posix_memalign((void **)&bm->shadow, 512, map_size);
- if (err) {
- bm->shadow = NULL;
+
+ bm->map = map;
+
+ err = posix_memalign(&shadow, 512, map_size);
+ if (err)
goto fail;
- }
+
+ bm->shadow = shadow;
memset(bm->map, 0, map_size);
memset(bm->shadow, 0, map_size);
@@ -508,6 +528,8 @@ fail:
static int
vhd_initialize_dynamic_disk(struct vhd_state *s)
{
+ uint32_t bm_size;
+ void *buf;
int err;
err = vhd_get_header(&s->vhd);
@@ -527,6 +549,21 @@ vhd_initialize_dynamic_disk(struct vhd_s
s->spb = s->vhd.header.block_size >> VHD_SECTOR_SHIFT;
s->bm_secs = secs_round_up_no_zero(s->spb >> 3);
+ s->padbm_size = (s->bm_secs / getpagesize()) * getpagesize();
+ if (s->bm_secs % getpagesize())
+ s->padbm_size += getpagesize();
+
+ err = posix_memalign(&buf, 512, s->padbm_size);
+ if (err)
+ return -err;
+
+ s->padbm_buf = buf;
+ bm_size = s->bm_secs << VHD_SECTOR_SHIFT;
+ memset(s->padbm_buf, 0, s->padbm_size - bm_size);
+ memset(s->padbm_buf + (s->padbm_size - bm_size), ~0, bm_size);
+ s->debug_skipped_redundant_writes = 0;
+ s->debug_done_redundant_writes = 0;
+
if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_NO_CACHE))
return 0;
@@ -616,6 +653,9 @@ static int
o_flags = ((test_vhd_flag(flags, VHD_FLAG_OPEN_RDONLY)) ?
VHD_OPEN_RDONLY : VHD_OPEN_RDWR);
+ if (test_vhd_flag(flags, VHD_FLAG_OPEN_STRICT))
+ set_vhd_flag(o_flags, VHD_OPEN_STRICT);
+
err = vhd_open(&s->vhd, name, o_flags);
if (err) {
libvhd_set_log_level(1);
@@ -650,8 +690,7 @@ static int
driver->info.sector_size = VHD_SECTOR_SIZE;
driver->info.info = 0;
- DBG(TLOG_INFO, "vhd_open: done (sz:%"PRIu64",
sct:%"PRIu64
- ", inf:%u)\n",
+ DBG(TLOG_INFO, "vhd_open: done (sz:%"PRIu64", sct:%lu,
inf:%u)\n",
driver->info.size, driver->info.sector_size, driver->info.info);
if (test_vhd_flag(flags, VHD_FLAG_OPEN_STRICT) &&
@@ -692,6 +731,8 @@ static int
VHD_FLAG_OPEN_NO_CACHE);
/* pre-allocate for all but NFS and LVM storage */
+ driver->storage = tapdisk_storage_type(name);
+
if (driver->storage != TAPDISK_STORAGE_TYPE_NFS &&
driver->storage != TAPDISK_STORAGE_TYPE_LVM)
vhd_flags |= VHD_FLAG_OPEN_PREALLOCATE;
@@ -726,11 +767,14 @@ static int
{
int err;
struct vhd_state *s;
- struct vhd_bitmap *bm;
DBG(TLOG_WARN, "vhd_close\n");
s = (struct vhd_state *)driver->data;
+ DPRINTF("gaps written/skipped: %ld/%ld\n",
+ s->debug_done_redundant_writes,
+ s->debug_skipped_redundant_writes);
+
/* don''t write footer if tapdisk is read-only */
if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_RDONLY))
goto free;
@@ -770,10 +814,9 @@ static int
int
vhd_validate_parent(td_driver_t *child_driver,
- td_driver_t *parent_driver, td_flag_t flags)
+ td_driver_t *parent_driver,
+ __attribute__((unused)) td_flag_t flags)
{
- uint32_t status;
- struct stat stats;
struct vhd_state *child = (struct vhd_state *)child_driver->data;
struct vhd_state *parent;
@@ -807,7 +850,7 @@ vhd_validate_parent(td_driver_t *child_d
}
*/
- if (vhd_uuid_compare(&child->vhd.header.prt_uuid,
&parent->vhd.footer.uuid)) {
+ if (uuid_compare(child->vhd.header.prt_uuid, parent->vhd.footer.uuid)) {
DPRINTF("ERROR: %s: %s, %s: parent uuid has changed since "
"snapshot. Child image no longer valid.\n",
__func__, child->vhd.file, parent->vhd.file);
@@ -838,12 +881,10 @@ vhd_get_parent_id(td_driver_t *driver, t
if (err)
return err;
- id->name = parent;
- id->drivertype = DISK_TYPE_VHD;
- if (vhd_parent_raw(&s->vhd)) {
- DPRINTF("VHD: parent is raw\n");
- id->drivertype = DISK_TYPE_AIO;
- }
+ id->name = parent;
+ id->type = vhd_parent_raw(&s->vhd) ? DISK_TYPE_AIO :
DISK_TYPE_VHD;
+ id->flags |= TD_OPEN_SHAREABLE|TD_OPEN_RDONLY;
+
return 0;
}
@@ -1034,7 +1075,7 @@ static struct vhd_bitmap *
remove_lru_bitmap(struct vhd_state *s)
{
int i, idx = 0;
- u64 seq = s->bm_lru;
+ uint64_t seq = s->bm_lru;
struct vhd_bitmap *bm, *lru = NULL;
for (i = 0; i < VHD_CACHE_SIZE; i++) {
@@ -1138,7 +1179,7 @@ free_vhd_bitmap(struct vhd_state *s, str
static int
read_bitmap_cache(struct vhd_state *s, uint64_t sector, uint8_t op)
{
- u32 blk, sec;
+ uint32_t blk, sec;
struct vhd_bitmap *bm;
/* in fixed disks, every block is present */
@@ -1186,7 +1227,7 @@ read_bitmap_cache_span(struct vhd_state
uint64_t sector, int nr_secs, int value)
{
int ret;
- u32 blk, sec;
+ uint32_t blk, sec;
struct vhd_bitmap *bm;
/* in fixed disks, every block is present */
@@ -1285,9 +1326,9 @@ static int
schedule_bat_write(struct vhd_state *s)
{
int i;
- u32 blk;
+ uint32_t blk;
char *buf;
- u64 offset;
+ uint64_t offset;
struct vhd_request *req;
ASSERT(bat_locked(s));
@@ -1299,10 +1340,10 @@ schedule_bat_write(struct vhd_state *s)
init_vhd_request(s, req);
memcpy(buf, &bat_entry(s, blk - (blk % 128)), 512);
- ((u32 *)buf)[blk % 128] = s->bat.pbw_offset;
+ ((uint32_t *)buf)[blk % 128] = s->bat.pbw_offset;
for (i = 0; i < 128; i++)
- BE32_OUT(&((u32 *)buf)[i]);
+ BE32_OUT(&((uint32_t *)buf)[i]);
offset = s->vhd.header.table_offset + (blk - (blk % 128)) * 4;
req->treq.secs = 1;
@@ -1343,6 +1384,55 @@ schedule_zero_bm_write(struct vhd_state
aio_write(s, req, offset);
}
+/* This is a performance optimization. When writing sequentially into full
+ * blocks, skipping (up-to-date) bitmaps causes an approx. 25% reduction in
+ * throughput. To prevent skipping, we issue redundant writes into the (padded)
+ * bitmap area just to make all writes sequential. This will help VHDs on raw
+ * block devices, while the FS-based VHDs shouldn''t suffer much.
+ *
+ * Note that it only makes sense to perform this reduntant bitmap write if the
+ * block is completely full (i.e. the batmap entry is set). If the block is not
+ * completely full then one of the following two things will be true:
+ * 1. we''ll either be allocating new sectors in this block and
writing its
+ * bitmap transactionally, which will be slow anyways; or
+ * 2. the IO will be skipping over the unallocated sectors again, so the
+ * pattern will not be sequential anyways
+ * In either case a redundant bitmap write becomes pointless. This fact
+ * simplifies the implementation of redundant writes: since we know the bitmap
+ * cannot be updated by anyone else, we don''t have to worry about
transactions
+ * or potential write conflicts.
+ * */
+static void
+schedule_redundant_bm_write(struct vhd_state *s, uint32_t blk)
+{
+ uint64_t offset;
+ struct vhd_request *req;
+
+ ASSERT(s->vhd.footer.type != HD_TYPE_FIXED);
+ ASSERT(test_batmap(s, blk));
+
+ req = alloc_vhd_request(s);
+ if (!req)
+ return;
+
+ req->treq.buf = s->padbm_buf;
+
+ offset = bat_entry(s, blk);
+ ASSERT(offset != DD_BLK_UNUSED);
+ offset <<= VHD_SECTOR_SHIFT;
+ offset -= s->padbm_size - (s->bm_secs << VHD_SECTOR_SHIFT);
+
+ req->op = VHD_OP_REDUNDANT_BM_WRITE;
+ req->treq.sec = blk * s->spb;
+ req->treq.secs = s->padbm_size >> VHD_SECTOR_SHIFT;
+ req->next = NULL;
+
+ DBG(TLOG_DBG, "blk: %u, writing redundant bitmap at %" PRIu64
"\n",
+ blk, offset);
+
+ aio_write(s, req, offset);
+}
+
static int
update_bat(struct vhd_state *s, uint32_t blk)
{
@@ -1380,10 +1470,10 @@ update_bat(struct vhd_state *s, uint32_t
static int
allocate_block(struct vhd_state *s, uint32_t blk)
{
- char *zeros;
int err, gap;
uint64_t offset, size;
struct vhd_bitmap *bm;
+ ssize_t count;
ASSERT(bat_entry(s, blk) == DD_BLK_UNUSED);
@@ -1410,15 +1500,16 @@ allocate_block(struct vhd_state *s, uint
blk, s->bat.pbw_offset);
if (lseek(s->vhd.fd, offset, SEEK_SET) == (off_t)-1) {
- ERR(errno, "lseek failed\n");
+ ERR(s, -errno, "lseek failed\n");
return -errno;
}
- size = vhd_sectors_to_bytes(s->spb + s->bm_secs + gap);
- err = write(s->vhd.fd, vhd_zeros(size), size);
- if (err != size) {
- err = (err == -1 ? -errno : -EIO);
- ERR(err, "write failed");
+ size = vhd_sectors_to_bytes(s->spb + s->bm_secs + gap);
+ count = write(s->vhd.fd, vhd_zeros(size), size);
+ if (count != size) {
+ err = count < 0 ? -errno : -ENOSPC;
+ ERR(s, -errno,
+ "write failed (%zd, offset %"PRIu64")\n", count,
offset);
return err;
}
@@ -1445,8 +1536,8 @@ allocate_block(struct vhd_state *s, uint
static int
schedule_data_read(struct vhd_state *s, td_request_t treq, vhd_flag_t flags)
{
- u64 offset;
- u32 blk = 0, sec = 0;
+ uint64_t offset;
+ uint32_t blk = 0, sec = 0;
struct vhd_bitmap *bm;
struct vhd_request *req;
@@ -1490,8 +1581,8 @@ static int
schedule_data_write(struct vhd_state *s, td_request_t treq, vhd_flag_t flags)
{
int err;
- u64 offset;
- u32 blk = 0, sec = 0;
+ uint64_t offset;
+ uint32_t blk = 0, sec = 0;
struct vhd_bitmap *bm = NULL;
struct vhd_request *req;
@@ -1539,7 +1630,11 @@ schedule_data_write(struct vhd_state *s,
set_vhd_flag(req->flags, VHD_FLAG_REQ_QUEUED);
} else
add_to_transaction(&bm->tx, req);
- }
+ } else if (sec == 0 && /* first sector inside data block */
+ s->vhd.footer.type != HD_TYPE_FIXED &&
+ bat_entry(s, blk) != s->first_db &&
+ test_batmap(s, blk))
+ schedule_redundant_bm_write(s, blk);
aio_write(s, req, offset);
@@ -1554,7 +1649,7 @@ static int
schedule_bitmap_read(struct vhd_state *s, uint32_t blk)
{
int err;
- u64 offset;
+ uint64_t offset;
struct vhd_bitmap *bm;
struct vhd_request *req = NULL;
@@ -1596,7 +1691,7 @@ schedule_bitmap_read(struct vhd_state *s
static void
schedule_bitmap_write(struct vhd_state *s, uint32_t blk)
{
- u64 offset;
+ uint64_t offset;
struct vhd_bitmap *bm;
struct vhd_request *req;
@@ -1641,7 +1736,7 @@ schedule_bitmap_write(struct vhd_state *
static int
__vhd_queue_request(struct vhd_state *s, uint8_t op, td_request_t treq)
{
- u32 blk;
+ uint32_t blk;
struct vhd_bitmap *bm;
struct vhd_request *req;
@@ -1767,7 +1862,6 @@ vhd_queue_write(td_driver_t *driver, td_
case VHD_BM_BAT_LOCKED:
err = -EBUSY;
- clone.blocked = 1;
goto fail;
case VHD_BM_BAT_CLEAR:
@@ -1860,9 +1954,9 @@ signal_completion(struct vhd_request *li
static void
start_new_bitmap_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
{
- int i, error = 0;
struct vhd_transaction *tx;
struct vhd_request *r, *next;
+ int i;
if (!bm->queue.head)
return;
@@ -1885,7 +1979,7 @@ start_new_bitmap_transaction(struct vhd_
if (test_vhd_flag(r->flags, VHD_FLAG_REQ_FINISHED)) {
tx->finished++;
if (!r->error) {
- u32 sec = r->treq.sec % s->spb;
+ uint32_t sec = r->treq.sec % s->spb;
for (i = 0; i < r->treq.secs; i++)
vhd_bitmap_set(&s->vhd,
bm->shadow, sec + i);
@@ -2027,7 +2121,7 @@ finish_bat_write(struct vhd_request *req
static void
finish_zero_bm_write(struct vhd_request *req)
{
- u32 blk;
+ uint32_t blk;
struct vhd_bitmap *bm;
struct vhd_transaction *tx = req->tx;
struct vhd_state *s = req->state;
@@ -2058,10 +2152,30 @@ finish_zero_bm_write(struct vhd_request
finish_data_transaction(s, bm);
}
+static int
+finish_redundant_bm_write(struct vhd_request *req)
+{
+ /* uint32_t blk; */
+ struct vhd_state *s = (struct vhd_state *) req->state;
+
+ s->returned++;
+ TRACE(s);
+ /* blk = req->treq.sec / s->spb;
+ DBG(TLOG_DBG, "blk: %u\n", blk); */
+
+ if (req->error) {
+ ERR(s, req->error, "lsec: 0x%08"PRIx64, req->treq.sec);
+ }
+ free_vhd_request(s, req);
+ s->debug_done_redundant_writes++;
+ return 0;
+}
+
+
static void
finish_bitmap_read(struct vhd_request *req)
{
- u32 blk;
+ uint32_t blk;
struct vhd_bitmap *bm;
struct vhd_request *r, *next;
struct vhd_state *s = req->state;
@@ -2113,7 +2227,7 @@ finish_bitmap_read(struct vhd_request *r
static void
finish_bitmap_write(struct vhd_request *req)
{
- u32 blk;
+ uint32_t blk;
struct vhd_bitmap *bm;
struct vhd_transaction *tx;
struct vhd_state *s = req->state;
@@ -2156,7 +2270,7 @@ finish_data_write(struct vhd_request *re
set_vhd_flag(req->flags, VHD_FLAG_REQ_FINISHED);
if (tx) {
- u32 blk, sec;
+ uint32_t blk, sec;
struct vhd_bitmap *bm;
blk = req->treq.sec / s->spb;
@@ -2199,7 +2313,7 @@ vhd_complete(void *arg, struct tiocb *ti
req->error = err;
if (req->error)
- ERR(req->error, "%s: op: %u, lsec: %"PRIu64", secs: %u,
"
+ ERR(s, req->error, "%s: op: %u, lsec: %"PRIu64", secs: %u,
"
"nbytes: %lu, blk: %"PRIu64", blk_offset: %u",
s->vhd.file, req->op, req->treq.sec, req->treq.secs,
io->u.c.nbytes, req->treq.sec / s->spb,
@@ -2226,6 +2340,10 @@ vhd_complete(void *arg, struct tiocb *ti
finish_zero_bm_write(req);
break;
+ case VHD_OP_REDUNDANT_BM_WRITE:
+ finish_redundant_bm_write(req);
+ break;
+
case VHD_OP_BAT_WRITE:
finish_bat_write(req);
break;
@@ -2250,14 +2368,15 @@ vhd_debug(td_driver_t *driver)
DBG(TLOG_WARN, "READS: 0x%08"PRIx64", AVG_READ_SIZE:
%f\n",
s->reads, (s->reads ? ((float)s->read_size / s->reads) :
0.0));
- DBG(TLOG_WARN, "ALLOCATED REQUESTS: (%lu total)\n", VHD_REQS_DATA);
+ DBG(TLOG_WARN, "ALLOCATED REQUESTS: (%u total)\n", VHD_REQS_DATA);
for (i = 0; i < VHD_REQS_DATA; i++) {
struct vhd_request *r = &s->vreq_list[i];
td_request_t *t = &r->treq;
+ const char *vname = t->vreq ? t->vreq->name: NULL;
if (t->secs)
- DBG(TLOG_WARN, "%d: id: 0x%04"PRIx64", err: %d, op: %d,"
+ DBG(TLOG_WARN, "%d: vreq: %s.%d, err: %d, op: %d,"
" lsec: 0x%08"PRIx64", flags: %d, this: %p, "
- "next: %p, tx: %p\n", i, t->id, r->error, r->op,
+ "next: %p, tx: %p\n", i, vname, t->sidx, r->error,
r->op,
t->sec, r->flags, r, r->next, r->tx);
}