1
The following changes since commit 609ef9f451759151d0bfe7c3843410ab94d68f18:
1
The following changes since commit ba29883206d92a29ad5a466e679ccfc2ee6132ef:
2
2
3
Merge remote-tracking branch 'remotes/berrange/tags/qio-next-pull-request' into staging (2018-06-28 17:53:31 +0100)
3
Merge remote-tracking branch 'remotes/borntraeger/tags/s390x-20200310' into staging (2020-03-10 16:50:28 +0000)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 583c99d39368526dfb57a715b04a6ceea27dbe1e:
9
for you to fetch changes up to 8bb3b023f2055054ee119cb45b42d2b14be7fc8a:
10
10
11
block: Remove unused sector-based vectored I/O (2018-06-29 14:20:56 +0200)
11
qemu-iotests: adding LUKS cleanup for non-UTF8 secret error (2020-03-11 15:54:38 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- Make truncate operations asynchronous (so that preallocation in
16
- Relax restrictions for blockdev-snapshot (allows libvirt to do live
17
blockdev-create doesn't block the main loop any more)
17
storage migration with blockdev-mirror)
18
- usb-storage: Add rerror/werror properties
18
- luks: Delete created files when block_crypto_co_create_opts_luks fails
19
- nvme: Add num_queues property
19
- Fix memleaks in qmp_object_add
20
- qemu-img convert: Copy offloading fixes (including data corruption fix)
21
- qcow2: Fix cluster leak on temporary write error
22
- Use byte-based functions instead of bdrv_co_readv/writev()
23
- Various small fixes and cleanups
24
20
25
----------------------------------------------------------------
21
----------------------------------------------------------------
26
Eric Blake (8):
22
Daniel Henrique Barboza (4):
27
parallels: Switch to byte-based calls
23
block: introducing 'bdrv_co_delete_file' interface
28
qcow: Switch get_cluster_offset to be byte-based
24
block.c: adding bdrv_co_delete_file
29
qcow: Switch qcow_co_readv to byte-based calls
25
crypto.c: cleanup created file when block_crypto_co_create_opts_luks fails
30
qcow: Switch qcow_co_writev to byte-based calls
26
qemu-iotests: adding LUKS cleanup for non-UTF8 secret error
31
qcow: Switch to a byte-based driver
32
replication: Switch to byte-based calls
33
vhdx: Switch to byte-based calls
34
block: Remove unused sector-based vectored I/O
35
27
36
Fam Zheng (5):
28
Kevin Wolf (6):
37
qcow2: Remove dead check on !ret
29
block: Make bdrv_get_cumulative_perm() public
38
block: Move request tracking to children in copy offloading
30
block: Relax restrictions for blockdev-snapshot
39
qcow2: Fix src_offset in copy offloading
31
iotests: Fix run_job() with use_log=False
40
iscsi: Don't blindly use designator length in response for memcpy
32
iotests: Test mirror with temporarily disabled target backing file
41
file-posix: Fix EINTR handling
33
block: Fix cross-AioContext blockdev-snapshot
34
iotests: Add iothread cases to 155
42
35
43
Kevin Wolf (12):
36
Pan Nengyuan (1):
44
qapi/job: The next release will be 3.0
37
qom-qmp-cmds: fix two memleaks in qmp_object_add
45
usb-storage: Add rerror/werror properties
46
qcow2: Fix qcow2_truncate() error return value
47
block: Convert .bdrv_truncate callback to coroutine_fn
48
qcow2: Remove coroutine trampoline for preallocate_co()
49
block: Move bdrv_truncate() implementation to io.c
50
block: Use tracked request for truncate
51
file-posix: Make .bdrv_co_truncate asynchronous
52
qemu-iotests: Update 026.out.nocache reference output
53
qcow2: Free allocated clusters on write error
54
qemu-iotests: Test qcow2 not leaking clusters on write error
55
file-posix: Implement co versions of discard/flush
56
38
57
Markus Armbruster (3):
39
Peter Krempa (1):
58
block-qdict: Pacify Coverity after commit f1b34a248e9
40
qapi: Add '@allow-write-only-overlay' feature for 'blockdev-snapshot'
59
block/crypto: Pacify Coverity after commit f853465aacb
60
block/crypto: Simplify block_crypto_{open,create}_opts_init()
61
41
62
Weiping Zhang (1):
42
Philippe Mathieu-Daudé (1):
63
hw/block/nvme: add optional parameter num_queues for nvme device
43
tests/qemu-iotests: Fix socket_scm_helper build path
64
44
65
qapi/job.json | 18 +-
45
qapi/block-core.json | 9 ++++-
66
block/crypto.h | 8 +-
46
include/block/block.h | 1 +
67
block/qcow2.h | 1 +
47
include/block/block_int.h | 7 ++++
68
include/block/block.h | 8 +-
48
block.c | 33 ++++++++++++++--
69
include/block/block_int.h | 7 +-
49
block/crypto.c | 18 +++++++++
70
include/block/raw-aio.h | 4 +-
50
block/file-posix.c | 23 +++++++++++
71
include/hw/scsi/scsi.h | 2 +
51
blockdev.c | 30 ++++-----------
72
block.c | 64 +------
52
qom/qom-qmp-cmds.c | 16 +++-----
73
block/copy-on-read.c | 8 +-
53
tests/qemu-iotests/iotests.py | 5 ++-
74
block/crypto.c | 112 +++--------
54
tests/Makefile.include | 1 +
75
block/file-posix.c | 367 +++++++++++++++++++------------------
55
tests/qemu-iotests/085.out | 4 +-
76
block/file-win32.c | 6 +-
56
tests/qemu-iotests/155 | 88 ++++++++++++++++++++++++++++++++++++-------
77
block/gluster.c | 14 +-
57
tests/qemu-iotests/155.out | 4 +-
78
block/io.c | 219 +++++++++++++++-------
58
tests/qemu-iotests/282 | 67 ++++++++++++++++++++++++++++++++
79
block/iscsi.c | 10 +-
59
tests/qemu-iotests/282.out | 11 ++++++
80
block/nfs.c | 7 +-
60
tests/qemu-iotests/group | 1 +
81
block/parallels.c | 16 +-
61
tests/qtest/Makefile.include | 1 -
82
block/qcow.c | 135 +++++++-------
62
17 files changed, 262 insertions(+), 57 deletions(-)
83
block/qcow2-cluster.c | 11 ++
63
create mode 100755 tests/qemu-iotests/282
84
block/qcow2.c | 140 ++++++--------
64
create mode 100644 tests/qemu-iotests/282.out
85
block/qed.c | 8 +-
86
block/raw-format.c | 8 +-
87
block/rbd.c | 8 +-
88
block/replication.c | 14 +-
89
block/sheepdog.c | 12 +-
90
block/ssh.c | 6 +-
91
block/vhdx.c | 12 +-
92
hw/block/nvme.c | 5 +-
93
hw/scsi/scsi-bus.c | 11 +-
94
hw/usb/dev-storage.c | 2 +
95
qobject/block-qdict.c | 16 +-
96
tests/qemu-iotests/026 | 17 ++
97
tests/qemu-iotests/026.out | 8 +
98
tests/qemu-iotests/026.out.nocache | 14 +-
99
tests/qemu-iotests/063 | 9 +
100
tests/qemu-iotests/063.out | 12 ++
101
36 files changed, 685 insertions(+), 634 deletions(-)
102
65
66
diff view generated by jsdifflib
Deleted patch
1
From: Markus Armbruster <armbru@redhat.com>
2
1
3
Commit f1b34a248e9 replaced less-than-obvious test in
4
qdict_flatten_qdict() by the obvious one. Sadly, it made something
5
else non-obvious: the fact that @new_key passed to qdict_put_obj()
6
can't be null, because that depends on the function's precondition
7
(target == qdict) == !prefix.
8
9
Tweak the function some more to help Coverity and human readers alike.
10
11
Fixes: CID 1393620
12
Signed-off-by: Markus Armbruster <armbru@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
qobject/block-qdict.c | 16 ++++++++--------
16
1 file changed, 8 insertions(+), 8 deletions(-)
17
18
diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/qobject/block-qdict.c
21
+++ b/qobject/block-qdict.c
22
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
23
const QDictEntry *entry, *next;
24
QDict *dict_val;
25
QList *list_val;
26
- char *new_key;
27
+ char *key, *new_key;
28
29
entry = qdict_first(qdict);
30
31
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
32
value = qdict_entry_value(entry);
33
dict_val = qobject_to(QDict, value);
34
list_val = qobject_to(QList, value);
35
- new_key = NULL;
36
37
if (prefix) {
38
- new_key = g_strdup_printf("%s.%s", prefix, entry->key);
39
+ key = new_key = g_strdup_printf("%s.%s", prefix, entry->key);
40
+ } else {
41
+ key = entry->key;
42
+ new_key = NULL;
43
}
44
45
/*
46
@@ -XXX,XX +XXX,XX @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
47
* well advised not to modify them altogether.)
48
*/
49
if (dict_val && qdict_size(dict_val)) {
50
- qdict_flatten_qdict(dict_val, target,
51
- new_key ? new_key : entry->key);
52
+ qdict_flatten_qdict(dict_val, target, key);
53
if (target == qdict) {
54
qdict_del(qdict, entry->key);
55
}
56
} else if (list_val && !qlist_empty(list_val)) {
57
- qdict_flatten_qlist(list_val, target,
58
- new_key ? new_key : entry->key);
59
+ qdict_flatten_qlist(list_val, target, key);
60
if (target == qdict) {
61
qdict_del(qdict, entry->key);
62
}
63
} else if (target != qdict) {
64
- qdict_put_obj(target, new_key, qobject_ref(value));
65
+ qdict_put_obj(target, key, qobject_ref(value));
66
}
67
68
g_free(new_key);
69
--
70
2.13.6
71
72
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Pan Nengyuan <pannengyuan@huawei.com>
2
2
3
We are gradually moving away from sector-based interfaces, towards
3
'type/id' forgot to free in qmp_object_add, this patch fix that.
4
byte-based. Now that all callers of vectored I/O have been converted
5
to use our preferred byte-based bdrv_co_p{read,write}v(), we can
6
delete the unused bdrv_co_{read,write}v().
7
4
8
Furthermore, this gets rid of the signature difference between the
5
The leak stack:
9
public bdrv_co_writev() and the callback .bdrv_co_writev (the
6
Direct leak of 84 byte(s) in 6 object(s) allocated from:
10
latter still exists, because some drivers still need more work
7
#0 0x7fe2a5ebf768 in __interceptor_malloc (/lib64/libasan.so.5+0xef768)
11
before they are fully byte-based).
8
#1 0x7fe2a5044445 in g_malloc (/lib64/libglib-2.0.so.0+0x52445)
9
#2 0x7fe2a505dd92 in g_strdup (/lib64/libglib-2.0.so.0+0x6bd92)
10
#3 0x56344954e692 in qmp_object_add /mnt/sdb/qemu-new/qemu_test/qemu/qom/qom-qmp-cmds.c:258
11
#4 0x563449960f5a in do_qmp_dispatch /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qmp-dispatch.c:132
12
#5 0x563449960f5a in qmp_dispatch /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qmp-dispatch.c:175
13
#6 0x563449498a30 in monitor_qmp_dispatch /mnt/sdb/qemu-new/qemu_test/qemu/monitor/qmp.c:145
14
#7 0x56344949a64f in monitor_qmp_bh_dispatcher /mnt/sdb/qemu-new/qemu_test/qemu/monitor/qmp.c:234
15
#8 0x563449a92a3a in aio_bh_call /mnt/sdb/qemu-new/qemu_test/qemu/util/async.c:136
12
16
13
Signed-off-by: Eric Blake <eblake@redhat.com>
17
Direct leak of 54 byte(s) in 6 object(s) allocated from:
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
18
#0 0x7fe2a5ebf768 in __interceptor_malloc (/lib64/libasan.so.5+0xef768)
15
Reviewed-by: Jeff Cody <jcody@redhat.com>
19
#1 0x7fe2a5044445 in g_malloc (/lib64/libglib-2.0.so.0+0x52445)
20
#2 0x7fe2a505dd92 in g_strdup (/lib64/libglib-2.0.so.0+0x6bd92)
21
#3 0x56344954e6c4 in qmp_object_add /mnt/sdb/qemu-new/qemu_test/qemu/qom/qom-qmp-cmds.c:267
22
#4 0x563449960f5a in do_qmp_dispatch /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qmp-dispatch.c:132
23
#5 0x563449960f5a in qmp_dispatch /mnt/sdb/qemu-new/qemu_test/qemu/qapi/qmp-dispatch.c:175
24
#6 0x563449498a30 in monitor_qmp_dispatch /mnt/sdb/qemu-new/qemu_test/qemu/monitor/qmp.c:145
25
#7 0x56344949a64f in monitor_qmp_bh_dispatcher /mnt/sdb/qemu-new/qemu_test/qemu/monitor/qmp.c:234
26
#8 0x563449a92a3a in aio_bh_call /mnt/sdb/qemu-new/qemu_test/qemu/util/async.c:136
27
28
Fixes: 5f07c4d60d091320186e7b0edaf9ed2cc16b2d1e
29
Reported-by: Euler Robot <euler.robot@huawei.com>
30
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
31
Message-Id: <20200310064640.5059-1-pannengyuan@huawei.com>
32
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
33
Acked-by: Igor Mammedov <imammedo@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
35
---
18
include/block/block.h | 4 ----
36
qom/qom-qmp-cmds.c | 16 ++++++----------
19
block/io.c | 36 ------------------------------------
37
1 file changed, 6 insertions(+), 10 deletions(-)
20
2 files changed, 40 deletions(-)
21
38
22
diff --git a/include/block/block.h b/include/block/block.h
39
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
23
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/block.h
41
--- a/qom/qom-qmp-cmds.c
25
+++ b/include/block/block.h
42
+++ b/qom/qom-qmp-cmds.c
26
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes);
43
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
27
int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov);
44
QDict *pdict;
28
int bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
45
Visitor *v;
29
const void *buf, int count);
46
Object *obj;
30
-int coroutine_fn bdrv_co_readv(BdrvChild *child, int64_t sector_num,
47
- const char *type;
31
- int nb_sectors, QEMUIOVector *qiov);
48
- const char *id;
32
-int coroutine_fn bdrv_co_writev(BdrvChild *child, int64_t sector_num,
49
+ g_autofree char *type = NULL;
33
- int nb_sectors, QEMUIOVector *qiov);
50
+ g_autofree char *id = NULL;
34
/*
51
35
* Efficiently zero a region of the disk image. Note that this is a regular
52
- type = qdict_get_try_str(qdict, "qom-type");
36
* I/O request like read or write and should have a reasonable size. This
53
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
37
diff --git a/block/io.c b/block/io.c
54
if (!type) {
38
index XXXXXXX..XXXXXXX 100644
55
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
39
--- a/block/io.c
56
return;
40
+++ b/block/io.c
57
- } else {
41
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv(BdrvChild *child,
58
- type = g_strdup(type);
42
return ret;
59
- qdict_del(qdict, "qom-type");
43
}
60
}
44
61
+ qdict_del(qdict, "qom-type");
45
-static int coroutine_fn bdrv_co_do_readv(BdrvChild *child,
62
46
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
63
- id = qdict_get_try_str(qdict, "id");
47
- BdrvRequestFlags flags)
64
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
48
-{
65
if (!id) {
49
- if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
66
error_setg(errp, QERR_MISSING_PARAMETER, "id");
50
- return -EINVAL;
67
return;
51
- }
68
- } else {
52
-
69
- id = g_strdup(id);
53
- return bdrv_co_preadv(child, sector_num << BDRV_SECTOR_BITS,
70
- qdict_del(qdict, "id");
54
- nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
71
}
55
-}
72
+ qdict_del(qdict, "id");
56
-
73
57
-int coroutine_fn bdrv_co_readv(BdrvChild *child, int64_t sector_num,
74
props = qdict_get(qdict, "props");
58
- int nb_sectors, QEMUIOVector *qiov)
75
if (props) {
59
-{
60
- return bdrv_co_do_readv(child, sector_num, nb_sectors, qiov, 0);
61
-}
62
-
63
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
64
int64_t offset, int bytes, BdrvRequestFlags flags)
65
{
66
@@ -XXX,XX +XXX,XX @@ out:
67
return ret;
68
}
69
70
-static int coroutine_fn bdrv_co_do_writev(BdrvChild *child,
71
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
72
- BdrvRequestFlags flags)
73
-{
74
- if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
75
- return -EINVAL;
76
- }
77
-
78
- return bdrv_co_pwritev(child, sector_num << BDRV_SECTOR_BITS,
79
- nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
80
-}
81
-
82
-int coroutine_fn bdrv_co_writev(BdrvChild *child, int64_t sector_num,
83
- int nb_sectors, QEMUIOVector *qiov)
84
-{
85
- return bdrv_co_do_writev(child, sector_num, nb_sectors, qiov, 0);
86
-}
87
-
88
int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
89
int bytes, BdrvRequestFlags flags)
90
{
91
--
76
--
92
2.13.6
77
2.20.1
93
78
94
79
diff view generated by jsdifflib
1
bdrv_truncate() is an operation that can block (even for a quite long
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
time, depending on the PreallocMode) in I/O paths that shouldn't block.
2
Message-Id: <20200310113831.27293-2-kwolf@redhat.com>
3
Convert it to a coroutine_fn so that we have the infrastructure for
3
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
4
drivers to make their .bdrv_co_truncate implementation asynchronous.
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
include/block/block_int.h | 3 +++
7
block.c | 6 ++----
8
2 files changed, 5 insertions(+), 4 deletions(-)
5
9
6
This change could potentially introduce new race conditions because
7
bdrv_truncate() isn't necessarily executed atomically any more. Whether
8
this is a problem needs to be evaluated for each block driver that
9
supports truncate:
10
11
* file-posix/win32, gluster, iscsi, nfs, rbd, ssh, sheepdog: The
12
protocol drivers are trivially safe because they don't actually yield
13
yet, so there is no change in behaviour.
14
15
* copy-on-read, crypto, raw-format: Essentially just filter drivers that
16
pass the request to a child node, no problem.
17
18
* qcow2: The implementation modifies metadata, so it needs to hold
19
s->lock to be safe with concurrent I/O requests. In order to avoid
20
double locking, this requires pulling the locking out into
21
preallocate_co() and using qcow2_write_caches() instead of
22
bdrv_flush().
23
24
* qed: Does a single header update, this is fine without locking.
25
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
28
---
29
include/block/block.h | 4 +++
30
include/block/block_int.h | 4 +--
31
block.c | 63 +++++++++++++++++++++++++++++++++++-----
32
block/copy-on-read.c | 8 ++---
33
block/crypto.c | 9 +++---
34
block/file-posix.c | 12 ++++----
35
block/file-win32.c | 6 ++--
36
block/gluster.c | 14 +++++----
37
block/iscsi.c | 8 ++---
38
block/nfs.c | 7 +++--
39
block/qcow2.c | 74 ++++++++++++++++++++++++++++-------------------
40
block/qed.c | 8 +++--
41
block/raw-format.c | 8 ++---
42
block/rbd.c | 8 +++--
43
block/sheepdog.c | 12 ++++----
44
block/ssh.c | 6 ++--
45
16 files changed, 162 insertions(+), 89 deletions(-)
46
47
diff --git a/include/block/block.h b/include/block/block.h
48
index XXXXXXX..XXXXXXX 100644
49
--- a/include/block/block.h
50
+++ b/include/block/block.h
51
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
52
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
53
const char *backing_file);
54
void bdrv_refresh_filename(BlockDriverState *bs);
55
+
56
+int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
57
+ PreallocMode prealloc, Error **errp);
58
int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
59
Error **errp);
60
+
61
int64_t bdrv_nb_sectors(BlockDriverState *bs);
62
int64_t bdrv_getlength(BlockDriverState *bs);
63
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
64
diff --git a/include/block/block_int.h b/include/block/block_int.h
10
diff --git a/include/block/block_int.h b/include/block/block_int.h
65
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
66
--- a/include/block/block_int.h
12
--- a/include/block/block_int.h
67
+++ b/include/block/block_int.h
13
+++ b/include/block/block_int.h
68
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
14
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
69
* bdrv_parse_filename.
15
void *opaque, Error **errp);
70
*/
16
void bdrv_root_unref_child(BdrvChild *child);
71
const char *protocol_name;
17
72
- int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset,
18
+void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
73
- PreallocMode prealloc, Error **errp);
19
+ uint64_t *shared_perm);
74
+ int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
20
+
75
+ PreallocMode prealloc, Error **errp);
21
/**
76
22
* Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use
77
int64_t (*bdrv_getlength)(BlockDriverState *bs);
23
* bdrv_child_refresh_perms() instead and make the parent's
78
bool has_variable_length;
79
diff --git a/block.c b/block.c
24
diff --git a/block.c b/block.c
80
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
81
--- a/block.c
26
--- a/block.c
82
+++ b/block.c
27
+++ b/block.c
83
@@ -XXX,XX +XXX,XX @@ exit:
28
@@ -XXX,XX +XXX,XX @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
84
/**
29
bool *tighten_restrictions, Error **errp);
85
* Truncate file to 'offset' bytes (needed only for file protocols)
30
static void bdrv_child_abort_perm_update(BdrvChild *c);
86
*/
31
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
87
-int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
32
-static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
88
- Error **errp)
33
- uint64_t *shared_perm);
89
+int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
34
90
+ PreallocMode prealloc, Error **errp)
35
typedef struct BlockReopenQueueEntry {
91
{
36
bool prepared;
92
BlockDriverState *bs = child->bs;
37
@@ -XXX,XX +XXX,XX @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms,
93
BlockDriver *drv = bs->drv;
94
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
95
return -EINVAL;
96
}
97
98
- if (!drv->bdrv_truncate) {
99
+ bdrv_inc_in_flight(bs);
100
+
101
+ if (!drv->bdrv_co_truncate) {
102
if (bs->file && drv->is_filter) {
103
- return bdrv_truncate(bs->file, offset, prealloc, errp);
104
+ ret = bdrv_co_truncate(bs->file, offset, prealloc, errp);
105
+ goto out;
106
}
107
error_setg(errp, "Image format driver does not support resize");
108
- return -ENOTSUP;
109
+ ret = -ENOTSUP;
110
+ goto out;
111
}
112
if (bs->read_only) {
113
error_setg(errp, "Image is read-only");
114
- return -EACCES;
115
+ ret = -EACCES;
116
+ goto out;
117
}
118
119
assert(!(bs->open_flags & BDRV_O_INACTIVE));
120
121
- ret = drv->bdrv_truncate(bs, offset, prealloc, errp);
122
+ ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp);
123
if (ret < 0) {
124
- return ret;
125
+ goto out;
126
}
127
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
128
if (ret < 0) {
129
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
130
bdrv_dirty_bitmap_truncate(bs, offset);
131
bdrv_parent_cb_resize(bs);
132
atomic_inc(&bs->write_gen);
133
+
134
+out:
135
+ bdrv_dec_in_flight(bs);
136
return ret;
137
}
138
139
+typedef struct TruncateCo {
140
+ BdrvChild *child;
141
+ int64_t offset;
142
+ PreallocMode prealloc;
143
+ Error **errp;
144
+ int ret;
145
+} TruncateCo;
146
+
147
+static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
148
+{
149
+ TruncateCo *tco = opaque;
150
+ tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc,
151
+ tco->errp);
152
+}
153
+
154
+int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
155
+ Error **errp)
156
+{
157
+ Coroutine *co;
158
+ TruncateCo tco = {
159
+ .child = child,
160
+ .offset = offset,
161
+ .prealloc = prealloc,
162
+ .errp = errp,
163
+ .ret = NOT_DONE,
164
+ };
165
+
166
+ if (qemu_in_coroutine()) {
167
+ /* Fast-path if already in coroutine context */
168
+ bdrv_truncate_co_entry(&tco);
169
+ } else {
170
+ co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco);
171
+ qemu_coroutine_enter(co);
172
+ BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE);
173
+ }
174
+
175
+ return tco.ret;
176
+}
177
+
178
/**
179
* Length of a allocated file in bytes. Sparse files are counted by actual
180
* allocated space. Return < 0 if error or unknown.
181
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
182
index XXXXXXX..XXXXXXX 100644
183
--- a/block/copy-on-read.c
184
+++ b/block/copy-on-read.c
185
@@ -XXX,XX +XXX,XX @@ static int64_t cor_getlength(BlockDriverState *bs)
186
}
187
188
189
-static int cor_truncate(BlockDriverState *bs, int64_t offset,
190
- PreallocMode prealloc, Error **errp)
191
+static int coroutine_fn cor_co_truncate(BlockDriverState *bs, int64_t offset,
192
+ PreallocMode prealloc, Error **errp)
193
{
194
- return bdrv_truncate(bs->file, offset, prealloc, errp);
195
+ return bdrv_co_truncate(bs->file, offset, prealloc, errp);
196
}
197
198
199
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_copy_on_read = {
200
.bdrv_child_perm = cor_child_perm,
201
202
.bdrv_getlength = cor_getlength,
203
- .bdrv_truncate = cor_truncate,
204
+ .bdrv_co_truncate = cor_co_truncate,
205
206
.bdrv_co_preadv = cor_co_preadv,
207
.bdrv_co_pwritev = cor_co_pwritev,
208
diff --git a/block/crypto.c b/block/crypto.c
209
index XXXXXXX..XXXXXXX 100644
210
--- a/block/crypto.c
211
+++ b/block/crypto.c
212
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
213
return ret;
214
}
215
216
-static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
217
- PreallocMode prealloc, Error **errp)
218
+static int coroutine_fn
219
+block_crypto_co_truncate(BlockDriverState *bs, int64_t offset,
220
+ PreallocMode prealloc, Error **errp)
221
{
222
BlockCrypto *crypto = bs->opaque;
223
uint64_t payload_offset =
224
@@ -XXX,XX +XXX,XX @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
225
226
offset += payload_offset;
227
228
- return bdrv_truncate(bs->file, offset, prealloc, errp);
229
+ return bdrv_co_truncate(bs->file, offset, prealloc, errp);
230
}
231
232
static void block_crypto_close(BlockDriverState *bs)
233
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
234
.bdrv_child_perm = bdrv_format_default_perms,
235
.bdrv_co_create = block_crypto_co_create_luks,
236
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
237
- .bdrv_truncate = block_crypto_truncate,
238
+ .bdrv_co_truncate = block_crypto_co_truncate,
239
.create_opts = &block_crypto_create_opts_luks,
240
241
.bdrv_reopen_prepare = block_crypto_reopen_prepare,
242
diff --git a/block/file-posix.c b/block/file-posix.c
243
index XXXXXXX..XXXXXXX 100644
244
--- a/block/file-posix.c
245
+++ b/block/file-posix.c
246
@@ -XXX,XX +XXX,XX @@ out:
247
return result;
248
}
249
250
-static int raw_truncate(BlockDriverState *bs, int64_t offset,
251
- PreallocMode prealloc, Error **errp)
252
+static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
253
+ PreallocMode prealloc, Error **errp)
254
{
255
BDRVRawState *s = bs->opaque;
256
struct stat st;
257
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
258
.bdrv_io_unplug = raw_aio_unplug,
259
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
260
261
- .bdrv_truncate = raw_truncate,
262
+ .bdrv_co_truncate = raw_co_truncate,
263
.bdrv_getlength = raw_getlength,
264
.bdrv_get_info = raw_get_info,
265
.bdrv_get_allocated_file_size
266
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = {
267
.bdrv_io_plug = raw_aio_plug,
268
.bdrv_io_unplug = raw_aio_unplug,
269
270
- .bdrv_truncate = raw_truncate,
271
+ .bdrv_co_truncate = raw_co_truncate,
272
.bdrv_getlength    = raw_getlength,
273
.bdrv_get_info = raw_get_info,
274
.bdrv_get_allocated_file_size
275
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = {
276
.bdrv_io_plug = raw_aio_plug,
277
.bdrv_io_unplug = raw_aio_unplug,
278
279
- .bdrv_truncate = raw_truncate,
280
+ .bdrv_co_truncate = raw_co_truncate,
281
.bdrv_getlength = raw_getlength,
282
.has_variable_length = true,
283
.bdrv_get_allocated_file_size
284
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = {
285
.bdrv_io_plug = raw_aio_plug,
286
.bdrv_io_unplug = raw_aio_unplug,
287
288
- .bdrv_truncate = raw_truncate,
289
+ .bdrv_co_truncate = raw_co_truncate,
290
.bdrv_getlength = raw_getlength,
291
.has_variable_length = true,
292
.bdrv_get_allocated_file_size
293
diff --git a/block/file-win32.c b/block/file-win32.c
294
index XXXXXXX..XXXXXXX 100644
295
--- a/block/file-win32.c
296
+++ b/block/file-win32.c
297
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
298
}
38
}
299
}
39
}
300
40
301
-static int raw_truncate(BlockDriverState *bs, int64_t offset,
41
-static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
302
- PreallocMode prealloc, Error **errp)
42
- uint64_t *shared_perm)
303
+static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
43
+void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
304
+ PreallocMode prealloc, Error **errp)
44
+ uint64_t *shared_perm)
305
{
45
{
306
BDRVRawState *s = bs->opaque;
46
BdrvChild *c;
307
LONG low, high;
47
uint64_t cumulative_perms = 0;
308
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
309
.bdrv_aio_pwritev = raw_aio_pwritev,
310
.bdrv_aio_flush = raw_aio_flush,
311
312
- .bdrv_truncate    = raw_truncate,
313
+ .bdrv_co_truncate = raw_co_truncate,
314
.bdrv_getlength    = raw_getlength,
315
.bdrv_get_allocated_file_size
316
= raw_get_allocated_file_size,
317
diff --git a/block/gluster.c b/block/gluster.c
318
index XXXXXXX..XXXXXXX 100644
319
--- a/block/gluster.c
320
+++ b/block/gluster.c
321
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
322
return acb.ret;
323
}
324
325
-static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
326
- PreallocMode prealloc, Error **errp)
327
+static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
328
+ int64_t offset,
329
+ PreallocMode prealloc,
330
+ Error **errp)
331
{
332
BDRVGlusterState *s = bs->opaque;
333
return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
334
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster = {
335
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
336
.bdrv_getlength = qemu_gluster_getlength,
337
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
338
- .bdrv_truncate = qemu_gluster_truncate,
339
+ .bdrv_co_truncate = qemu_gluster_co_truncate,
340
.bdrv_co_readv = qemu_gluster_co_readv,
341
.bdrv_co_writev = qemu_gluster_co_writev,
342
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
343
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_tcp = {
344
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
345
.bdrv_getlength = qemu_gluster_getlength,
346
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
347
- .bdrv_truncate = qemu_gluster_truncate,
348
+ .bdrv_co_truncate = qemu_gluster_co_truncate,
349
.bdrv_co_readv = qemu_gluster_co_readv,
350
.bdrv_co_writev = qemu_gluster_co_writev,
351
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
352
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_unix = {
353
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
354
.bdrv_getlength = qemu_gluster_getlength,
355
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
356
- .bdrv_truncate = qemu_gluster_truncate,
357
+ .bdrv_co_truncate = qemu_gluster_co_truncate,
358
.bdrv_co_readv = qemu_gluster_co_readv,
359
.bdrv_co_writev = qemu_gluster_co_writev,
360
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
361
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_rdma = {
362
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
363
.bdrv_getlength = qemu_gluster_getlength,
364
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
365
- .bdrv_truncate = qemu_gluster_truncate,
366
+ .bdrv_co_truncate = qemu_gluster_co_truncate,
367
.bdrv_co_readv = qemu_gluster_co_readv,
368
.bdrv_co_writev = qemu_gluster_co_writev,
369
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
370
diff --git a/block/iscsi.c b/block/iscsi.c
371
index XXXXXXX..XXXXXXX 100644
372
--- a/block/iscsi.c
373
+++ b/block/iscsi.c
374
@@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
375
}
376
}
377
378
-static int iscsi_truncate(BlockDriverState *bs, int64_t offset,
379
- PreallocMode prealloc, Error **errp)
380
+static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
381
+ PreallocMode prealloc, Error **errp)
382
{
383
IscsiLun *iscsilun = bs->opaque;
384
Error *local_err = NULL;
385
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = {
386
387
.bdrv_getlength = iscsi_getlength,
388
.bdrv_get_info = iscsi_get_info,
389
- .bdrv_truncate = iscsi_truncate,
390
+ .bdrv_co_truncate = iscsi_co_truncate,
391
.bdrv_refresh_limits = iscsi_refresh_limits,
392
393
.bdrv_co_block_status = iscsi_co_block_status,
394
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iser = {
395
396
.bdrv_getlength = iscsi_getlength,
397
.bdrv_get_info = iscsi_get_info,
398
- .bdrv_truncate = iscsi_truncate,
399
+ .bdrv_co_truncate = iscsi_co_truncate,
400
.bdrv_refresh_limits = iscsi_refresh_limits,
401
402
.bdrv_co_block_status = iscsi_co_block_status,
403
diff --git a/block/nfs.c b/block/nfs.c
404
index XXXXXXX..XXXXXXX 100644
405
--- a/block/nfs.c
406
+++ b/block/nfs.c
407
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
408
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
409
}
410
411
-static int nfs_file_truncate(BlockDriverState *bs, int64_t offset,
412
- PreallocMode prealloc, Error **errp)
413
+static int coroutine_fn
414
+nfs_file_co_truncate(BlockDriverState *bs, int64_t offset,
415
+ PreallocMode prealloc, Error **errp)
416
{
417
NFSClient *client = bs->opaque;
418
int ret;
419
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
420
421
.bdrv_has_zero_init = nfs_has_zero_init,
422
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
423
- .bdrv_truncate = nfs_file_truncate,
424
+ .bdrv_co_truncate = nfs_file_co_truncate,
425
426
.bdrv_file_open = nfs_file_open,
427
.bdrv_close = nfs_file_close,
428
diff --git a/block/qcow2.c b/block/qcow2.c
429
index XXXXXXX..XXXXXXX 100644
430
--- a/block/qcow2.c
431
+++ b/block/qcow2.c
432
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn preallocate_co(void *opaque)
433
BlockDriverState *bs = params->bs;
434
uint64_t offset = params->offset;
435
uint64_t new_length = params->new_length;
436
- BDRVQcow2State *s = bs->opaque;
437
uint64_t bytes;
438
uint64_t host_offset = 0;
439
unsigned int cur_bytes;
440
int ret;
441
QCowL2Meta *meta;
442
443
- qemu_co_mutex_lock(&s->lock);
444
-
445
assert(offset <= new_length);
446
bytes = new_length - offset;
447
448
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn preallocate_co(void *opaque)
449
ret = 0;
450
451
done:
452
- qemu_co_mutex_unlock(&s->lock);
453
params->ret = ret;
454
}
455
456
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
457
458
/* And if we're supposed to preallocate metadata, do that now */
459
if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) {
460
+ BDRVQcow2State *s = blk_bs(blk)->opaque;
461
+ qemu_co_mutex_lock(&s->lock);
462
ret = preallocate(blk_bs(blk), 0, qcow2_opts->size);
463
+ qemu_co_mutex_unlock(&s->lock);
464
+
465
if (ret < 0) {
466
error_setg_errno(errp, -ret, "Could not preallocate metadata");
467
goto out;
468
@@ -XXX,XX +XXX,XX @@ fail:
469
return ret;
470
}
471
472
-static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
473
- PreallocMode prealloc, Error **errp)
474
+static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
475
+ PreallocMode prealloc, Error **errp)
476
{
477
BDRVQcow2State *s = bs->opaque;
478
uint64_t old_length;
479
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
480
return -EINVAL;
481
}
482
483
+ qemu_co_mutex_lock(&s->lock);
484
+
485
/* cannot proceed if image has snapshots */
486
if (s->nb_snapshots) {
487
error_setg(errp, "Can't resize an image which has snapshots");
488
- return -ENOTSUP;
489
+ ret = -ENOTSUP;
490
+ goto fail;
491
}
492
493
/* cannot proceed if image has bitmaps */
494
if (s->nb_bitmaps) {
495
/* TODO: resize bitmaps in the image */
496
error_setg(errp, "Can't resize an image which has bitmaps");
497
- return -ENOTSUP;
498
+ ret = -ENOTSUP;
499
+ goto fail;
500
}
501
502
old_length = bs->total_sectors * 512;
503
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
504
if (prealloc != PREALLOC_MODE_OFF) {
505
error_setg(errp,
506
"Preallocation can't be used for shrinking an image");
507
- return -EINVAL;
508
+ ret = -EINVAL;
509
+ goto fail;
510
}
511
512
ret = qcow2_cluster_discard(bs, ROUND_UP(offset, s->cluster_size),
513
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
514
QCOW2_DISCARD_ALWAYS, true);
515
if (ret < 0) {
516
error_setg_errno(errp, -ret, "Failed to discard cropped clusters");
517
- return ret;
518
+ goto fail;
519
}
520
521
ret = qcow2_shrink_l1_table(bs, new_l1_size);
522
if (ret < 0) {
523
error_setg_errno(errp, -ret,
524
"Failed to reduce the number of L2 tables");
525
- return ret;
526
+ goto fail;
527
}
528
529
ret = qcow2_shrink_reftable(bs);
530
if (ret < 0) {
531
error_setg_errno(errp, -ret,
532
"Failed to discard unused refblocks");
533
- return ret;
534
+ goto fail;
535
}
536
537
old_file_size = bdrv_getlength(bs->file->bs);
538
if (old_file_size < 0) {
539
error_setg_errno(errp, -old_file_size,
540
"Failed to inquire current file length");
541
- return old_file_size;
542
+ ret = old_file_size;
543
+ goto fail;
544
}
545
last_cluster = qcow2_get_last_cluster(bs, old_file_size);
546
if (last_cluster < 0) {
547
error_setg_errno(errp, -last_cluster,
548
"Failed to find the last cluster");
549
- return last_cluster;
550
+ ret = last_cluster;
551
+ goto fail;
552
}
553
if ((last_cluster + 1) * s->cluster_size < old_file_size) {
554
Error *local_err = NULL;
555
556
- bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
557
- PREALLOC_MODE_OFF, &local_err);
558
+ bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
559
+ PREALLOC_MODE_OFF, &local_err);
560
if (local_err) {
561
warn_reportf_err(local_err,
562
"Failed to truncate the tail of the image: ");
563
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
564
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
565
if (ret < 0) {
566
error_setg_errno(errp, -ret, "Failed to grow the L1 table");
567
- return ret;
568
+ goto fail;
569
}
570
}
571
572
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
573
ret = preallocate(bs, old_length, offset);
574
if (ret < 0) {
575
error_setg_errno(errp, -ret, "Preallocation failed");
576
- return ret;
577
+ goto fail;
578
}
579
break;
580
581
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
582
if (old_file_size < 0) {
583
error_setg_errno(errp, -old_file_size,
584
"Failed to inquire current file length");
585
- return old_file_size;
586
+ ret = old_file_size;
587
+ goto fail;
588
}
589
old_file_size = ROUND_UP(old_file_size, s->cluster_size);
590
591
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
592
if (allocation_start < 0) {
593
error_setg_errno(errp, -allocation_start,
594
"Failed to resize refcount structures");
595
- return allocation_start;
596
+ ret = allocation_start;
597
+ goto fail;
598
}
599
600
clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start,
601
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
602
if (clusters_allocated < 0) {
603
error_setg_errno(errp, -clusters_allocated,
604
"Failed to allocate data clusters");
605
- return clusters_allocated;
606
+ ret = clusters_allocated;
607
+ goto fail;
608
}
609
610
assert(clusters_allocated == nb_new_data_clusters);
611
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
612
/* Allocate the data area */
613
new_file_size = allocation_start +
614
nb_new_data_clusters * s->cluster_size;
615
- ret = bdrv_truncate(bs->file, new_file_size, prealloc, errp);
616
+ ret = bdrv_co_truncate(bs->file, new_file_size, prealloc, errp);
617
if (ret < 0) {
618
error_prepend(errp, "Failed to resize underlying file: ");
619
qcow2_free_clusters(bs, allocation_start,
620
nb_new_data_clusters * s->cluster_size,
621
QCOW2_DISCARD_OTHER);
622
- return ret;
623
+ goto fail;
624
}
625
626
/* Create the necessary L2 entries */
627
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
628
qcow2_free_clusters(bs, host_offset,
629
nb_new_data_clusters * s->cluster_size,
630
QCOW2_DISCARD_OTHER);
631
- return ret;
632
+ goto fail;
633
}
634
635
guest_offset += nb_clusters * s->cluster_size;
636
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
637
638
if (prealloc != PREALLOC_MODE_OFF) {
639
/* Flush metadata before actually changing the image size */
640
- ret = bdrv_flush(bs);
641
+ ret = qcow2_write_caches(bs);
642
if (ret < 0) {
643
error_setg_errno(errp, -ret,
644
"Failed to flush the preallocated area to disk");
645
- return ret;
646
+ goto fail;
647
}
648
}
649
650
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
651
&offset, sizeof(uint64_t));
652
if (ret < 0) {
653
error_setg_errno(errp, -ret, "Failed to update the image size");
654
- return ret;
655
+ goto fail;
656
}
657
658
s->l1_vm_state_index = new_l1_size;
659
- return 0;
660
+ ret = 0;
661
+fail:
662
+ qemu_co_mutex_unlock(&s->lock);
663
+ return ret;
664
}
665
666
/* XXX: put compressed sectors first, then all the cluster aligned
667
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
668
if (cluster_offset < 0) {
669
return cluster_offset;
670
}
671
- return bdrv_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, NULL);
672
+ return bdrv_co_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF,
673
+ NULL);
674
}
675
676
if (offset_into_cluster(s, offset)) {
677
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
678
.bdrv_co_pdiscard = qcow2_co_pdiscard,
679
.bdrv_co_copy_range_from = qcow2_co_copy_range_from,
680
.bdrv_co_copy_range_to = qcow2_co_copy_range_to,
681
- .bdrv_truncate = qcow2_truncate,
682
+ .bdrv_co_truncate = qcow2_co_truncate,
683
.bdrv_co_pwritev_compressed = qcow2_co_pwritev_compressed,
684
.bdrv_make_empty = qcow2_make_empty,
685
686
diff --git a/block/qed.c b/block/qed.c
687
index XXXXXXX..XXXXXXX 100644
688
--- a/block/qed.c
689
+++ b/block/qed.c
690
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
691
QED_AIOCB_WRITE | QED_AIOCB_ZERO);
692
}
693
694
-static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset,
695
- PreallocMode prealloc, Error **errp)
696
+static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
697
+ int64_t offset,
698
+ PreallocMode prealloc,
699
+ Error **errp)
700
{
701
BDRVQEDState *s = bs->opaque;
702
uint64_t old_image_size;
703
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
704
.bdrv_co_readv = bdrv_qed_co_readv,
705
.bdrv_co_writev = bdrv_qed_co_writev,
706
.bdrv_co_pwrite_zeroes = bdrv_qed_co_pwrite_zeroes,
707
- .bdrv_truncate = bdrv_qed_truncate,
708
+ .bdrv_co_truncate = bdrv_qed_co_truncate,
709
.bdrv_getlength = bdrv_qed_getlength,
710
.bdrv_get_info = bdrv_qed_get_info,
711
.bdrv_refresh_limits = bdrv_qed_refresh_limits,
712
diff --git a/block/raw-format.c b/block/raw-format.c
713
index XXXXXXX..XXXXXXX 100644
714
--- a/block/raw-format.c
715
+++ b/block/raw-format.c
716
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
717
}
718
}
719
720
-static int raw_truncate(BlockDriverState *bs, int64_t offset,
721
- PreallocMode prealloc, Error **errp)
722
+static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
723
+ PreallocMode prealloc, Error **errp)
724
{
725
BDRVRawState *s = bs->opaque;
726
727
@@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset,
728
729
s->size = offset;
730
offset += s->offset;
731
- return bdrv_truncate(bs->file, offset, prealloc, errp);
732
+ return bdrv_co_truncate(bs->file, offset, prealloc, errp);
733
}
734
735
static void raw_eject(BlockDriverState *bs, bool eject_flag)
736
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
737
.bdrv_co_block_status = &raw_co_block_status,
738
.bdrv_co_copy_range_from = &raw_co_copy_range_from,
739
.bdrv_co_copy_range_to = &raw_co_copy_range_to,
740
- .bdrv_truncate = &raw_truncate,
741
+ .bdrv_co_truncate = &raw_co_truncate,
742
.bdrv_getlength = &raw_getlength,
743
.has_variable_length = true,
744
.bdrv_measure = &raw_measure,
745
diff --git a/block/rbd.c b/block/rbd.c
746
index XXXXXXX..XXXXXXX 100644
747
--- a/block/rbd.c
748
+++ b/block/rbd.c
749
@@ -XXX,XX +XXX,XX @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs)
750
return info.size;
751
}
752
753
-static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset,
754
- PreallocMode prealloc, Error **errp)
755
+static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
756
+ int64_t offset,
757
+ PreallocMode prealloc,
758
+ Error **errp)
759
{
760
BDRVRBDState *s = bs->opaque;
761
int r;
762
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
763
.bdrv_get_info = qemu_rbd_getinfo,
764
.create_opts = &qemu_rbd_create_opts,
765
.bdrv_getlength = qemu_rbd_getlength,
766
- .bdrv_truncate = qemu_rbd_truncate,
767
+ .bdrv_co_truncate = qemu_rbd_co_truncate,
768
.protocol_name = "rbd",
769
770
.bdrv_aio_preadv = qemu_rbd_aio_preadv,
771
diff --git a/block/sheepdog.c b/block/sheepdog.c
772
index XXXXXXX..XXXXXXX 100644
773
--- a/block/sheepdog.c
774
+++ b/block/sheepdog.c
775
@@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs)
776
return s->inode.vdi_size;
777
}
778
779
-static int sd_truncate(BlockDriverState *bs, int64_t offset,
780
- PreallocMode prealloc, Error **errp)
781
+static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
782
+ PreallocMode prealloc, Error **errp)
783
{
784
BDRVSheepdogState *s = bs->opaque;
785
int ret, fd;
786
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
787
788
assert(!flags);
789
if (offset > s->inode.vdi_size) {
790
- ret = sd_truncate(bs, offset, PREALLOC_MODE_OFF, NULL);
791
+ ret = sd_co_truncate(bs, offset, PREALLOC_MODE_OFF, NULL);
792
if (ret < 0) {
793
return ret;
794
}
795
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog = {
796
.bdrv_has_zero_init = bdrv_has_zero_init_1,
797
.bdrv_getlength = sd_getlength,
798
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
799
- .bdrv_truncate = sd_truncate,
800
+ .bdrv_co_truncate = sd_co_truncate,
801
802
.bdrv_co_readv = sd_co_readv,
803
.bdrv_co_writev = sd_co_writev,
804
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_tcp = {
805
.bdrv_has_zero_init = bdrv_has_zero_init_1,
806
.bdrv_getlength = sd_getlength,
807
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
808
- .bdrv_truncate = sd_truncate,
809
+ .bdrv_co_truncate = sd_co_truncate,
810
811
.bdrv_co_readv = sd_co_readv,
812
.bdrv_co_writev = sd_co_writev,
813
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_unix = {
814
.bdrv_has_zero_init = bdrv_has_zero_init_1,
815
.bdrv_getlength = sd_getlength,
816
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
817
- .bdrv_truncate = sd_truncate,
818
+ .bdrv_co_truncate = sd_co_truncate,
819
820
.bdrv_co_readv = sd_co_readv,
821
.bdrv_co_writev = sd_co_writev,
822
diff --git a/block/ssh.c b/block/ssh.c
823
index XXXXXXX..XXXXXXX 100644
824
--- a/block/ssh.c
825
+++ b/block/ssh.c
826
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
827
return length;
828
}
829
830
-static int ssh_truncate(BlockDriverState *bs, int64_t offset,
831
- PreallocMode prealloc, Error **errp)
832
+static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
833
+ PreallocMode prealloc, Error **errp)
834
{
835
BDRVSSHState *s = bs->opaque;
836
837
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ssh = {
838
.bdrv_co_readv = ssh_co_readv,
839
.bdrv_co_writev = ssh_co_writev,
840
.bdrv_getlength = ssh_getlength,
841
- .bdrv_truncate = ssh_truncate,
842
+ .bdrv_co_truncate = ssh_co_truncate,
843
.bdrv_co_flush_to_disk = ssh_co_flush,
844
.create_opts = &ssh_create_opts,
845
};
846
--
48
--
847
2.13.6
49
2.20.1
848
50
849
51
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
blockdev-snapshot returned an error if the overlay was already in use,
2
which it defined as having any BlockBackend parent. This is in fact both
3
too strict (some parents can tolerate the change of visible data caused
4
by attaching a backing file) and too loose (some non-BlockBackend
5
parents may not be happy with it).
2
6
3
We are gradually moving away from sector-based interfaces, towards
7
One important use case that is prevented by the too strict check is live
4
byte-based. Make the change for the last few sector-based calls
8
storage migration with blockdev-mirror. Here, the target node is
5
into the block layer from the replication driver.
9
usually opened without a backing file so that the active layer is
10
mirrored while its backing chain can be copied in the background.
6
11
7
Ideally, the replication driver should switch to doing everything
12
The backing chain should be attached to the mirror target node when
8
byte-based, but that's a more invasive change that requires a
13
finalising the job, just before switching the users of the source node
9
bit more auditing.
14
to the new copy (at which point the mirror job still has a reference to
15
the node). drive-mirror did this automatically, but with blockdev-mirror
16
this is the job of the QMP client, so it needs a way to do this.
10
17
11
Signed-off-by: Eric Blake <eblake@redhat.com>
18
blockdev-snapshot is the obvious way, so this patch makes it work in
12
Reviewed-by: Jeff Cody <jcody@redhat.com>
19
this scenario. The new condition is that no parent uses CONSISTENT_READ
20
permissions. This will ensure that the operation will still be blocked
21
when the node is attached to the guest device, so blockdev-snapshot
22
remains safe.
23
24
(For the sake of completeness, x-blockdev-reopen can be used to achieve
25
the same, however it is a big hammer, performs the graph change
26
completely unchecked and is still experimental. So even with the option
27
of using x-blockdev-reopen, there are reasons why blockdev-snapshot
28
should be able to perform this operation.)
29
30
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Message-Id: <20200310113831.27293-3-kwolf@redhat.com>
32
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
33
Tested-by: Peter Krempa <pkrempa@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
35
---
15
block/replication.c | 14 ++++++++------
36
blockdev.c | 14 ++++++++------
16
1 file changed, 8 insertions(+), 6 deletions(-)
37
tests/qemu-iotests/085.out | 4 ++--
38
2 files changed, 10 insertions(+), 8 deletions(-)
17
39
18
diff --git a/block/replication.c b/block/replication.c
40
diff --git a/blockdev.c b/blockdev.c
19
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
20
--- a/block/replication.c
42
--- a/blockdev.c
21
+++ b/block/replication.c
43
+++ b/blockdev.c
22
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_readv(BlockDriverState *bs,
44
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
23
backup_cow_request_begin(&req, child->bs->job,
45
TransactionAction *action = common->action;
24
sector_num * BDRV_SECTOR_SIZE,
46
AioContext *aio_context;
25
remaining_bytes);
47
AioContext *old_context;
26
- ret = bdrv_co_readv(bs->file, sector_num, remaining_sectors,
48
+ uint64_t perm, shared;
27
- qiov);
49
int ret;
28
+ ret = bdrv_co_preadv(bs->file, sector_num * BDRV_SECTOR_SIZE,
50
29
+ remaining_bytes, qiov, 0);
51
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
30
backup_cow_request_end(&req);
52
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
31
goto out;
53
goto out;
32
}
54
}
33
55
34
- ret = bdrv_co_readv(bs->file, sector_num, remaining_sectors, qiov);
56
- if (bdrv_has_blk(state->new_bs)) {
35
+ ret = bdrv_co_preadv(bs->file, sector_num * BDRV_SECTOR_SIZE,
57
+ /*
36
+ remaining_sectors * BDRV_SECTOR_SIZE, qiov, 0);
58
+ * Allow attaching a backing file to an overlay that's already in use only
37
out:
59
+ * if the parents don't assume that they are already seeing a valid image.
38
return replication_return_value(s, ret);
60
+ * (Specifically, allow it as a mirror target, which is write-only access.)
39
}
61
+ */
40
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_writev(BlockDriverState *bs,
62
+ bdrv_get_cumulative_perm(state->new_bs, &perm, &shared);
63
+ if (perm & BLK_PERM_CONSISTENT_READ) {
64
error_setg(errp, "The overlay is already in use");
65
goto out;
41
}
66
}
42
67
43
if (ret == 0) {
68
- if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
44
- ret = bdrv_co_writev(top, sector_num,
69
- errp)) {
45
- remaining_sectors, qiov);
70
- goto out;
46
+ ret = bdrv_co_pwritev(top, sector_num * BDRV_SECTOR_SIZE,
71
- }
47
+ remaining_sectors * BDRV_SECTOR_SIZE, qiov, 0);
72
-
48
return replication_return_value(s, ret);
73
if (state->new_bs->backing != NULL) {
49
}
74
error_setg(errp, "The overlay already has a backing image");
50
75
goto out;
51
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_writev(BlockDriverState *bs,
76
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
52
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, count);
77
index XXXXXXX..XXXXXXX 100644
53
78
--- a/tests/qemu-iotests/085.out
54
target = ret ? top : base;
79
+++ b/tests/qemu-iotests/085.out
55
- ret = bdrv_co_writev(target, sector_num, n, &hd_qiov);
80
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_f
56
+ ret = bdrv_co_pwritev(target, sector_num * BDRV_SECTOR_SIZE,
81
=== Invalid command - cannot create a snapshot using a file BDS ===
57
+ n * BDRV_SECTOR_SIZE, &hd_qiov, 0);
82
58
if (ret < 0) {
83
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node':'virtio0', 'overlay':'file_12' } }
59
goto out1;
84
-{"error": {"class": "GenericError", "desc": "The overlay does not support backing images"}}
60
}
85
+{"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
86
87
=== Invalid command - snapshot node used as active layer ===
88
89
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_f
90
=== Invalid command - snapshot node used as backing hd ===
91
92
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_11' } }
93
-{"error": {"class": "GenericError", "desc": "Node 'snap_11' is busy: node is used as backing hd of 'snap_12'"}}
94
+{"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
95
96
=== Invalid command - snapshot node has a backing image ===
97
61
--
98
--
62
2.13.6
99
2.20.1
63
100
64
101
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
The 'job-complete' QMP command should be run with qmp() rather than
2
qmp_log() if use_log=False is passed.
2
3
3
We are gradually moving away from sector-based interfaces, towards
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
byte-based. Make the change for the last few sector-based calls
5
Message-Id: <20200310113831.27293-4-kwolf@redhat.com>
5
into the block layer from the vhdx driver.
6
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
6
7
Ideally, the vhdx driver should switch to doing everything
8
byte-based, but that's a more invasive change that requires a
9
bit more auditing.
10
11
Signed-off-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Jeff Cody <jcody@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
8
---
15
block/vhdx.c | 12 ++++++------
9
tests/qemu-iotests/iotests.py | 5 ++++-
16
1 file changed, 6 insertions(+), 6 deletions(-)
10
1 file changed, 4 insertions(+), 1 deletion(-)
17
11
18
diff --git a/block/vhdx.c b/block/vhdx.c
12
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
19
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
20
--- a/block/vhdx.c
14
--- a/tests/qemu-iotests/iotests.py
21
+++ b/block/vhdx.c
15
+++ b/tests/qemu-iotests/iotests.py
22
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
16
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
23
break;
17
if use_log:
24
case PAYLOAD_BLOCK_FULLY_PRESENT:
18
log('Job failed: %s' % (j['error']))
25
qemu_co_mutex_unlock(&s->lock);
19
elif status == 'ready':
26
- ret = bdrv_co_readv(bs->file,
20
- self.qmp_log('job-complete', id=job)
27
- sinfo.file_offset >> BDRV_SECTOR_BITS,
21
+ if use_log:
28
- sinfo.sectors_avail, &hd_qiov);
22
+ self.qmp_log('job-complete', id=job)
29
+ ret = bdrv_co_preadv(bs->file, sinfo.file_offset,
23
+ else:
30
+ sinfo.sectors_avail * BDRV_SECTOR_SIZE,
24
+ self.qmp('job-complete', id=job)
31
+ &hd_qiov, 0);
25
elif status == 'pending' and not auto_finalize:
32
qemu_co_mutex_lock(&s->lock);
26
if pre_finalize:
33
if (ret < 0) {
27
pre_finalize()
34
goto exit;
35
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
36
}
37
/* block exists, so we can just overwrite it */
38
qemu_co_mutex_unlock(&s->lock);
39
- ret = bdrv_co_writev(bs->file,
40
- sinfo.file_offset >> BDRV_SECTOR_BITS,
41
- sectors_to_write, &hd_qiov);
42
+ ret = bdrv_co_pwritev(bs->file, sinfo.file_offset,
43
+ sectors_to_write * BDRV_SECTOR_SIZE,
44
+ &hd_qiov, 0);
45
qemu_co_mutex_lock(&s->lock);
46
if (ret < 0) {
47
goto error_bat_restore;
48
--
28
--
49
2.13.6
29
2.20.1
50
30
51
31
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
The newly tested scenario is a common live storage migration scenario:
2
The target node is opened without a backing file so that the active
3
layer is mirrored while its backing chain can be copied in the
4
background.
2
5
3
We are gradually moving away from sector-based interfaces, towards
6
The backing chain should be attached to the mirror target node when
4
byte-based. The qcow driver is now ready to fully utilize the
7
finalising the job, just before switching the users of the source node
5
byte-based callback interface, as long as we override the default
8
to the new copy (at which point the mirror job still has a reference to
6
alignment to still be 512 (needed at least for asserts present
9
the node). drive-mirror did this automatically, but with blockdev-mirror
7
because of encryption, but easier to do everywhere than to audit
10
this is the job of the QMP client.
8
which sub-sector requests are handled correctly, especially since
9
we no longer recommend qcow for new disk images).
10
11
11
Signed-off-by: Eric Blake <eblake@redhat.com>
12
This patch adds test cases for two ways to achieve the desired result,
12
Reviewed-by: Jeff Cody <jcody@redhat.com>
13
using either x-blockdev-reopen or blockdev-snapshot.
14
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Message-Id: <20200310113831.27293-5-kwolf@redhat.com>
17
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
19
---
15
block/qcow.c | 35 ++++++++++++++++++++---------------
20
tests/qemu-iotests/155 | 56 ++++++++++++++++++++++++++++++++++----
16
1 file changed, 20 insertions(+), 15 deletions(-)
21
tests/qemu-iotests/155.out | 4 +--
22
2 files changed, 53 insertions(+), 7 deletions(-)
17
23
18
diff --git a/block/qcow.c b/block/qcow.c
24
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
25
index XXXXXXX..XXXXXXX 100755
26
--- a/tests/qemu-iotests/155
27
+++ b/tests/qemu-iotests/155
28
@@ -XXX,XX +XXX,XX @@ target_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt)
29
# image during runtime, only makes sense if
30
# target_blockdev_backing is not None
31
# (None: same as target_backing)
32
+# target_open_with_backing: If True, the target image is added with its backing
33
+# chain opened right away. If False, blockdev-add
34
+# opens it without a backing file and job completion
35
+# is supposed to open the backing chain.
36
37
class BaseClass(iotests.QMPTestCase):
38
target_blockdev_backing = None
39
target_real_backing = None
40
+ target_open_with_backing = True
41
42
def setUp(self):
43
qemu_img('create', '-f', iotests.imgfmt, back0_img, '1440K')
44
@@ -XXX,XX +XXX,XX @@ class BaseClass(iotests.QMPTestCase):
45
options = { 'node-name': 'target',
46
'driver': iotests.imgfmt,
47
'file': { 'driver': 'file',
48
+ 'node-name': 'target-file',
49
'filename': target_img } }
50
- if self.target_blockdev_backing:
51
- options['backing'] = self.target_blockdev_backing
52
+
53
+ if not self.target_open_with_backing:
54
+ options['backing'] = None
55
+ elif self.target_blockdev_backing:
56
+ options['backing'] = self.target_blockdev_backing
57
58
result = self.vm.qmp('blockdev-add', **options)
59
self.assert_qmp(result, 'return', {})
60
@@ -XXX,XX +XXX,XX @@ class BaseClass(iotests.QMPTestCase):
61
# cmd: Mirroring command to execute, either drive-mirror or blockdev-mirror
62
63
class MirrorBaseClass(BaseClass):
64
+ def openBacking(self):
65
+ pass
66
+
67
def runMirror(self, sync):
68
if self.cmd == 'blockdev-mirror':
69
result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source',
70
- sync=sync, target='target')
71
+ sync=sync, target='target',
72
+ auto_finalize=False)
73
else:
74
if self.existing:
75
mode = 'existing'
76
@@ -XXX,XX +XXX,XX @@ class MirrorBaseClass(BaseClass):
77
result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source',
78
sync=sync, target=target_img,
79
format=iotests.imgfmt, mode=mode,
80
- node_name='target')
81
+ node_name='target', auto_finalize=False)
82
83
self.assert_qmp(result, 'return', {})
84
85
- self.complete_and_wait('mirror-job')
86
+ self.vm.run_job('mirror-job', use_log=False, auto_finalize=False,
87
+ pre_finalize=self.openBacking, auto_dismiss=True)
88
89
def testFull(self):
90
self.runMirror('full')
91
@@ -XXX,XX +XXX,XX @@ class TestBlockdevMirrorForcedBacking(MirrorBaseClass):
92
target_blockdev_backing = { 'driver': 'null-co' }
93
target_real_backing = 'null-co://'
94
95
+# Attach the backing chain only during completion, with blockdev-reopen
96
+class TestBlockdevMirrorReopen(MirrorBaseClass):
97
+ cmd = 'blockdev-mirror'
98
+ existing = True
99
+ target_backing = 'null-co://'
100
+ target_open_with_backing = False
101
+
102
+ def openBacking(self):
103
+ if not self.target_open_with_backing:
104
+ result = self.vm.qmp('blockdev-add', node_name="backing",
105
+ driver="null-co")
106
+ self.assert_qmp(result, 'return', {})
107
+ result = self.vm.qmp('x-blockdev-reopen', node_name="target",
108
+ driver=iotests.imgfmt, file="target-file",
109
+ backing="backing")
110
+ self.assert_qmp(result, 'return', {})
111
+
112
+# Attach the backing chain only during completion, with blockdev-snapshot
113
+class TestBlockdevMirrorSnapshot(MirrorBaseClass):
114
+ cmd = 'blockdev-mirror'
115
+ existing = True
116
+ target_backing = 'null-co://'
117
+ target_open_with_backing = False
118
+
119
+ def openBacking(self):
120
+ if not self.target_open_with_backing:
121
+ result = self.vm.qmp('blockdev-add', node_name="backing",
122
+ driver="null-co")
123
+ self.assert_qmp(result, 'return', {})
124
+ result = self.vm.qmp('blockdev-snapshot', node="backing",
125
+ overlay="target")
126
+ self.assert_qmp(result, 'return', {})
127
128
class TestCommit(BaseClass):
129
existing = False
130
diff --git a/tests/qemu-iotests/155.out b/tests/qemu-iotests/155.out
19
index XXXXXXX..XXXXXXX 100644
131
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow.c
132
--- a/tests/qemu-iotests/155.out
21
+++ b/block/qcow.c
133
+++ b/tests/qemu-iotests/155.out
22
@@ -XXX,XX +XXX,XX @@ typedef struct QCowHeader {
134
@@ -XXX,XX +XXX,XX @@
23
typedef struct BDRVQcowState {
135
-...................
24
int cluster_bits;
136
+.........................
25
int cluster_size;
137
----------------------------------------------------------------------
26
- int cluster_sectors;
138
-Ran 19 tests
27
int l2_bits;
139
+Ran 25 tests
28
int l2_size;
140
29
unsigned int l1_size;
141
OK
30
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
31
}
32
s->cluster_bits = header.cluster_bits;
33
s->cluster_size = 1 << s->cluster_bits;
34
- s->cluster_sectors = 1 << (s->cluster_bits - 9);
35
s->l2_bits = header.l2_bits;
36
s->l2_size = 1 << s->l2_bits;
37
bs->total_sectors = header.size / 512;
38
@@ -XXX,XX +XXX,XX @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
39
return 0;
40
}
41
42
-static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
43
- int nb_sectors, QEMUIOVector *qiov)
44
+static void qcow_refresh_limits(BlockDriverState *bs, Error **errp)
45
+{
46
+ /* At least encrypted images require 512-byte alignment. Apply the
47
+ * limit universally, rather than just on encrypted images, as
48
+ * it's easier to let the block layer handle rounding than to
49
+ * audit this code further. */
50
+ bs->bl.request_alignment = BDRV_SECTOR_SIZE;
51
+}
52
+
53
+static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset,
54
+ uint64_t bytes, QEMUIOVector *qiov,
55
+ int flags)
56
{
57
BDRVQcowState *s = bs->opaque;
58
int offset_in_cluster;
59
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
60
QEMUIOVector hd_qiov;
61
uint8_t *buf;
62
void *orig_buf;
63
- int64_t offset = sector_num * BDRV_SECTOR_SIZE;
64
- int64_t bytes = nb_sectors * BDRV_SECTOR_SIZE;
65
66
+ assert(!flags);
67
if (qiov->niov > 1) {
68
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
69
if (buf == NULL) {
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
71
return ret;
72
}
73
74
-static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
75
- int nb_sectors, QEMUIOVector *qiov,
76
- int flags)
77
+static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, uint64_t offset,
78
+ uint64_t bytes, QEMUIOVector *qiov,
79
+ int flags)
80
{
81
BDRVQcowState *s = bs->opaque;
82
int offset_in_cluster;
83
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
84
QEMUIOVector hd_qiov;
85
uint8_t *buf;
86
void *orig_buf;
87
- int64_t offset = sector_num * BDRV_SECTOR_SIZE;
88
- int64_t bytes = nb_sectors * BDRV_SECTOR_SIZE;
89
90
assert(!flags);
91
s->cluster_cache_offset = -1; /* disable compressed cache */
92
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
93
94
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
95
/* could not compress: write normal cluster */
96
- ret = qcow_co_writev(bs, offset >> BDRV_SECTOR_BITS,
97
- bytes >> BDRV_SECTOR_BITS, qiov, 0);
98
+ ret = qcow_co_pwritev(bs, offset, bytes, qiov, 0);
99
if (ret < 0) {
100
goto fail;
101
}
102
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qcow = {
103
.bdrv_co_create_opts = qcow_co_create_opts,
104
.bdrv_has_zero_init = bdrv_has_zero_init_1,
105
.supports_backing = true,
106
+ .bdrv_refresh_limits = qcow_refresh_limits,
107
108
- .bdrv_co_readv = qcow_co_readv,
109
- .bdrv_co_writev = qcow_co_writev,
110
+ .bdrv_co_preadv = qcow_co_preadv,
111
+ .bdrv_co_pwritev = qcow_co_pwritev,
112
.bdrv_co_block_status = qcow_co_block_status,
113
114
.bdrv_make_empty = qcow_make_empty,
115
--
142
--
116
2.13.6
143
2.20.1
117
144
118
145
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
external_snapshot_prepare() tries to move the overlay to the AioContext
2
of the backing file (the snapshotted node). However, it's possible that
3
this doesn't work, but the backing file can instead be moved to the
4
overlay's AioContext (e.g. opening the backing chain for a mirror
5
target).
2
6
3
block_crypto_open_opts_init() and block_crypto_create_opts_init()
7
bdrv_append() already indirectly uses bdrv_attach_node(), which takes
4
contain a virtual visit of QCryptoBlockOptions and
8
care to move nodes to make sure they use the same AioContext and which
5
QCryptoBlockCreateOptions less member "format", respectively.
9
tries both directions.
6
10
7
Change their callers to put member "format" in the QDict, so they can
11
So the problem has a simple fix: Just delete the unnecessary extra
8
use the generated visitors for these types instead.
12
bdrv_try_set_aio_context() call in external_snapshot_prepare() and
13
instead assert in bdrv_append() that both nodes were indeed moved to the
14
same AioContext.
9
15
10
Signed-off-by: Markus Armbruster <armbru@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Message-Id: <20200310113831.27293-6-kwolf@redhat.com>
18
Tested-by: Peter Krempa <pkrempa@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
20
---
14
block/crypto.h | 8 ++---
21
block.c | 1 +
15
block/crypto.c | 99 +++++++++-------------------------------------------------
22
blockdev.c | 16 ----------------
16
block/qcow.c | 5 ++-
23
2 files changed, 1 insertion(+), 16 deletions(-)
17
block/qcow2.c | 10 +++---
18
4 files changed, 22 insertions(+), 100 deletions(-)
19
24
20
diff --git a/block/crypto.h b/block/crypto.h
25
diff --git a/block.c b/block.c
21
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
22
--- a/block/crypto.h
27
--- a/block.c
23
+++ b/block/crypto.h
28
+++ b/block.c
24
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
30
bdrv_ref(from);
31
32
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
33
+ assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
34
bdrv_drained_begin(from);
35
36
/* Put all parents into @list and calculate their cumulative permissions */
37
diff --git a/blockdev.c b/blockdev.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/blockdev.c
40
+++ b/blockdev.c
41
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
42
DO_UPCAST(ExternalSnapshotState, common, common);
43
TransactionAction *action = common->action;
44
AioContext *aio_context;
45
- AioContext *old_context;
46
uint64_t perm, shared;
47
- int ret;
48
49
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
50
* purpose but a different set of parameters */
51
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
52
goto out;
25
}
53
}
26
54
27
QCryptoBlockCreateOptions *
55
- /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
28
-block_crypto_create_opts_init(QCryptoBlockFormat format,
56
- old_context = bdrv_get_aio_context(state->new_bs);
29
- QDict *opts,
57
- aio_context_release(aio_context);
30
- Error **errp);
58
- aio_context_acquire(old_context);
31
+block_crypto_create_opts_init(QDict *opts, Error **errp);
32
33
QCryptoBlockOpenOptions *
34
-block_crypto_open_opts_init(QCryptoBlockFormat format,
35
- QDict *opts,
36
- Error **errp);
37
+block_crypto_open_opts_init(QDict *opts, Error **errp);
38
39
#endif /* BLOCK_CRYPTO_H__ */
40
diff --git a/block/crypto.c b/block/crypto.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/block/crypto.c
43
+++ b/block/crypto.c
44
@@ -XXX,XX +XXX,XX @@ static QemuOptsList block_crypto_create_opts_luks = {
45
46
47
QCryptoBlockOpenOptions *
48
-block_crypto_open_opts_init(QCryptoBlockFormat format,
49
- QDict *opts,
50
- Error **errp)
51
+block_crypto_open_opts_init(QDict *opts, Error **errp)
52
{
53
Visitor *v;
54
- QCryptoBlockOpenOptions *ret = NULL;
55
- Error *local_err = NULL;
56
-
59
-
57
- ret = g_new0(QCryptoBlockOpenOptions, 1);
60
- ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp);
58
- ret->format = format;
61
-
59
+ QCryptoBlockOpenOptions *ret;
62
- aio_context_release(old_context);
60
63
- aio_context_acquire(aio_context);
61
- v = qobject_input_visitor_new_flat_confused(opts, &local_err);
64
-
62
+ v = qobject_input_visitor_new_flat_confused(opts, errp);
65
- if (ret < 0) {
63
if (!v) {
64
- goto out;
66
- goto out;
65
- }
67
- }
66
-
68
-
67
- visit_start_struct(v, NULL, NULL, 0, &local_err);
69
/* This removes our old bs and adds the new bs. This is an operation that
68
- if (local_err) {
70
* can fail, so we need to do it in .prepare; undoing it for abort is
69
- goto out;
71
* always possible. */
70
- }
71
-
72
- switch (format) {
73
- case Q_CRYPTO_BLOCK_FORMAT_LUKS:
74
- visit_type_QCryptoBlockOptionsLUKS_members(
75
- v, &ret->u.luks, &local_err);
76
- break;
77
-
78
- case Q_CRYPTO_BLOCK_FORMAT_QCOW:
79
- visit_type_QCryptoBlockOptionsQCow_members(
80
- v, &ret->u.qcow, &local_err);
81
- break;
82
-
83
- default:
84
- error_setg(&local_err, "Unsupported block format %d", format);
85
- break;
86
- }
87
- if (!local_err) {
88
- visit_check_struct(v, &local_err);
89
+ return NULL;
90
}
91
92
- visit_end_struct(v, NULL);
93
+ visit_type_QCryptoBlockOpenOptions(v, NULL, &ret, errp);
94
95
- out:
96
- if (local_err) {
97
- error_propagate(errp, local_err);
98
- qapi_free_QCryptoBlockOpenOptions(ret);
99
- ret = NULL;
100
- }
101
visit_free(v);
102
return ret;
103
}
104
105
106
QCryptoBlockCreateOptions *
107
-block_crypto_create_opts_init(QCryptoBlockFormat format,
108
- QDict *opts,
109
- Error **errp)
110
+block_crypto_create_opts_init(QDict *opts, Error **errp)
111
{
112
Visitor *v;
113
- QCryptoBlockCreateOptions *ret = NULL;
114
- Error *local_err = NULL;
115
-
116
- ret = g_new0(QCryptoBlockCreateOptions, 1);
117
- ret->format = format;
118
+ QCryptoBlockCreateOptions *ret;
119
120
- v = qobject_input_visitor_new_flat_confused(opts, &local_err);
121
+ v = qobject_input_visitor_new_flat_confused(opts, errp);
122
if (!v) {
123
- goto out;
124
- }
125
-
126
- visit_start_struct(v, NULL, NULL, 0, &local_err);
127
- if (local_err) {
128
- goto out;
129
- }
130
-
131
- switch (format) {
132
- case Q_CRYPTO_BLOCK_FORMAT_LUKS:
133
- visit_type_QCryptoBlockCreateOptionsLUKS_members(
134
- v, &ret->u.luks, &local_err);
135
- break;
136
-
137
- case Q_CRYPTO_BLOCK_FORMAT_QCOW:
138
- visit_type_QCryptoBlockOptionsQCow_members(
139
- v, &ret->u.qcow, &local_err);
140
- break;
141
-
142
- default:
143
- error_setg(&local_err, "Unsupported block format %d", format);
144
- break;
145
- }
146
- if (!local_err) {
147
- visit_check_struct(v, &local_err);
148
+ return NULL;
149
}
150
151
- visit_end_struct(v, NULL);
152
+ visit_type_QCryptoBlockCreateOptions(v, NULL, &ret, errp);
153
154
- out:
155
- if (local_err) {
156
- error_propagate(errp, local_err);
157
- qapi_free_QCryptoBlockCreateOptions(ret);
158
- ret = NULL;
159
- }
160
visit_free(v);
161
return ret;
162
}
163
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
164
}
165
166
cryptoopts = qemu_opts_to_qdict(opts, NULL);
167
+ qdict_put_str(cryptoopts, "format", QCryptoBlockFormat_str(format));
168
169
- open_opts = block_crypto_open_opts_init(format, cryptoopts, errp);
170
+ open_opts = block_crypto_open_opts_init(cryptoopts, errp);
171
if (!open_opts) {
172
goto cleanup;
173
}
174
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
175
&block_crypto_create_opts_luks,
176
true);
177
178
- create_opts = block_crypto_create_opts_init(Q_CRYPTO_BLOCK_FORMAT_LUKS,
179
- cryptoopts, errp);
180
+ qdict_put_str(cryptoopts, "format", "luks");
181
+ create_opts = block_crypto_create_opts_init(cryptoopts, errp);
182
if (!create_opts) {
183
ret = -EINVAL;
184
goto fail;
185
diff --git a/block/qcow.c b/block/qcow.c
186
index XXXXXXX..XXXXXXX 100644
187
--- a/block/qcow.c
188
+++ b/block/qcow.c
189
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
190
ret = -EINVAL;
191
goto fail;
192
}
193
- qdict_del(encryptopts, "format");
194
- crypto_opts = block_crypto_open_opts_init(
195
- Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
196
+ qdict_put_str(encryptopts, "format", "qcow");
197
+ crypto_opts = block_crypto_open_opts_init(encryptopts, errp);
198
if (!crypto_opts) {
199
ret = -EINVAL;
200
goto fail;
201
diff --git a/block/qcow2.c b/block/qcow2.c
202
index XXXXXXX..XXXXXXX 100644
203
--- a/block/qcow2.c
204
+++ b/block/qcow2.c
205
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
206
ret = -EINVAL;
207
goto fail;
208
}
209
- qdict_del(encryptopts, "format");
210
- r->crypto_opts = block_crypto_open_opts_init(
211
- Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
212
+ qdict_put_str(encryptopts, "format", "qcow");
213
+ r->crypto_opts = block_crypto_open_opts_init(encryptopts, errp);
214
break;
215
216
case QCOW_CRYPT_LUKS:
217
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
218
ret = -EINVAL;
219
goto fail;
220
}
221
- qdict_del(encryptopts, "format");
222
- r->crypto_opts = block_crypto_open_opts_init(
223
- Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp);
224
+ qdict_put_str(encryptopts, "format", "luks");
225
+ r->crypto_opts = block_crypto_open_opts_init(encryptopts, errp);
226
break;
227
228
default:
229
--
72
--
230
2.13.6
73
2.20.1
231
74
232
75
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
This patch adds test cases for attaching the backing chain to a mirror
2
job target right before finalising the job, where the image is in a
3
non-mainloop AioContext (i.e. the backing chain needs to be moved to the
4
AioContext of the mirror target).
2
5
3
We are gradually moving away from sector-based interfaces, towards
6
This requires switching the test case from virtio-blk to virtio-scsi
4
byte-based. Make the change for the internals of the qcow
7
because virtio-blk only actually starts using the iothreads when the
5
driver write function, by iterating over offset/bytes instead of
8
guest driver initialises the device (which never happens in a test case
6
sector_num/nb_sectors, and with a rename of index_in_cluster and
9
without a guest OS). virtio-scsi always keeps its block nodes in the
7
repurposing of n to track bytes instead of sectors.
10
AioContext of the the requested iothread without guest interaction.
8
11
9
A later patch will then switch the qcow driver as a whole over
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
to byte-based operation.
13
Message-Id: <20200310113831.27293-7-kwolf@redhat.com>
11
14
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
12
Signed-off-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Jeff Cody <jcody@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
---
16
block/qcow.c | 36 +++++++++++++++++-------------------
17
tests/qemu-iotests/155 | 32 +++++++++++++++++++++++---------
17
1 file changed, 17 insertions(+), 19 deletions(-)
18
tests/qemu-iotests/155.out | 4 ++--
19
2 files changed, 25 insertions(+), 11 deletions(-)
18
20
19
diff --git a/block/qcow.c b/block/qcow.c
21
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
22
index XXXXXXX..XXXXXXX 100755
23
--- a/tests/qemu-iotests/155
24
+++ b/tests/qemu-iotests/155
25
@@ -XXX,XX +XXX,XX @@ target_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt)
26
# chain opened right away. If False, blockdev-add
27
# opens it without a backing file and job completion
28
# is supposed to open the backing chain.
29
+# use_iothread: If True, an iothread is configured for the virtio-blk device
30
+# that uses the image being mirrored
31
32
class BaseClass(iotests.QMPTestCase):
33
target_blockdev_backing = None
34
target_real_backing = None
35
target_open_with_backing = True
36
+ use_iothread = False
37
38
def setUp(self):
39
qemu_img('create', '-f', iotests.imgfmt, back0_img, '1440K')
40
@@ -XXX,XX +XXX,XX @@ class BaseClass(iotests.QMPTestCase):
41
'file': {'driver': 'file',
42
'filename': source_img}}
43
self.vm.add_blockdev(self.vm.qmp_to_opts(blockdev))
44
- self.vm.add_device('virtio-blk,id=qdev0,drive=source')
45
+
46
+ if self.use_iothread:
47
+ self.vm.add_object('iothread,id=iothread0')
48
+ iothread = ",iothread=iothread0"
49
+ else:
50
+ iothread = ""
51
+
52
+ self.vm.add_device('virtio-scsi%s' % iothread)
53
+ self.vm.add_device('scsi-hd,id=qdev0,drive=source')
54
+
55
self.vm.launch()
56
57
self.assertIntactSourceBackingChain()
58
@@ -XXX,XX +XXX,XX @@ class MirrorBaseClass(BaseClass):
59
def testFull(self):
60
self.runMirror('full')
61
62
- node = self.findBlockNode('target',
63
- '/machine/peripheral/qdev0/virtio-backend')
64
+ node = self.findBlockNode('target', 'qdev0')
65
self.assertCorrectBackingImage(node, None)
66
self.assertIntactSourceBackingChain()
67
68
def testTop(self):
69
self.runMirror('top')
70
71
- node = self.findBlockNode('target',
72
- '/machine/peripheral/qdev0/virtio-backend')
73
+ node = self.findBlockNode('target', 'qdev0')
74
self.assertCorrectBackingImage(node, back2_img)
75
self.assertIntactSourceBackingChain()
76
77
def testNone(self):
78
self.runMirror('none')
79
80
- node = self.findBlockNode('target',
81
- '/machine/peripheral/qdev0/virtio-backend')
82
+ node = self.findBlockNode('target', 'qdev0')
83
self.assertCorrectBackingImage(node, source_img)
84
self.assertIntactSourceBackingChain()
85
86
@@ -XXX,XX +XXX,XX @@ class TestBlockdevMirrorReopen(MirrorBaseClass):
87
backing="backing")
88
self.assert_qmp(result, 'return', {})
89
90
+class TestBlockdevMirrorReopenIothread(TestBlockdevMirrorReopen):
91
+ use_iothread = True
92
+
93
# Attach the backing chain only during completion, with blockdev-snapshot
94
class TestBlockdevMirrorSnapshot(MirrorBaseClass):
95
cmd = 'blockdev-mirror'
96
@@ -XXX,XX +XXX,XX @@ class TestBlockdevMirrorSnapshot(MirrorBaseClass):
97
overlay="target")
98
self.assert_qmp(result, 'return', {})
99
100
+class TestBlockdevMirrorSnapshotIothread(TestBlockdevMirrorSnapshot):
101
+ use_iothread = True
102
+
103
class TestCommit(BaseClass):
104
existing = False
105
106
@@ -XXX,XX +XXX,XX @@ class TestCommit(BaseClass):
107
108
self.vm.event_wait('BLOCK_JOB_COMPLETED')
109
110
- node = self.findBlockNode(None,
111
- '/machine/peripheral/qdev0/virtio-backend')
112
+ node = self.findBlockNode(None, 'qdev0')
113
self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename',
114
back1_img)
115
self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename',
116
diff --git a/tests/qemu-iotests/155.out b/tests/qemu-iotests/155.out
20
index XXXXXXX..XXXXXXX 100644
117
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow.c
118
--- a/tests/qemu-iotests/155.out
22
+++ b/block/qcow.c
119
+++ b/tests/qemu-iotests/155.out
23
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
120
@@ -XXX,XX +XXX,XX @@
24
int flags)
121
-.........................
25
{
122
+...............................
26
BDRVQcowState *s = bs->opaque;
123
----------------------------------------------------------------------
27
- int index_in_cluster;
124
-Ran 25 tests
28
+ int offset_in_cluster;
125
+Ran 31 tests
29
uint64_t cluster_offset;
126
30
int ret = 0, n;
127
OK
31
struct iovec hd_iov;
32
QEMUIOVector hd_qiov;
33
uint8_t *buf;
34
void *orig_buf;
35
+ int64_t offset = sector_num * BDRV_SECTOR_SIZE;
36
+ int64_t bytes = nb_sectors * BDRV_SECTOR_SIZE;
37
38
assert(!flags);
39
s->cluster_cache_offset = -1; /* disable compressed cache */
40
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
41
42
qemu_co_mutex_lock(&s->lock);
43
44
- while (nb_sectors != 0) {
45
-
46
- index_in_cluster = sector_num & (s->cluster_sectors - 1);
47
- n = s->cluster_sectors - index_in_cluster;
48
- if (n > nb_sectors) {
49
- n = nb_sectors;
50
+ while (bytes != 0) {
51
+ offset_in_cluster = offset & (s->cluster_size - 1);
52
+ n = s->cluster_size - offset_in_cluster;
53
+ if (n > bytes) {
54
+ n = bytes;
55
}
56
- ret = get_cluster_offset(bs, sector_num << 9, 1, 0,
57
- index_in_cluster << 9,
58
- (index_in_cluster + n) << 9, &cluster_offset);
59
+ ret = get_cluster_offset(bs, offset, 1, 0, offset_in_cluster,
60
+ offset_in_cluster + n, &cluster_offset);
61
if (ret < 0) {
62
break;
63
}
64
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
65
}
66
if (bs->encrypted) {
67
assert(s->crypto);
68
- if (qcrypto_block_encrypt(s->crypto, sector_num * BDRV_SECTOR_SIZE,
69
- buf, n * BDRV_SECTOR_SIZE, NULL) < 0) {
70
+ if (qcrypto_block_encrypt(s->crypto, offset, buf, n, NULL) < 0) {
71
ret = -EIO;
72
break;
73
}
74
}
75
76
hd_iov.iov_base = (void *)buf;
77
- hd_iov.iov_len = n * 512;
78
+ hd_iov.iov_len = n;
79
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
80
qemu_co_mutex_unlock(&s->lock);
81
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
82
- ret = bdrv_co_writev(bs->file,
83
- (cluster_offset >> 9) + index_in_cluster,
84
- n, &hd_qiov);
85
+ ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
86
+ n, &hd_qiov, 0);
87
qemu_co_mutex_lock(&s->lock);
88
if (ret < 0) {
89
break;
90
}
91
ret = 0;
92
93
- nb_sectors -= n;
94
- sector_num += n;
95
- buf += n * 512;
96
+ bytes -= n;
97
+ offset += n;
98
+ buf += n;
99
}
100
qemu_co_mutex_unlock(&s->lock);
101
102
--
128
--
103
2.13.6
129
2.20.1
104
130
105
131
diff view generated by jsdifflib
1
Commit 51f63ec7d tried to change all references to 2.13 into 3.0, but
1
From: Peter Krempa <pkrempa@redhat.com>
2
it failed to achieve this because it was not properly rebased on top of
3
the series introducing qapi/job.json. Change the references now.
4
2
3
Anounce that 'blockdev-snapshot' command's permissions allow changing
4
of the backing file if the 'consistent_read' permission is not required.
5
6
This is useful for libvirt to allow late opening of the backing chain
7
during a blockdev-mirror.
8
9
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
Message-Id: <20200310113831.27293-8-kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
13
---
9
qapi/job.json | 18 +++++++++---------
14
qapi/block-core.json | 9 ++++++++-
10
1 file changed, 9 insertions(+), 9 deletions(-)
15
1 file changed, 8 insertions(+), 1 deletion(-)
11
16
12
diff --git a/qapi/job.json b/qapi/job.json
17
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/job.json
19
--- a/qapi/block-core.json
15
+++ b/qapi/job.json
20
+++ b/qapi/block-core.json
16
@@ -XXX,XX +XXX,XX @@
17
# @id: The job identifier
18
# @status: The new job status
19
#
20
-# Since: 2.13
21
+# Since: 3.0
22
##
23
{ 'event': 'JOB_STATUS_CHANGE',
24
'data': { 'id': 'str',
25
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@
26
#
22
#
27
# @id: The job identifier.
23
# For the arguments, see the documentation of BlockdevSnapshot.
28
#
24
#
29
-# Since: 2.13
25
+# Features:
30
+# Since: 3.0
26
+# @allow-write-only-overlay: If present, the check whether this operation is safe
31
##
27
+# was relaxed so that it can be used to change
32
{ 'command': 'job-pause', 'data': { 'id': 'str' } }
28
+# backing file of a destination of a blockdev-mirror.
33
29
+# (since 5.0)
30
+#
31
# Since: 2.5
32
#
33
# Example:
34
@@ -XXX,XX +XXX,XX @@
34
@@ -XXX,XX +XXX,XX @@
35
#
35
#
36
# @id : The job identifier.
37
#
38
-# Since: 2.13
39
+# Since: 3.0
40
##
36
##
41
{ 'command': 'job-resume', 'data': { 'id': 'str' } }
37
{ 'command': 'blockdev-snapshot',
42
38
- 'data': 'BlockdevSnapshot' }
43
@@ -XXX,XX +XXX,XX @@
39
+ 'data': 'BlockdevSnapshot',
44
#
40
+ 'features': [ 'allow-write-only-overlay' ] }
45
# @id: The job identifier.
41
46
#
47
-# Since: 2.13
48
+# Since: 3.0
49
##
42
##
50
{ 'command': 'job-cancel', 'data': { 'id': 'str' } }
43
# @change-backing-file:
51
52
@@ -XXX,XX +XXX,XX @@
53
#
54
# @id: The job identifier.
55
#
56
-# Since: 2.13
57
+# Since: 3.0
58
##
59
{ 'command': 'job-complete', 'data': { 'id': 'str' } }
60
61
@@ -XXX,XX +XXX,XX @@
62
#
63
# @id: The job identifier.
64
#
65
-# Since: 2.13
66
+# Since: 3.0
67
##
68
{ 'command': 'job-dismiss', 'data': { 'id': 'str' } }
69
70
@@ -XXX,XX +XXX,XX @@
71
# @id: The identifier of any job in the transaction, or of a job that is not
72
# part of any transaction.
73
#
74
-# Since: 2.13
75
+# Since: 3.0
76
##
77
{ 'command': 'job-finalize', 'data': { 'id': 'str' } }
78
79
@@ -XXX,XX +XXX,XX @@
80
# the reason for the job failure. It should not be parsed
81
# by applications.
82
#
83
-# Since: 2.13
84
+# Since: 3.0
85
##
86
{ 'struct': 'JobInfo',
87
'data': { 'id': 'str', 'type': 'JobType', 'status': 'JobStatus',
88
@@ -XXX,XX +XXX,XX @@
89
#
90
# Returns: a list with a @JobInfo for each active job
91
#
92
-# Since: 2.13
93
+# Since: 3.0
94
##
95
{ 'command': 'query-jobs', 'returns': ['JobInfo'] }
96
--
44
--
97
2.13.6
45
2.20.1
98
46
99
47
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
We are gradually moving away from sector-based interfaces, towards
3
The socket_scm_helper path got corrupted during the mechanical
4
byte-based. Make the change for the internals of the qcow
4
refactor moving the qtests files into their own sub-directory.
5
driver read function, by iterating over offset/bytes instead of
6
sector_num/nb_sectors, and with a rename of index_in_cluster and
7
repurposing of n to track bytes instead of sectors.
8
5
9
A later patch will then switch the qcow driver as a whole over
6
Fixes: 1e8a1fae7 ("test: Move qtests to a separate directory")
10
to byte-based operation.
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
11
8
Message-Id: <20200306165751.18986-1-philmd@redhat.com>
12
Signed-off-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
13
Reviewed-by: Jeff Cody <jcody@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
11
---
16
block/qcow.c | 42 ++++++++++++++++++++----------------------
12
tests/Makefile.include | 1 +
17
1 file changed, 20 insertions(+), 22 deletions(-)
13
tests/qtest/Makefile.include | 1 -
14
2 files changed, 1 insertion(+), 1 deletion(-)
18
15
19
diff --git a/block/qcow.c b/block/qcow.c
16
diff --git a/tests/Makefile.include b/tests/Makefile.include
20
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow.c
18
--- a/tests/Makefile.include
22
+++ b/block/qcow.c
19
+++ b/tests/Makefile.include
23
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
20
@@ -XXX,XX +XXX,XX @@ include $(SRC_PATH)/tests/qtest/Makefile.include
24
int nb_sectors, QEMUIOVector *qiov)
21
tests/test-qga$(EXESUF): qemu-ga$(EXESUF)
25
{
22
tests/test-qga$(EXESUF): tests/test-qga.o $(qtest-obj-y)
26
BDRVQcowState *s = bs->opaque;
23
tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o $(test-util-obj-y) libvhost-user.a
27
- int index_in_cluster;
24
+tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
28
+ int offset_in_cluster;
25
29
int ret = 0, n;
26
SPEED = quick
30
uint64_t cluster_offset;
27
31
struct iovec hd_iov;
28
diff --git a/tests/qtest/Makefile.include b/tests/qtest/Makefile.include
32
QEMUIOVector hd_qiov;
29
index XXXXXXX..XXXXXXX 100644
33
uint8_t *buf;
30
--- a/tests/qtest/Makefile.include
34
void *orig_buf;
31
+++ b/tests/qtest/Makefile.include
35
+ int64_t offset = sector_num * BDRV_SECTOR_SIZE;
32
@@ -XXX,XX +XXX,XX @@ tests/qtest/usb-hcd-ehci-test$(EXESUF): tests/qtest/usb-hcd-ehci-test.o $(libqos
36
+ int64_t bytes = nb_sectors * BDRV_SECTOR_SIZE;
33
tests/qtest/usb-hcd-xhci-test$(EXESUF): tests/qtest/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
37
34
tests/qtest/cpu-plug-test$(EXESUF): tests/qtest/cpu-plug-test.o
38
if (qiov->niov > 1) {
35
tests/qtest/migration-test$(EXESUF): tests/qtest/migration-test.o tests/qtest/migration-helpers.o
39
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
36
-tests/qtest/qemu-iotests/qtest/socket_scm_helper$(EXESUF): tests/qtest/qemu-iotests/qtest/socket_scm_helper.o
40
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
37
tests/qtest/test-netfilter$(EXESUF): tests/qtest/test-netfilter.o $(qtest-obj-y)
41
38
tests/qtest/test-filter-mirror$(EXESUF): tests/qtest/test-filter-mirror.o $(qtest-obj-y)
42
qemu_co_mutex_lock(&s->lock);
39
tests/qtest/test-filter-redirector$(EXESUF): tests/qtest/test-filter-redirector.o $(qtest-obj-y)
43
44
- while (nb_sectors != 0) {
45
+ while (bytes != 0) {
46
/* prepare next request */
47
- ret = get_cluster_offset(bs, sector_num << 9,
48
- 0, 0, 0, 0, &cluster_offset);
49
+ ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset);
50
if (ret < 0) {
51
break;
52
}
53
- index_in_cluster = sector_num & (s->cluster_sectors - 1);
54
- n = s->cluster_sectors - index_in_cluster;
55
- if (n > nb_sectors) {
56
- n = nb_sectors;
57
+ offset_in_cluster = offset & (s->cluster_size - 1);
58
+ n = s->cluster_size - offset_in_cluster;
59
+ if (n > bytes) {
60
+ n = bytes;
61
}
62
63
if (!cluster_offset) {
64
if (bs->backing) {
65
/* read from the base image */
66
hd_iov.iov_base = (void *)buf;
67
- hd_iov.iov_len = n * 512;
68
+ hd_iov.iov_len = n;
69
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
70
qemu_co_mutex_unlock(&s->lock);
71
/* qcow2 emits this on bs->file instead of bs->backing */
72
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
73
- ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
74
+ ret = bdrv_co_preadv(bs->backing, offset, n, &hd_qiov, 0);
75
qemu_co_mutex_lock(&s->lock);
76
if (ret < 0) {
77
break;
78
}
79
} else {
80
/* Note: in this case, no need to wait */
81
- memset(buf, 0, 512 * n);
82
+ memset(buf, 0, n);
83
}
84
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
85
/* add AIO support for compressed blocks ? */
86
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
87
ret = -EIO;
88
break;
89
}
90
- memcpy(buf,
91
- s->cluster_cache + index_in_cluster * 512, 512 * n);
92
+ memcpy(buf, s->cluster_cache + offset_in_cluster, n);
93
} else {
94
if ((cluster_offset & 511) != 0) {
95
ret = -EIO;
96
break;
97
}
98
hd_iov.iov_base = (void *)buf;
99
- hd_iov.iov_len = n * 512;
100
+ hd_iov.iov_len = n;
101
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
102
qemu_co_mutex_unlock(&s->lock);
103
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
104
- ret = bdrv_co_readv(bs->file,
105
- (cluster_offset >> 9) + index_in_cluster,
106
- n, &hd_qiov);
107
+ ret = bdrv_co_preadv(bs->file, cluster_offset + offset_in_cluster,
108
+ n, &hd_qiov, 0);
109
qemu_co_mutex_lock(&s->lock);
110
if (ret < 0) {
111
break;
112
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
113
if (bs->encrypted) {
114
assert(s->crypto);
115
if (qcrypto_block_decrypt(s->crypto,
116
- sector_num * BDRV_SECTOR_SIZE, buf,
117
- n * BDRV_SECTOR_SIZE, NULL) < 0) {
118
+ offset, buf, n, NULL) < 0) {
119
ret = -EIO;
120
break;
121
}
122
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
123
}
124
ret = 0;
125
126
- nb_sectors -= n;
127
- sector_num += n;
128
- buf += n * 512;
129
+ bytes -= n;
130
+ offset += n;
131
+ buf += n;
132
}
133
134
qemu_co_mutex_unlock(&s->lock);
135
--
40
--
136
2.13.6
41
2.20.1
137
42
138
43
diff view generated by jsdifflib
1
This moves the code to resize an image file to the thread pool to avoid
1
From: Daniel Henrique Barboza <danielhb413@gmail.com>
2
blocking.
3
2
4
Creating large images with preallocation with blockdev-create is now
3
Adding to Block Drivers the capability of being able to clean up
5
actually a background job instead of blocking the monitor (and most
4
its created files can be useful in certain situations. For the
6
other things) until the preallocation has completed.
5
LUKS driver, for instance, a failure in one of its authentication
6
steps can leave files in the host that weren't there before.
7
7
8
This patch adds the 'bdrv_co_delete_file' interface to block
9
drivers and add it to the 'file' driver in file-posix.c. The
10
implementation is given by 'raw_co_delete_file'.
11
12
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
13
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
14
Message-Id: <20200130213907.2830642-2-danielhb413@gmail.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
16
---
11
include/block/raw-aio.h | 4 +-
17
include/block/block_int.h | 4 ++++
12
block/file-posix.c | 266 +++++++++++++++++++++++++++---------------------
18
block/file-posix.c | 23 +++++++++++++++++++++++
13
2 files changed, 154 insertions(+), 116 deletions(-)
19
2 files changed, 27 insertions(+)
14
20
15
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
16
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
17
--- a/include/block/raw-aio.h
23
--- a/include/block/block_int.h
18
+++ b/include/block/raw-aio.h
24
+++ b/include/block/block_int.h
19
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
20
#define QEMU_AIO_DISCARD 0x0010
26
*/
21
#define QEMU_AIO_WRITE_ZEROES 0x0020
27
int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
22
#define QEMU_AIO_COPY_RANGE 0x0040
28
23
+#define QEMU_AIO_TRUNCATE 0x0080
29
+ /* Delete a created file. */
24
#define QEMU_AIO_TYPE_MASK \
30
+ int coroutine_fn (*bdrv_co_delete_file)(BlockDriverState *bs,
25
(QEMU_AIO_READ | \
31
+ Error **errp);
26
QEMU_AIO_WRITE | \
32
+
27
@@ -XXX,XX +XXX,XX @@
33
/*
28
QEMU_AIO_FLUSH | \
34
* Flushes all data that was already written to the OS all the way down to
29
QEMU_AIO_DISCARD | \
35
* the disk (for example file-posix.c calls fsync()).
30
QEMU_AIO_WRITE_ZEROES | \
31
- QEMU_AIO_COPY_RANGE)
32
+ QEMU_AIO_COPY_RANGE | \
33
+ QEMU_AIO_TRUNCATE)
34
35
/* AIO flags */
36
#define QEMU_AIO_MISALIGNED 0x1000
37
diff --git a/block/file-posix.c b/block/file-posix.c
36
diff --git a/block/file-posix.c b/block/file-posix.c
38
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
39
--- a/block/file-posix.c
38
--- a/block/file-posix.c
40
+++ b/block/file-posix.c
39
+++ b/block/file-posix.c
41
@@ -XXX,XX +XXX,XX @@ typedef struct RawPosixAIOData {
40
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
42
#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
41
return raw_co_create(&options, errp);
43
off_t aio_offset;
44
int aio_type;
45
- int aio_fd2;
46
- off_t aio_offset2;
47
+ union {
48
+ struct {
49
+ int aio_fd2;
50
+ off_t aio_offset2;
51
+ };
52
+ struct {
53
+ PreallocMode prealloc;
54
+ Error **errp;
55
+ };
56
+ };
57
} RawPosixAIOData;
58
59
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
60
@@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
61
return ret;
62
}
42
}
63
43
64
+static int handle_aiocb_truncate(RawPosixAIOData *aiocb)
44
+static int coroutine_fn raw_co_delete_file(BlockDriverState *bs,
45
+ Error **errp)
65
+{
46
+{
66
+ int result = 0;
67
+ int64_t current_length = 0;
68
+ char *buf = NULL;
69
+ struct stat st;
47
+ struct stat st;
70
+ int fd = aiocb->aio_fildes;
48
+ int ret;
71
+ int64_t offset = aiocb->aio_offset;
72
+ Error **errp = aiocb->errp;
73
+
49
+
74
+ if (fstat(fd, &st) < 0) {
50
+ if (!(stat(bs->filename, &st) == 0) || !S_ISREG(st.st_mode)) {
75
+ result = -errno;
51
+ error_setg_errno(errp, ENOENT, "%s is not a regular file",
76
+ error_setg_errno(errp, -result, "Could not stat file");
52
+ bs->filename);
77
+ return result;
53
+ return -ENOENT;
78
+ }
54
+ }
79
+
55
+
80
+ current_length = st.st_size;
56
+ ret = unlink(bs->filename);
81
+ if (current_length > offset && aiocb->prealloc != PREALLOC_MODE_OFF) {
57
+ if (ret < 0) {
82
+ error_setg(errp, "Cannot use preallocation for shrinking files");
58
+ ret = -errno;
83
+ return -ENOTSUP;
59
+ error_setg_errno(errp, -ret, "Error when deleting file %s",
60
+ bs->filename);
84
+ }
61
+ }
85
+
62
+
86
+ switch (aiocb->prealloc) {
63
+ return ret;
87
+#ifdef CONFIG_POSIX_FALLOCATE
88
+ case PREALLOC_MODE_FALLOC:
89
+ /*
90
+ * Truncating before posix_fallocate() makes it about twice slower on
91
+ * file systems that do not support fallocate(), trying to check if a
92
+ * block is allocated before allocating it, so don't do that here.
93
+ */
94
+ if (offset != current_length) {
95
+ result = -posix_fallocate(fd, current_length,
96
+ offset - current_length);
97
+ if (result != 0) {
98
+ /* posix_fallocate() doesn't set errno. */
99
+ error_setg_errno(errp, -result,
100
+ "Could not preallocate new data");
101
+ }
102
+ } else {
103
+ result = 0;
104
+ }
105
+ goto out;
106
+#endif
107
+ case PREALLOC_MODE_FULL:
108
+ {
109
+ int64_t num = 0, left = offset - current_length;
110
+ off_t seek_result;
111
+
112
+ /*
113
+ * Knowing the final size from the beginning could allow the file
114
+ * system driver to do less allocations and possibly avoid
115
+ * fragmentation of the file.
116
+ */
117
+ if (ftruncate(fd, offset) != 0) {
118
+ result = -errno;
119
+ error_setg_errno(errp, -result, "Could not resize file");
120
+ goto out;
121
+ }
122
+
123
+ buf = g_malloc0(65536);
124
+
125
+ seek_result = lseek(fd, current_length, SEEK_SET);
126
+ if (seek_result < 0) {
127
+ result = -errno;
128
+ error_setg_errno(errp, -result,
129
+ "Failed to seek to the old end of file");
130
+ goto out;
131
+ }
132
+
133
+ while (left > 0) {
134
+ num = MIN(left, 65536);
135
+ result = write(fd, buf, num);
136
+ if (result < 0) {
137
+ result = -errno;
138
+ error_setg_errno(errp, -result,
139
+ "Could not write zeros for preallocation");
140
+ goto out;
141
+ }
142
+ left -= result;
143
+ }
144
+ if (result >= 0) {
145
+ result = fsync(fd);
146
+ if (result < 0) {
147
+ result = -errno;
148
+ error_setg_errno(errp, -result,
149
+ "Could not flush file to disk");
150
+ goto out;
151
+ }
152
+ }
153
+ goto out;
154
+ }
155
+ case PREALLOC_MODE_OFF:
156
+ if (ftruncate(fd, offset) != 0) {
157
+ result = -errno;
158
+ error_setg_errno(errp, -result, "Could not resize file");
159
+ }
160
+ return result;
161
+ default:
162
+ result = -ENOTSUP;
163
+ error_setg(errp, "Unsupported preallocation mode: %s",
164
+ PreallocMode_str(aiocb->prealloc));
165
+ return result;
166
+ }
167
+
168
+out:
169
+ if (result < 0) {
170
+ if (ftruncate(fd, current_length) < 0) {
171
+ error_report("Failed to restore old file length: %s",
172
+ strerror(errno));
173
+ }
174
+ }
175
+
176
+ g_free(buf);
177
+ return result;
178
+}
64
+}
179
+
65
+
180
static int aio_worker(void *arg)
66
/*
181
{
67
* Find allocation range in @bs around offset @start.
182
RawPosixAIOData *aiocb = arg;
68
* May change underlying file descriptor's file offset.
183
@@ -XXX,XX +XXX,XX @@ static int aio_worker(void *arg)
69
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
184
case QEMU_AIO_COPY_RANGE:
70
.bdrv_co_block_status = raw_co_block_status,
185
ret = handle_aiocb_copy_range(aiocb);
71
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
186
break;
72
.bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
187
+ case QEMU_AIO_TRUNCATE:
73
+ .bdrv_co_delete_file = raw_co_delete_file,
188
+ ret = handle_aiocb_truncate(aiocb);
74
189
+ break;
75
.bdrv_co_preadv = raw_co_preadv,
190
default:
76
.bdrv_co_pwritev = raw_co_pwritev,
191
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
192
ret = -EINVAL;
193
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
194
*
195
* Returns: 0 on success, -errno on failure.
196
*/
197
-static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
198
- Error **errp)
199
+static int coroutine_fn
200
+raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
201
+ PreallocMode prealloc, Error **errp)
202
{
203
- int result = 0;
204
- int64_t current_length = 0;
205
- char *buf = NULL;
206
- struct stat st;
207
-
208
- if (fstat(fd, &st) < 0) {
209
- result = -errno;
210
- error_setg_errno(errp, -result, "Could not stat file");
211
- return result;
212
- }
213
-
214
- current_length = st.st_size;
215
- if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
216
- error_setg(errp, "Cannot use preallocation for shrinking files");
217
- return -ENOTSUP;
218
- }
219
-
220
- switch (prealloc) {
221
-#ifdef CONFIG_POSIX_FALLOCATE
222
- case PREALLOC_MODE_FALLOC:
223
- /*
224
- * Truncating before posix_fallocate() makes it about twice slower on
225
- * file systems that do not support fallocate(), trying to check if a
226
- * block is allocated before allocating it, so don't do that here.
227
- */
228
- if (offset != current_length) {
229
- result = -posix_fallocate(fd, current_length, offset - current_length);
230
- if (result != 0) {
231
- /* posix_fallocate() doesn't set errno. */
232
- error_setg_errno(errp, -result,
233
- "Could not preallocate new data");
234
- }
235
- } else {
236
- result = 0;
237
- }
238
- goto out;
239
-#endif
240
- case PREALLOC_MODE_FULL:
241
- {
242
- int64_t num = 0, left = offset - current_length;
243
- off_t seek_result;
244
-
245
- /*
246
- * Knowing the final size from the beginning could allow the file
247
- * system driver to do less allocations and possibly avoid
248
- * fragmentation of the file.
249
- */
250
- if (ftruncate(fd, offset) != 0) {
251
- result = -errno;
252
- error_setg_errno(errp, -result, "Could not resize file");
253
- goto out;
254
- }
255
-
256
- buf = g_malloc0(65536);
257
-
258
- seek_result = lseek(fd, current_length, SEEK_SET);
259
- if (seek_result < 0) {
260
- result = -errno;
261
- error_setg_errno(errp, -result,
262
- "Failed to seek to the old end of file");
263
- goto out;
264
- }
265
-
266
- while (left > 0) {
267
- num = MIN(left, 65536);
268
- result = write(fd, buf, num);
269
- if (result < 0) {
270
- result = -errno;
271
- error_setg_errno(errp, -result,
272
- "Could not write zeros for preallocation");
273
- goto out;
274
- }
275
- left -= result;
276
- }
277
- if (result >= 0) {
278
- result = fsync(fd);
279
- if (result < 0) {
280
- result = -errno;
281
- error_setg_errno(errp, -result,
282
- "Could not flush file to disk");
283
- goto out;
284
- }
285
- }
286
- goto out;
287
- }
288
- case PREALLOC_MODE_OFF:
289
- if (ftruncate(fd, offset) != 0) {
290
- result = -errno;
291
- error_setg_errno(errp, -result, "Could not resize file");
292
- }
293
- return result;
294
- default:
295
- result = -ENOTSUP;
296
- error_setg(errp, "Unsupported preallocation mode: %s",
297
- PreallocMode_str(prealloc));
298
- return result;
299
- }
300
+ RawPosixAIOData *acb = g_new(RawPosixAIOData, 1);
301
+ ThreadPool *pool;
302
303
-out:
304
- if (result < 0) {
305
- if (ftruncate(fd, current_length) < 0) {
306
- error_report("Failed to restore old file length: %s",
307
- strerror(errno));
308
- }
309
- }
310
+ *acb = (RawPosixAIOData) {
311
+ .bs = bs,
312
+ .aio_fildes = fd,
313
+ .aio_type = QEMU_AIO_TRUNCATE,
314
+ .aio_offset = offset,
315
+ .prealloc = prealloc,
316
+ .errp = errp,
317
+ };
318
319
- g_free(buf);
320
- return result;
321
+ /* @bs can be NULL, bdrv_get_aio_context() returns the main context then */
322
+ pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
323
+ return thread_pool_submit_co(pool, aio_worker, acb);
324
}
325
326
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
327
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
328
}
329
330
if (S_ISREG(st.st_mode)) {
331
- return raw_regular_truncate(s->fd, offset, prealloc, errp);
332
+ return raw_regular_truncate(bs, s->fd, offset, prealloc, errp);
333
}
334
335
if (prealloc != PREALLOC_MODE_OFF) {
336
@@ -XXX,XX +XXX,XX @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
337
return (int64_t)st.st_blocks * 512;
338
}
339
340
-static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
341
+static int coroutine_fn
342
+raw_co_create(BlockdevCreateOptions *options, Error **errp)
343
{
344
BlockdevCreateOptionsFile *file_opts;
345
int fd;
346
@@ -XXX,XX +XXX,XX @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
347
}
348
349
/* Clear the file by truncating it to 0 */
350
- result = raw_regular_truncate(fd, 0, PREALLOC_MODE_OFF, errp);
351
+ result = raw_regular_truncate(NULL, fd, 0, PREALLOC_MODE_OFF, errp);
352
if (result < 0) {
353
goto out_close;
354
}
355
@@ -XXX,XX +XXX,XX @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
356
357
/* Resize and potentially preallocate the file to the desired
358
* final size */
359
- result = raw_regular_truncate(fd, file_opts->size, file_opts->preallocation,
360
- errp);
361
+ result = raw_regular_truncate(NULL, fd, file_opts->size,
362
+ file_opts->preallocation, errp);
363
if (result < 0) {
364
goto out_close;
365
}
366
--
77
--
367
2.13.6
78
2.20.1
368
79
369
80
diff view generated by jsdifflib
1
This moves the bdrv_truncate() implementation from block.c to block/io.c
1
From: Daniel Henrique Barboza <danielhb413@gmail.com>
2
so it can have access to the tracked requests infrastructure.
3
2
4
This involves making refresh_total_sectors() public (in block_int.h).
3
Using the new 'bdrv_co_delete_file' interface, a pure co_routine function
4
'bdrv_co_delete_file' inside block.c can can be used in a way similar of
5
the existing bdrv_create_file to to clean up a created file.
5
6
7
We're creating a pure co_routine because the only caller of
8
'bdrv_co_delete_file' will be already in co_routine context, thus there
9
is no need to add all the machinery to check for qemu_in_coroutine() and
10
create a separated co_routine to do the job.
11
12
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
13
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
14
Message-Id: <20200130213907.2830642-3-danielhb413@gmail.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
16
---
9
include/block/block_int.h | 2 +
17
include/block/block.h | 1 +
10
block.c | 111 +---------------------------------------------
18
block.c | 26 ++++++++++++++++++++++++++
11
block/io.c | 109 +++++++++++++++++++++++++++++++++++++++++++++
19
2 files changed, 27 insertions(+)
12
3 files changed, 112 insertions(+), 110 deletions(-)
13
20
14
diff --git a/include/block/block_int.h b/include/block/block_int.h
21
diff --git a/include/block/block.h b/include/block/block.h
15
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block_int.h
23
--- a/include/block/block.h
17
+++ b/include/block/block_int.h
24
+++ b/include/block/block.h
18
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
25
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
19
BdrvChild *dst, uint64_t dst_offset,
26
int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
20
uint64_t bytes, BdrvRequestFlags flags);
27
Error **errp);
21
28
void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
22
+int refresh_total_sectors(BlockDriverState *bs, int64_t hint);
29
+int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp);
23
+
30
24
#endif /* BLOCK_INT_H */
31
32
typedef struct BdrvCheckResult {
25
diff --git a/block.c b/block.c
33
diff --git a/block.c b/block.c
26
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
27
--- a/block.c
35
--- a/block.c
28
+++ b/block.c
36
+++ b/block.c
29
@@ -XXX,XX +XXX,XX @@ static int find_image_format(BlockBackend *file, const char *filename,
37
@@ -XXX,XX +XXX,XX @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
30
* Set the current 'total_sectors' value
31
* Return 0 on success, -errno on error.
32
*/
33
-static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
34
+int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
35
{
36
BlockDriver *drv = bs->drv;
37
38
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load)
39
}
38
}
40
}
39
}
41
40
42
-static void bdrv_parent_cb_resize(BlockDriverState *bs)
41
+int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp)
43
-{
44
- BdrvChild *c;
45
- QLIST_FOREACH(c, &bs->parents, next_parent) {
46
- if (c->role->resize) {
47
- c->role->resize(c);
48
- }
49
- }
50
-}
51
-
52
/*
53
* Sets the backing file link of a BDS. A new reference is created; callers
54
* which don't need their own reference any more must call bdrv_unref().
55
@@ -XXX,XX +XXX,XX @@ exit:
56
}
57
58
/**
59
- * Truncate file to 'offset' bytes (needed only for file protocols)
60
- */
61
-int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
62
- PreallocMode prealloc, Error **errp)
63
-{
64
- BlockDriverState *bs = child->bs;
65
- BlockDriver *drv = bs->drv;
66
- int ret;
67
-
68
- assert(child->perm & BLK_PERM_RESIZE);
69
-
70
- /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
71
- if (!drv) {
72
- error_setg(errp, "No medium inserted");
73
- return -ENOMEDIUM;
74
- }
75
- if (offset < 0) {
76
- error_setg(errp, "Image size cannot be negative");
77
- return -EINVAL;
78
- }
79
-
80
- bdrv_inc_in_flight(bs);
81
-
82
- if (!drv->bdrv_co_truncate) {
83
- if (bs->file && drv->is_filter) {
84
- ret = bdrv_co_truncate(bs->file, offset, prealloc, errp);
85
- goto out;
86
- }
87
- error_setg(errp, "Image format driver does not support resize");
88
- ret = -ENOTSUP;
89
- goto out;
90
- }
91
- if (bs->read_only) {
92
- error_setg(errp, "Image is read-only");
93
- ret = -EACCES;
94
- goto out;
95
- }
96
-
97
- assert(!(bs->open_flags & BDRV_O_INACTIVE));
98
-
99
- ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp);
100
- if (ret < 0) {
101
- goto out;
102
- }
103
- ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
104
- if (ret < 0) {
105
- error_setg_errno(errp, -ret, "Could not refresh total sector count");
106
- } else {
107
- offset = bs->total_sectors * BDRV_SECTOR_SIZE;
108
- }
109
- bdrv_dirty_bitmap_truncate(bs, offset);
110
- bdrv_parent_cb_resize(bs);
111
- atomic_inc(&bs->write_gen);
112
-
113
-out:
114
- bdrv_dec_in_flight(bs);
115
- return ret;
116
-}
117
-
118
-typedef struct TruncateCo {
119
- BdrvChild *child;
120
- int64_t offset;
121
- PreallocMode prealloc;
122
- Error **errp;
123
- int ret;
124
-} TruncateCo;
125
-
126
-static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
127
-{
128
- TruncateCo *tco = opaque;
129
- tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc,
130
- tco->errp);
131
-}
132
-
133
-int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
134
- Error **errp)
135
-{
136
- Coroutine *co;
137
- TruncateCo tco = {
138
- .child = child,
139
- .offset = offset,
140
- .prealloc = prealloc,
141
- .errp = errp,
142
- .ret = NOT_DONE,
143
- };
144
-
145
- if (qemu_in_coroutine()) {
146
- /* Fast-path if already in coroutine context */
147
- bdrv_truncate_co_entry(&tco);
148
- } else {
149
- co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco);
150
- qemu_coroutine_enter(co);
151
- BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE);
152
- }
153
-
154
- return tco.ret;
155
-}
156
-
157
-/**
158
* Length of a allocated file in bytes. Sparse files are counted by actual
159
* allocated space. Return < 0 if error or unknown.
160
*/
161
diff --git a/block/io.c b/block/io.c
162
index XXXXXXX..XXXXXXX 100644
163
--- a/block/io.c
164
+++ b/block/io.c
165
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
166
bdrv_dec_in_flight(dst_bs);
167
return ret;
168
}
169
+
170
+static void bdrv_parent_cb_resize(BlockDriverState *bs)
171
+{
42
+{
172
+ BdrvChild *c;
43
+ Error *local_err = NULL;
173
+ QLIST_FOREACH(c, &bs->parents, next_parent) {
174
+ if (c->role->resize) {
175
+ c->role->resize(c);
176
+ }
177
+ }
178
+}
179
+
180
+/**
181
+ * Truncate file to 'offset' bytes (needed only for file protocols)
182
+ */
183
+int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
184
+ PreallocMode prealloc, Error **errp)
185
+{
186
+ BlockDriverState *bs = child->bs;
187
+ BlockDriver *drv = bs->drv;
188
+ int ret;
44
+ int ret;
189
+
45
+
190
+ assert(child->perm & BLK_PERM_RESIZE);
46
+ assert(bs != NULL);
191
+
47
+
192
+ /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
48
+ if (!bs->drv) {
193
+ if (!drv) {
49
+ error_setg(errp, "Block node '%s' is not opened", bs->filename);
194
+ error_setg(errp, "No medium inserted");
195
+ return -ENOMEDIUM;
50
+ return -ENOMEDIUM;
196
+ }
51
+ }
197
+ if (offset < 0) {
52
+
198
+ error_setg(errp, "Image size cannot be negative");
53
+ if (!bs->drv->bdrv_co_delete_file) {
199
+ return -EINVAL;
54
+ error_setg(errp, "Driver '%s' does not support image deletion",
55
+ bs->drv->format_name);
56
+ return -ENOTSUP;
200
+ }
57
+ }
201
+
58
+
202
+ bdrv_inc_in_flight(bs);
59
+ ret = bs->drv->bdrv_co_delete_file(bs, &local_err);
203
+
60
+ if (ret < 0) {
204
+ if (!drv->bdrv_co_truncate) {
61
+ error_propagate(errp, local_err);
205
+ if (bs->file && drv->is_filter) {
206
+ ret = bdrv_co_truncate(bs->file, offset, prealloc, errp);
207
+ goto out;
208
+ }
209
+ error_setg(errp, "Image format driver does not support resize");
210
+ ret = -ENOTSUP;
211
+ goto out;
212
+ }
213
+ if (bs->read_only) {
214
+ error_setg(errp, "Image is read-only");
215
+ ret = -EACCES;
216
+ goto out;
217
+ }
62
+ }
218
+
63
+
219
+ assert(!(bs->open_flags & BDRV_O_INACTIVE));
220
+
221
+ ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp);
222
+ if (ret < 0) {
223
+ goto out;
224
+ }
225
+ ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
226
+ if (ret < 0) {
227
+ error_setg_errno(errp, -ret, "Could not refresh total sector count");
228
+ } else {
229
+ offset = bs->total_sectors * BDRV_SECTOR_SIZE;
230
+ }
231
+ bdrv_dirty_bitmap_truncate(bs, offset);
232
+ bdrv_parent_cb_resize(bs);
233
+ atomic_inc(&bs->write_gen);
234
+
235
+out:
236
+ bdrv_dec_in_flight(bs);
237
+ return ret;
64
+ return ret;
238
+}
65
+}
239
+
66
+
240
+typedef struct TruncateCo {
67
/**
241
+ BdrvChild *child;
68
* Try to get @bs's logical and physical block size.
242
+ int64_t offset;
69
* On success, store them in @bsz struct and return 0.
243
+ PreallocMode prealloc;
244
+ Error **errp;
245
+ int ret;
246
+} TruncateCo;
247
+
248
+static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
249
+{
250
+ TruncateCo *tco = opaque;
251
+ tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc,
252
+ tco->errp);
253
+}
254
+
255
+int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
256
+ Error **errp)
257
+{
258
+ Coroutine *co;
259
+ TruncateCo tco = {
260
+ .child = child,
261
+ .offset = offset,
262
+ .prealloc = prealloc,
263
+ .errp = errp,
264
+ .ret = NOT_DONE,
265
+ };
266
+
267
+ if (qemu_in_coroutine()) {
268
+ /* Fast-path if already in coroutine context */
269
+ bdrv_truncate_co_entry(&tco);
270
+ } else {
271
+ co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco);
272
+ qemu_coroutine_enter(co);
273
+ BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE);
274
+ }
275
+
276
+ return tco.ret;
277
+}
278
--
70
--
279
2.13.6
71
2.20.1
280
72
281
73
diff view generated by jsdifflib
1
From: Markus Armbruster <armbru@redhat.com>
1
From: Daniel Henrique Barboza <danielhb413@gmail.com>
2
2
3
Coverity can't see that qobject_input_visitor_new_flat_confused()
3
When using a non-UTF8 secret to create a volume using qemu-img, the
4
returns non-null when it doesn't set @local_err. Check the return
4
following error happens:
5
value instead, like all the other callers do.
6
5
7
Fixes: CID 1393615
6
$ qemu-img create -f luks --object secret,id=vol_1_encrypt0,file=vol_resize_pool.vol_1.secret.qzVQrI -o key-secret=vol_1_encrypt0 /var/tmp/pool_target/vol_1 10240K
8
Fixes: CID 1393616
7
9
Signed-off-by: Markus Armbruster <armbru@redhat.com>
8
Formatting '/var/tmp/pool_target/vol_1', fmt=luks size=10485760 key-secret=vol_1_encrypt0
9
qemu-img: /var/tmp/pool_target/vol_1: Data from secret vol_1_encrypt0 is not valid UTF-8
10
11
However, the created file '/var/tmp/pool_target/vol_1' is left behind in the
12
file system after the failure. This behavior can be observed when creating
13
the volume using Libvirt, via 'virsh vol-create', and then getting "volume
14
target path already exist" errors when trying to re-create the volume.
15
16
The volume file is created inside block_crypto_co_create_opts_luks(), in
17
block/crypto.c. If the bdrv_create_file() call is successful but any
18
succeeding step fails*, the existing 'fail' label does not take into
19
account the created file, leaving it behind.
20
21
This patch changes block_crypto_co_create_opts_luks() to delete
22
'filename' in case of failure. A failure in this point means that
23
the volume is now truncated/corrupted, so even if 'filename' was an
24
existing volume before calling qemu-img, it is now unusable. Deleting
25
the file it is not much worse than leaving it in the filesystem in
26
this scenario, and we don't have to deal with checking the file
27
pre-existence in the code.
28
29
* in our case, block_crypto_co_create_generic calls qcrypto_block_create,
30
which calls qcrypto_block_luks_create, and this function fails when
31
calling qcrypto_secret_lookup_as_utf8.
32
33
Reported-by: Srikanth Aithal <bssrikanth@in.ibm.com>
34
Suggested-by: Kevin Wolf <kwolf@redhat.com>
35
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
36
Message-Id: <20200130213907.2830642-4-danielhb413@gmail.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
37
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
38
---
12
block/crypto.c | 4 ++--
39
block/crypto.c | 18 ++++++++++++++++++
13
1 file changed, 2 insertions(+), 2 deletions(-)
40
1 file changed, 18 insertions(+)
14
41
15
diff --git a/block/crypto.c b/block/crypto.c
42
diff --git a/block/crypto.c b/block/crypto.c
16
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
17
--- a/block/crypto.c
44
--- a/block/crypto.c
18
+++ b/block/crypto.c
45
+++ b/block/crypto.c
19
@@ -XXX,XX +XXX,XX @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
46
@@ -XXX,XX +XXX,XX @@
20
ret->format = format;
47
#include "qapi/error.h"
21
48
#include "qemu/module.h"
22
v = qobject_input_visitor_new_flat_confused(opts, &local_err);
49
#include "qemu/option.h"
23
- if (local_err) {
50
+#include "qemu/cutils.h"
24
+ if (!v) {
51
#include "crypto.h"
25
goto out;
52
26
}
53
typedef struct BlockCrypto BlockCrypto;
27
54
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
28
@@ -XXX,XX +XXX,XX @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
55
29
ret->format = format;
56
ret = 0;
30
57
fail:
31
v = qobject_input_visitor_new_flat_confused(opts, &local_err);
58
+ /*
32
- if (local_err) {
59
+ * If an error occurred, delete 'filename'. Even if the file existed
33
+ if (!v) {
60
+ * beforehand, it has been truncated and corrupted in the process.
34
goto out;
61
+ */
35
}
62
+ if (ret && bs) {
36
63
+ Error *local_delete_err = NULL;
64
+ int r_del = bdrv_co_delete_file(bs, &local_delete_err);
65
+ /*
66
+ * ENOTSUP will happen if the block driver doesn't support
67
+ * the 'bdrv_co_delete_file' interface. This is a predictable
68
+ * scenario and shouldn't be reported back to the user.
69
+ */
70
+ if ((r_del < 0) && (r_del != -ENOTSUP)) {
71
+ error_report_err(local_delete_err);
72
+ }
73
+ }
74
+
75
bdrv_unref(bs);
76
qapi_free_QCryptoBlockCreateOptions(create_opts);
77
qobject_unref(cryptoopts);
37
--
78
--
38
2.13.6
79
2.20.1
39
80
40
81
diff view generated by jsdifflib
Deleted patch
1
The error handling policy was traditionally set with -drive, but with
2
-blockdev it is no longer possible to set frontend options. scsi-disk
3
(and other block devices) have long supported qdev properties to
4
configure the error handling policy, so let's add these options to
5
usb-storage as well and just forward them to the internal scsi-disk
6
instance.
7
1
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
10
---
11
include/hw/scsi/scsi.h | 2 ++
12
hw/scsi/scsi-bus.c | 11 ++++++++++-
13
hw/usb/dev-storage.c | 2 ++
14
3 files changed, 14 insertions(+), 1 deletion(-)
15
16
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/scsi/scsi.h
19
+++ b/include/hw/scsi/scsi.h
20
@@ -XXX,XX +XXX,XX @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
21
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
22
int unit, bool removable, int bootindex,
23
bool share_rw,
24
+ BlockdevOnError rerror,
25
+ BlockdevOnError werror,
26
const char *serial, Error **errp);
27
void scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
28
void scsi_legacy_handle_cmdline(void);
29
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/hw/scsi/scsi-bus.c
32
+++ b/hw/scsi/scsi-bus.c
33
@@ -XXX,XX +XXX,XX @@ static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp)
34
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
35
int unit, bool removable, int bootindex,
36
bool share_rw,
37
+ BlockdevOnError rerror,
38
+ BlockdevOnError werror,
39
const char *serial, Error **errp)
40
{
41
const char *driver;
42
@@ -XXX,XX +XXX,XX @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
43
object_unparent(OBJECT(dev));
44
return NULL;
45
}
46
+
47
+ qdev_prop_set_enum(dev, "rerror", rerror);
48
+ qdev_prop_set_enum(dev, "werror", werror);
49
+
50
object_property_set_bool(OBJECT(dev), true, "realized", &err);
51
if (err != NULL) {
52
error_propagate(errp, err);
53
@@ -XXX,XX +XXX,XX @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
54
}
55
qemu_opts_loc_restore(dinfo->opts);
56
scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo),
57
- unit, false, -1, false, NULL, &error_fatal);
58
+ unit, false, -1, false,
59
+ BLOCKDEV_ON_ERROR_AUTO,
60
+ BLOCKDEV_ON_ERROR_AUTO,
61
+ NULL, &error_fatal);
62
}
63
loc_pop(&loc);
64
}
65
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/hw/usb/dev-storage.c
68
+++ b/hw/usb/dev-storage.c
69
@@ -XXX,XX +XXX,XX @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
70
&usb_msd_scsi_info_storage, NULL);
71
scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
72
s->conf.bootindex, s->conf.share_rw,
73
+ s->conf.rerror, s->conf.werror,
74
dev->serial,
75
errp);
76
blk_unref(blk);
77
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_usb_msd = {
78
79
static Property msd_properties[] = {
80
DEFINE_BLOCK_PROPERTIES(MSDState, conf),
81
+ DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf),
82
DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
83
DEFINE_PROP_END_OF_LIST(),
84
};
85
--
86
2.13.6
87
88
diff view generated by jsdifflib
Deleted patch
1
From: Weiping Zhang <zhangweiping@didichuxing.com>
2
1
3
Add an optional paramter num_queues for device, and set it
4
to 64 by default.
5
6
Signed-off-by: Weiping Zhang <zhangweiping@didichuxing.com>
7
Acked-by: Keith Busch <keith.busch@intel.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
hw/block/nvme.c | 5 +++--
11
1 file changed, 3 insertions(+), 2 deletions(-)
12
13
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/block/nvme.c
16
+++ b/hw/block/nvme.c
17
@@ -XXX,XX +XXX,XX @@
18
* Usage: add options:
19
* -drive file=<file>,if=none,id=<drive_id>
20
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
21
- * cmb_size_mb=<cmb_size_mb[optional]>
22
+ * cmb_size_mb=<cmb_size_mb[optional]>, \
23
+ * num_queues=<N[optional]>
24
*
25
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
26
* offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
27
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
28
pcie_endpoint_cap_init(&n->parent_obj, 0x80);
29
30
n->num_namespaces = 1;
31
- n->num_queues = 64;
32
n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4);
33
n->ns_size = bs_size / (uint64_t)n->num_namespaces;
34
35
@@ -XXX,XX +XXX,XX @@ static Property nvme_props[] = {
36
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
37
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
38
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
39
+ DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
40
DEFINE_PROP_END_OF_LIST(),
41
};
42
43
--
44
2.13.6
45
46
diff view generated by jsdifflib
Deleted patch
1
If qcow2_alloc_clusters_at() returns an error, we do need to negate it
2
to get back the positive errno code for error_setg_errno(), but we still
3
need to return the negative error code.
4
1
5
Fixes: 772d1f973f87269f6a4a4ea4b880680f3779bbdf
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
9
block/qcow2.c | 2 +-
10
1 file changed, 1 insertion(+), 1 deletion(-)
11
12
diff --git a/block/qcow2.c b/block/qcow2.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/qcow2.c
15
+++ b/block/qcow2.c
16
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
17
if (clusters_allocated < 0) {
18
error_setg_errno(errp, -clusters_allocated,
19
"Failed to allocate data clusters");
20
- return -clusters_allocated;
21
+ return clusters_allocated;
22
}
23
24
assert(clusters_allocated == nb_new_data_clusters);
25
--
26
2.13.6
27
28
diff view generated by jsdifflib
Deleted patch
1
All callers are coroutine_fns now, so we can just directly call
2
preallocate_co().
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/qcow2.c | 51 ++++++++-------------------------------------------
8
1 file changed, 8 insertions(+), 43 deletions(-)
9
10
diff --git a/block/qcow2.c b/block/qcow2.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qcow2.c
13
+++ b/block/qcow2.c
14
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs,
15
return ret;
16
}
17
18
-
19
-typedef struct PreallocCo {
20
- BlockDriverState *bs;
21
- uint64_t offset;
22
- uint64_t new_length;
23
-
24
- int ret;
25
-} PreallocCo;
26
-
27
/**
28
* Preallocates metadata structures for data clusters between @offset (in the
29
* guest disk) and @new_length (which is thus generally the new guest disk
30
@@ -XXX,XX +XXX,XX @@ typedef struct PreallocCo {
31
*
32
* Returns: 0 on success, -errno on failure.
33
*/
34
-static void coroutine_fn preallocate_co(void *opaque)
35
+static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
36
+ uint64_t new_length)
37
{
38
- PreallocCo *params = opaque;
39
- BlockDriverState *bs = params->bs;
40
- uint64_t offset = params->offset;
41
- uint64_t new_length = params->new_length;
42
uint64_t bytes;
43
uint64_t host_offset = 0;
44
unsigned int cur_bytes;
45
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn preallocate_co(void *opaque)
46
ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
47
&host_offset, &meta);
48
if (ret < 0) {
49
- goto done;
50
+ return ret;
51
}
52
53
while (meta) {
54
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn preallocate_co(void *opaque)
55
if (ret < 0) {
56
qcow2_free_any_clusters(bs, meta->alloc_offset,
57
meta->nb_clusters, QCOW2_DISCARD_NEVER);
58
- goto done;
59
+ return ret;
60
}
61
62
/* There are no dependent requests, but we need to remove our
63
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn preallocate_co(void *opaque)
64
ret = bdrv_pwrite(bs->file, (host_offset + cur_bytes) - 1,
65
&data, 1);
66
if (ret < 0) {
67
- goto done;
68
+ return ret;
69
}
70
}
71
72
- ret = 0;
73
-
74
-done:
75
- params->ret = ret;
76
-}
77
-
78
-static int preallocate(BlockDriverState *bs,
79
- uint64_t offset, uint64_t new_length)
80
-{
81
- PreallocCo params = {
82
- .bs = bs,
83
- .offset = offset,
84
- .new_length = new_length,
85
- .ret = -EINPROGRESS,
86
- };
87
-
88
- if (qemu_in_coroutine()) {
89
- preallocate_co(&params);
90
- } else {
91
- Coroutine *co = qemu_coroutine_create(preallocate_co, &params);
92
- bdrv_coroutine_enter(bs, co);
93
- BDRV_POLL_WHILE(bs, params.ret == -EINPROGRESS);
94
- }
95
- return params.ret;
96
+ return 0;
97
}
98
99
/* qcow2_refcount_metadata_size:
100
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
101
if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) {
102
BDRVQcow2State *s = blk_bs(blk)->opaque;
103
qemu_co_mutex_lock(&s->lock);
104
- ret = preallocate(blk_bs(blk), 0, qcow2_opts->size);
105
+ ret = preallocate_co(blk_bs(blk), 0, qcow2_opts->size);
106
qemu_co_mutex_unlock(&s->lock);
107
108
if (ret < 0) {
109
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
110
break;
111
112
case PREALLOC_MODE_METADATA:
113
- ret = preallocate(bs, old_length, offset);
114
+ ret = preallocate_co(bs, old_length, offset);
115
if (ret < 0) {
116
error_setg_errno(errp, -ret, "Preallocation failed");
117
goto fail;
118
--
119
2.13.6
120
121
diff view generated by jsdifflib
Deleted patch
1
When growing an image, block drivers (especially protocol drivers) may
2
initialise the newly added area. I/O requests to the same area need to
3
wait for this initialisation to be completed so that data writes don't
4
get overwritten and reads don't read uninitialised data.
5
1
6
To avoid overhead in the fast I/O path by adding new locking in the
7
protocol drivers and to restrict the impact to requests that actually
8
touch the new area, reuse the existing tracked request infrastructure in
9
block/io.c and mark all discard requests as serialising.
10
11
With this change, it is safe for protocol drivers to make
12
.bdrv_co_truncate actually asynchronous.
13
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
---
17
include/block/block_int.h | 1 +
18
block/io.c | 25 +++++++++++++++++++++++++
19
2 files changed, 26 insertions(+)
20
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/block/block_int.h
24
+++ b/include/block/block_int.h
25
@@ -XXX,XX +XXX,XX @@ enum BdrvTrackedRequestType {
26
BDRV_TRACKED_READ,
27
BDRV_TRACKED_WRITE,
28
BDRV_TRACKED_DISCARD,
29
+ BDRV_TRACKED_TRUNCATE,
30
};
31
32
typedef struct BdrvTrackedRequest {
33
diff --git a/block/io.c b/block/io.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/block/io.c
36
+++ b/block/io.c
37
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
38
{
39
BlockDriverState *bs = child->bs;
40
BlockDriver *drv = bs->drv;
41
+ BdrvTrackedRequest req;
42
+ int64_t old_size, new_bytes;
43
int ret;
44
45
assert(child->perm & BLK_PERM_RESIZE);
46
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
47
return -EINVAL;
48
}
49
50
+ old_size = bdrv_getlength(bs);
51
+ if (old_size < 0) {
52
+ error_setg_errno(errp, -old_size, "Failed to get old image size");
53
+ return old_size;
54
+ }
55
+
56
+ if (offset > old_size) {
57
+ new_bytes = offset - old_size;
58
+ } else {
59
+ new_bytes = 0;
60
+ }
61
+
62
bdrv_inc_in_flight(bs);
63
+ tracked_request_begin(&req, bs, offset, new_bytes, BDRV_TRACKED_TRUNCATE);
64
+
65
+ /* If we are growing the image and potentially using preallocation for the
66
+ * new area, we need to make sure that no write requests are made to it
67
+ * concurrently or they might be overwritten by preallocation. */
68
+ if (new_bytes) {
69
+ mark_request_serialising(&req, 1);
70
+ wait_serialising_requests(&req);
71
+ }
72
73
if (!drv->bdrv_co_truncate) {
74
if (bs->file && drv->is_filter) {
75
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
76
atomic_inc(&bs->write_gen);
77
78
out:
79
+ tracked_request_end(&req);
80
bdrv_dec_in_flight(bs);
81
+
82
return ret;
83
}
84
85
--
86
2.13.6
87
88
diff view generated by jsdifflib
Deleted patch
1
From: Fam Zheng <famz@redhat.com>
2
1
3
In the beginning of the function, we initialize the local variable to 0,
4
and in the body of the function, we check the assigned values and exit
5
the loop immediately. So here it can never be non-zero.
6
7
Reported-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Fam Zheng <famz@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block/qcow2.c | 2 +-
14
1 file changed, 1 insertion(+), 1 deletion(-)
15
16
diff --git a/block/qcow2.c b/block/qcow2.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.c
19
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs,
21
while (l2meta != NULL) {
22
QCowL2Meta *next;
23
24
- if (!ret && link_l2) {
25
+ if (link_l2) {
26
ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
27
if (ret) {
28
goto out;
29
--
30
2.13.6
31
32
diff view generated by jsdifflib
Deleted patch
1
From: Fam Zheng <famz@redhat.com>
2
1
3
in_flight and tracked requests need to be tracked in every layer during
4
recursion. For now the only user is qemu-img convert where overlapping
5
requests and IOThreads don't exist, therefore this change doesn't make
6
much difference form user point of view, but it is incorrect as part of
7
the API. Fix it.
8
9
Reported-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Fam Zheng <famz@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
block/io.c | 59 ++++++++++++++++++++++++++++-------------------------------
15
1 file changed, 28 insertions(+), 31 deletions(-)
16
17
diff --git a/block/io.c b/block/io.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/io.c
20
+++ b/block/io.c
21
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
22
BdrvRequestFlags flags,
23
bool recurse_src)
24
{
25
+ BdrvTrackedRequest src_req, dst_req;
26
+ BlockDriverState *src_bs = src->bs;
27
+ BlockDriverState *dst_bs = dst->bs;
28
int ret;
29
30
if (!src || !dst || !src->bs || !dst->bs) {
31
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
32
|| src->bs->encrypted || dst->bs->encrypted) {
33
return -ENOTSUP;
34
}
35
+ bdrv_inc_in_flight(src_bs);
36
+ bdrv_inc_in_flight(dst_bs);
37
+ tracked_request_begin(&src_req, src_bs, src_offset,
38
+ bytes, BDRV_TRACKED_READ);
39
+ tracked_request_begin(&dst_req, dst_bs, dst_offset,
40
+ bytes, BDRV_TRACKED_WRITE);
41
+
42
+ wait_serialising_requests(&src_req);
43
+ wait_serialising_requests(&dst_req);
44
if (recurse_src) {
45
- return src->bs->drv->bdrv_co_copy_range_from(src->bs,
46
- src, src_offset,
47
- dst, dst_offset,
48
- bytes, flags);
49
+ ret = src->bs->drv->bdrv_co_copy_range_from(src->bs,
50
+ src, src_offset,
51
+ dst, dst_offset,
52
+ bytes, flags);
53
} else {
54
- return dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
55
- src, src_offset,
56
- dst, dst_offset,
57
- bytes, flags);
58
+ ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
59
+ src, src_offset,
60
+ dst, dst_offset,
61
+ bytes, flags);
62
}
63
+ tracked_request_end(&src_req);
64
+ tracked_request_end(&dst_req);
65
+ bdrv_dec_in_flight(src_bs);
66
+ bdrv_dec_in_flight(dst_bs);
67
+ return ret;
68
}
69
70
/* Copy range from @src to @dst.
71
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
72
BdrvChild *dst, uint64_t dst_offset,
73
uint64_t bytes, BdrvRequestFlags flags)
74
{
75
- BdrvTrackedRequest src_req, dst_req;
76
- BlockDriverState *src_bs = src->bs;
77
- BlockDriverState *dst_bs = dst->bs;
78
- int ret;
79
-
80
- bdrv_inc_in_flight(src_bs);
81
- bdrv_inc_in_flight(dst_bs);
82
- tracked_request_begin(&src_req, src_bs, src_offset,
83
- bytes, BDRV_TRACKED_READ);
84
- tracked_request_begin(&dst_req, dst_bs, dst_offset,
85
- bytes, BDRV_TRACKED_WRITE);
86
-
87
- wait_serialising_requests(&src_req);
88
- wait_serialising_requests(&dst_req);
89
- ret = bdrv_co_copy_range_from(src, src_offset,
90
- dst, dst_offset,
91
- bytes, flags);
92
-
93
- tracked_request_end(&src_req);
94
- tracked_request_end(&dst_req);
95
- bdrv_dec_in_flight(src_bs);
96
- bdrv_dec_in_flight(dst_bs);
97
- return ret;
98
+ return bdrv_co_copy_range_from(src, src_offset,
99
+ dst, dst_offset,
100
+ bytes, flags);
101
}
102
103
static void bdrv_parent_cb_resize(BlockDriverState *bs)
104
--
105
2.13.6
106
107
diff view generated by jsdifflib
Deleted patch
1
Commit abf754fe406 updated 026.out, but forgot to also update
2
026.out.nocache.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
7
tests/qemu-iotests/026.out.nocache | 6 +++---
8
1 file changed, 3 insertions(+), 3 deletions(-)
9
10
diff --git a/tests/qemu-iotests/026.out.nocache b/tests/qemu-iotests/026.out.nocache
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/qemu-iotests/026.out.nocache
13
+++ b/tests/qemu-iotests/026.out.nocache
14
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
15
Failed to flush the refcount block cache: No space left on device
16
write failed: No space left on device
17
18
-11 leaked clusters were found on the image.
19
+10 leaked clusters were found on the image.
20
This means waste of disk space, but no harm to data.
21
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
22
23
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
24
Failed to flush the refcount block cache: No space left on device
25
write failed: No space left on device
26
27
-11 leaked clusters were found on the image.
28
+10 leaked clusters were found on the image.
29
This means waste of disk space, but no harm to data.
30
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
31
32
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
33
Failed to flush the refcount block cache: No space left on device
34
write failed: No space left on device
35
36
-11 leaked clusters were found on the image.
37
+10 leaked clusters were found on the image.
38
This means waste of disk space, but no harm to data.
39
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
40
41
--
42
2.13.6
43
44
diff view generated by jsdifflib
Deleted patch
1
If we managed to allocate the clusters, but then failed to write the
2
data, there's a good chance that we'll still be able to free the
3
clusters again in order to avoid cluster leaks (the refcounts are
4
cached, so even if we can't write them out right now, we may be able to
5
do so when the VM is resumed after a werror=stop/enospc pause).
6
1
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Tested-by: Eric Blake <eblake@redhat.com>
11
---
12
block/qcow2.h | 1 +
13
block/qcow2-cluster.c | 11 +++++++++++
14
block/qcow2.c | 2 ++
15
3 files changed, 14 insertions(+)
16
17
diff --git a/block/qcow2.h b/block/qcow2.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2.h
20
+++ b/block/qcow2.h
21
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
22
int compressed_size);
23
24
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
25
+void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
26
int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
27
uint64_t bytes, enum qcow2_discard_type type,
28
bool full_discard);
29
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2-cluster.c
32
+++ b/block/qcow2-cluster.c
33
@@ -XXX,XX +XXX,XX @@ err:
34
return ret;
35
}
36
37
+/**
38
+ * Frees the allocated clusters because the request failed and they won't
39
+ * actually be linked.
40
+ */
41
+void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
42
+{
43
+ BDRVQcow2State *s = bs->opaque;
44
+ qcow2_free_clusters(bs, m->alloc_offset, m->nb_clusters << s->cluster_bits,
45
+ QCOW2_DISCARD_NEVER);
46
+}
47
+
48
/*
49
* Returns the number of contiguous clusters that can be used for an allocating
50
* write, but require COW to be performed (this includes yet unallocated space,
51
diff --git a/block/qcow2.c b/block/qcow2.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/block/qcow2.c
54
+++ b/block/qcow2.c
55
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs,
56
if (ret) {
57
goto out;
58
}
59
+ } else {
60
+ qcow2_alloc_cluster_abort(bs, l2meta);
61
}
62
63
/* Take the request off the list of running requests */
64
--
65
2.13.6
66
67
diff view generated by jsdifflib
Deleted patch
1
This adds a test for a temporary write failure, which simulates the
2
situation after werror=stop/enospc has stopped the VM. We shouldn't
3
leave leaked clusters behind in such cases.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/026 | 17 +++++++++++++++++
9
tests/qemu-iotests/026.out | 8 ++++++++
10
tests/qemu-iotests/026.out.nocache | 8 ++++++++
11
3 files changed, 33 insertions(+)
12
13
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
14
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/026
16
+++ b/tests/qemu-iotests/026
17
@@ -XXX,XX +XXX,XX @@ done
18
done
19
done
20
21
+echo
22
+echo === Avoid cluster leaks after temporary failure ===
23
+echo
24
+
25
+cat > "$TEST_DIR/blkdebug.conf" <<EOF
26
+[inject-error]
27
+event = "write_aio"
28
+errno = "5"
29
+once = "on"
30
+EOF
31
+
32
+# After the failed first write, do a second write so that the updated refcount
33
+# block is actually written back
34
+_make_test_img 64M
35
+$QEMU_IO -c "write 0 1M" -c "write 0 1M" "$BLKDBG_TEST_IMG" | _filter_qemu_io
36
+_check_test_img
37
+
38
# success, all done
39
echo "*** done"
40
rm -f $seq.full
41
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
42
index XXXXXXX..XXXXXXX 100644
43
--- a/tests/qemu-iotests/026.out
44
+++ b/tests/qemu-iotests/026.out
45
@@ -XXX,XX +XXX,XX @@ write failed: No space left on device
46
47
96 leaked clusters were found on the image.
48
This means waste of disk space, but no harm to data.
49
+
50
+=== Avoid cluster leaks after temporary failure ===
51
+
52
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
53
+write failed: Input/output error
54
+wrote 1048576/1048576 bytes at offset 0
55
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
56
+No errors were found on the image.
57
*** done
58
diff --git a/tests/qemu-iotests/026.out.nocache b/tests/qemu-iotests/026.out.nocache
59
index XXXXXXX..XXXXXXX 100644
60
--- a/tests/qemu-iotests/026.out.nocache
61
+++ b/tests/qemu-iotests/026.out.nocache
62
@@ -XXX,XX +XXX,XX @@ write failed: No space left on device
63
64
96 leaked clusters were found on the image.
65
This means waste of disk space, but no harm to data.
66
+
67
+=== Avoid cluster leaks after temporary failure ===
68
+
69
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
70
+write failed: Input/output error
71
+wrote 1048576/1048576 bytes at offset 0
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
73
+No errors were found on the image.
74
*** done
75
--
76
2.13.6
77
78
diff view generated by jsdifflib
Deleted patch
1
This simplifies file-posix by implementing the coroutine variants of
2
the discard and flush BlockDriver callbacks. These were the last
3
remaining users of paio_submit(), which can be removed now.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
block/file-posix.c | 72 ++++++++++++++++++------------------------------------
9
1 file changed, 24 insertions(+), 48 deletions(-)
10
11
diff --git a/block/file-posix.c b/block/file-posix.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/file-posix.c
14
+++ b/block/file-posix.c
15
@@ -XXX,XX +XXX,XX @@ static inline int paio_submit_co(BlockDriverState *bs, int fd,
16
return paio_submit_co_full(bs, fd, offset, -1, 0, qiov, bytes, type);
17
}
18
19
-static BlockAIOCB *paio_submit(BlockDriverState *bs, int fd,
20
- int64_t offset, QEMUIOVector *qiov, int bytes,
21
- BlockCompletionFunc *cb, void *opaque, int type)
22
-{
23
- RawPosixAIOData *acb = g_new(RawPosixAIOData, 1);
24
- ThreadPool *pool;
25
-
26
- acb->bs = bs;
27
- acb->aio_type = type;
28
- acb->aio_fildes = fd;
29
-
30
- acb->aio_nbytes = bytes;
31
- acb->aio_offset = offset;
32
-
33
- if (qiov) {
34
- acb->aio_iov = qiov->iov;
35
- acb->aio_niov = qiov->niov;
36
- assert(qiov->size == acb->aio_nbytes);
37
- }
38
-
39
- trace_paio_submit(acb, opaque, offset, bytes, type);
40
- pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
41
- return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
42
-}
43
-
44
static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
45
uint64_t bytes, QEMUIOVector *qiov, int type)
46
{
47
@@ -XXX,XX +XXX,XX @@ static void raw_aio_unplug(BlockDriverState *bs)
48
#endif
49
}
50
51
-static BlockAIOCB *raw_aio_flush(BlockDriverState *bs,
52
- BlockCompletionFunc *cb, void *opaque)
53
+static int raw_co_flush_to_disk(BlockDriverState *bs)
54
{
55
BDRVRawState *s = bs->opaque;
56
+ int ret;
57
58
- if (fd_open(bs) < 0)
59
- return NULL;
60
+ ret = fd_open(bs);
61
+ if (ret < 0) {
62
+ return ret;
63
+ }
64
65
- return paio_submit(bs, s->fd, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
66
+ return paio_submit_co(bs, s->fd, 0, NULL, 0, QEMU_AIO_FLUSH);
67
}
68
69
static void raw_aio_attach_aio_context(BlockDriverState *bs,
70
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_invalidate_cache(BlockDriverState *bs,
71
#endif /* !__linux__ */
72
}
73
74
-static coroutine_fn BlockAIOCB *raw_aio_pdiscard(BlockDriverState *bs,
75
- int64_t offset, int bytes,
76
- BlockCompletionFunc *cb, void *opaque)
77
+static coroutine_fn int
78
+raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
79
{
80
BDRVRawState *s = bs->opaque;
81
82
- return paio_submit(bs, s->fd, offset, NULL, bytes,
83
- cb, opaque, QEMU_AIO_DISCARD);
84
+ return paio_submit_co(bs, s->fd, offset, NULL, bytes, QEMU_AIO_DISCARD);
85
}
86
87
static int coroutine_fn raw_co_pwrite_zeroes(
88
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
89
90
.bdrv_co_preadv = raw_co_preadv,
91
.bdrv_co_pwritev = raw_co_pwritev,
92
- .bdrv_aio_flush = raw_aio_flush,
93
- .bdrv_aio_pdiscard = raw_aio_pdiscard,
94
+ .bdrv_co_flush_to_disk = raw_co_flush_to_disk,
95
+ .bdrv_co_pdiscard = raw_co_pdiscard,
96
.bdrv_co_copy_range_from = raw_co_copy_range_from,
97
.bdrv_co_copy_range_to = raw_co_copy_range_to,
98
.bdrv_refresh_limits = raw_refresh_limits,
99
@@ -XXX,XX +XXX,XX @@ static int fd_open(BlockDriverState *bs)
100
return -EIO;
101
}
102
103
-static coroutine_fn BlockAIOCB *hdev_aio_pdiscard(BlockDriverState *bs,
104
- int64_t offset, int bytes,
105
- BlockCompletionFunc *cb, void *opaque)
106
+static coroutine_fn int
107
+hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
108
{
109
BDRVRawState *s = bs->opaque;
110
+ int ret;
111
112
- if (fd_open(bs) < 0) {
113
- return NULL;
114
+ ret = fd_open(bs);
115
+ if (ret < 0) {
116
+ return ret;
117
}
118
- return paio_submit(bs, s->fd, offset, NULL, bytes,
119
- cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
120
+ return paio_submit_co(bs, s->fd, offset, NULL, bytes,
121
+ QEMU_AIO_DISCARD | QEMU_AIO_BLKDEV);
122
}
123
124
static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
125
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = {
126
127
.bdrv_co_preadv = raw_co_preadv,
128
.bdrv_co_pwritev = raw_co_pwritev,
129
- .bdrv_aio_flush    = raw_aio_flush,
130
- .bdrv_aio_pdiscard = hdev_aio_pdiscard,
131
+ .bdrv_co_flush_to_disk = raw_co_flush_to_disk,
132
+ .bdrv_co_pdiscard = hdev_co_pdiscard,
133
.bdrv_co_copy_range_from = raw_co_copy_range_from,
134
.bdrv_co_copy_range_to = raw_co_copy_range_to,
135
.bdrv_refresh_limits = raw_refresh_limits,
136
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = {
137
138
.bdrv_co_preadv = raw_co_preadv,
139
.bdrv_co_pwritev = raw_co_pwritev,
140
- .bdrv_aio_flush    = raw_aio_flush,
141
+ .bdrv_co_flush_to_disk = raw_co_flush_to_disk,
142
.bdrv_refresh_limits = raw_refresh_limits,
143
.bdrv_io_plug = raw_aio_plug,
144
.bdrv_io_unplug = raw_aio_unplug,
145
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = {
146
147
.bdrv_co_preadv = raw_co_preadv,
148
.bdrv_co_pwritev = raw_co_pwritev,
149
- .bdrv_aio_flush    = raw_aio_flush,
150
+ .bdrv_co_flush_to_disk = raw_co_flush_to_disk,
151
.bdrv_refresh_limits = raw_refresh_limits,
152
.bdrv_io_plug = raw_aio_plug,
153
.bdrv_io_unplug = raw_aio_unplug,
154
--
155
2.13.6
156
157
diff view generated by jsdifflib
Deleted patch
1
From: Fam Zheng <famz@redhat.com>
2
1
3
Not updating src_offset will result in wrong data being written to dst
4
image.
5
6
Reported-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Fam Zheng <famz@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
block/qcow2.c | 1 +
11
tests/qemu-iotests/063 | 9 +++++++++
12
tests/qemu-iotests/063.out | 12 ++++++++++++
13
3 files changed, 22 insertions(+)
14
15
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2.c
18
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
20
}
21
22
bytes -= cur_bytes;
23
+ src_offset += cur_bytes;
24
dst_offset += cur_bytes;
25
}
26
ret = 0;
27
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
28
index XXXXXXX..XXXXXXX 100755
29
--- a/tests/qemu-iotests/063
30
+++ b/tests/qemu-iotests/063
31
@@ -XXX,XX +XXX,XX @@ if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG.orig" "$TEST_IMG" >/dev
32
exit 1
33
fi
34
35
+echo "== Regression testing for copy offloading bug =="
36
+
37
+_make_test_img 1M
38
+TEST_IMG="$TEST_IMG.target" _make_test_img 1M
39
+$QEMU_IO -c 'write -P 1 0 512k' -c 'write -P 2 512k 512k' "$TEST_IMG" | _filter_qemu_io
40
+$QEMU_IO -c 'write -P 4 512k 512k' -c 'write -P 3 0 512k' "$TEST_IMG.target" | _filter_qemu_io
41
+$QEMU_IMG convert -n -O $IMGFMT "$TEST_IMG" "$TEST_IMG.target"
42
+$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.target"
43
+
44
echo "*** done"
45
rm -f $seq.full
46
status=0
47
diff --git a/tests/qemu-iotests/063.out b/tests/qemu-iotests/063.out
48
index XXXXXXX..XXXXXXX 100644
49
--- a/tests/qemu-iotests/063.out
50
+++ b/tests/qemu-iotests/063.out
51
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
52
No errors were found on the image.
53
== Testing conversion to a smaller file fails ==
54
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
55
+== Regression testing for copy offloading bug ==
56
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
57
+Formatting 'TEST_DIR/t.IMGFMT.target', fmt=IMGFMT size=1048576
58
+wrote 524288/524288 bytes at offset 0
59
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
60
+wrote 524288/524288 bytes at offset 524288
61
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
62
+wrote 524288/524288 bytes at offset 524288
63
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
64
+wrote 524288/524288 bytes at offset 0
65
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
66
+Images are identical.
67
*** done
68
--
69
2.13.6
70
71
diff view generated by jsdifflib
Deleted patch
1
From: Fam Zheng <famz@redhat.com>
2
1
3
Per SCSI definition the designator_length we receive from INQUIRY is 8,
4
12 or at most 16, but we should be careful because the remote iscsi
5
target may misbehave, otherwise we could have a buffer overflow.
6
7
Reported-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Fam Zheng <famz@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block/iscsi.c | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
14
diff --git a/block/iscsi.c b/block/iscsi.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/iscsi.c
17
+++ b/block/iscsi.c
18
@@ -XXX,XX +XXX,XX @@ static void iscsi_populate_target_desc(unsigned char *desc, IscsiLun *lun)
19
desc[5] = (dd->designator_type & 0xF)
20
| ((dd->association & 3) << 4);
21
desc[7] = dd->designator_length;
22
- memcpy(desc + 8, dd->designator, dd->designator_length);
23
+ memcpy(desc + 8, dd->designator, MIN(dd->designator_length, 20));
24
25
desc[28] = 0;
26
desc[29] = (lun->block_size >> 16) & 0xFF;
27
--
28
2.13.6
29
30
diff view generated by jsdifflib
Deleted patch
1
From: Fam Zheng <famz@redhat.com>
2
1
3
EINTR should be checked against errno, not ret. While fixing the bug,
4
collect the branches with a switch block.
5
6
Also, change the return value from -ENOSTUP to -ENOSPC when the actual
7
issue is request range passes EOF, which should be distinguishable from
8
the case of error == ENOSYS by the caller, so that it could still retry
9
with other byte ranges, whereas it shouldn't retry anymore upon ENOSYS.
10
11
Signed-off-by: Fam Zheng <famz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
block/file-posix.c | 17 +++++++++--------
15
1 file changed, 9 insertions(+), 8 deletions(-)
16
17
diff --git a/block/file-posix.c b/block/file-posix.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/file-posix.c
20
+++ b/block/file-posix.c
21
@@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_copy_range(RawPosixAIOData *aiocb)
22
ssize_t ret = copy_file_range(aiocb->aio_fildes, &in_off,
23
aiocb->aio_fd2, &out_off,
24
bytes, 0);
25
- if (ret == -EINTR) {
26
- continue;
27
+ if (ret == 0) {
28
+ /* No progress (e.g. when beyond EOF), let the caller fall back to
29
+ * buffer I/O. */
30
+ return -ENOSPC;
31
}
32
if (ret < 0) {
33
- if (errno == ENOSYS) {
34
+ switch (errno) {
35
+ case ENOSYS:
36
return -ENOTSUP;
37
- } else {
38
+ case EINTR:
39
+ continue;
40
+ default:
41
return -errno;
42
}
43
}
44
- if (!ret) {
45
- /* No progress (e.g. when beyond EOF), fall back to buffer I/O. */
46
- return -ENOTSUP;
47
- }
48
bytes -= ret;
49
}
50
return 0;
51
--
52
2.13.6
53
54
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
We are gradually moving away from sector-based interfaces, towards
4
byte-based. Make the change for the last few sector-based calls
5
into the block layer from the parallels driver.
6
7
Ideally, the parallels driver should switch to doing everything
8
byte-based, but that's a more invasive change that requires a
9
bit more auditing.
10
11
Signed-off-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Denis V. Lunev <den@openvz.org>
14
Reviewed-by: Jeff Cody <jcody@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/parallels.c | 16 ++++++++++------
18
1 file changed, 10 insertions(+), 6 deletions(-)
19
20
diff --git a/block/parallels.c b/block/parallels.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/parallels.c
23
+++ b/block/parallels.c
24
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
25
};
26
qemu_iovec_init_external(&qiov, &iov, 1);
27
28
- ret = bdrv_co_readv(bs->backing, idx * s->tracks, nb_cow_sectors,
29
- &qiov);
30
+ ret = bdrv_co_preadv(bs->backing, idx * s->tracks * BDRV_SECTOR_SIZE,
31
+ nb_cow_bytes, &qiov, 0);
32
if (ret < 0) {
33
qemu_vfree(iov.iov_base);
34
return ret;
35
}
36
37
- ret = bdrv_co_writev(bs->file, s->data_end, nb_cow_sectors, &qiov);
38
+ ret = bdrv_co_pwritev(bs->file, s->data_end * BDRV_SECTOR_SIZE,
39
+ nb_cow_bytes, &qiov, 0);
40
qemu_vfree(iov.iov_base);
41
if (ret < 0) {
42
return ret;
43
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
44
qemu_iovec_reset(&hd_qiov);
45
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
46
47
- ret = bdrv_co_writev(bs->file, position, n, &hd_qiov);
48
+ ret = bdrv_co_pwritev(bs->file, position * BDRV_SECTOR_SIZE, nbytes,
49
+ &hd_qiov, 0);
50
if (ret < 0) {
51
break;
52
}
53
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
54
55
if (position < 0) {
56
if (bs->backing) {
57
- ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
58
+ ret = bdrv_co_preadv(bs->backing, sector_num * BDRV_SECTOR_SIZE,
59
+ nbytes, &hd_qiov, 0);
60
if (ret < 0) {
61
break;
62
}
63
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
64
qemu_iovec_memset(&hd_qiov, 0, 0, nbytes);
65
}
66
} else {
67
- ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
68
+ ret = bdrv_co_preadv(bs->file, position * BDRV_SECTOR_SIZE, nbytes,
69
+ &hd_qiov, 0);
70
if (ret < 0) {
71
break;
72
}
73
--
74
2.13.6
75
76
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Daniel Henrique Barboza <danielhb413@gmail.com>
2
2
3
We are gradually moving away from sector-based interfaces, towards
3
This patch adds a new test file to exercise the case where
4
byte-based. Make the change for the internal helper function
4
qemu-img fails to complete for the LUKS format when a non-UTF8
5
get_cluster_offset(), by changing n_start and n_end to be byte
5
secret is used.
6
offsets rather than sector indices within the cluster being
7
allocated. However, assert that these values are still
8
sector-aligned (at least qcrypto_block_encrypt() still wants that).
9
For now we get that alignment for free because we still use
10
sector-based driver callbacks.
11
6
12
A later patch will then switch the qcow driver as a whole over
7
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
13
to byte-based operation; but will still leave things at sector
8
Message-Id: <20200130213907.2830642-5-danielhb413@gmail.com>
14
alignments as it is not worth auditing the qcow image format
15
to worry about sub-sector requests.
16
17
Signed-off-by: Eric Blake <eblake@redhat.com>
18
Reviewed-by: Jeff Cody <jcody@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
10
---
21
block/qcow.c | 29 +++++++++++++++--------------
11
tests/qemu-iotests/282 | 67 ++++++++++++++++++++++++++++++++++++++
22
1 file changed, 15 insertions(+), 14 deletions(-)
12
tests/qemu-iotests/282.out | 11 +++++++
13
tests/qemu-iotests/group | 1 +
14
3 files changed, 79 insertions(+)
15
create mode 100755 tests/qemu-iotests/282
16
create mode 100644 tests/qemu-iotests/282.out
23
17
24
diff --git a/block/qcow.c b/block/qcow.c
18
diff --git a/tests/qemu-iotests/282 b/tests/qemu-iotests/282
19
new file mode 100755
20
index XXXXXXX..XXXXXXX
21
--- /dev/null
22
+++ b/tests/qemu-iotests/282
23
@@ -XXX,XX +XXX,XX @@
24
+#!/usr/bin/env bash
25
+#
26
+# Test qemu-img file cleanup for LUKS when using a non-UTF8 secret
27
+#
28
+# Copyright (C) 2020, IBM Corporation.
29
+#
30
+# This program is free software; you can redistribute it and/or modify
31
+# it under the terms of the GNU General Public License as published by
32
+# the Free Software Foundation; either version 2 of the License, or
33
+# (at your option) any later version.
34
+#
35
+# This program is distributed in the hope that it will be useful,
36
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
37
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38
+# GNU General Public License for more details.
39
+#
40
+# You should have received a copy of the GNU General Public License
41
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
42
+#
43
+
44
+seq=`basename $0`
45
+echo "QA output created by $seq"
46
+
47
+status=1    # failure is the default!
48
+TEST_IMAGE_FILE='vol.img'
49
+
50
+_cleanup()
51
+{
52
+ _cleanup_test_img
53
+ rm non_utf8_secret
54
+ rm -f $TEST_IMAGE_FILE
55
+}
56
+trap "_cleanup; exit \$status" 0 1 2 3 15
57
+
58
+# get standard environment, filters and checks
59
+. ./common.rc
60
+. ./common.filter
61
+
62
+_supported_fmt luks
63
+_supported_proto generic
64
+_unsupported_proto vxhs
65
+
66
+echo "== Create non-UTF8 secret =="
67
+echo -n -e '\x3a\x3c\x3b\xff' > non_utf8_secret
68
+SECRET="secret,id=sec0,file=non_utf8_secret"
69
+
70
+echo "== Throws an error because of invalid UTF-8 secret =="
71
+$QEMU_IMG create -f $IMGFMT --object $SECRET -o "key-secret=sec0" $TEST_IMAGE_FILE 4M
72
+
73
+echo "== Image file should not exist after the error =="
74
+if test -f "$TEST_IMAGE_FILE"; then
75
+ exit 1
76
+fi
77
+
78
+echo "== Create a stub image file and run qemu-img again =="
79
+touch $TEST_IMAGE_FILE
80
+$QEMU_IMG create -f $IMGFMT --object $SECRET -o "key-secret=sec0" $TEST_IMAGE_FILE 4M
81
+
82
+echo "== Pre-existing image file should also be deleted after the error =="
83
+if test -f "$TEST_IMAGE_FILE"; then
84
+ exit 1
85
+fi
86
+
87
+# success, all done
88
+echo "*** done"
89
+rm -f $seq.full
90
+status=0
91
diff --git a/tests/qemu-iotests/282.out b/tests/qemu-iotests/282.out
92
new file mode 100644
93
index XXXXXXX..XXXXXXX
94
--- /dev/null
95
+++ b/tests/qemu-iotests/282.out
96
@@ -XXX,XX +XXX,XX @@
97
+QA output created by 282
98
+== Create non-UTF8 secret ==
99
+== Throws an error because of invalid UTF-8 secret ==
100
+qemu-img: vol.img: Data from secret sec0 is not valid UTF-8
101
+Formatting 'vol.img', fmt=luks size=4194304 key-secret=sec0
102
+== Image file should not exist after the error ==
103
+== Create a stub image file and run qemu-img again ==
104
+qemu-img: vol.img: Data from secret sec0 is not valid UTF-8
105
+Formatting 'vol.img', fmt=luks size=4194304 key-secret=sec0
106
+== Pre-existing image file should also be deleted after the error ==
107
+ *** done
108
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
25
index XXXXXXX..XXXXXXX 100644
109
index XXXXXXX..XXXXXXX 100644
26
--- a/block/qcow.c
110
--- a/tests/qemu-iotests/group
27
+++ b/block/qcow.c
111
+++ b/tests/qemu-iotests/group
28
@@ -XXX,XX +XXX,XX @@ static int qcow_reopen_prepare(BDRVReopenState *state,
112
@@ -XXX,XX +XXX,XX @@
29
*
113
279 rw backing quick
30
* 0 to not allocate.
114
280 rw migration quick
31
*
115
281 rw quick
32
- * 1 to allocate a normal cluster (for sector indexes 'n_start' to
116
+282 rw img quick
33
- * 'n_end')
117
283 auto quick
34
+ * 1 to allocate a normal cluster (for sector-aligned byte offsets 'n_start'
118
284 rw
35
+ * to 'n_end' within the cluster)
119
286 rw quick
36
*
37
* 2 to allocate a compressed cluster of size
38
* 'compressed_size'. 'compressed_size' must be > 0 and <
39
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
40
if (!allocate)
41
return 0;
42
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
43
+ assert(QEMU_IS_ALIGNED(n_start | n_end, BDRV_SECTOR_SIZE));
44
/* allocate a new cluster */
45
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
46
- (n_end - n_start) < s->cluster_sectors) {
47
+ (n_end - n_start) < s->cluster_size) {
48
/* if the cluster is already compressed, we must
49
decompress it in the case it is not completely
50
overwritten */
51
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
52
/* if encrypted, we must initialize the cluster
53
content which won't be written */
54
if (bs->encrypted &&
55
- (n_end - n_start) < s->cluster_sectors) {
56
- uint64_t start_sect;
57
+ (n_end - n_start) < s->cluster_size) {
58
+ uint64_t start_offset;
59
assert(s->crypto);
60
- start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
61
- for(i = 0; i < s->cluster_sectors; i++) {
62
+ start_offset = offset & ~(s->cluster_size - 1);
63
+ for (i = 0; i < s->cluster_size; i += BDRV_SECTOR_SIZE) {
64
if (i < n_start || i >= n_end) {
65
- memset(s->cluster_data, 0x00, 512);
66
+ memset(s->cluster_data, 0x00, BDRV_SECTOR_SIZE);
67
if (qcrypto_block_encrypt(s->crypto,
68
- (start_sect + i) *
69
- BDRV_SECTOR_SIZE,
70
+ start_offset + i,
71
s->cluster_data,
72
BDRV_SECTOR_SIZE,
73
NULL) < 0) {
74
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
75
}
76
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
77
ret = bdrv_pwrite(bs->file,
78
- cluster_offset + i * 512,
79
- s->cluster_data, 512);
80
+ cluster_offset + i,
81
+ s->cluster_data,
82
+ BDRV_SECTOR_SIZE);
83
if (ret < 0) {
84
return ret;
85
}
86
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
87
n = nb_sectors;
88
}
89
ret = get_cluster_offset(bs, sector_num << 9, 1, 0,
90
- index_in_cluster,
91
- index_in_cluster + n, &cluster_offset);
92
+ index_in_cluster << 9,
93
+ (index_in_cluster + n) << 9, &cluster_offset);
94
if (ret < 0) {
95
break;
96
}
97
--
120
--
98
2.13.6
121
2.20.1
99
122
100
123
diff view generated by jsdifflib