1
The following changes since commit 527266f324def9f7f392fe3b0dd940cb8dc699d9:
1
The following changes since commit 67b6526cf042f22521feff5ea521a05d3dd2bf8f:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-pflash-2019-03-26' into staging (2019-03-26 09:57:07 +0000)
3
Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging (2022-01-13 13:59:56 +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 c6e3f520c802c5cb2de80576aba7f9f1fe985d8b:
9
for you to fetch changes up to e5e748739562268ef4063ee77bf53ad7040b25c7:
10
10
11
qemu-io: Add write -n for BDRV_REQ_NO_FALLBACK (2019-03-26 11:37:51 +0100)
11
iotests/testrunner.py: refactor test_field_width (2022-01-14 12:03:16 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- Fix slow pre-zeroing in qemu-img convert
16
- qemu-storage-daemon: Add vhost-user-blk help
17
- Test case for block job pausing on I/O errors
17
- block-backend: Fix use-after-free for BDS pointers after aio_poll()
18
- qemu-img: Fix sparseness of output image with unaligned ranges
19
- vvfat: Fix crashes in read-write mode
20
- Fix device deletion events with -device JSON syntax
21
- Code cleanups
18
22
19
----------------------------------------------------------------
23
----------------------------------------------------------------
20
Kevin Wolf (6):
24
Daniel P. Berrangé (1):
21
block: Remove error messages in bdrv_make_zero()
25
softmmu: fix device deletion events with -device JSON syntax
22
block: Add BDRV_REQ_NO_FALLBACK
23
block: Advertise BDRV_REQ_NO_FALLBACK in filter drivers
24
file-posix: Support BDRV_REQ_NO_FALLBACK for zero writes
25
qemu-img: Use BDRV_REQ_NO_FALLBACK for pre-zeroing
26
qemu-io: Add write -n for BDRV_REQ_NO_FALLBACK
27
26
28
Vladimir Sementsov-Ogievskiy (1):
27
Emanuele Giuseppe Esposito (3):
29
iotests: add 248: test resume mirror after auto pause on ENOSPC
28
block_int: make bdrv_backing_overridden static
29
include/sysemu/blockdev.h: remove drive_mark_claimed_by_board and inline drive_def
30
include/sysemu/blockdev.h: remove drive_get_max_devs
30
31
31
include/block/block.h | 7 ++++-
32
Hanna Reitz (2):
32
include/block/raw-aio.h | 1 +
33
iotests/stream-error-on-reset: New test
33
block/blkdebug.c | 2 +-
34
iotests/308: Fix for CAP_DAC_OVERRIDE
34
block/copy-on-read.c | 7 ++---
35
block/file-posix.c | 24 ++++++++++------
36
block/io.c | 16 +++++++----
37
block/mirror.c | 3 +-
38
block/raw-format.c | 2 +-
39
qemu-img.c | 2 +-
40
qemu-io-cmds.c | 13 +++++++--
41
tests/qemu-iotests/248 | 71 ++++++++++++++++++++++++++++++++++++++++++++++
42
tests/qemu-iotests/248.out | 8 ++++++
43
tests/qemu-iotests/group | 1 +
44
13 files changed, 133 insertions(+), 24 deletions(-)
45
create mode 100755 tests/qemu-iotests/248
46
create mode 100644 tests/qemu-iotests/248.out
47
35
36
Kevin Wolf (3):
37
vvfat: Fix size of temporary qcow file
38
vvfat: Fix vvfat_write() for writes before the root directory
39
iotests: Test qemu-img convert of zeroed data cluster
40
41
Philippe Mathieu-Daudé (3):
42
docs: Correct 'vhost-user-blk' spelling
43
qemu-storage-daemon: Add vhost-user-blk help
44
qapi/block: Restrict vhost-user-blk to CONFIG_VHOST_USER_BLK_SERVER
45
46
Stefan Hajnoczi (1):
47
block-backend: prevent dangling BDS pointers across aio_poll()
48
49
Vladimir Sementsov-Ogievskiy (3):
50
qemu-img: make is_allocated_sectors() more efficient
51
block: drop BLK_PERM_GRAPH_MOD
52
iotests/testrunner.py: refactor test_field_width
53
54
qapi/block-core.json | 7 +-
55
qapi/block-export.json | 6 +-
56
qapi/qdev.json | 5 +-
57
docs/tools/qemu-storage-daemon.rst | 2 +-
58
include/block/block.h | 9 +-
59
include/block/block_int.h | 3 -
60
include/sysemu/blockdev.h | 3 -
61
block.c | 11 +-
62
block/block-backend.c | 19 ++-
63
block/commit.c | 1 -
64
block/mirror.c | 15 +--
65
block/monitor/block-hmp-cmds.c | 2 +-
66
block/vvfat.c | 37 ++++--
67
blockdev.c | 24 +---
68
hw/block/block.c | 3 +-
69
qemu-img.c | 23 +++-
70
softmmu/vl.c | 8 +-
71
storage-daemon/qemu-storage-daemon.c | 13 ++
72
tests/qtest/device-plug-test.c | 19 +++
73
scripts/render_block_graph.py | 1 -
74
tests/qemu-iotests/testrunner.py | 21 ++--
75
tests/qemu-iotests/122 | 1 +
76
tests/qemu-iotests/122.out | 2 +
77
tests/qemu-iotests/273.out | 4 -
78
tests/qemu-iotests/308 | 25 +++-
79
tests/qemu-iotests/308.out | 2 +-
80
tests/qemu-iotests/tests/stream-error-on-reset | 140 +++++++++++++++++++++
81
tests/qemu-iotests/tests/stream-error-on-reset.out | 5 +
82
28 files changed, 307 insertions(+), 104 deletions(-)
83
create mode 100755 tests/qemu-iotests/tests/stream-error-on-reset
84
create mode 100644 tests/qemu-iotests/tests/stream-error-on-reset.out
85
86
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
bdrv_backing_overridden is only used in block.c, so there is
4
no need to leave it in block_int.h
5
6
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20211215121140.456939-2-eesposit@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
include/block/block_int.h | 3 ---
12
block.c | 4 +++-
13
2 files changed, 3 insertions(+), 4 deletions(-)
14
15
diff --git a/include/block/block_int.h b/include/block/block_int.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/block/block_int.h
18
+++ b/include/block/block_int.h
19
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
20
void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
21
QDict *options);
22
23
-bool bdrv_backing_overridden(BlockDriverState *bs);
24
-
25
-
26
/**
27
* bdrv_add_aio_context_notifier:
28
*
29
diff --git a/block.c b/block.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
32
+++ b/block.c
33
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
34
static void bdrv_reopen_commit(BDRVReopenState *reopen_state);
35
static void bdrv_reopen_abort(BDRVReopenState *reopen_state);
36
37
+static bool bdrv_backing_overridden(BlockDriverState *bs);
38
+
39
/* If non-zero, use only whitelisted block drivers */
40
static int use_bdrv_whitelist;
41
42
@@ -XXX,XX +XXX,XX @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
43
/* Note: This function may return false positives; it may return true
44
* even if opening the backing file specified by bs's image header
45
* would result in exactly bs->backing. */
46
-bool bdrv_backing_overridden(BlockDriverState *bs)
47
+static bool bdrv_backing_overridden(BlockDriverState *bs)
48
{
49
if (bs->backing) {
50
return strcmp(bs->auto_backing_file,
51
--
52
2.31.1
53
54
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
drive_def is only a particular use case of
4
qemu_opts_parse_noisily, so it can be inlined.
5
6
Also remove drive_mark_claimed_by_board, as it is only defined
7
but not implemented (nor used) anywhere.
8
9
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
Message-Id: <20211215121140.456939-3-eesposit@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
include/sysemu/blockdev.h | 2 --
14
block/monitor/block-hmp-cmds.c | 2 +-
15
blockdev.c | 7 +------
16
softmmu/vl.c | 4 +++-
17
4 files changed, 5 insertions(+), 10 deletions(-)
18
19
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/sysemu/blockdev.h
22
+++ b/include/sysemu/blockdev.h
23
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo);
24
void override_max_devs(BlockInterfaceType type, int max_devs);
25
26
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
27
-void drive_mark_claimed_by_board(void);
28
void drive_check_orphaned(void);
29
DriveInfo *drive_get_by_index(BlockInterfaceType type, int index);
30
int drive_get_max_bus(BlockInterfaceType type);
31
int drive_get_max_devs(BlockInterfaceType type);
32
33
-QemuOpts *drive_def(const char *optstr);
34
QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
35
const char *optstr);
36
DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType block_default_type,
37
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/block/monitor/block-hmp-cmds.c
40
+++ b/block/monitor/block-hmp-cmds.c
41
@@ -XXX,XX +XXX,XX @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
42
return;
43
}
44
45
- opts = drive_def(optstr);
46
+ opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false);
47
if (!opts)
48
return;
49
50
diff --git a/blockdev.c b/blockdev.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/blockdev.c
53
+++ b/blockdev.c
54
@@ -XXX,XX +XXX,XX @@ static int drive_index_to_unit_id(BlockInterfaceType type, int index)
55
return max_devs ? index % max_devs : index;
56
}
57
58
-QemuOpts *drive_def(const char *optstr)
59
-{
60
- return qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false);
61
-}
62
-
63
QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
64
const char *optstr)
65
{
66
QemuOpts *opts;
67
68
- opts = drive_def(optstr);
69
+ opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false);
70
if (!opts) {
71
return NULL;
72
}
73
diff --git a/softmmu/vl.c b/softmmu/vl.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/softmmu/vl.c
76
+++ b/softmmu/vl.c
77
@@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv, char **envp)
78
break;
79
}
80
case QEMU_OPTION_drive:
81
- if (drive_def(optarg) == NULL) {
82
+ opts = qemu_opts_parse_noisily(qemu_find_opts("drive"),
83
+ optarg, false);
84
+ if (opts == NULL) {
85
exit(1);
86
}
87
break;
88
--
89
2.31.1
90
91
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
Remove drive_get_max_devs, as it is not used by anyone.
4
5
Last use was removed in commit 8f2d75e81d5
6
("hw: Drop superfluous special checks for orphaned -drive").
7
8
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-Id: <20211215121140.456939-4-eesposit@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
include/sysemu/blockdev.h | 1 -
15
blockdev.c | 17 -----------------
16
2 files changed, 18 deletions(-)
17
18
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/sysemu/blockdev.h
21
+++ b/include/sysemu/blockdev.h
22
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
23
void drive_check_orphaned(void);
24
DriveInfo *drive_get_by_index(BlockInterfaceType type, int index);
25
int drive_get_max_bus(BlockInterfaceType type);
26
-int drive_get_max_devs(BlockInterfaceType type);
27
28
QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
29
const char *optstr);
30
diff --git a/blockdev.c b/blockdev.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/blockdev.c
33
+++ b/blockdev.c
34
@@ -XXX,XX +XXX,XX @@ void blockdev_auto_del(BlockBackend *blk)
35
}
36
}
37
38
-/**
39
- * Returns the current mapping of how many units per bus
40
- * a particular interface can support.
41
- *
42
- * A positive integer indicates n units per bus.
43
- * 0 implies the mapping has not been established.
44
- * -1 indicates an invalid BlockInterfaceType was given.
45
- */
46
-int drive_get_max_devs(BlockInterfaceType type)
47
-{
48
- if (type >= IF_IDE && type < IF_COUNT) {
49
- return if_max_devs[type];
50
- }
51
-
52
- return -1;
53
-}
54
-
55
static int drive_index_to_bus_id(BlockInterfaceType type, int index)
56
{
57
int max_devs = if_max_devs[type];
58
--
59
2.31.1
60
61
diff view generated by jsdifflib
New patch
1
From: Daniel P. Berrangé <berrange@redhat.com>
1
2
3
The -device JSON syntax impl leaks a reference on the created
4
DeviceState instance. As a result when you hot-unplug the
5
device, the device_finalize method won't be called and thus
6
it will fail to emit the required DEVICE_DELETED event.
7
8
A 'json-cli' feature was previously added against the
9
'device_add' QMP command QAPI schema to indicated to mgmt
10
apps that -device supported JSON syntax. Given the hotplug
11
bug that feature flag is not usable for its purpose, so
12
we add a new 'json-cli-hotplug' feature to indicate the
13
-device supports JSON without breaking hotplug.
14
15
Fixes: 5dacda5167560b3af8eadbce5814f60ba44b467e
16
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/802
17
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
18
Message-Id: <20220105123847.4047954-2-berrange@redhat.com>
19
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
20
Tested-by: Ján Tomko <jtomko@redhat.com>
21
Reviewed-by: Thomas Huth <thuth@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
24
qapi/qdev.json | 5 ++++-
25
softmmu/vl.c | 4 +++-
26
tests/qtest/device-plug-test.c | 19 +++++++++++++++++++
27
3 files changed, 26 insertions(+), 2 deletions(-)
28
29
diff --git a/qapi/qdev.json b/qapi/qdev.json
30
index XXXXXXX..XXXXXXX 100644
31
--- a/qapi/qdev.json
32
+++ b/qapi/qdev.json
33
@@ -XXX,XX +XXX,XX @@
34
# @json-cli: If present, the "-device" command line option supports JSON
35
# syntax with a structure identical to the arguments of this
36
# command.
37
+# @json-cli-hotplug: If present, the "-device" command line option supports JSON
38
+# syntax without the reference counting leak that broke
39
+# hot-unplug
40
#
41
# Notes:
42
#
43
@@ -XXX,XX +XXX,XX @@
44
{ 'command': 'device_add',
45
'data': {'driver': 'str', '*bus': 'str', '*id': 'str'},
46
'gen': false, # so we can get the additional arguments
47
- 'features': ['json-cli'] }
48
+ 'features': ['json-cli', 'json-cli-hotplug'] }
49
50
##
51
# @device_del:
52
diff --git a/softmmu/vl.c b/softmmu/vl.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/softmmu/vl.c
55
+++ b/softmmu/vl.c
56
@@ -XXX,XX +XXX,XX @@ static void qemu_create_cli_devices(void)
57
qemu_opts_foreach(qemu_find_opts("device"),
58
device_init_func, NULL, &error_fatal);
59
QTAILQ_FOREACH(opt, &device_opts, next) {
60
+ DeviceState *dev;
61
loc_push_restore(&opt->loc);
62
/*
63
* TODO Eventually we should call qmp_device_add() here to make sure it
64
@@ -XXX,XX +XXX,XX @@ static void qemu_create_cli_devices(void)
65
* from the start, so call qdev_device_add_from_qdict() directly for
66
* now.
67
*/
68
- qdev_device_add_from_qdict(opt->opts, true, &error_fatal);
69
+ dev = qdev_device_add_from_qdict(opt->opts, true, &error_fatal);
70
+ object_unref(OBJECT(dev));
71
loc_pop(&opt->loc);
72
}
73
rom_reset_order_override();
74
diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/tests/qtest/device-plug-test.c
77
+++ b/tests/qtest/device-plug-test.c
78
@@ -XXX,XX +XXX,XX @@ static void test_pci_unplug_request(void)
79
qtest_quit(qtest);
80
}
81
82
+static void test_pci_unplug_json_request(void)
83
+{
84
+ QTestState *qtest = qtest_initf(
85
+ "-device '{\"driver\": \"virtio-mouse-pci\", \"id\": \"dev0\"}'");
86
+
87
+ /*
88
+ * Request device removal. As the guest is not running, the request won't
89
+ * be processed. However during system reset, the removal will be
90
+ * handled, removing the device.
91
+ */
92
+ device_del(qtest, "dev0");
93
+ system_reset(qtest);
94
+ wait_device_deleted_event(qtest, "dev0");
95
+
96
+ qtest_quit(qtest);
97
+}
98
+
99
static void test_ccw_unplug(void)
100
{
101
QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0");
102
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
103
*/
104
qtest_add_func("/device-plug/pci-unplug-request",
105
test_pci_unplug_request);
106
+ qtest_add_func("/device-plug/pci-unplug-json-request",
107
+ test_pci_unplug_json_request);
108
109
if (!strcmp(arch, "s390x")) {
110
qtest_add_func("/device-plug/ccw-unplug",
111
--
112
2.31.1
113
114
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Reported-by: Eric Blake <eblake@redhat.com>
4
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Message-Id: <20220107105420.395011-2-f4bug@amsat.org>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
docs/tools/qemu-storage-daemon.rst | 2 +-
9
1 file changed, 1 insertion(+), 1 deletion(-)
10
11
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
12
index XXXXXXX..XXXXXXX 100644
13
--- a/docs/tools/qemu-storage-daemon.rst
14
+++ b/docs/tools/qemu-storage-daemon.rst
15
@@ -XXX,XX +XXX,XX @@ Export raw image file ``disk.img`` over NBD UNIX domain socket ``nbd.sock``::
16
--nbd-server addr.type=unix,addr.path=nbd.sock \
17
--export type=nbd,id=export,node-name=disk,writable=on
18
19
-Export a qcow2 image file ``disk.qcow2`` as a vhosts-user-blk device over UNIX
20
+Export a qcow2 image file ``disk.qcow2`` as a vhost-user-blk device over UNIX
21
domain socket ``vhost-user-blk.sock``::
22
23
$ qemu-storage-daemon \
24
--
25
2.31.1
26
27
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
2
3
Add missing vhost-user-blk help:
4
5
$ qemu-storage-daemon -h
6
...
7
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,
8
addr.type=unix,addr.path=<socket-path>[,writable=on|off]
9
[,logical-block-size=<block-size>][,num-queues=<num-queues>]
10
export the specified block node as a
11
vhosts-user-blk device over UNIX domain socket
12
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,
13
fd,addr.str=<fd>[,writable=on|off]
14
[,logical-block-size=<block-size>][,num-queues=<num-queues>]
15
export the specified block node as a
16
vhosts-user-blk device over file descriptor
17
...
18
19
Fixes: 90fc91d50b7 ("convert vhost-user-blk server to block export API")
20
Reported-by: Qing Wang <qinwang@redhat.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
22
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
23
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Message-Id: <20220107105420.395011-3-f4bug@amsat.org>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
---
27
storage-daemon/qemu-storage-daemon.c | 13 +++++++++++++
28
1 file changed, 13 insertions(+)
29
30
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/storage-daemon/qemu-storage-daemon.c
33
+++ b/storage-daemon/qemu-storage-daemon.c
34
@@ -XXX,XX +XXX,XX @@ static void help(void)
35
" export the specified block node over FUSE\n"
36
"\n"
37
#endif /* CONFIG_FUSE */
38
+#ifdef CONFIG_VHOST_USER_BLK_SERVER
39
+" --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,\n"
40
+" addr.type=unix,addr.path=<socket-path>[,writable=on|off]\n"
41
+" [,logical-block-size=<block-size>][,num-queues=<num-queues>]\n"
42
+" export the specified block node as a\n"
43
+" vhost-user-blk device over UNIX domain socket\n"
44
+" --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,\n"
45
+" fd,addr.str=<fd>[,writable=on|off]\n"
46
+" [,logical-block-size=<block-size>][,num-queues=<num-queues>]\n"
47
+" export the specified block node as a\n"
48
+" vhost-user-blk device over file descriptor\n"
49
+"\n"
50
+#endif /* CONFIG_VHOST_USER_BLK_SERVER */
51
" --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n"
52
" configure a QMP monitor\n"
53
"\n"
54
--
55
2.31.1
56
57
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
2
3
When building QEMU with --disable-vhost-user and using introspection,
4
query-qmp-schema lists vhost-user-blk even though it's not actually
5
available:
6
7
{ "execute": "query-qmp-schema" }
8
{
9
"return": [
10
...
11
{
12
"name": "312",
13
"members": [
14
{
15
"name": "nbd"
16
},
17
{
18
"name": "vhost-user-blk"
19
}
20
],
21
"meta-type": "enum",
22
"values": [
23
"nbd",
24
"vhost-user-blk"
25
]
26
},
27
28
Restrict vhost-user-blk in BlockExportType when
29
CONFIG_VHOST_USER_BLK_SERVER is disabled, so it
30
doesn't end listed by query-qmp-schema.
31
32
Fixes: 90fc91d50b7 ("convert vhost-user-blk server to block export API")
33
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
34
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
35
Message-Id: <20220107105420.395011-4-f4bug@amsat.org>
36
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
37
---
38
qapi/block-export.json | 6 ++++--
39
1 file changed, 4 insertions(+), 2 deletions(-)
40
41
diff --git a/qapi/block-export.json b/qapi/block-export.json
42
index XXXXXXX..XXXXXXX 100644
43
--- a/qapi/block-export.json
44
+++ b/qapi/block-export.json
45
@@ -XXX,XX +XXX,XX @@
46
# Since: 4.2
47
##
48
{ 'enum': 'BlockExportType',
49
- 'data': [ 'nbd', 'vhost-user-blk',
50
+ 'data': [ 'nbd',
51
+ { 'name': 'vhost-user-blk', 'if': 'CONFIG_VHOST_USER_BLK_SERVER' },
52
{ 'name': 'fuse', 'if': 'CONFIG_FUSE' } ] }
53
54
##
55
@@ -XXX,XX +XXX,XX @@
56
'discriminator': 'type',
57
'data': {
58
'nbd': 'BlockExportOptionsNbd',
59
- 'vhost-user-blk': 'BlockExportOptionsVhostUserBlk',
60
+ 'vhost-user-blk': { 'type': 'BlockExportOptionsVhostUserBlk',
61
+ 'if': 'CONFIG_VHOST_USER_BLK_SERVER' },
62
'fuse': { 'type': 'BlockExportOptionsFuse',
63
'if': 'CONFIG_FUSE' }
64
} }
65
--
66
2.31.1
67
68
diff view generated by jsdifflib
1
This makes the new BDRV_REQ_NO_FALLBACK flag available in the qemu-io
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
write command.
3
2
3
The BlockBackend root child can change when aio_poll() is invoked. This
4
happens when a temporary filter node is removed upon blockjob
5
completion, for example.
6
7
Functions in block/block-backend.c must be aware of this when using a
8
blk_bs() pointer across aio_poll() because the BlockDriverState refcnt
9
may reach 0, resulting in a stale pointer.
10
11
One example is scsi_device_purge_requests(), which calls blk_drain() to
12
wait for in-flight requests to cancel. If the backup blockjob is active,
13
then the BlockBackend root child is a temporary filter BDS owned by the
14
blockjob. The blockjob can complete during bdrv_drained_begin() and the
15
last reference to the BDS is released when the temporary filter node is
16
removed. This results in a use-after-free when blk_drain() calls
17
bdrv_drained_end(bs) on the dangling pointer.
18
19
Explicitly hold a reference to bs across block APIs that invoke
20
aio_poll().
21
22
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2021778
23
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2036178
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
Message-Id: <20220111153613.25453-2-stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Acked-by: Eric Blake <eblake@redhat.com>
6
---
27
---
7
qemu-io-cmds.c | 13 +++++++++++--
28
block/block-backend.c | 19 +++++++++++++++++--
8
1 file changed, 11 insertions(+), 2 deletions(-)
29
1 file changed, 17 insertions(+), 2 deletions(-)
9
30
10
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
31
diff --git a/block/block-backend.c b/block/block-backend.c
11
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
12
--- a/qemu-io-cmds.c
33
--- a/block/block-backend.c
13
+++ b/qemu-io-cmds.c
34
+++ b/block/block-backend.c
14
@@ -XXX,XX +XXX,XX @@ static void write_help(void)
35
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
15
" -b, -- write to the VM state rather than the virtual disk\n"
36
void blk_remove_bs(BlockBackend *blk)
16
" -c, -- write compressed data with blk_write_compressed\n"
37
{
17
" -f, -- use Force Unit Access semantics\n"
38
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
18
+" -n, -- with -z, don't allow slow fallback\n"
39
- BlockDriverState *bs;
19
" -p, -- ignored for backwards compatibility\n"
40
BdrvChild *root;
20
" -P, -- use different pattern to fill file\n"
41
21
" -C, -- report statistics in a machine parsable format\n"
42
notifier_list_notify(&blk->remove_bs_notifiers, blk);
22
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t write_cmd = {
43
if (tgm->throttle_state) {
23
.perm = BLK_PERM_WRITE,
44
- bs = blk_bs(blk);
24
.argmin = 2,
45
+ BlockDriverState *bs = blk_bs(blk);
25
.argmax = -1,
46
+
26
- .args = "[-bcCfquz] [-P pattern] off len",
47
+ /*
27
+ .args = "[-bcCfnquz] [-P pattern] off len",
48
+ * Take a ref in case blk_bs() changes across bdrv_drained_begin(), for
28
.oneline = "writes a number of bytes at a specified offset",
49
+ * example, if a temporary filter node is removed by a blockjob.
29
.help = write_help,
50
+ */
30
};
51
+ bdrv_ref(bs);
31
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
52
bdrv_drained_begin(bs);
32
int64_t total = 0;
53
throttle_group_detach_aio_context(tgm);
33
int pattern = 0xcd;
54
throttle_group_attach_aio_context(tgm, qemu_get_aio_context());
34
55
bdrv_drained_end(bs);
35
- while ((c = getopt(argc, argv, "bcCfpP:quz")) != -1) {
56
+ bdrv_unref(bs);
36
+ while ((c = getopt(argc, argv, "bcCfnpP:quz")) != -1) {
37
switch (c) {
38
case 'b':
39
bflag = true;
40
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
41
case 'f':
42
flags |= BDRV_REQ_FUA;
43
break;
44
+ case 'n':
45
+ flags |= BDRV_REQ_NO_FALLBACK;
46
+ break;
47
case 'p':
48
/* Ignored for backwards compatibility */
49
break;
50
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
51
return -EINVAL;
52
}
57
}
53
58
54
+ if ((flags & BDRV_REQ_NO_FALLBACK) && !zflag) {
59
blk_update_root_state(blk);
55
+ printf("-n requires -z to be specified\n");
60
@@ -XXX,XX +XXX,XX @@ void blk_drain(BlockBackend *blk)
56
+ return -EINVAL;
61
BlockDriverState *bs = blk_bs(blk);
57
+ }
62
63
if (bs) {
64
+ bdrv_ref(bs);
65
bdrv_drained_begin(bs);
66
}
67
68
@@ -XXX,XX +XXX,XX @@ void blk_drain(BlockBackend *blk)
69
70
if (bs) {
71
bdrv_drained_end(bs);
72
+ bdrv_unref(bs);
73
}
74
}
75
76
@@ -XXX,XX +XXX,XX @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
77
int ret;
78
79
if (bs) {
80
+ bdrv_ref(bs);
58
+
81
+
59
if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) {
82
if (update_root_node) {
60
printf("-u requires -z to be specified\n");
83
ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root,
61
return -EINVAL;
84
errp);
85
if (ret < 0) {
86
+ bdrv_unref(bs);
87
return ret;
88
}
89
}
90
@@ -XXX,XX +XXX,XX @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
91
throttle_group_attach_aio_context(tgm, new_context);
92
bdrv_drained_end(bs);
93
}
94
+
95
+ bdrv_unref(bs);
96
}
97
98
blk->ctx = new_context;
99
@@ -XXX,XX +XXX,XX @@ void blk_io_limits_disable(BlockBackend *blk)
100
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
101
assert(tgm->throttle_state);
102
if (bs) {
103
+ bdrv_ref(bs);
104
bdrv_drained_begin(bs);
105
}
106
throttle_group_unregister_tgm(tgm);
107
if (bs) {
108
bdrv_drained_end(bs);
109
+ bdrv_unref(bs);
110
}
111
}
112
62
--
113
--
63
2.20.1
114
2.31.1
64
115
65
116
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
Test that mirror job actually resume on resume command after being
3
Test the following scenario:
4
automatically paused on ENOSPC error.
4
- Simple stream block in two-layer backing chain (base and top)
5
- The job is drained via blk_drain(), then an error occurs while the job
6
settles the ongoing request
7
- And so the job completes while in blk_drain()
5
8
6
It's a follow-up test for 8d9648cbf3e
9
This was reported as a segfault, but is fixed by "block-backend: prevent
7
"blockjob: fix user pause in block_job_error_action"
10
dangling BDS pointers across aio_poll()".
8
11
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2036178
10
Tested-by: John Snow <jsnow@redhat.com>
13
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
Reviewed-by: John Snow <jsnow@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-Id: <20220111153613.25453-3-stefanha@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
17
---
14
tests/qemu-iotests/248 | 71 ++++++++++++++++++++++++++++++++++++++
18
.../qemu-iotests/tests/stream-error-on-reset | 140 ++++++++++++++++++
15
tests/qemu-iotests/248.out | 8 +++++
19
.../tests/stream-error-on-reset.out | 5 +
16
tests/qemu-iotests/group | 1 +
20
2 files changed, 145 insertions(+)
17
3 files changed, 80 insertions(+)
21
create mode 100755 tests/qemu-iotests/tests/stream-error-on-reset
18
create mode 100755 tests/qemu-iotests/248
22
create mode 100644 tests/qemu-iotests/tests/stream-error-on-reset.out
19
create mode 100644 tests/qemu-iotests/248.out
20
23
21
diff --git a/tests/qemu-iotests/248 b/tests/qemu-iotests/248
24
diff --git a/tests/qemu-iotests/tests/stream-error-on-reset b/tests/qemu-iotests/tests/stream-error-on-reset
22
new file mode 100755
25
new file mode 100755
23
index XXXXXXX..XXXXXXX
26
index XXXXXXX..XXXXXXX
24
--- /dev/null
27
--- /dev/null
25
+++ b/tests/qemu-iotests/248
28
+++ b/tests/qemu-iotests/tests/stream-error-on-reset
26
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@
27
+#!/usr/bin/env python
30
+#!/usr/bin/env python3
31
+# group: rw quick
28
+#
32
+#
29
+# Test resume mirror after auto pause on ENOSPC
33
+# Test what happens when a stream job completes in a blk_drain().
30
+#
34
+#
31
+# Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved.
35
+# Copyright (C) 2022 Red Hat, Inc.
32
+#
36
+#
33
+# This program is free software; you can redistribute it and/or modify
37
+# This program is free software; you can redistribute it and/or modify
34
+# it under the terms of the GNU General Public License as published by
38
+# it under the terms of the GNU General Public License as published by
35
+# the Free Software Foundation; either version 2 of the License, or
39
+# the Free Software Foundation; either version 2 of the License, or
36
+# (at your option) any later version.
40
+# (at your option) any later version.
...
...
42
+#
46
+#
43
+# You should have received a copy of the GNU General Public License
47
+# You should have received a copy of the GNU General Public License
44
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
48
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
45
+#
49
+#
46
+
50
+
51
+import os
47
+import iotests
52
+import iotests
48
+from iotests import qemu_img_create, qemu_io, file_path, filter_qmp_testfiles
53
+from iotests import imgfmt, qemu_img_create, qemu_io_silent, QMPTestCase
49
+
54
+
50
+iotests.verify_image_format(supported_fmts=['qcow2'])
51
+
55
+
52
+source, target = file_path('source', 'target')
56
+image_size = 1 * 1024 * 1024
53
+size = 5 * 1024 * 1024
57
+data_size = 64 * 1024
54
+limit = 2 * 1024 * 1024
58
+base = os.path.join(iotests.test_dir, 'base.img')
59
+top = os.path.join(iotests.test_dir, 'top.img')
55
+
60
+
56
+qemu_img_create('-f', iotests.imgfmt, source, str(size))
57
+qemu_img_create('-f', iotests.imgfmt, target, str(size))
58
+qemu_io('-c', 'write 0 {}'.format(size), source)
59
+
61
+
60
+# raw format don't like empty files
62
+# We want to test completing a stream job in a blk_drain().
61
+qemu_io('-c', 'write 0 {}'.format(size), target)
63
+#
64
+# The blk_drain() we are going to use is a virtio-scsi device resetting,
65
+# which we can trigger by resetting the system.
66
+#
67
+# In order to have the block job complete on drain, we (1) throttle its
68
+# base image so we can start the drain after it has begun, but before it
69
+# completes, and (2) make it encounter an I/O error on the ensuing write.
70
+# (If it completes regularly, the completion happens after the drain for
71
+# some reason.)
62
+
72
+
63
+vm = iotests.VM().add_drive(source)
73
+class TestStreamErrorOnReset(QMPTestCase):
64
+vm.launch()
74
+ def setUp(self) -> None:
75
+ """
76
+ Create two images:
77
+ - base image {base} with {data_size} bytes allocated
78
+ - top image {top} without any data allocated
65
+
79
+
66
+blockdev_opts = {
80
+ And the following VM configuration:
67
+ 'driver': iotests.imgfmt,
81
+ - base image throttled to {data_size}
68
+ 'node-name': 'target',
82
+ - top image with a blkdebug configuration so the first write access
69
+ 'file': {
83
+ to it will result in an error
70
+ 'driver': 'raw',
84
+ - top image is attached to a virtio-scsi device
71
+ 'size': limit,
85
+ """
72
+ 'file': {
86
+ assert qemu_img_create('-f', imgfmt, base, str(image_size)) == 0
73
+ 'driver': 'file',
87
+ assert qemu_io_silent('-c', f'write 0 {data_size}', base) == 0
74
+ 'filename': target
88
+ assert qemu_img_create('-f', imgfmt, top, str(image_size)) == 0
75
+ }
76
+ }
77
+}
78
+vm.qmp_log('blockdev-add', filters=[filter_qmp_testfiles], **blockdev_opts)
79
+
89
+
80
+vm.qmp_log('blockdev-mirror', device='drive0', sync='full', target='target',
90
+ self.vm = iotests.VM()
81
+ on_target_error='enospc')
91
+ self.vm.add_args('-accel', 'tcg') # Make throttling work properly
92
+ self.vm.add_object(self.vm.qmp_to_opts({
93
+ 'qom-type': 'throttle-group',
94
+ 'id': 'thrgr',
95
+ 'x-bps-total': str(data_size)
96
+ }))
97
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
98
+ 'driver': imgfmt,
99
+ 'node-name': 'base',
100
+ 'file': {
101
+ 'driver': 'throttle',
102
+ 'throttle-group': 'thrgr',
103
+ 'file': {
104
+ 'driver': 'file',
105
+ 'filename': base
106
+ }
107
+ }
108
+ }))
109
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
110
+ 'driver': imgfmt,
111
+ 'node-name': 'top',
112
+ 'file': {
113
+ 'driver': 'blkdebug',
114
+ 'node-name': 'top-blkdebug',
115
+ 'inject-error': [{
116
+ 'event': 'pwritev',
117
+ 'immediately': 'true',
118
+ 'once': 'true'
119
+ }],
120
+ 'image': {
121
+ 'driver': 'file',
122
+ 'filename': top
123
+ }
124
+ },
125
+ 'backing': 'base'
126
+ }))
127
+ self.vm.add_device(self.vm.qmp_to_opts({
128
+ 'driver': 'virtio-scsi',
129
+ 'id': 'vscsi'
130
+ }))
131
+ self.vm.add_device(self.vm.qmp_to_opts({
132
+ 'driver': 'scsi-hd',
133
+ 'bus': 'vscsi.0',
134
+ 'drive': 'top'
135
+ }))
136
+ self.vm.launch()
82
+
137
+
83
+vm.event_wait('JOB_STATUS_CHANGE', timeout=3.0,
138
+ def tearDown(self) -> None:
84
+ match={'data': {'status': 'paused'}})
139
+ self.vm.shutdown()
140
+ os.remove(top)
141
+ os.remove(base)
85
+
142
+
86
+# drop other cached events, to not interfere with further wait for 'running'
143
+ def test_stream_error_on_reset(self) -> None:
87
+vm.get_qmp_events()
144
+ # Launch a stream job, which will take at least a second to
145
+ # complete, because the base image is throttled (so we can
146
+ # get in between it having started and it having completed)
147
+ res = self.vm.qmp('block-stream', job_id='stream', device='top')
148
+ self.assert_qmp(res, 'return', {})
88
+
149
+
89
+del blockdev_opts['file']['size']
150
+ while True:
90
+vm.qmp_log('x-blockdev-reopen', filters=[filter_qmp_testfiles],
151
+ ev = self.vm.event_wait('JOB_STATUS_CHANGE')
91
+ **blockdev_opts)
152
+ if ev['data']['status'] == 'running':
153
+ # Once the stream job is running, reset the system, which
154
+ # forces the virtio-scsi device to be reset, thus draining
155
+ # the stream job, and making it complete. Completing
156
+ # inside of that drain should not result in a segfault.
157
+ res = self.vm.qmp('system_reset')
158
+ self.assert_qmp(res, 'return', {})
159
+ elif ev['data']['status'] == 'null':
160
+ # The test is done once the job is gone
161
+ break
92
+
162
+
93
+vm.qmp_log('block-job-resume', device='drive0')
94
+vm.event_wait('JOB_STATUS_CHANGE', timeout=1.0,
95
+ match={'data': {'status': 'running'}})
96
+
163
+
97
+vm.shutdown()
164
+if __name__ == '__main__':
98
diff --git a/tests/qemu-iotests/248.out b/tests/qemu-iotests/248.out
165
+ # Passes with any format with backing file support, but qed and
166
+ # qcow1 do not seem to exercise the used-to-be problematic code
167
+ # path, so there is no point in having them in this list
168
+ iotests.main(supported_fmts=['qcow2', 'vmdk'],
169
+ supported_protocols=['file'])
170
diff --git a/tests/qemu-iotests/tests/stream-error-on-reset.out b/tests/qemu-iotests/tests/stream-error-on-reset.out
99
new file mode 100644
171
new file mode 100644
100
index XXXXXXX..XXXXXXX
172
index XXXXXXX..XXXXXXX
101
--- /dev/null
173
--- /dev/null
102
+++ b/tests/qemu-iotests/248.out
174
+++ b/tests/qemu-iotests/tests/stream-error-on-reset.out
103
@@ -XXX,XX +XXX,XX @@
175
@@ -XXX,XX +XXX,XX @@
104
+{"execute": "blockdev-add", "arguments": {"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}, "size": 2097152}, "node-name": "target"}}
176
+.
105
+{"return": {}}
177
+----------------------------------------------------------------------
106
+{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "on-target-error": "enospc", "sync": "full", "target": "target"}}
178
+Ran 1 tests
107
+{"return": {}}
179
+
108
+{"execute": "x-blockdev-reopen", "arguments": {"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}}, "node-name": "target"}}
180
+OK
109
+{"return": {}}
110
+{"execute": "block-job-resume", "arguments": {"device": "drive0"}}
111
+{"return": {}}
112
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
113
index XXXXXXX..XXXXXXX 100644
114
--- a/tests/qemu-iotests/group
115
+++ b/tests/qemu-iotests/group
116
@@ -XXX,XX +XXX,XX @@
117
245 rw auto
118
246 rw auto quick
119
247 rw auto quick
120
+248 rw auto quick
121
--
181
--
122
2.20.1
182
2.31.1
123
183
124
184
diff view generated by jsdifflib
New patch
1
From: Hanna Reitz <hreitz@redhat.com>
1
2
3
With CAP_DAC_OVERRIDE (which e.g. root generally has), permission checks
4
will be bypassed when opening files.
5
6
308 in one instance tries to open a read-only file (FUSE export) with
7
qemu-io as read/write, and expects this to fail. However, when running
8
it as root, opening will succeed (thanks to CAP_DAC_OVERRIDE) and only
9
the actual write operation will fail.
10
11
Note this as "Case not run", but have the test pass in either case.
12
13
Reported-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Fixes: 2c7dd057aa7bd7a875e9b1a53975c220d6380bc4
15
("export/fuse: Pass default_permissions for mount")
16
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
17
Message-Id: <20220103120014.13061-1-hreitz@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
tests/qemu-iotests/308 | 25 +++++++++++++++++++++++--
21
tests/qemu-iotests/308.out | 2 +-
22
2 files changed, 24 insertions(+), 3 deletions(-)
23
24
diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308
25
index XXXXXXX..XXXXXXX 100755
26
--- a/tests/qemu-iotests/308
27
+++ b/tests/qemu-iotests/308
28
@@ -XXX,XX +XXX,XX @@ echo '=== Writable export ==='
29
fuse_export_add 'export-mp' "'mountpoint': '$EXT_MP', 'writable': true"
30
31
# Check that writing to the read-only export fails
32
-$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \
33
- | _filter_qemu_io | _filter_testdir | _filter_imgfmt
34
+output=$($QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \
35
+ | _filter_qemu_io | _filter_testdir | _filter_imgfmt)
36
+
37
+# Expected reference output: Opening the file fails because it has no
38
+# write permission
39
+reference="Could not open 'TEST_DIR/t.IMGFMT': Permission denied"
40
+
41
+if echo "$output" | grep -q "$reference"; then
42
+ echo "Writing to read-only export failed: OK"
43
+elif echo "$output" | grep -q "write failed: Permission denied"; then
44
+ # With CAP_DAC_OVERRIDE (e.g. when running this test as root), the export
45
+ # can be opened regardless of its file permissions, but writing will then
46
+ # fail. This is not the result for which we want to test, so count this as
47
+ # a SKIP.
48
+ _casenotrun "Opening RO export as R/W succeeded, perhaps because of" \
49
+ "CAP_DAC_OVERRIDE"
50
+
51
+ # Still, write this to the reference output to make the test pass
52
+ echo "Writing to read-only export failed: OK"
53
+else
54
+ echo "Writing to read-only export failed: ERROR"
55
+ echo "$output"
56
+fi
57
58
# But here it should work
59
$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$EXT_MP" | _filter_qemu_io
60
diff --git a/tests/qemu-iotests/308.out b/tests/qemu-iotests/308.out
61
index XXXXXXX..XXXXXXX 100644
62
--- a/tests/qemu-iotests/308.out
63
+++ b/tests/qemu-iotests/308.out
64
@@ -XXX,XX +XXX,XX @@ virtual size: 0 B (0 bytes)
65
'mountpoint': 'TEST_DIR/t.IMGFMT.fuse', 'writable': true
66
} }
67
{"return": {}}
68
-qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
69
+Writing to read-only export failed: OK
70
wrote 65536/65536 bytes at offset 1048576
71
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
72
wrote 65536/65536 bytes at offset 1048576
73
--
74
2.31.1
75
76
diff view generated by jsdifflib
1
We know that the kernel implements a slow fallback code path for
1
The size of the qcow size was calculated so that only the FAT partition
2
BLKZEROOUT, so if BDRV_REQ_NO_FALLBACK is given, we shouldn't call it.
2
would fit on it, but not the whole disk. However, offsets relative to
3
The other operations we call in the context of .bdrv_co_pwrite_zeroes
3
the whole disk are used to access it, so increase its size to be large
4
should usually be quick, so no modification should be needed for them.
4
enough for that.
5
If we ever notice that there are additional problematic cases, we can
6
still make these conditional as well.
7
5
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Acked-by: Eric Blake <eblake@redhat.com>
7
Message-Id: <20211209151815.23495-1-kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
9
---
11
include/block/raw-aio.h | 1 +
10
block/vvfat.c | 7 +++----
12
block/file-posix.c | 24 ++++++++++++++++--------
11
1 file changed, 3 insertions(+), 4 deletions(-)
13
2 files changed, 17 insertions(+), 8 deletions(-)
14
12
15
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
13
diff --git a/block/vvfat.c b/block/vvfat.c
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/include/block/raw-aio.h
15
--- a/block/vvfat.c
18
+++ b/include/block/raw-aio.h
16
+++ b/block/vvfat.c
19
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
20
/* AIO flags */
18
dirname, cyls, heads, secs));
21
#define QEMU_AIO_MISALIGNED 0x1000
19
22
#define QEMU_AIO_BLKDEV 0x2000
20
s->sector_count = cyls * heads * secs - s->offset_to_bootsector;
23
+#define QEMU_AIO_NO_FALLBACK 0x4000
21
+ bs->total_sectors = cyls * heads * secs;
24
22
25
23
if (qemu_opt_get_bool(opts, "rw", false)) {
26
/* linux-aio.c - Linux native implementation */
24
if (!bdrv_is_read_only(bs)) {
27
diff --git a/block/file-posix.c b/block/file-posix.c
25
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
28
index XXXXXXX..XXXXXXX 100644
26
}
29
--- a/block/file-posix.c
30
+++ b/block/file-posix.c
31
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
32
}
27
}
33
#endif
28
34
29
- bs->total_sectors = cyls * heads * secs;
35
- bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
30
-
36
+ bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
31
if (init_directories(s, dirname, heads, secs, errp)) {
37
ret = 0;
32
ret = -EIO;
38
fail:
33
goto fail;
39
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
34
@@ -XXX,XX +XXX,XX @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
40
@@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb)
41
}
35
}
42
36
43
#ifdef BLKZEROOUT
37
opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
44
- do {
38
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512,
45
- uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes };
39
- &error_abort);
46
- if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) {
40
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
47
- return 0;
41
+ bs->total_sectors * BDRV_SECTOR_SIZE, &error_abort);
48
- }
42
qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:", &error_abort);
49
- } while (errno == EINTR);
43
50
+ /* The BLKZEROOUT implementation in the kernel doesn't set
44
ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp);
51
+ * BLKDEV_ZERO_NOFALLBACK, so we can't call this if we have to avoid slow
52
+ * fallbacks. */
53
+ if (!(aiocb->aio_type & QEMU_AIO_NO_FALLBACK)) {
54
+ do {
55
+ uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes };
56
+ if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) {
57
+ return 0;
58
+ }
59
+ } while (errno == EINTR);
60
61
- ret = translate_err(-errno);
62
+ ret = translate_err(-errno);
63
+ }
64
#endif
65
66
if (ret == -ENOTSUP) {
67
@@ -XXX,XX +XXX,XX @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
68
if (blkdev) {
69
acb.aio_type |= QEMU_AIO_BLKDEV;
70
}
71
+ if (flags & BDRV_REQ_NO_FALLBACK) {
72
+ acb.aio_type |= QEMU_AIO_NO_FALLBACK;
73
+ }
74
75
if (flags & BDRV_REQ_MAY_UNMAP) {
76
acb.aio_type |= QEMU_AIO_DISCARD;
77
--
45
--
78
2.20.1
46
2.31.1
79
47
80
48
diff view generated by jsdifflib
1
Filter drivers that support .bdrv_co_pwrite_zeroes can safely advertise
1
The calculation in sector2cluster() is done relative to the offset of
2
BDRV_REQ_NO_FALLBACK because they just forward the request flags to
2
the root directory. Any writes to blocks before the start of the root
3
their child node.
3
directory (in particular, writes to the FAT) result in negative values,
4
which are not handled correctly in vvfat_write().
5
6
This changes sector2cluster() to return a signed value, and makes sure
7
that vvfat_write() doesn't try to find mappings for negative cluster
8
number. It clarifies the code in vvfat_write() to make it more obvious
9
that the cluster numbers can be negative.
4
10
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Acked-by: Eric Blake <eblake@redhat.com>
12
Message-Id: <20211209152231.23756-1-kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
14
---
8
block/blkdebug.c | 2 +-
15
block/vvfat.c | 30 ++++++++++++++++++++++--------
9
block/copy-on-read.c | 7 +++----
16
1 file changed, 22 insertions(+), 8 deletions(-)
10
block/mirror.c | 3 ++-
11
block/raw-format.c | 2 +-
12
4 files changed, 7 insertions(+), 7 deletions(-)
13
17
14
diff --git a/block/blkdebug.c b/block/blkdebug.c
18
diff --git a/block/vvfat.c b/block/vvfat.c
15
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
16
--- a/block/blkdebug.c
20
--- a/block/vvfat.c
17
+++ b/block/blkdebug.c
21
+++ b/block/vvfat.c
18
@@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
22
@@ -XXX,XX +XXX,XX @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
19
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
20
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
21
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
22
- ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
23
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
24
bs->file->bs->supported_zero_flags);
25
ret = -EINVAL;
26
27
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/block/copy-on-read.c
30
+++ b/block/copy-on-read.c
31
@@ -XXX,XX +XXX,XX @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
32
}
33
34
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
35
- (BDRV_REQ_FUA &
36
- bs->file->bs->supported_write_flags);
37
+ (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
38
39
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
40
- ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
41
- bs->file->bs->supported_zero_flags);
42
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
43
+ bs->file->bs->supported_zero_flags);
44
45
return 0;
23
return 0;
46
}
24
}
47
diff --git a/block/mirror.c b/block/mirror.c
25
48
index XXXXXXX..XXXXXXX 100644
26
-static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
49
--- a/block/mirror.c
27
+static inline int32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
50
+++ b/block/mirror.c
28
{
51
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
29
return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster;
30
}
31
@@ -XXX,XX +XXX,XX @@ static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
32
{
33
BDRVVVFATState *s = bs->opaque;
34
int i, ret;
35
+ int first_cluster, last_cluster;
36
37
DLOG(checkpoint());
38
39
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
40
if (sector_num < s->offset_to_fat)
41
return -1;
42
43
- for (i = sector2cluster(s, sector_num);
44
- i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
45
- mapping_t* mapping = find_mapping_for_cluster(s, i);
46
+ /*
47
+ * Values will be negative for writes to the FAT, which is located before
48
+ * the root directory.
49
+ */
50
+ first_cluster = sector2cluster(s, sector_num);
51
+ last_cluster = sector2cluster(s, sector_num + nb_sectors - 1);
52
+
53
+ for (i = first_cluster; i <= last_cluster;) {
54
+ mapping_t *mapping = NULL;
55
+
56
+ if (i >= 0) {
57
+ mapping = find_mapping_for_cluster(s, i);
58
+ }
59
+
60
if (mapping) {
61
if (mapping->read_only) {
62
fprintf(stderr, "Tried to write to write-protected file %s\n",
63
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
64
}
65
}
66
i = mapping->end;
67
- } else
68
+ } else {
69
i++;
70
+ }
52
}
71
}
53
mirror_top_bs->total_sectors = bs->total_sectors;
72
54
mirror_top_bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
73
/*
55
- mirror_top_bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
74
@@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sec
56
+ mirror_top_bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
75
return ret;
57
+ BDRV_REQ_NO_FALLBACK;
76
}
58
bs_opaque = g_new0(MirrorBDSOpaque, 1);
77
59
mirror_top_bs->opaque = bs_opaque;
78
- for (i = sector2cluster(s, sector_num);
60
bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
79
- i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
61
diff --git a/block/raw-format.c b/block/raw-format.c
80
- if (i >= 0)
62
index XXXXXXX..XXXXXXX 100644
81
+ for (i = first_cluster; i <= last_cluster; i++) {
63
--- a/block/raw-format.c
82
+ if (i >= 0) {
64
+++ b/block/raw-format.c
83
s->used_clusters[i] |= USED_ALLOCATED;
65
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
84
+ }
66
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
85
+ }
67
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
86
68
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
87
DLOG(checkpoint());
69
- ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
88
/* TODO: add timeout */
70
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
71
bs->file->bs->supported_zero_flags);
72
73
if (bs->probed && !bdrv_is_read_only(bs)) {
74
--
89
--
75
2.20.1
90
2.31.1
76
91
77
92
diff view generated by jsdifflib
1
There is only a single caller of bdrv_make_zero(), which is qemu-img
1
This demonstrates what happens when the block status changes in
2
convert. If the function fails, we just fall back to a different method
2
sub-min_sparse granularity, but all of the parts are zeroed out. The
3
of zeroing out blocks on the target image. There is no good reason to
3
alignment logic in is_allocated_sectors() prevents that the target image
4
print error messages on stderr when the higher level operation will
4
remains fully sparse as expected, but turns it into a data cluster of
5
actually succeed.
5
explicit zeros.
6
6
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Acked-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Message-Id: <20211217164654.1184218-2-vsementsov@virtuozzo.com>
10
Tested-by: Peter Lieven <pl@kamp.de>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
12
---
10
block/io.c | 4 ----
13
tests/qemu-iotests/122 | 1 +
11
1 file changed, 4 deletions(-)
14
tests/qemu-iotests/122.out | 10 ++++++++--
15
2 files changed, 9 insertions(+), 2 deletions(-)
12
16
13
diff --git a/block/io.c b/block/io.c
17
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122
18
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/qemu-iotests/122
20
+++ b/tests/qemu-iotests/122
21
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "write -P 0 0 64k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_test
22
$QEMU_IO -c "write 0 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
23
$QEMU_IO -c "write 8k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
24
$QEMU_IO -c "write 17k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
25
+$QEMU_IO -c "write -P 0 65k 1k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
26
27
for min_sparse in 4k 8k; do
28
echo
29
diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out
14
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
15
--- a/block/io.c
31
--- a/tests/qemu-iotests/122.out
16
+++ b/block/io.c
32
+++ b/tests/qemu-iotests/122.out
17
@@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
33
@@ -XXX,XX +XXX,XX @@ wrote 1024/1024 bytes at offset 8192
18
}
34
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
19
ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL);
35
wrote 1024/1024 bytes at offset 17408
20
if (ret < 0) {
36
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
21
- error_report("error getting block status at offset %" PRId64 ": %s",
37
+wrote 1024/1024 bytes at offset 66560
22
- offset, strerror(-ret));
38
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
23
return ret;
39
24
}
40
convert -S 4k
25
if (ret & BDRV_BLOCK_ZERO) {
41
[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
26
@@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
42
@@ -XXX,XX +XXX,XX @@ convert -S 4k
27
}
43
{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
28
ret = bdrv_pwrite_zeroes(child, offset, bytes, flags);
44
{ "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false},
29
if (ret < 0) {
45
{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
30
- error_report("error writing zeroes at offset %" PRId64 ": %s",
46
-{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false}]
31
- offset, strerror(-ret));
47
+{ "start": 20480, "length": 46080, "depth": 0, "present": false, "zero": true, "data": false},
32
return ret;
48
+{ "start": 66560, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
33
}
49
+{ "start": 67584, "length": 67041280, "depth": 0, "present": false, "zero": true, "data": false}]
34
offset += bytes;
50
51
convert -c -S 4k
52
[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
53
@@ -XXX,XX +XXX,XX @@ convert -c -S 4k
54
55
convert -S 8k
56
[{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
57
-{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false}]
58
+{ "start": 24576, "length": 41984, "depth": 0, "present": false, "zero": true, "data": false},
59
+{ "start": 66560, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
60
+{ "start": 67584, "length": 67041280, "depth": 0, "present": false, "zero": true, "data": false}]
61
62
convert -c -S 8k
63
[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
35
--
64
--
36
2.20.1
65
2.31.1
37
66
38
67
diff view generated by jsdifflib
1
If qemu-img convert sees that the target image isn't zero-initialised
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
yet, it tries to do an efficient zero write for the whole image first
3
to save the overhead of repeated explicit zero writes during the
4
conversion. Obviously, this provides only an advantage if the
5
pre-zeroing is actually efficient. Otherwise, we can end up writing
6
zeroes slowly while zeroing out the whole image, and then overwrite the
7
same blocks again with real data, potentially doubling the written data.
8
2
9
Pass BDRV_REQ_NO_FALLBACK to blk_make_zero() to avoid this case. If we
3
Consider the case when the whole buffer is zero and end is unaligned.
10
can't efficiently zero out, we'll instead write explicit zeroes only if
11
there is no data to be written to a block.
12
4
5
If i <= tail, we return 1 and do one unaligned WRITE, RMW happens.
6
7
If i > tail, we do on aligned WRITE_ZERO (or skip if target is zeroed)
8
and again one unaligned WRITE, RMW happens.
9
10
Let's do better: don't fragment the whole-zero buffer and report it as
11
ZERO: in case of zeroed target we just do nothing and avoid RMW. If
12
target is not zeroes, one unaligned WRITE_ZERO should not be much worse
13
than one unaligned WRITE.
14
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Message-Id: <20211217164654.1184218-3-vsementsov@virtuozzo.com>
17
Tested-by: Peter Lieven <pl@kamp.de>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Acked-by: Eric Blake <eblake@redhat.com>
15
---
19
---
16
qemu-img.c | 2 +-
20
qemu-img.c | 23 +++++++++++++++++++----
17
1 file changed, 1 insertion(+), 1 deletion(-)
21
tests/qemu-iotests/122.out | 8 ++------
22
2 files changed, 21 insertions(+), 10 deletions(-)
18
23
19
diff --git a/qemu-img.c b/qemu-img.c
24
diff --git a/qemu-img.c b/qemu-img.c
20
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
21
--- a/qemu-img.c
26
--- a/qemu-img.c
22
+++ b/qemu-img.c
27
+++ b/qemu-img.c
23
@@ -XXX,XX +XXX,XX @@ static int convert_do_copy(ImgConvertState *s)
28
@@ -XXX,XX +XXX,XX @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum,
24
if (!s->has_zero_init && !s->target_has_backing &&
25
bdrv_can_write_zeroes_with_unmap(blk_bs(s->target)))
26
{
27
- ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP);
28
+ ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK);
29
if (ret == 0) {
30
s->has_zero_init = true;
31
}
29
}
30
}
31
32
+ if (i == n) {
33
+ /*
34
+ * The whole buf is the same.
35
+ * No reason to split it into chunks, so return now.
36
+ */
37
+ *pnum = i;
38
+ return !is_zero;
39
+ }
40
+
41
tail = (sector_num + i) & (alignment - 1);
42
if (tail) {
43
if (is_zero && i <= tail) {
44
- /* treat unallocated areas which only consist
45
- * of a small tail as allocated. */
46
+ /*
47
+ * For sure next sector after i is data, and it will rewrite this
48
+ * tail anyway due to RMW. So, let's just write data now.
49
+ */
50
is_zero = false;
51
}
52
if (!is_zero) {
53
- /* align up end offset of allocated areas. */
54
+ /* If possible, align up end offset of allocated areas. */
55
i += alignment - tail;
56
i = MIN(i, n);
57
} else {
58
- /* align down end offset of zero areas. */
59
+ /*
60
+ * For sure next sector after i is data, and it will rewrite this
61
+ * tail anyway due to RMW. Better is avoid RMW and write zeroes up
62
+ * to aligned bound.
63
+ */
64
i -= tail;
65
}
66
}
67
diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out
68
index XXXXXXX..XXXXXXX 100644
69
--- a/tests/qemu-iotests/122.out
70
+++ b/tests/qemu-iotests/122.out
71
@@ -XXX,XX +XXX,XX @@ convert -S 4k
72
{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
73
{ "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false},
74
{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
75
-{ "start": 20480, "length": 46080, "depth": 0, "present": false, "zero": true, "data": false},
76
-{ "start": 66560, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
77
-{ "start": 67584, "length": 67041280, "depth": 0, "present": false, "zero": true, "data": false}]
78
+{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false}]
79
80
convert -c -S 4k
81
[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
82
@@ -XXX,XX +XXX,XX @@ convert -c -S 4k
83
84
convert -S 8k
85
[{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
86
-{ "start": 24576, "length": 41984, "depth": 0, "present": false, "zero": true, "data": false},
87
-{ "start": 66560, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
88
-{ "start": 67584, "length": 67041280, "depth": 0, "present": false, "zero": true, "data": false}]
89
+{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false}]
90
91
convert -c -S 8k
92
[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
32
--
93
--
33
2.20.1
94
2.31.1
34
95
35
96
diff view generated by jsdifflib
1
For qemu-img convert, we want an operation that zeroes out the whole
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
image if this can be done efficiently, but that returns an error
2
3
otherwise so we don't write explicit zeroes and immediately overwrite
3
First, this permission never protected a node from being changed, as
4
them with the real data, potentially doubling the amount of data to be
4
generic child-replacing functions don't check it.
5
written.
5
6
6
Second, it's a strange thing: it presents a permission of parent node
7
to change its child. But generally, children are replaced by different
8
mechanisms, like jobs or qmp commands, not by nodes.
9
10
Graph-mod permission is hard to understand. All other permissions
11
describe operations which done by parent node on its child: read,
12
write, resize. Graph modification operations are something completely
13
different.
14
15
The only place where BLK_PERM_GRAPH_MOD is used as "perm" (not shared
16
perm) is mirror_start_job, for s->target. Still modern code should use
17
bdrv_freeze_backing_chain() to protect from graph modification, if we
18
don't do it somewhere it may be considered as a bug. So, it's a bit
19
risky to drop GRAPH_MOD, and analyzing of possible loss of protection
20
is hard. But one day we should do it, let's do it now.
21
22
One more bit of information is that locking the corresponding byte in
23
file-posix doesn't make sense at all.
24
25
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
26
Message-Id: <20210902093754.2352-1-vsementsov@virtuozzo.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Acked-by: Eric Blake <eblake@redhat.com>
9
---
28
---
10
include/block/block.h | 7 ++++++-
29
qapi/block-core.json | 7 ++-----
11
block/io.c | 12 +++++++++++-
30
include/block/block.h | 9 +++++----
12
2 files changed, 17 insertions(+), 2 deletions(-)
31
block.c | 7 +------
13
32
block/commit.c | 1 -
33
block/mirror.c | 15 +++------------
34
hw/block/block.c | 3 +--
35
scripts/render_block_graph.py | 1 -
36
tests/qemu-iotests/273.out | 4 ----
37
8 files changed, 12 insertions(+), 35 deletions(-)
38
39
diff --git a/qapi/block-core.json b/qapi/block-core.json
40
index XXXXXXX..XXXXXXX 100644
41
--- a/qapi/block-core.json
42
+++ b/qapi/block-core.json
43
@@ -XXX,XX +XXX,XX @@
44
#
45
# @resize: This permission is required to change the size of a block node.
46
#
47
-# @graph-mod: This permission is required to change the node that this
48
-# BdrvChild points to.
49
-#
50
# Since: 4.0
51
##
52
{ 'enum': 'BlockPermission',
53
- 'data': [ 'consistent-read', 'write', 'write-unchanged', 'resize',
54
- 'graph-mod' ] }
55
+ 'data': [ 'consistent-read', 'write', 'write-unchanged', 'resize' ] }
56
+
57
##
58
# @XDbgBlockGraphEdge:
59
#
14
diff --git a/include/block/block.h b/include/block/block.h
60
diff --git a/include/block/block.h b/include/block/block.h
15
index XXXXXXX..XXXXXXX 100644
61
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block.h
62
--- a/include/block/block.h
17
+++ b/include/block/block.h
63
+++ b/include/block/block.h
18
@@ -XXX,XX +XXX,XX @@ typedef enum {
64
@@ -XXX,XX +XXX,XX @@ enum {
65
BLK_PERM_RESIZE = 0x08,
66
67
/**
68
- * This permission is required to change the node that this BdrvChild
69
- * points to.
70
+ * There was a now-removed bit BLK_PERM_GRAPH_MOD, with value of 0x10. QEMU
71
+ * 6.1 and earlier may still lock the corresponding byte in block/file-posix
72
+ * locking. So, implementing some new permission should be very careful to
73
+ * not interfere with this old unused thing.
19
*/
74
*/
20
BDRV_REQ_SERIALISING = 0x80,
75
- BLK_PERM_GRAPH_MOD = 0x10,
21
76
22
+ /* Execute the request only if the operation can be offloaded or otherwise
77
- BLK_PERM_ALL = 0x1f,
23
+ * be executed efficiently, but return an error instead of using a slow
78
+ BLK_PERM_ALL = 0x0f,
24
+ * fallback. */
79
25
+ BDRV_REQ_NO_FALLBACK = 0x100,
80
DEFAULT_PERM_PASSTHROUGH = BLK_PERM_CONSISTENT_READ
26
+
81
| BLK_PERM_WRITE
27
/* Mask of valid flags */
82
diff --git a/block.c b/block.c
28
- BDRV_REQ_MASK = 0xff,
83
index XXXXXXX..XXXXXXX 100644
29
+ BDRV_REQ_MASK = 0x1ff,
84
--- a/block.c
30
} BdrvRequestFlags;
85
+++ b/block.c
31
86
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
32
typedef struct BlockSizes {
87
{ BLK_PERM_WRITE, "write" },
33
diff --git a/block/io.c b/block/io.c
88
{ BLK_PERM_WRITE_UNCHANGED, "write unchanged" },
34
index XXXXXXX..XXXXXXX 100644
89
{ BLK_PERM_RESIZE, "resize" },
35
--- a/block/io.c
90
- { BLK_PERM_GRAPH_MOD, "change children" },
36
+++ b/block/io.c
91
{ 0, NULL }
37
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
92
};
38
unsigned int nb_sectors;
93
39
94
@@ -XXX,XX +XXX,XX @@ static void bdrv_default_perms_for_cow(BlockDriverState *bs, BdrvChild *c,
40
assert(!(flags & ~BDRV_REQ_MASK));
95
shared = 0;
41
+ assert(!(flags & BDRV_REQ_NO_FALLBACK));
96
}
42
97
43
if (!drv) {
98
- shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD |
44
return -ENOMEDIUM;
99
- BLK_PERM_WRITE_UNCHANGED;
45
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
100
+ shared |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
46
int ret;
101
47
102
if (bs->open_flags & BDRV_O_INACTIVE) {
48
assert(!(flags & ~BDRV_REQ_MASK));
103
shared |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
49
+ assert(!(flags & BDRV_REQ_NO_FALLBACK));
104
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
50
105
[BLOCK_PERMISSION_WRITE] = BLK_PERM_WRITE,
51
if (!drv) {
106
[BLOCK_PERMISSION_WRITE_UNCHANGED] = BLK_PERM_WRITE_UNCHANGED,
52
return -ENOMEDIUM;
107
[BLOCK_PERMISSION_RESIZE] = BLK_PERM_RESIZE,
53
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
108
- [BLOCK_PERMISSION_GRAPH_MOD] = BLK_PERM_GRAPH_MOD,
54
return -ENOMEDIUM;
109
};
55
}
110
56
111
QEMU_BUILD_BUG_ON(ARRAY_SIZE(permissions) != BLOCK_PERMISSION__MAX);
57
+ if ((flags & ~bs->supported_zero_flags) & BDRV_REQ_NO_FALLBACK) {
112
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
58
+ return -ENOTSUP;
113
update_inherits_from = bdrv_inherits_from_recursive(base, explicit_top);
59
+ }
114
60
+
115
/* success - we can delete the intermediate states, and link top->base */
61
assert(alignment % bs->bl.request_alignment == 0);
116
- /* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once
62
head = offset % alignment;
117
- * we've figured out how they should work. */
63
tail = (offset + bytes) % alignment;
118
if (!backing_file_str) {
64
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
119
bdrv_refresh_filename(base);
65
assert(!bs->supported_zero_flags);
120
backing_file_str = base->filename;
121
diff --git a/block/commit.c b/block/commit.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/block/commit.c
124
+++ b/block/commit.c
125
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
126
s->base = blk_new(s->common.job.aio_context,
127
base_perms,
128
BLK_PERM_CONSISTENT_READ
129
- | BLK_PERM_GRAPH_MOD
130
| BLK_PERM_WRITE_UNCHANGED);
131
ret = blk_insert_bs(s->base, base, errp);
132
if (ret < 0) {
133
diff --git a/block/mirror.c b/block/mirror.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/block/mirror.c
136
+++ b/block/mirror.c
137
@@ -XXX,XX +XXX,XX @@ static void mirror_complete(Job *job, Error **errp)
138
replace_aio_context = bdrv_get_aio_context(s->to_replace);
139
aio_context_acquire(replace_aio_context);
140
141
- /* TODO Translate this into permission system. Current definition of
142
- * GRAPH_MOD would require to request it for the parents; they might
143
- * not even be BlockDriverStates, however, so a BdrvChild can't address
144
- * them. May need redefinition of GRAPH_MOD. */
145
+ /* TODO Translate this into child freeze system. */
146
error_setg(&s->replace_blocker,
147
"block device is in use by block-job-complete");
148
bdrv_op_block_all(s->to_replace, s->replace_blocker);
149
@@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job(
150
s = block_job_create(job_id, driver, NULL, mirror_top_bs,
151
BLK_PERM_CONSISTENT_READ,
152
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
153
- BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,
154
+ BLK_PERM_WRITE, speed,
155
creation_flags, cb, opaque, errp);
156
if (!s) {
157
goto fail;
158
@@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job(
159
target_perms |= BLK_PERM_RESIZE;
66
}
160
}
67
161
68
- if (ret == -ENOTSUP) {
162
- target_shared_perms |= BLK_PERM_CONSISTENT_READ
69
+ if (ret == -ENOTSUP && !(flags & BDRV_REQ_NO_FALLBACK)) {
163
- | BLK_PERM_WRITE
70
/* Fall back to bounce buffer if write zeroes is unsupported */
164
- | BLK_PERM_GRAPH_MOD;
71
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
165
+ target_shared_perms |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
72
166
} else if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) {
73
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(
167
/*
74
BdrvTrackedRequest req;
168
* We may want to allow this in the future, but it would
75
int ret;
169
@@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job(
76
170
goto fail;
77
+ /* TODO We can support BDRV_REQ_NO_FALLBACK here */
171
}
78
+ assert(!(read_flags & BDRV_REQ_NO_FALLBACK));
172
79
+ assert(!(write_flags & BDRV_REQ_NO_FALLBACK));
173
- if (backing_mode != MIRROR_LEAVE_BACKING_CHAIN) {
80
+
174
- target_perms |= BLK_PERM_GRAPH_MOD;
81
if (!dst || !dst->bs) {
175
- }
82
return -ENOMEDIUM;
176
-
83
}
177
s->target = blk_new(s->common.job.aio_context,
178
target_perms, target_shared_perms);
179
ret = blk_insert_bs(s->target, target, errp);
180
diff --git a/hw/block/block.c b/hw/block/block.c
181
index XXXXXXX..XXXXXXX 100644
182
--- a/hw/block/block.c
183
+++ b/hw/block/block.c
184
@@ -XXX,XX +XXX,XX @@ bool blkconf_apply_backend_options(BlockConf *conf, bool readonly,
185
perm |= BLK_PERM_WRITE;
186
}
187
188
- shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
189
- BLK_PERM_GRAPH_MOD;
190
+ shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
191
if (resizable) {
192
shared_perm |= BLK_PERM_RESIZE;
193
}
194
diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py
195
index XXXXXXX..XXXXXXX 100755
196
--- a/scripts/render_block_graph.py
197
+++ b/scripts/render_block_graph.py
198
@@ -XXX,XX +XXX,XX @@ def perm(arr):
199
s = 'w' if 'write' in arr else '_'
200
s += 'r' if 'consistent-read' in arr else '_'
201
s += 'u' if 'write-unchanged' in arr else '_'
202
- s += 'g' if 'graph-mod' in arr else '_'
203
s += 's' if 'resize' in arr else '_'
204
return s
205
206
diff --git a/tests/qemu-iotests/273.out b/tests/qemu-iotests/273.out
207
index XXXXXXX..XXXXXXX 100644
208
--- a/tests/qemu-iotests/273.out
209
+++ b/tests/qemu-iotests/273.out
210
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
211
"name": "file",
212
"parent": 5,
213
"shared-perm": [
214
- "graph-mod",
215
"write-unchanged",
216
"consistent-read"
217
],
218
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
219
"name": "backing",
220
"parent": 5,
221
"shared-perm": [
222
- "graph-mod",
223
"resize",
224
"write-unchanged",
225
"write",
226
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
227
"name": "file",
228
"parent": 3,
229
"shared-perm": [
230
- "graph-mod",
231
"write-unchanged",
232
"consistent-read"
233
],
234
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
235
"name": "backing",
236
"parent": 3,
237
"shared-perm": [
238
- "graph-mod",
239
"resize",
240
"write-unchanged",
241
"write",
84
--
242
--
85
2.20.1
243
2.31.1
86
244
87
245
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
A lot of Optional[] types doesn't make code beautiful.
4
test_field_width defaults to 8, but that is never used in the code.
5
6
More over, if we want some default behavior for single call of
7
test_run(), it should just print the whole test name, not limiting or
8
expanding its width, so 8 is bad default.
9
10
So, just drop the default as unused for now.
11
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Message-Id: <20211210201450.101576-1-vsementsov@virtuozzo.com>
14
Reviewed-by: John Snow <jsnow@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
tests/qemu-iotests/testrunner.py | 21 ++++++++++-----------
18
1 file changed, 10 insertions(+), 11 deletions(-)
19
20
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
21
index XXXXXXX..XXXXXXX 100644
22
--- a/tests/qemu-iotests/testrunner.py
23
+++ b/tests/qemu-iotests/testrunner.py
24
@@ -XXX,XX +XXX,XX @@ def __enter__(self) -> 'TestRunner':
25
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
26
self._stack.close()
27
28
- def test_print_one_line(self, test: str, starttime: str,
29
+ def test_print_one_line(self, test: str,
30
+ test_field_width: int,
31
+ starttime: str,
32
endtime: Optional[str] = None, status: str = '...',
33
lasttime: Optional[float] = None,
34
thistime: Optional[float] = None,
35
description: str = '',
36
- test_field_width: Optional[int] = None,
37
end: str = '\n') -> None:
38
""" Print short test info before/after test run """
39
test = os.path.basename(test)
40
41
- if test_field_width is None:
42
- test_field_width = 8
43
-
44
if self.makecheck and status != '...':
45
if status and status != 'pass':
46
status = f' [{status}]'
47
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str, mp: bool) -> TestResult:
48
casenotrun=casenotrun)
49
50
def run_test(self, test: str,
51
- test_field_width: Optional[int] = None,
52
+ test_field_width: int,
53
mp: bool = False) -> TestResult:
54
"""
55
Run one test and print short status
56
@@ -XXX,XX +XXX,XX @@ def run_test(self, test: str,
57
58
if not self.makecheck:
59
self.test_print_one_line(test=test,
60
+ test_field_width=test_field_width,
61
status = 'started' if mp else '...',
62
starttime=start,
63
lasttime=last_el,
64
- end = '\n' if mp else '\r',
65
- test_field_width=test_field_width)
66
+ end = '\n' if mp else '\r')
67
68
res = self.do_run_test(test, mp)
69
70
end = datetime.datetime.now().strftime('%H:%M:%S')
71
- self.test_print_one_line(test=test, status=res.status,
72
+ self.test_print_one_line(test=test,
73
+ test_field_width=test_field_width,
74
+ status=res.status,
75
starttime=start, endtime=end,
76
lasttime=last_el, thistime=res.elapsed,
77
- description=res.description,
78
- test_field_width=test_field_width)
79
+ description=res.description)
80
81
if res.casenotrun:
82
print(res.casenotrun)
83
--
84
2.31.1
85
86
diff view generated by jsdifflib