qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: John Snow <jsnow@redhat.com>
To: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>
Cc: "eblake@redhat.com" <eblake@redhat.com>,
	Kevin Wolf <kwolf@redhat.com>,
	"qemu-block@nongnu.org" <qemu-block@nongnu.org>,
	Max Reitz <mreitz@redhat.com>
Subject: Re: [Qemu-devel] [PATCH 4/5] block/qcow2-bitmap: Allow resizes with persistent bitmaps
Date: Wed, 6 Mar 2019 10:41:00 -0500	[thread overview]
Message-ID: <737eb62f-47f4-1824-909d-8578584b8794@redhat.com> (raw)
In-Reply-To: <6c9c5b9b-8093-e993-1027-db692d20e2e1@virtuozzo.com>



On 3/6/19 10:33 AM, Vladimir Sementsov-Ogievskiy wrote:
> 06.03.2019 2:43, John Snow wrote:
>> Since we now load all bitmaps into memory anyway, we can just truncate them
>> in-memory and then flush them back to disk. Just in case, we will still check
>> and enforce that this shortcut is valid -- i.e. that any bitmap described
>> on-disk is indeed in-memory and can be modified.
>>
>> If there are any inconsistent bitmaps, we refuse to allow the truncate as
>> we do not actually load these bitmaps into memory, and it isn't safe or
>> reasonable to attempt to truncate corrupted data.
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   block/qcow2.h        |  1 +
>>   block/qcow2-bitmap.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>>   block/qcow2.c        | 27 ++++++++++++++++++++-------
>>   3 files changed, 63 insertions(+), 7 deletions(-)
>>
>> diff --git a/block/qcow2.h b/block/qcow2.h
>> index 4c1fdfcbec..b9227a72cc 100644
>> --- a/block/qcow2.h
>> +++ b/block/qcow2.h
>> @@ -689,6 +689,7 @@ Qcow2BitmapInfoList *qcow2_get_bitmap_info_list(BlockDriverState *bs,
>>   int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated,
>>                                    Error **errp);
>>   int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
>> +int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
>>   void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
>>   void qcow2_flush_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
>>   int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
>> diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
>> index 9373055d3b..24f280bccc 100644
>> --- a/block/qcow2-bitmap.c
>> +++ b/block/qcow2-bitmap.c
>> @@ -1167,6 +1167,48 @@ int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp)
>>       return qcow2_reopen_bitmaps_rw_hint(bs, NULL, errp);
>>   }
>>   
>> +/* Checks to see if it's safe to resize bitmaps */
>> +int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp)
>> +{
>> +    BDRVQcow2State *s = bs->opaque;
>> +    Qcow2BitmapList *bm_list;
>> +    Qcow2Bitmap *bm;
>> +    int ret = 0;
>> +
>> +    if (s->nb_bitmaps == 0) {
>> +        return 0;
>> +    }
>> +
>> +    bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
>> +                               s->bitmap_directory_size, false, errp);
>> +    if (bm_list == NULL) {
>> +        return -EINVAL;
>> +    }
>> +
>> +    QSIMPLEQ_FOREACH(bm, bm_list, entry) {
>> +        BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name);
>> +        if (bitmap == NULL) {
>> +            /* We rely on all bitmaps being in-memory to be able to resize them,
>> +             * Otherwise, we'd need to resize them on disk explicitly */
>> +            error_setg(errp, "Cannot resize qcow2 with persistent bitmaps that "
>> +                       "were not loaded into memory");
>> +            ret = -ENOTSUP;
>> +            goto out;
>> +        }
>> +
>> +        /* The checks against readonly and busy are redundant, but certainly
>> +         * do no harm. checks against inconsistent are crucial: */
>> +        if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
>> +            ret = -ENOTSUP;
>> +            goto out;
>> +        }
>> +    }
>> +
>> +out:
>> +    bitmap_list_free(bm_list);
>> +    return ret;
>> +}
>> +
>>   /* store_bitmap_data()
>>    * Store bitmap to image, filling bitmap table accordingly.
>>    */
>> diff --git a/block/qcow2.c b/block/qcow2.c
>> index 7fb2730f09..6fd9252494 100644
>> --- a/block/qcow2.c
>> +++ b/block/qcow2.c
>> @@ -3472,7 +3472,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
>>   {
>>       BDRVQcow2State *s = bs->opaque;
>>       uint64_t old_length;
>> -    int64_t new_l1_size;
>> +    int64_t new_l1_size, offset_be;
>>       int ret;
>>       QDict *options;
>>   
>> @@ -3498,10 +3498,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
>>           goto fail;
>>       }
>>   
>> -    /* cannot proceed if image has bitmaps */
>> -    if (s->nb_bitmaps) {
>> -        /* TODO: resize bitmaps in the image */
>> -        error_setg(errp, "Can't resize an image which has bitmaps");
>> +    /* Only certain persistent bitmaps can be resized: */
>> +    if (qcow2_truncate_bitmaps_check(bs, errp)) {
>>           ret = -ENOTSUP;
>>           goto fail;
>>       }
>> @@ -3702,9 +3700,9 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
>>       bs->total_sectors = offset / BDRV_SECTOR_SIZE;
>>   
>>       /* write updated header.size */
>> -    offset = cpu_to_be64(offset);
>> +    offset_be = cpu_to_be64(offset);
>>       ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
>> -                           &offset, sizeof(uint64_t));
>> +                           &offset_be, sizeof(uint64_t));
>>       if (ret < 0) {
>>           error_setg_errno(errp, -ret, "Failed to update the image size");
>>           goto fail;
>> @@ -3719,6 +3717,21 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
>>       if (ret < 0) {
>>           goto fail;
>>       }
>> +
>> +    /* Flush bitmaps */
>> +    if (s->nb_bitmaps) {
>> +        Error *local_err = NULL;
>> +
>> +        /* Usually, bitmaps get resized after this call.
>> +         * Force it earlier so we can make the metadata consistent. */
>> +        bdrv_dirty_bitmap_truncate(bs, offset);
>> +        qcow2_flush_persistent_dirty_bitmaps(bs, &local_err);
>> +        if (local_err) {
>> +            ret = -EINVAL;
>> +            goto fail;
>> +        }
>> +    }
> 
> Why to flush after resize? Bitmaps will be IN_USE in the image anyway...
> 
> Could we implement resize without flush first,  it would be one patch + test? And then consider
> flushing in separate?
> 

If you don't flush it to disk, all calls to retrieve the bm_list begin
failing because of inconsistent metadata.

Future calls to add bitmaps, remove bitmaps, etc will start failing. It
seemed safest and easiest to just flush the whole suite to disk. I am
trying to avoid premature optimizations at this stage, as I believe
resizes will be very infrequent events.

--js

  parent reply	other threads:[~2019-03-06 15:41 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-05 23:43 [Qemu-devel] [PATCH 0/5] block/qcow2-bitmap: Enable resize with persistent bitmaps John Snow
2019-03-05 23:43 ` [Qemu-devel] [PATCH 1/5] block/qcow2-bitmap: Skip length check in some cases John Snow
2019-03-06 12:34   ` Eric Blake
2019-03-06 15:21   ` Vladimir Sementsov-Ogievskiy
2019-03-06 15:35     ` John Snow
2019-03-06 16:07   ` Vladimir Sementsov-Ogievskiy
2019-03-08 22:10     ` John Snow
2019-03-05 23:43 ` [Qemu-devel] [PATCH 2/5] block/qcow2-bitmap: Allow bitmap flushing John Snow
2019-03-06 12:58   ` Eric Blake
2019-03-06 15:59     ` John Snow
2019-03-06 16:12       ` Vladimir Sementsov-Ogievskiy
2019-03-08 22:11         ` John Snow
2019-03-05 23:43 ` [Qemu-devel] [PATCH 3/5] block/qcow2-bitmap: don't remove bitmaps on reopen John Snow
2019-03-06 15:28   ` Vladimir Sementsov-Ogievskiy
2019-03-06 15:38     ` John Snow
2019-03-05 23:43 ` [Qemu-devel] [PATCH 4/5] block/qcow2-bitmap: Allow resizes with persistent bitmaps John Snow
2019-03-06 15:33   ` Vladimir Sementsov-Ogievskiy
2019-03-06 15:36     ` Eric Blake
2019-03-06 15:44       ` Vladimir Sementsov-Ogievskiy
2019-03-06 15:41     ` John Snow [this message]
2019-03-06 15:52       ` Vladimir Sementsov-Ogievskiy
2019-03-06 15:56         ` Vladimir Sementsov-Ogievskiy
2019-03-09  0:35         ` John Snow
2019-03-05 23:43 ` [Qemu-devel] [PATCH 5/5] tests/qemu-iotests: add bitmap resize test 246 John Snow
2019-03-06  0:02 ` [Qemu-devel] [PATCH 0/5] block/qcow2-bitmap: Enable resize with persistent bitmaps John Snow
2019-03-10 16:50 ` no-reply
2019-03-11 16:18 ` Eric Blake
2019-03-11 17:36   ` Vladimir Sementsov-Ogievskiy
2019-03-11 17:48     ` Eric Blake
2019-03-11 18:05       ` Vladimir Sementsov-Ogievskiy
2019-03-11 18:05     ` John Snow
2019-03-11 18:26       ` Vladimir Sementsov-Ogievskiy
2019-03-11 18:35         ` John Snow

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=737eb62f-47f4-1824-909d-8578584b8794@redhat.com \
    --to=jsnow@redhat.com \
    --cc=eblake@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=vsementsov@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).