On Tue, Apr 01, 2014 at 02:06:10PM +0800, Jun Li wrote: > Signed-off-by: Jun Li <junm...@gmail.com> > > This patch can make sure the data still existing after shrinking. And only > discard the unused (guest) clusters. If shrinking to the size which stored > data, It will return an error and will not do any change. > As this patch can support shrinking, so changed the func name of > qcow2_grow_l1_table to qcow2_truncate_l1_table.
Please follow the patch formatting conventions: qcow2: add qcow2_truncate() shrinking support ...patch description... Signed-off-by: ... > -int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, > +int qcow2_truncate_l1_table(BlockDriverState *bs, uint64_t min_size, > bool exact_size) > { > BDRVQcowState *s = bs->opaque; > @@ -39,9 +39,6 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t > min_size, > int64_t new_l1_table_offset, new_l1_size; > uint8_t data[12]; > > - if (min_size <= s->l1_size) > - return 0; > - > if (exact_size) { > new_l1_size = min_size; > } else { > @@ -66,7 +63,18 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t > min_size, > > new_l1_size2 = sizeof(uint64_t) * new_l1_size; > new_l1_table = g_malloc0(align_offset(new_l1_size2, 512)); > - memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t)); > + > + /* shrinking the image */ > + if (min_size <= s->l1_size) { > + if (s->l1_table[new_l1_size] != 0) { > + error_report("Could not shrink to this size, " > + "it will destory image data"); > + return -ENOTSUP; > + } > + memcpy(new_l1_table, s->l1_table, new_l1_size2); > + } > + > + memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t)); In the shrink case the second memcpy() overflows new_l1_table. But the bigger issue I see with this patch is that bdrv_truncate() is supposed to shrink the file, whether there is data present or not. Please drop the if (s->l1_table[new_l1_size] != 0) test. > > /* write new table (align to cluster) */ > BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE); > @@ -559,7 +567,7 @@ static int get_cluster_table(BlockDriverState *bs, > uint64_t offset, > > l1_index = offset >> (s->l2_bits + s->cluster_bits); > if (l1_index >= s->l1_size) { > - ret = qcow2_grow_l1_table(bs, l1_index + 1, false); > + ret = qcow2_truncate_l1_table(bs, l1_index + 1, false); > if (ret < 0) { > return ret; > } > diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c > index 2fc6320..ab16c52 100644 > --- a/block/qcow2-snapshot.c > +++ b/block/qcow2-snapshot.c > @@ -491,7 +491,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char > *snapshot_id) > * L1 table of the snapshot. If the snapshot L1 table is smaller, the > * current one must be padded with zeros. > */ > - ret = qcow2_grow_l1_table(bs, sn->l1_size, true); > + ret = qcow2_truncate_l1_table(bs, sn->l1_size, true); > if (ret < 0) { > goto fail; > } > diff --git a/block/qcow2.c b/block/qcow2.c > index b9dc960..4797879 100644 > --- a/block/qcow2.c > +++ b/block/qcow2.c > @@ -1764,14 +1764,8 @@ static int qcow2_truncate(BlockDriverState *bs, > int64_t offset) > return -ENOTSUP; > } > > - /* shrinking is currently not supported */ > - if (offset < bs->total_sectors * 512) { > - error_report("qcow2 doesn't support shrinking images yet"); > - return -ENOTSUP; > - } > - > new_l1_size = size_to_l1(s, offset); > - ret = qcow2_grow_l1_table(bs, new_l1_size, true); > + ret = qcow2_truncate_l1_table(bs, new_l1_size, true); > if (ret < 0) { > return ret; > } > diff --git a/block/qcow2.h b/block/qcow2.h > index 0b0eac8..298d84e 100644 > --- a/block/qcow2.h > +++ b/block/qcow2.h > @@ -455,7 +455,7 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, > int ign, int64_t offset, > int64_t size); > > /* qcow2-cluster.c functions */ > -int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, > +int qcow2_truncate_l1_table(BlockDriverState *bs, uint64_t min_size, > bool exact_size); Please indent "bool exact_size" up to the '(': +int qcow2_truncate_l1_table(BlockDriverState *bs, uint64_t min_size, + bool exact_size);