Block layer patches for 2.11.0-rc2

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJaFEGYAAoJEH8JsnLIjy/WiNYP/2kkepEzCiDpuMlzJVoyzBV0
 wy3AIfZkdbLTBrsGTfGhdCNJB8dLKrOeZPW/YhhfnKoOpNV50PAG7r51y6/clavq
 6QRO7tFq4OzIaNlVXzftNfFK96hWyUV1f+AazCoCdDxEL1PSOpKj8jvedUzfq8bq
 mxbGeGY7romGmJ3ahPUZ/U1U7KbkpSm6Mcri+YnD4/xcT20b8FoC7mgPCDV/kOgi
 sVGR858F54+Os/Gy1+VlvEmUxosOVA8ZBtRjwRQhS3b2/oIVbJR15Y2RHAK1TfzJ
 4OAXkKpBNh6kybO9hsbfSXujK5aWuseov4gdy+c11msshkTt6YnLPZuH1HETYQ4M
 wMYaIKcY54VF8jFFrh3aFqvZCdpvxtdZFYzuWq8vvubDSt1RkTGjZ0EpWpy+693o
 IDrjdEqd18lU56K9/R57nwAYQKmocrWO8zzqPQrr2w2c3vo+TpoJENMV/4AQOUtJ
 rV8p7AD8oKOtDWLCacDBM1sHXarTr6olFFFyZ1wMzxsdqo968mmWUbPARxygYj3C
 9zfSomp5l7heDwFm19Qyd9z0Ah0ubQOqy5DSEtqqHg84OyOezcnLas0gXfH7Tc5C
 zROup2vkB2y+cgDI/SS894QViJeaqLynuoga8cz5/XEImZhmM7s6mwmTj1n3wdYn
 GcI52qfslBTZyovjJtvr
 =qdJf
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block layer patches for 2.11.0-rc2

# gpg: Signature made Tue 21 Nov 2017 15:09:12 GMT
# gpg:                using RSA key 0x7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream:
  iotests: Fix 176 on 32-bit host
  block: Close a BlockDriverState completely even when bs->drv is NULL
  block: Error out on load_vm with active dirty bitmaps
  block: Add errp to bdrv_all_goto_snapshot()
  block: Add errp to bdrv_snapshot_goto()
  block: Don't request I/O permission with BDRV_O_NO_IO
  block: Don't use BLK_PERM_CONSISTENT_READ for format probing

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-11-21 15:50:13 +00:00
commit fc7dbc119e
10 changed files with 107 additions and 72 deletions

10
block.c
View file

