Skip to content

Commit

Permalink
qcow2: record fragmentation statistics during check
Browse files Browse the repository at this point in the history
The qemu-img check command can display fragmentation statistics:
 * Total number of clusters in virtual disk
 * Number of allocated clusters
 * Number of fragmented clusters

This patch adds fragmentation statistics support to qcow2.

Compressed and normal clusters count as allocated.  Zero clusters are
not counted as allocated unless their L2 entry has a non-zero offset
(e.g. preallocation).

Only the current L1 table counts towards the statistics - snapshots are
ignored.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
  • Loading branch information
stefanhaRH authored and kevmw committed Feb 22, 2013
1 parent 801f704 commit fba31ba
Showing 1 changed file with 24 additions and 1 deletion.
25 changes: 24 additions & 1 deletion block/qcow2-refcount.c
Expand Up @@ -917,6 +917,7 @@ static void inc_refcounts(BlockDriverState *bs,
/* Flags for check_refcounts_l1() and check_refcounts_l2() */
enum {
CHECK_OFLAG_COPIED = 0x1, /* check QCOW_OFLAG_COPIED matches refcount */
CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */
};

/*
Expand All @@ -933,6 +934,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
{
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table, l2_entry;
uint64_t next_contiguous_offset = 0;
int i, l2_size, nb_csectors, refcount;

/* Read L2 table from disk */
Expand Down Expand Up @@ -963,6 +965,17 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
l2_entry &= s->cluster_offset_mask;
inc_refcounts(bs, res, refcount_table, refcount_table_size,
l2_entry & ~511, nb_csectors * 512);

if (flags & CHECK_FRAG_INFO) {
res->bfi.allocated_clusters++;

/* Compressed clusters are fragmented by nature. Since they
* take up sub-sector space but we only have sector granularity
* I/O we need to re-read the same sectors even for adjacent
* compressed clusters.
*/
res->bfi.fragmented_clusters++;
}
break;

case QCOW2_CLUSTER_ZERO:
Expand Down Expand Up @@ -990,6 +1003,15 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
}
}

if (flags & CHECK_FRAG_INFO) {
res->bfi.allocated_clusters++;
if (next_contiguous_offset &&
offset != next_contiguous_offset) {
res->bfi.fragmented_clusters++;
}
next_contiguous_offset = offset + s->cluster_size;
}

/* Mark cluster as used */
inc_refcounts(bs, res, refcount_table,refcount_table_size,
offset, s->cluster_size);
Expand Down Expand Up @@ -1125,6 +1147,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,

size = bdrv_getlength(bs->file);
nb_clusters = size_to_clusters(s, size);
res->bfi.total_clusters = nb_clusters;
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));

/* header */
Expand All @@ -1134,7 +1157,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
/* current L1 table */
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size,
CHECK_OFLAG_COPIED);
CHECK_OFLAG_COPIED | CHECK_FRAG_INFO);
if (ret < 0) {
goto fail;
}
Expand Down

0 comments on commit fba31ba

Please sign in to comment.