On Tue, Jul 30, 2013 at 03:52:53PM +0800, Fam Zheng wrote: > @@ -1518,6 +1519,9 @@ static void bdrv_move_feature_fields(BlockDriverState > *bs_dest, > /* dirty bitmap */ > bs_dest->dirty_bitmap = bs_src->dirty_bitmap; > > + /* reference count */ > + bs_dest->refcnt = bs_src->refcnt; > + > /* job */ > bs_dest->in_use = bs_src->in_use; > bs_dest->job = bs_src->job;
Not sure this is correct, but then bdrv_swap() is hard to reason about... :) Imagine an emulated storage controller holds a reference to the BlockDriverState. When we create an external snapshot we'll bdrv_swap(old_top, new_top). We must not move new_top's refcount into old_top since the old_top object is still being referenced by the emulated storage controller. When the emulated storage controller does bdrv_unref() we'll hit the recount < 0 assertion and be accessing freed memory. > @@ -4392,6 +4396,24 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs) > } > } > > +/* Get a reference to bs */ > +void bdrv_ref(BlockDriverState *bs) > +{ > + bs->refcnt++; > +} > + > +/* Release a previously grabbed reference to bs. > + * If after releasing, reference count is zero, the BlockDriverState is > + * deleted. */ > +void bdrv_unref(BlockDriverState *bs) > +{ > + assert(bs->refcnt > 0); > + if (--bs->refcnt == 0) { > + bdrv_close(bs); > + bdrv_delete(bs); bdrv_delete() already calls bdrv_close() internally, no need to call bdrv_close() here.