@ -2579,7 +2579,10 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
goto fail; goto fail;
} }
if (file_bs != NULL) { if (file_bs != NULL) {
file = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL); /* Not requesting BLK_PERM_CONSISTENT_READ because we're only
* looking at the header to guess the image format. This works even
* in cases where a guest would not see a consistent state. */
file = blk_new(0, BLK_PERM_ALL);
blk_insert_bs(file, file_bs, &local_err); blk_insert_bs(file, file_bs, &local_err);
bdrv_unref(file_bs); bdrv_unref(file_bs);
if (local_err) { if (local_err) {
@ -3195,6 +3198,7 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
static void bdrv_close(BlockDriverState *bs) static void bdrv_close(BlockDriverState *bs)
{ {
BdrvAioNotifier *ban, *ban_next; BdrvAioNotifier *ban, *ban_next;
BdrvChild *child, *next;
assert(!bs->job); assert(!bs->job);
assert(!bs->refcnt); assert(!bs->refcnt);
@ -3204,10 +3208,9 @@ static void bdrv_close(BlockDriverState *bs)
bdrv_drain(bs); /* in case flush left pending I/O */ bdrv_drain(bs); /* in case flush left pending I/O */
if (bs->drv) { if (bs->drv) {
BdrvChild *child, *next;
bs->drv->bdrv_close(bs); bs->drv->bdrv_close(bs);
bs->drv = NULL; bs->drv = NULL;
}
bdrv_set_backing_hd(bs, NULL, &error_abort); bdrv_set_backing_hd(bs, NULL, &error_abort);
@ -3239,7 +3242,6 @@ static void bdrv_close(BlockDriverState *bs)
bs->explicit_options = NULL; bs->explicit_options = NULL;
QDECREF(bs->full_open_options); QDECREF(bs->full_open_options);
bs->full_open_options = NULL; bs->full_open_options = NULL;
}
bdrv_release_named_dirty_bitmaps(bs); bdrv_release_named_dirty_bitmaps(bs);
assert(QLIST_EMPTY(&bs->dirty_bitmaps)); assert(QLIST_EMPTY(&bs->dirty_bitmaps));

View file

@ -299,7 +299,7 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
{ {
BlockBackend *blk; BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
uint64_t perm; uint64_t perm = 0;
/* blk_new_open() is mainly used in .bdrv_create implementations and the /* blk_new_open() is mainly used in .bdrv_create implementations and the
* tools where sharing isn't a concern because the BDS stays private, so we * tools where sharing isn't a concern because the BDS stays private, so we
@ -309,10 +309,12 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
* caller of blk_new_open() doesn't make use of the permissions, but they * caller of blk_new_open() doesn't make use of the permissions, but they
* shouldn't hurt either. We can still share everything here because the * shouldn't hurt either. We can still share everything here because the
* guest devices will add their own blockers if they can't share. */ * guest devices will add their own blockers if they can't share. */
perm = BLK_PERM_CONSISTENT_READ; if ((flags & BDRV_O_NO_IO) == 0) {
perm |= BLK_PERM_CONSISTENT_READ;
if (flags & BDRV_O_RDWR) { if (flags & BDRV_O_RDWR) {
perm |= BLK_PERM_WRITE; perm |= BLK_PERM_WRITE;
} }
}
if (flags & BDRV_O_RESIZE) { if (flags & BDRV_O_RESIZE) {
perm |= BLK_PERM_RESIZE; perm |= BLK_PERM_RESIZE;
} }

View file

@ -177,36 +177,35 @@ int bdrv_snapshot_create(BlockDriverState *bs,
} }
int bdrv_snapshot_goto(BlockDriverState *bs, int bdrv_snapshot_goto(BlockDriverState *bs,
const char *snapshot_id) const char *snapshot_id,
Error **errp)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
int ret, open_ret; int ret, open_ret;
int64_t len;
if (!drv) { if (!drv) {
error_setg(errp, "Block driver is closed");
return -ENOMEDIUM; return -ENOMEDIUM;
} }
len = bdrv_getlength(bs); if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
if (len < 0) { error_setg(errp, "Device has active dirty bitmaps");
return len; return -EBUSY;
} }
/* We should set all bits in all enabled dirty bitmaps, because dirty
* bitmaps reflect active state of disk and snapshot switch operation
* actually dirties active state.
* TODO: It may make sense not to set all bits but analyze block status of
* current state and destination snapshot and do not set bits corresponding
* to both-zero or both-unallocated areas. */
bdrv_set_dirty(bs, 0, len);
if (drv->bdrv_snapshot_goto) { if (drv->bdrv_snapshot_goto) {
return drv->bdrv_snapshot_goto(bs, snapshot_id); ret = drv->bdrv_snapshot_goto(bs, snapshot_id);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to load snapshot");
}
return ret;
} }
if (bs->file) { if (bs->file) {
BlockDriverState *file; BlockDriverState *file;
QDict *options = qdict_clone_shallow(bs->options); QDict *options = qdict_clone_shallow(bs->options);
QDict *file_options; QDict *file_options;
Error *local_err = NULL;
file = bs->file->bs; file = bs->file->bs;
/* Prevent it from getting deleted when detached from bs */ /* Prevent it from getting deleted when detached from bs */
@ -220,13 +219,15 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
bdrv_unref_child(bs, bs->file); bdrv_unref_child(bs, bs->file);
bs->file = NULL; bs->file = NULL;
ret = bdrv_snapshot_goto(file, snapshot_id); ret = bdrv_snapshot_goto(file, snapshot_id, errp);
open_ret = drv->bdrv_open(bs, options, bs->open_flags, NULL); open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
QDECREF(options); QDECREF(options);
if (open_ret < 0) { if (open_ret < 0) {
bdrv_unref(file); bdrv_unref(file);
bs->drv = NULL; bs->drv = NULL;
return open_ret; /* A bdrv_snapshot_goto() error takes precedence */
error_propagate(errp, local_err);
return ret < 0 ? ret : open_ret;
} }
assert(bs->file->bs == file); assert(bs->file->bs == file);
@ -234,6 +235,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
return ret; return ret;
} }
error_setg(errp, "Block driver does not support snapshots");
return -ENOTSUP; return -ENOTSUP;
} }
@ -456,9 +458,10 @@ fail:
} }
int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs) int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs,
Error **errp)
{ {
int err = 0; int ret = 0;
BlockDriverState *bs; BlockDriverState *bs;
BdrvNextIterator it; BdrvNextIterator it;
@ -467,10 +470,10 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs)
aio_context_acquire(ctx); aio_context_acquire(ctx);
if (bdrv_can_snapshot(bs)) { if (bdrv_can_snapshot(bs)) {
err = bdrv_snapshot_goto(bs, name); ret = bdrv_snapshot_goto(bs, name, errp);
} }
aio_context_release(ctx); aio_context_release(ctx);
if (err < 0) { if (ret < 0) {
bdrv_next_cleanup(&it); bdrv_next_cleanup(&it);
goto fail; goto fail;
} }
@ -478,7 +481,7 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs)
fail: fail:
*first_bad_bs = bs; *first_bad_bs = bs;
return err; return ret;
} }
int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs) int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs)

View file

