Pull request

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+ber27ys35W+dsvQfe+BBqr8OQ4FAlztyykACgkQfe+BBqr8
 OQ4EaA//QQVDpIBRcMN+LeKWeEs8VSLziPUrZuFvuhMEEnjnaU6gbKq8G8xbFQ62
 JIHg0DBGhTt8ymE9Ay6O/cooR8F0z+XyfDr7UlpI7JL/Uwl7JguGKQrWUYBRMqCv
 Q2cLaWStLkfdkuW7Y3WRc16VEnIlizDxjRzfjE2ESYpuzD2fFsBY3KZbgbJwYwZw
 SujWUQ3MdsNdw5kDmerlrDUy7r/eyl2cLXyIt6ClHNoqq392oGMoUn4XbsaLnCWE
 H5s46qm33eXtvBHqxVGoOMAli5FwCnhwF+H3xg93jIG6vC/RXQYCIhlEmEwKyrU2
 g2DWWe/8+9b0iX+zTIcAPTcn1pmjVivGRorOurP0AtMtjV/8PvV+hAQQeSg2ARB3
 rLpXaEphD4WTwu7mYlZ5kX0qvX2SftaMU08k1IgR3mfo8Z3X9znVoFIv8HLlHuy+
 OhCmwT5OWYw4mNABTXeBMH/Dcs9EcU4+T/KhAGLReHo18CSyjeT2xsT+XCsETagF
 KlAP88dP0EdJ9Oiccyb8as22u7ygKWIiDYPplBdb4SkKg/koQnYGDjeDAzB2vXS3
 cGVhGJD2DBbcePA8iaCfWzsSCDOTBFQLa45uhPD3DnkAJylhecSsiDQP+IrLslK3
 h/8v9e8MAlHMgrueSnS7foMDI9rdrTNsChuNCJWOOaUI/ZWnXFg=
 =kCrN
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/jnsnow/tags/bitmaps-pull-request' into staging

Pull request

# gpg: Signature made Wed 29 May 2019 00:58:33 BST
# gpg:                using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [full]
# Primary key fingerprint: FAEB 9711 A12C F475 812F  18F2 88A9 064D 1835 61EB
#      Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76  CBD0 7DEF 8106 AAFC 390E

* remotes/jnsnow/tags/bitmaps-pull-request:
  iotests: test external snapshot with bitmap copying
  qapi: support external bitmaps in block-dirty-bitmap-merge
  migration/dirty-bitmaps: change bitmap enumeration method

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-05-30 12:10:27 +01:00
commit 62f6849e7a
7 changed files with 167 additions and 33 deletions

View File

@ -816,10 +816,10 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
{ {
bool ret; bool ret;
/* only bitmaps from one bds are supported */
assert(dest->mutex == src->mutex);
qemu_mutex_lock(dest->mutex); qemu_mutex_lock(dest->mutex);
if (src->mutex != dest->mutex) {
qemu_mutex_lock(src->mutex);
}
if (bdrv_dirty_bitmap_check(dest, BDRV_BITMAP_DEFAULT, errp)) { if (bdrv_dirty_bitmap_check(dest, BDRV_BITMAP_DEFAULT, errp)) {
goto out; goto out;
@ -845,4 +845,7 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
out: out:
qemu_mutex_unlock(dest->mutex); qemu_mutex_unlock(dest->mutex);
if (src->mutex != dest->mutex) {
qemu_mutex_unlock(src->mutex);
}
} }

View File

@ -2112,11 +2112,10 @@ static void block_dirty_bitmap_disable_abort(BlkActionState *common)
} }
} }
static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node, static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(
const char *target, const char *node, const char *target,
strList *bitmaps, BlockDirtyBitmapMergeSourceList *bitmaps,
HBitmap **backup, HBitmap **backup, Error **errp);
Error **errp);
static void block_dirty_bitmap_merge_prepare(BlkActionState *common, static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
Error **errp) Error **errp)
@ -2965,15 +2964,14 @@ void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
bdrv_disable_dirty_bitmap(bitmap); bdrv_disable_dirty_bitmap(bitmap);
} }
static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node, static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(
const char *target, const char *node, const char *target,
strList *bitmaps, BlockDirtyBitmapMergeSourceList *bitmaps,
HBitmap **backup, HBitmap **backup, Error **errp)
Error **errp)
{ {
BlockDriverState *bs; BlockDriverState *bs;
BdrvDirtyBitmap *dst, *src, *anon; BdrvDirtyBitmap *dst, *src, *anon;
strList *lst; BlockDirtyBitmapMergeSourceList *lst;
Error *local_err = NULL; Error *local_err = NULL;
dst = block_dirty_bitmap_lookup(node, target, &bs, errp); dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
@ -2988,12 +2986,29 @@ static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node,
} }
for (lst = bitmaps; lst; lst = lst->next) { for (lst = bitmaps; lst; lst = lst->next) {
src = bdrv_find_dirty_bitmap(bs, lst->value); switch (lst->value->type) {
const char *name, *node;
case QTYPE_QSTRING:
name = lst->value->u.local;
src = bdrv_find_dirty_bitmap(bs, name);
if (!src) { if (!src) {
error_setg(errp, "Dirty bitmap '%s' not found", lst->value); error_setg(errp, "Dirty bitmap '%s' not found", name);
dst = NULL; dst = NULL;
goto out; goto out;
} }
break;
case QTYPE_QDICT:
node = lst->value->u.external.node;
name = lst->value->u.external.name;
src = block_dirty_bitmap_lookup(node, name, NULL, errp);
if (!src) {
dst = NULL;
goto out;
}
break;
default:
abort();
}
bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err); bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
if (local_err) { if (local_err) {
@ -3012,7 +3027,8 @@ static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node,
} }
void qmp_block_dirty_bitmap_merge(const char *node, const char *target, void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
strList *bitmaps, Error **errp) BlockDirtyBitmapMergeSourceList *bitmaps,
Error **errp)
{ {
do_block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp); do_block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
} }

