aboutsummaryrefslogtreecommitdiff
path: root/block/qed.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@linux.vnet.ibm.com>2010-12-06 16:08:01 +0000
committerKevin Wolf <kwolf@redhat.com>2010-12-17 16:11:04 +0100
commit298800cae72eb2a549374189e87615b2b0b79262 (patch)
treefadedcd0842fa60989078a4aa8c1959a27adbbd0 /block/qed.c
parent75411d236d93d79d8052e0116c3eeebe23e2778b (diff)
qed: Table, L2 cache, and cluster functions
This patch adds code to look up data cluster offsets in the image via the L1/L2 tables. The L2 tables are writethrough cached in memory for performance (each read/write requires a lookup so it is essential to cache the tables). With cluster lookup code in place it is possible to implement bdrv_is_allocated() to query the number of contiguous allocated/unallocated clusters. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block/qed.c')
-rw-r--r--block/qed.c54
1 files changed, 53 insertions, 1 deletions
diff --git a/block/qed.c b/block/qed.c
index 1436ac4ac4..cd1bead8c3 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -155,6 +155,13 @@ static int qed_read_string(BlockDriverState *file, uint64_t offset, size_t n,
return 0;
}
+QEDTable *qed_alloc_table(BDRVQEDState *s)
+{
+ /* Honor O_DIRECT memory alignment requirements */
+ return qemu_blockalign(s->bs,
+ s->header.cluster_size * s->header.table_size);
+}
+
static int bdrv_qed_open(BlockDriverState *bs, int flags)
{
BDRVQEDState *s = bs->opaque;
@@ -244,11 +251,23 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
bdrv_flush(bs->file);
}
+ s->l1_table = qed_alloc_table(s);
+ qed_init_l2_cache(&s->l2_cache);
+
+ ret = qed_read_l1_table_sync(s);
+ if (ret) {
+ qed_free_l2_cache(&s->l2_cache);
+ qemu_vfree(s->l1_table);
+ }
return ret;
}
static void bdrv_qed_close(BlockDriverState *bs)
{
+ BDRVQEDState *s = bs->opaque;
+
+ qed_free_l2_cache(&s->l2_cache);
+ qemu_vfree(s->l1_table);
}
static int bdrv_qed_flush(BlockDriverState *bs)
@@ -368,10 +387,43 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
backing_file, backing_fmt);
}
+typedef struct {
+ int is_allocated;
+ int *pnum;
+} QEDIsAllocatedCB;
+
+static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t len)
+{
+ QEDIsAllocatedCB *cb = opaque;
+ *cb->pnum = len / BDRV_SECTOR_SIZE;
+ cb->is_allocated = ret == QED_CLUSTER_FOUND;
+}
+
static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
- return -ENOTSUP;
+ BDRVQEDState *s = bs->opaque;
+ uint64_t pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
+ size_t len = (size_t)nb_sectors * BDRV_SECTOR_SIZE;
+ QEDIsAllocatedCB cb = {
+ .is_allocated = -1,
+ .pnum = pnum,
+ };
+ QEDRequest request = { .l2_table = NULL };
+
+ async_context_push();
+
+ qed_find_cluster(s, &request, pos, len, qed_is_allocated_cb, &cb);
+
+ while (cb.is_allocated == -1) {
+ qemu_aio_wait();
+ }
+
+ async_context_pop();
+
+ qed_unref_l2_cache_entry(request.l2_table);
+
+ return cb.is_allocated;
}
static int bdrv_qed_make_empty(BlockDriverState *bs)