@ -57,7 +57,8 @@ int bdrv_can_snapshot(BlockDriverState *bs);
int bdrv_snapshot_create(BlockDriverState *bs, int bdrv_snapshot_create(BlockDriverState *bs,
QEMUSnapshotInfo *sn_info); QEMUSnapshotInfo *sn_info);
int bdrv_snapshot_goto(BlockDriverState *bs, int bdrv_snapshot_goto(BlockDriverState *bs,
const char *snapshot_id); const char *snapshot_id,
Error **errp);
int bdrv_snapshot_delete(BlockDriverState *bs, int bdrv_snapshot_delete(BlockDriverState *bs,
const char *snapshot_id, const char *snapshot_id,
const char *name, const char *name,
@ -83,7 +84,8 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs); bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs);
int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bsd_bs, int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bsd_bs,
Error **err); Error **err);
int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bsd_bs); int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs,
Error **errp);
int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs); int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs);
int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
BlockDriverState *vm_state_bs, BlockDriverState *vm_state_bs,

View file

@ -2346,10 +2346,10 @@ int load_snapshot(const char *name, Error **errp)
/* Flush all IO requests so they don't interfere with the new state. */ /* Flush all IO requests so they don't interfere with the new state. */
bdrv_drain_all_begin(); bdrv_drain_all_begin();
ret = bdrv_all_goto_snapshot(name, &bs); ret = bdrv_all_goto_snapshot(name, &bs, errp);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Error %d while activating snapshot '%s' on '%s'", error_prepend(errp, "Could not load snapshot '%s' on '%s': ",
ret, name, bdrv_get_device_name(bs)); name, bdrv_get_device_name(bs));
goto err_drain; goto err_drain;
} }

View file

@ -2989,10 +2989,10 @@ static int img_snapshot(int argc, char **argv)
break; break;
case SNAPSHOT_APPLY: case SNAPSHOT_APPLY:
ret = bdrv_snapshot_goto(bs, snapshot_name); ret = bdrv_snapshot_goto(bs, snapshot_name, &err);
if (ret) { if (ret) {
error_report("Could not apply snapshot '%s': %d (%s)", error_reportf_err(err, "Could not apply snapshot '%s': ",
snapshot_name, ret, strerror(-ret)); snapshot_name);
} }
break; break;

View file

@ -426,6 +426,19 @@ echo '--- Repairing ---'
_check_test_img -q -r all _check_test_img -q -r all
_check_test_img -r all _check_test_img -r all
echo
echo "=== Testing the QEMU shutdown with a corrupted image ==="
echo
_make_test_img 64M
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
echo "{'execute': 'qmp_capabilities'}
{'execute': 'human-monitor-command',
'arguments': {'command-line': 'qemu-io drive \"write 0 512\"'}}
{'execute': 'quit'}" \
| $QEMU -qmp stdio -nographic -nodefaults \
-drive if=none,node-name=drive,file="$TEST_IMG",driver=qcow2 \
| _filter_qmp | _filter_qemu_io
# success, all done # success, all done
echo "*** done" echo "*** done"
rm -f $seq.full rm -f $seq.full

View file

@ -399,4 +399,16 @@ The following inconsistencies were found and repaired:
Double checking the fixed image now... Double checking the fixed image now...
No errors were found on the image. No errors were found on the image.
=== Testing the QEMU shutdown with a corrupted image ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount table); further corruption events will be suppressed
QMP_VERSION
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "none0", "msg": "Preventing invalid write on metadata (overlaps with refcount table)", "offset": 65536, "node-name": "drive", "fatal": true, "size": 65536}}
write failed: Input/output error
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
*** done *** done

View file

@ -52,7 +52,8 @@ _supported_os Linux
function run_qemu() function run_qemu()
{ {
$QEMU -nographic -qmp stdio -serial none "$@" 2>&1 \ $QEMU -nographic -qmp stdio -serial none "$@" 2>&1 \
| _filter_testdir | _filter_qmp | _filter_qemu | _filter_testdir | _filter_qmp | _filter_qemu \
| sed 's/"sha256": ".\{64\}"/"sha256": HASH/'
} }
for reason in snapshot bitmap; do for reason in snapshot bitmap; do

View file

@ -205,7 +205,7 @@ Offset Length File
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {"sha256": "e12600978d86b5a453861ae5c17d275204673fef3874b7c3c5433c6153d84706"}} {"return": {"sha256": HASH}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
@ -255,7 +255,7 @@ Offset Length File
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {"sha256": "e12600978d86b5a453861ae5c17d275204673fef3874b7c3c5433c6153d84706"}} {"return": {"sha256": HASH}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
@ -305,7 +305,7 @@ Offset Length File
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {"sha256": "e12600978d86b5a453861ae5c17d275204673fef3874b7c3c5433c6153d84706"}} {"return": {"sha256": HASH}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
@ -352,7 +352,7 @@ Offset Length File
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {"sha256": "e12600978d86b5a453861ae5c17d275204673fef3874b7c3c5433c6153d84706"}} {"return": {"sha256": HASH}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
*** done *** done