View File

@ -273,7 +273,6 @@ static int init_dirty_bitmap_migration(void)
BlockDriverState *bs; BlockDriverState *bs;
BdrvDirtyBitmap *bitmap; BdrvDirtyBitmap *bitmap;
DirtyBitmapMigBitmapState *dbms; DirtyBitmapMigBitmapState *dbms;
BdrvNextIterator it;
Error *local_err = NULL; Error *local_err = NULL;
dirty_bitmap_mig_state.bulk_completed = false; dirty_bitmap_mig_state.bulk_completed = false;
@ -281,13 +280,8 @@ static int init_dirty_bitmap_migration(void)
dirty_bitmap_mig_state.prev_bitmap = NULL; dirty_bitmap_mig_state.prev_bitmap = NULL;
dirty_bitmap_mig_state.no_bitmaps = false; dirty_bitmap_mig_state.no_bitmaps = false;
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { for (bs = bdrv_next_all_states(NULL); bs; bs = bdrv_next_all_states(bs)) {
const char *drive_name = bdrv_get_device_or_node_name(bs); const char *name = bdrv_get_device_or_node_name(bs);
/* skip automatically inserted nodes */
while (bs && bs->drv && bs->implicit) {
bs = backing_bs(bs);
}
for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap; for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap;
bitmap = bdrv_dirty_bitmap_next(bs, bitmap)) bitmap = bdrv_dirty_bitmap_next(bs, bitmap))
@ -296,7 +290,7 @@ static int init_dirty_bitmap_migration(void)
continue; continue;
} }
if (drive_name == NULL) { if (!name || strcmp(name, "") == 0) {
error_report("Found bitmap '%s' in unnamed node %p. It can't " error_report("Found bitmap '%s' in unnamed node %p. It can't "
"be migrated", bdrv_dirty_bitmap_name(bitmap), bs); "be migrated", bdrv_dirty_bitmap_name(bitmap), bs);
goto fail; goto fail;
@ -313,7 +307,7 @@ static int init_dirty_bitmap_migration(void)
dbms = g_new0(DirtyBitmapMigBitmapState, 1); dbms = g_new0(DirtyBitmapMigBitmapState, 1);
dbms->bs = bs; dbms->bs = bs;
dbms->node_name = drive_name; dbms->node_name = name;
dbms->bitmap = bitmap; dbms->bitmap = bitmap;
dbms->total_sectors = bdrv_nb_sectors(bs); dbms->total_sectors = bdrv_nb_sectors(bs);
dbms->sectors_per_chunk = CHUNK_SIZE * 8 * dbms->sectors_per_chunk = CHUNK_SIZE * 8 *

View File

@ -2003,19 +2003,35 @@
'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32', 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32',
'*persistent': 'bool', '*autoload': 'bool', '*disabled': 'bool' } } '*persistent': 'bool', '*autoload': 'bool', '*disabled': 'bool' } }
##
# @BlockDirtyBitmapMergeSource:
#
# @local: name of the bitmap, attached to the same node as target bitmap.
#
# @external: bitmap with specified node
#
# Since: 4.1
##
{ 'alternate': 'BlockDirtyBitmapMergeSource',
'data': { 'local': 'str',
'external': 'BlockDirtyBitmap' } }
## ##
# @BlockDirtyBitmapMerge: # @BlockDirtyBitmapMerge:
# #
# @node: name of device/node which the bitmap is tracking # @node: name of device/node which the @target bitmap is tracking
# #
# @target: name of the destination dirty bitmap # @target: name of the destination dirty bitmap
# #
# @bitmaps: name(s) of the source dirty bitmap(s) # @bitmaps: name(s) of the source dirty bitmap(s) at @node and/or fully
# specifed BlockDirtyBitmap elements. The latter are supported
# since 4.1.
# #
# Since: 4.0 # Since: 4.0
## ##
{ 'struct': 'BlockDirtyBitmapMerge', { 'struct': 'BlockDirtyBitmapMerge',
'data': { 'node': 'str', 'target': 'str', 'bitmaps': ['str'] } } 'data': { 'node': 'str', 'target': 'str',
'bitmaps': ['BlockDirtyBitmapMergeSource'] } }
## ##
# @block-dirty-bitmap-add: # @block-dirty-bitmap-add:

52
tests/qemu-iotests/254 Executable file
View File

@ -0,0 +1,52 @@
#!/usr/bin/env python
#
# Test external snapshot with bitmap copying.
#
# Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import iotests
from iotests import qemu_img_create, file_path, log
disk, top = file_path('disk', 'top')
size = 1024 * 1024
qemu_img_create('-f', iotests.imgfmt, disk, str(size))
vm = iotests.VM().add_drive(disk, opts='node-name=base')
vm.launch()
vm.qmp_log('block-dirty-bitmap-add', node='drive0', name='bitmap0')
vm.hmp_qemu_io('drive0', 'write 0 512K')
vm.qmp_log('transaction', indent=2, actions=[
{'type': 'blockdev-snapshot-sync',
'data': {'device': 'drive0', 'snapshot-file': top,
'snapshot-node-name': 'snap'}},
{'type': 'block-dirty-bitmap-add',
'data': {'node': 'snap', 'name': 'bitmap0'}},
{'type': 'block-dirty-bitmap-merge',
'data': {'node': 'snap', 'target': 'bitmap0',
'bitmaps': [{'node': 'base', 'name': 'bitmap0'}]}}
], filters=[iotests.filter_qmp_testfiles])
result = vm.qmp('query-block')['return'][0]
log("query-block: device = {}, node-name = {}, dirty-bitmaps:".format(
result['device'], result['inserted']['node-name']))
log(result['dirty-bitmaps'], indent=2)
vm.shutdown()

View File

@ -0,0 +1,52 @@
{"execute": "block-dirty-bitmap-add", "arguments": {"name": "bitmap0", "node": "drive0"}}
{"return": {}}
{
"execute": "transaction",
"arguments": {
"actions": [
{
"data": {
"device": "drive0",
"snapshot-file": "TEST_DIR/PID-top",
"snapshot-node-name": "snap"
},
"type": "blockdev-snapshot-sync"
},
{
"data": {
"name": "bitmap0",
"node": "snap"
},
"type": "block-dirty-bitmap-add"
},
{
"data": {
"bitmaps": [
{
"name": "bitmap0",
"node": "base"
}
],
"node": "snap",
"target": "bitmap0"
},
"type": "block-dirty-bitmap-merge"
}
]
}
}
{
"return": {}
}
query-block: device = drive0, node-name = snap, dirty-bitmaps:
[
{
"busy": false,
"count": 524288,
"granularity": 65536,
"name": "bitmap0",
"persistent": false,
"recording": true,
"status": "active"
}
]

View File

@ -264,3 +264,4 @@
249 rw auto quick 249 rw auto quick
252 rw auto backing quick 252 rw auto backing quick
253 rw auto quick 253 rw auto quick
254 rw auto backing quick