1
The following changes since commit 22dbfdecc3c52228d3489da3fe81da92b21197bf:
1
The following changes since commit 9db3065c62a983286d06c207f4981408cf42184d:
2
2
3
Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20191010.0' into staging (2019-10-14 15:09:08 +0100)
3
Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-6.1-pull-request' into staging (2021-07-08 16:30:18 +0100)
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 a1406a9262a087d9ec9627b88da13c4590b61dae:
9
for you to fetch changes up to e60edf69e2f64e818466019313517a2e6d6b63f4:
10
10
11
iotests: Test large write request to qcow2 file (2019-10-14 17:12:48 +0200)
11
block: Make blockdev-reopen stable API (2021-07-09 13:19:11 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- block: Fix crash with qcow2 partial cluster COW with small cluster
16
- Make blockdev-reopen stable
17
sizes (misaligned write requests with BDRV_REQ_NO_FALLBACK)
17
- Remove deprecated qemu-img backing file without format
18
- qcow2: Fix integer overflow potentially causing corruption with huge
18
- rbd: Convert to coroutines and add write zeroes support
19
requests
19
- rbd: Updated MAINTAINERS
20
- vhdx: Detect truncated image files
20
- export/fuse: Allow other users access to the export
21
- tools: Support help options for --object
21
- vhost-user: Fix backends without multiqueue support
22
- Various block-related replay improvements
22
- Fix drive-backup transaction endless drained section
23
- iotests/028: Fix for long $TEST_DIRs
24
23
25
----------------------------------------------------------------
24
----------------------------------------------------------------
26
Alberto Garcia (1):
25
Alberto Garcia (4):
27
block: Reject misaligned write requests with BDRV_REQ_NO_FALLBACK
26
block: Add bdrv_reopen_queue_free()
27
block: Support multiple reopening with x-blockdev-reopen
28
iotests: Test reopening multiple devices at the same time
29
block: Make blockdev-reopen stable API
28
30
29
Kevin Wolf (4):
31
Eric Blake (3):
30
vl: Split off user_creatable_print_help()
32
qcow2: Prohibit backing file changes in 'qemu-img amend'
31
qemu-io: Support help options for --object
33
qemu-img: Require -F with -b backing image
32
qemu-img: Support help options for --object
34
qemu-img: Improve error for rebase without backing format
33
qemu-nbd: Support help options for --object
34
35
35
Max Reitz (3):
36
Heinrich Schuchardt (1):
36
iotests/028: Fix for long $TEST_DIRs
37
util/uri: do not check argument of uri_free()
37
qcow2: Limit total allocation range to INT_MAX
38
iotests: Test large write request to qcow2 file
39
38
40
Pavel Dovgaluk (6):
39
Ilya Dryomov (1):
41
block: implement bdrv_snapshot_goto for blkreplay
40
MAINTAINERS: update block/rbd.c maintainer
42
replay: disable default snapshot for record/replay
43
replay: update docs for record/replay with block devices
44
replay: don't drain/flush bdrv queue while RR is working
45
replay: finish record/replay before closing the disks
46
replay: add BH oneshot event for block layer
47
41
48
Peter Lieven (1):
42
Kevin Wolf (3):
49
block/vhdx: add check for truncated image files
43
vhost-user: Fix backends without multiqueue support
44
qcow2: Fix dangling pointer after reopen for 'file'
45
block: Acquire AioContexts during bdrv_reopen_multiple()
50
46
51
docs/replay.txt | 12 +++-
47
Max Reitz (6):
52
include/qom/object_interfaces.h | 12 ++++
48
export/fuse: Pass default_permissions for mount
53
include/sysemu/replay.h | 4 ++
49
export/fuse: Add allow-other option
54
replay/replay-internal.h | 1 +
50
export/fuse: Give SET_ATTR_SIZE its own branch
55
block/blkreplay.c | 8 +++
51
export/fuse: Let permissions be adjustable
56
block/block-backend.c | 9 ++-
52
iotests/308: Test +w on read-only FUSE exports
57
block/io.c | 39 ++++++++++++-
53
iotests/fuse-allow-other: Test allow-other
58
block/iscsi.c | 5 +-
59
block/nfs.c | 6 +-
60
block/null.c | 4 +-
61
block/nvme.c | 6 +-
62
block/qcow2-cluster.c | 5 +-
63
block/rbd.c | 5 +-
64
block/vhdx.c | 120 ++++++++++++++++++++++++++++++++++------
65
block/vxhs.c | 5 +-
66
cpus.c | 2 -
67
qemu-img.c | 34 +++++++-----
68
qemu-io.c | 9 ++-
69
qemu-nbd.c | 9 ++-
70
qom/object_interfaces.c | 61 ++++++++++++++++++++
71
replay/replay-events.c | 16 ++++++
72
replay/replay.c | 2 +
73
stubs/replay-user.c | 9 +++
74
vl.c | 63 ++++-----------------
75
stubs/Makefile.objs | 1 +
76
tests/qemu-iotests/028 | 11 +++-
77
tests/qemu-iotests/028.out | 1 -
78
tests/qemu-iotests/268 | 55 ++++++++++++++++++
79
tests/qemu-iotests/268.out | 7 +++
80
tests/qemu-iotests/270 | 83 +++++++++++++++++++++++++++
81
tests/qemu-iotests/270.out | 9 +++
82
tests/qemu-iotests/group | 2 +
83
32 files changed, 504 insertions(+), 111 deletions(-)
84
create mode 100644 stubs/replay-user.c
85
create mode 100755 tests/qemu-iotests/268
86
create mode 100644 tests/qemu-iotests/268.out
87
create mode 100755 tests/qemu-iotests/270
88
create mode 100644 tests/qemu-iotests/270.out
89
54
55
Or Ozeri (1):
56
block/rbd: Add support for rbd image encryption
57
58
Peter Lieven (8):
59
block/rbd: bump librbd requirement to luminous release
60
block/rbd: store object_size in BDRVRBDState
61
block/rbd: update s->image_size in qemu_rbd_getlength
62
block/rbd: migrate from aio to coroutines
63
block/rbd: add write zeroes support
64
block/rbd: drop qemu_rbd_refresh_limits
65
block/rbd: fix type of task->complete
66
MAINTAINERS: add block/rbd.c reviewer
67
68
Vladimir Sementsov-Ogievskiy (1):
69
blockdev: fix drive-backup transaction endless drained section
70
71
qapi/block-core.json | 134 +++-
72
qapi/block-export.json | 33 +-
73
docs/system/deprecated.rst | 32 -
74
docs/system/removed-features.rst | 31 +
75
include/block/block.h | 3 +
76
block.c | 108 +--
77
block/export/fuse.c | 121 +++-
78
block/nfs.c | 4 +-
79
block/qcow2.c | 42 +-
80
block/rbd.c | 749 +++++++++++++--------
81
block/replication.c | 7 +
82
block/ssh.c | 4 +-
83
blockdev.c | 77 ++-
84
hw/virtio/vhost-user.c | 3 +
85
qemu-img.c | 9 +-
86
qemu-io-cmds.c | 7 +-
87
util/uri.c | 22 +-
88
MAINTAINERS | 3 +-
89
meson.build | 7 +-
90
tests/qemu-iotests/040 | 4 +-
91
tests/qemu-iotests/041 | 6 +-
92
tests/qemu-iotests/061 | 3 +
93
tests/qemu-iotests/061.out | 3 +-
94
tests/qemu-iotests/082.out | 6 +-
95
tests/qemu-iotests/114 | 18 +-
96
tests/qemu-iotests/114.out | 11 +-
97
tests/qemu-iotests/155 | 9 +-
98
tests/qemu-iotests/165 | 4 +-
99
tests/qemu-iotests/245 | 78 ++-
100
tests/qemu-iotests/245.out | 4 +-
101
tests/qemu-iotests/248 | 4 +-
102
tests/qemu-iotests/248.out | 2 +-
103
tests/qemu-iotests/296 | 11 +-
104
tests/qemu-iotests/298 | 4 +-
105
tests/qemu-iotests/301 | 4 +-
106
tests/qemu-iotests/301.out | 16 +-
107
tests/qemu-iotests/308 | 20 +-
108
tests/qemu-iotests/308.out | 6 +-
109
tests/qemu-iotests/common.rc | 6 +-
110
tests/qemu-iotests/tests/fuse-allow-other | 168 +++++
111
tests/qemu-iotests/tests/fuse-allow-other.out | 88 +++
112
.../qemu-iotests/tests/remove-bitmap-from-backing | 22 +-
113
42 files changed, 1350 insertions(+), 543 deletions(-)
114
create mode 100755 tests/qemu-iotests/tests/fuse-allow-other
115
create mode 100644 tests/qemu-iotests/tests/fuse-allow-other.out
116
117
diff view generated by jsdifflib
New patch
1
From: Ilya Dryomov <idryomov@gmail.com>
1
2
3
Jason has moved on from working on RBD and Ceph. I'm taking over
4
his role upstream.
5
6
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
7
Message-Id: <20210519112513.19694-1-idryomov@gmail.com>
8
Acked-by: Stefano Garzarella <sgarzare@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
MAINTAINERS | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
14
diff --git a/MAINTAINERS b/MAINTAINERS
15
index XXXXXXX..XXXXXXX 100644
16
--- a/MAINTAINERS
17
+++ b/MAINTAINERS
18
@@ -XXX,XX +XXX,XX @@ S: Supported
19
F: block/vmdk.c
20
21
RBD
22
-M: Jason Dillaman <dillaman@redhat.com>
23
+M: Ilya Dryomov <idryomov@gmail.com>
24
L: qemu-block@nongnu.org
25
S: Supported
26
F: block/rbd.c
27
--
28
2.31.1
29
30
diff view generated by jsdifflib
1
From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
1
From: Or Ozeri <oro@il.ibm.com>
2
2
3
Replay is capable of recording normal BH events, but sometimes
3
Starting from ceph Pacific, RBD has built-in support for image-level encryption.
4
there are single use callbacks scheduled with aio_bh_schedule_oneshot
4
Currently supported formats are LUKS version 1 and 2.
5
function. This patch enables recording and replaying such callbacks.
5
6
Block layer uses these events for calling the completion function.
6
There are 2 new relevant librbd APIs for controlling encryption, both expect an
7
Replaying these calls makes the execution deterministic.
7
open image context:
8
8
9
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
9
rbd_encryption_format: formats an image (i.e. writes the LUKS header)
10
Acked-by: Kevin Wolf <kwolf@redhat.com>
10
rbd_encryption_load: loads encryptor/decryptor to the image IO stack
11
12
This commit extends the qemu rbd driver API to support the above.
13
14
Signed-off-by: Or Ozeri <oro@il.ibm.com>
15
Message-Id: <20210627114635.39326-1-oro@il.ibm.com>
16
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
18
---
13
include/sysemu/replay.h | 4 ++++
19
qapi/block-core.json | 110 ++++++++++++-
14
replay/replay-internal.h | 1 +
20
block/rbd.c | 361 ++++++++++++++++++++++++++++++++++++++++++-
15
block/block-backend.c | 9 ++++++---
21
2 files changed, 465 insertions(+), 6 deletions(-)
16
block/io.c | 4 ++--
22
17
block/iscsi.c | 5 +++--
23
diff --git a/qapi/block-core.json b/qapi/block-core.json
18
block/nfs.c | 6 ++++--
19
block/null.c | 4 +++-
20
block/nvme.c | 6 ++++--
21
block/rbd.c | 5 +++--
22
block/vxhs.c | 5 +++--
23
replay/replay-events.c | 16 ++++++++++++++++
24
stubs/replay-user.c | 9 +++++++++
25
stubs/Makefile.objs | 1 +
26
13 files changed, 59 insertions(+), 16 deletions(-)
27
create mode 100644 stubs/replay-user.c
28
29
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
30
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
31
--- a/include/sysemu/replay.h
25
--- a/qapi/block-core.json
32
+++ b/include/sysemu/replay.h
26
+++ b/qapi/block-core.json
33
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@
34
#include "qapi/qapi-types-misc.h"
28
'extents': ['ImageInfo']
35
#include "qapi/qapi-types-run-state.h"
29
} }
36
#include "qapi/qapi-types-ui.h"
30
37
+#include "block/aio.h"
31
+##
38
32
+# @ImageInfoSpecificRbd:
39
/* replay clock kinds */
33
+#
40
enum ReplayClockKind {
34
+# @encryption-format: Image encryption format
41
@@ -XXX,XX +XXX,XX @@ void replay_enable_events(void);
35
+#
42
bool replay_events_enabled(void);
36
+# Since: 6.1
43
/*! Adds bottom half event to the queue */
37
+##
44
void replay_bh_schedule_event(QEMUBH *bh);
38
+{ 'struct': 'ImageInfoSpecificRbd',
45
+/* Adds oneshot bottom half event to the queue */
39
+ 'data': {
46
+void replay_bh_schedule_oneshot_event(AioContext *ctx,
40
+ '*encryption-format': 'RbdImageEncryptionFormat'
47
+ QEMUBHFunc *cb, void *opaque);
41
+ } }
48
/*! Adds input event to the queue */
42
+
49
void replay_input_event(QemuConsole *src, InputEvent *evt);
43
##
50
/*! Adds input sync event to the queue */
44
# @ImageInfoSpecific:
51
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
45
#
52
index XXXXXXX..XXXXXXX 100644
53
--- a/replay/replay-internal.h
54
+++ b/replay/replay-internal.h
55
@@ -XXX,XX +XXX,XX @@ enum ReplayEvents {
56
57
enum ReplayAsyncEventKind {
58
REPLAY_ASYNC_EVENT_BH,
59
+ REPLAY_ASYNC_EVENT_BH_ONESHOT,
60
REPLAY_ASYNC_EVENT_INPUT,
61
REPLAY_ASYNC_EVENT_INPUT_SYNC,
62
REPLAY_ASYNC_EVENT_CHAR_READ,
63
diff --git a/block/block-backend.c b/block/block-backend.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/block/block-backend.c
66
+++ b/block/block-backend.c
67
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@
68
#include "hw/qdev-core.h"
47
# If we need to add block driver specific parameters for
69
#include "sysemu/blockdev.h"
48
# LUKS in future, then we'll subclass QCryptoBlockInfoLUKS
70
#include "sysemu/runstate.h"
49
# to define a ImageInfoSpecificLUKS
71
+#include "sysemu/sysemu.h"
50
- 'luks': 'QCryptoBlockInfoLUKS'
72
+#include "sysemu/replay.h"
51
+ 'luks': 'QCryptoBlockInfoLUKS',
73
#include "qapi/error.h"
52
+ 'rbd': 'ImageInfoSpecificRbd'
74
#include "qapi/qapi-events-block.h"
53
} }
75
#include "qemu/id.h"
54
76
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
55
##
77
acb->blk = blk;
78
acb->ret = ret;
79
80
- aio_bh_schedule_oneshot(blk_get_aio_context(blk), error_callback_bh, acb);
81
+ replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
82
+ error_callback_bh, acb);
83
return &acb->common;
84
}
85
86
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
87
88
acb->has_returned = true;
89
if (acb->rwco.ret != NOT_DONE) {
90
- aio_bh_schedule_oneshot(blk_get_aio_context(blk),
91
- blk_aio_complete_bh, acb);
92
+ replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
93
+ blk_aio_complete_bh, acb);
94
}
95
96
return &acb->common;
97
diff --git a/block/io.c b/block/io.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/io.c
100
+++ b/block/io.c
101
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
102
if (bs) {
103
bdrv_inc_in_flight(bs);
104
}
105
- aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
106
- bdrv_co_drain_bh_cb, &data);
107
+ replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
108
+ bdrv_co_drain_bh_cb, &data);
109
110
qemu_coroutine_yield();
111
/* If we are resumed from some other event (such as an aio completion or a
112
diff --git a/block/iscsi.c b/block/iscsi.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/iscsi.c
115
+++ b/block/iscsi.c
116
@@ -XXX,XX +XXX,XX @@
56
@@ -XXX,XX +XXX,XX @@
117
#include "qemu/module.h"
57
{ 'enum': 'RbdAuthMode',
118
#include "qemu/option.h"
58
'data': [ 'cephx', 'none' ] }
119
#include "qemu/uuid.h"
59
120
+#include "sysemu/replay.h"
60
+##
121
#include "qapi/error.h"
61
+# @RbdImageEncryptionFormat:
122
#include "qapi/qapi-commands-misc.h"
62
+#
123
#include "qapi/qmp/qdict.h"
63
+# Since: 6.1
124
@@ -XXX,XX +XXX,XX @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
64
+##
125
}
65
+{ 'enum': 'RbdImageEncryptionFormat',
126
66
+ 'data': [ 'luks', 'luks2' ] }
127
if (iTask->co) {
67
+
128
- aio_bh_schedule_oneshot(iTask->iscsilun->aio_context,
68
+##
129
- iscsi_co_generic_bh_cb, iTask);
69
+# @RbdEncryptionOptionsLUKSBase:
130
+ replay_bh_schedule_oneshot_event(iTask->iscsilun->aio_context,
70
+#
131
+ iscsi_co_generic_bh_cb, iTask);
71
+# @key-secret: ID of a QCryptoSecret object providing a passphrase
132
} else {
72
+# for unlocking the encryption
133
iTask->complete = 1;
73
+#
134
}
74
+# Since: 6.1
135
diff --git a/block/nfs.c b/block/nfs.c
75
+##
136
index XXXXXXX..XXXXXXX 100644
76
+{ 'struct': 'RbdEncryptionOptionsLUKSBase',
137
--- a/block/nfs.c
77
+ 'data': { 'key-secret': 'str' } }
138
+++ b/block/nfs.c
78
+
79
+##
80
+# @RbdEncryptionCreateOptionsLUKSBase:
81
+#
82
+# @cipher-alg: The encryption algorithm
83
+#
84
+# Since: 6.1
85
+##
86
+{ 'struct': 'RbdEncryptionCreateOptionsLUKSBase',
87
+ 'base': 'RbdEncryptionOptionsLUKSBase',
88
+ 'data': { '*cipher-alg': 'QCryptoCipherAlgorithm' } }
89
+
90
+##
91
+# @RbdEncryptionOptionsLUKS:
92
+#
93
+# Since: 6.1
94
+##
95
+{ 'struct': 'RbdEncryptionOptionsLUKS',
96
+ 'base': 'RbdEncryptionOptionsLUKSBase',
97
+ 'data': { } }
98
+
99
+##
100
+# @RbdEncryptionOptionsLUKS2:
101
+#
102
+# Since: 6.1
103
+##
104
+{ 'struct': 'RbdEncryptionOptionsLUKS2',
105
+ 'base': 'RbdEncryptionOptionsLUKSBase',
106
+ 'data': { } }
107
+
108
+##
109
+# @RbdEncryptionCreateOptionsLUKS:
110
+#
111
+# Since: 6.1
112
+##
113
+{ 'struct': 'RbdEncryptionCreateOptionsLUKS',
114
+ 'base': 'RbdEncryptionCreateOptionsLUKSBase',
115
+ 'data': { } }
116
+
117
+##
118
+# @RbdEncryptionCreateOptionsLUKS2:
119
+#
120
+# Since: 6.1
121
+##
122
+{ 'struct': 'RbdEncryptionCreateOptionsLUKS2',
123
+ 'base': 'RbdEncryptionCreateOptionsLUKSBase',
124
+ 'data': { } }
125
+
126
+##
127
+# @RbdEncryptionOptions:
128
+#
129
+# Since: 6.1
130
+##
131
+{ 'union': 'RbdEncryptionOptions',
132
+ 'base': { 'format': 'RbdImageEncryptionFormat' },
133
+ 'discriminator': 'format',
134
+ 'data': { 'luks': 'RbdEncryptionOptionsLUKS',
135
+ 'luks2': 'RbdEncryptionOptionsLUKS2' } }
136
+
137
+##
138
+# @RbdEncryptionCreateOptions:
139
+#
140
+# Since: 6.1
141
+##
142
+{ 'union': 'RbdEncryptionCreateOptions',
143
+ 'base': { 'format': 'RbdImageEncryptionFormat' },
144
+ 'discriminator': 'format',
145
+ 'data': { 'luks': 'RbdEncryptionCreateOptionsLUKS',
146
+ 'luks2': 'RbdEncryptionCreateOptionsLUKS2' } }
147
+
148
##
149
# @BlockdevOptionsRbd:
150
#
139
@@ -XXX,XX +XXX,XX @@
151
@@ -XXX,XX +XXX,XX @@
140
#include "qemu/option.h"
152
#
141
#include "qemu/uri.h"
153
# @snapshot: Ceph snapshot name.
142
#include "qemu/cutils.h"
154
#
143
+#include "sysemu/sysemu.h"
155
+# @encrypt: Image encryption options. (Since 6.1)
144
+#include "sysemu/replay.h"
156
+#
145
#include "qapi/qapi-visit-block-core.h"
157
# @user: Ceph id name.
146
#include "qapi/qmp/qdict.h"
158
#
147
#include "qapi/qmp/qstring.h"
159
# @auth-client-required: Acceptable authentication modes.
148
@@ -XXX,XX +XXX,XX @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
149
if (task->ret < 0) {
150
error_report("NFS Error: %s", nfs_get_error(nfs));
151
}
152
- aio_bh_schedule_oneshot(task->client->aio_context,
153
- nfs_co_generic_bh_cb, task);
154
+ replay_bh_schedule_oneshot_event(task->client->aio_context,
155
+ nfs_co_generic_bh_cb, task);
156
}
157
158
static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
159
diff --git a/block/null.c b/block/null.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/block/null.c
162
+++ b/block/null.c
163
@@ -XXX,XX +XXX,XX @@
160
@@ -XXX,XX +XXX,XX @@
164
#include "qemu/module.h"
161
'image': 'str',
165
#include "qemu/option.h"
162
'*conf': 'str',
166
#include "block/block_int.h"
163
'*snapshot': 'str',
167
+#include "sysemu/replay.h"
164
+ '*encrypt': 'RbdEncryptionOptions',
168
165
'*user': 'str',
169
#define NULL_OPT_LATENCY "latency-ns"
166
'*auth-client-required': ['RbdAuthMode'],
170
#define NULL_OPT_ZEROES "read-zeroes"
167
'*key-secret': 'str',
171
@@ -XXX,XX +XXX,XX @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
172
timer_mod_ns(&acb->timer,
173
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
174
} else {
175
- aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb);
176
+ replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
177
+ null_bh_cb, acb);
178
}
179
return &acb->common;
180
}
181
diff --git a/block/nvme.c b/block/nvme.c
182
index XXXXXXX..XXXXXXX 100644
183
--- a/block/nvme.c
184
+++ b/block/nvme.c
185
@@ -XXX,XX +XXX,XX @@
168
@@ -XXX,XX +XXX,XX @@
186
#include "qemu/option.h"
169
# point to a snapshot.
187
#include "qemu/vfio-helpers.h"
170
# @size: Size of the virtual disk in bytes
188
#include "block/block_int.h"
171
# @cluster-size: RBD object size
189
+#include "sysemu/replay.h"
172
+# @encrypt: Image encryption options. (Since 6.1)
190
#include "trace.h"
173
#
191
174
# Since: 2.12
192
#include "block/nvme.h"
175
##
193
@@ -XXX,XX +XXX,XX @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q)
176
{ 'struct': 'BlockdevCreateOptionsRbd',
194
smp_mb_release();
177
'data': { 'location': 'BlockdevOptionsRbd',
195
*q->cq.doorbell = cpu_to_le32(q->cq.head);
178
'size': 'size',
196
if (!qemu_co_queue_empty(&q->free_req_queue)) {
179
- '*cluster-size' : 'size' } }
197
- aio_bh_schedule_oneshot(s->aio_context, nvme_free_req_queue_cb, q);
180
+ '*cluster-size' : 'size',
198
+ replay_bh_schedule_oneshot_event(s->aio_context,
181
+ '*encrypt' : 'RbdEncryptionCreateOptions' } }
199
+ nvme_free_req_queue_cb, q);
182
200
}
183
##
201
}
184
# @BlockdevVmdkSubformat:
202
q->busy = false;
203
@@ -XXX,XX +XXX,XX @@ static void nvme_rw_cb(void *opaque, int ret)
204
/* The rw coroutine hasn't yielded, don't try to enter. */
205
return;
206
}
207
- aio_bh_schedule_oneshot(data->ctx, nvme_rw_cb_bh, data);
208
+ replay_bh_schedule_oneshot_event(data->ctx, nvme_rw_cb_bh, data);
209
}
210
211
static coroutine_fn int nvme_co_prw_aligned(BlockDriverState *bs,
212
diff --git a/block/rbd.c b/block/rbd.c
185
diff --git a/block/rbd.c b/block/rbd.c
213
index XXXXXXX..XXXXXXX 100644
186
index XXXXXXX..XXXXXXX 100644
214
--- a/block/rbd.c
187
--- a/block/rbd.c
215
+++ b/block/rbd.c
188
+++ b/block/rbd.c
216
@@ -XXX,XX +XXX,XX @@
189
@@ -XXX,XX +XXX,XX @@
217
#include "block/qdict.h"
190
#define LIBRBD_USE_IOVEC 0
218
#include "crypto/secret.h"
191
#endif
219
#include "qemu/cutils.h"
192
220
+#include "sysemu/replay.h"
193
+#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
221
#include "qapi/qmp/qstring.h"
194
+
222
#include "qapi/qmp/qdict.h"
195
+static const char rbd_luks_header_verification[
223
#include "qapi/qmp/qjson.h"
196
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
224
@@ -XXX,XX +XXX,XX @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
197
+ 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1
225
rcb->ret = rbd_aio_get_return_value(c);
198
+};
226
rbd_aio_release(c);
199
+
227
200
+static const char rbd_luks2_header_verification[
228
- aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
201
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
229
- rbd_finish_bh, rcb);
202
+ 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
230
+ replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs),
203
+};
231
+ rbd_finish_bh, rcb);
204
+
205
typedef enum {
206
RBD_AIO_READ,
207
RBD_AIO_WRITE,
208
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
209
}
232
}
210
}
233
211
234
static int rbd_aio_discard_wrapper(rbd_image_t image,
212
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
235
diff --git a/block/vxhs.c b/block/vxhs.c
213
+static int qemu_rbd_convert_luks_options(
236
index XXXXXXX..XXXXXXX 100644
214
+ RbdEncryptionOptionsLUKSBase *luks_opts,
237
--- a/block/vxhs.c
215
+ char **passphrase,
238
+++ b/block/vxhs.c
216
+ size_t *passphrase_len,
239
@@ -XXX,XX +XXX,XX @@
217
+ Error **errp)
240
#include "qapi/error.h"
218
+{
241
#include "qemu/uuid.h"
219
+ return qcrypto_secret_lookup(luks_opts->key_secret, (uint8_t **)passphrase,
242
#include "crypto/tlscredsx509.h"
220
+ passphrase_len, errp);
243
+#include "sysemu/replay.h"
221
+}
244
222
+
245
#define VXHS_OPT_FILENAME "filename"
223
+static int qemu_rbd_convert_luks_create_options(
246
#define VXHS_OPT_VDISK_ID "vdisk-id"
224
+ RbdEncryptionCreateOptionsLUKSBase *luks_opts,
247
@@ -XXX,XX +XXX,XX @@ static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error)
225
+ rbd_encryption_algorithm_t *alg,
248
trace_vxhs_iio_callback(error);
226
+ char **passphrase,
227
+ size_t *passphrase_len,
228
+ Error **errp)
229
+{
230
+ int r = 0;
231
+
232
+ r = qemu_rbd_convert_luks_options(
233
+ qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),
234
+ passphrase, passphrase_len, errp);
235
+ if (r < 0) {
236
+ return r;
237
+ }
238
+
239
+ if (luks_opts->has_cipher_alg) {
240
+ switch (luks_opts->cipher_alg) {
241
+ case QCRYPTO_CIPHER_ALG_AES_128: {
242
+ *alg = RBD_ENCRYPTION_ALGORITHM_AES128;
243
+ break;
244
+ }
245
+ case QCRYPTO_CIPHER_ALG_AES_256: {
246
+ *alg = RBD_ENCRYPTION_ALGORITHM_AES256;
247
+ break;
248
+ }
249
+ default: {
250
+ r = -ENOTSUP;
251
+ error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
252
+ luks_opts->cipher_alg);
253
+ return r;
254
+ }
255
+ }
256
+ } else {
257
+ /* default alg */
258
+ *alg = RBD_ENCRYPTION_ALGORITHM_AES256;
259
+ }
260
+
261
+ return 0;
262
+}
263
+
264
+static int qemu_rbd_encryption_format(rbd_image_t image,
265
+ RbdEncryptionCreateOptions *encrypt,
266
+ Error **errp)
267
+{
268
+ int r = 0;
269
+ g_autofree char *passphrase = NULL;
270
+ size_t passphrase_len;
271
+ rbd_encryption_format_t format;
272
+ rbd_encryption_options_t opts;
273
+ rbd_encryption_luks1_format_options_t luks_opts;
274
+ rbd_encryption_luks2_format_options_t luks2_opts;
275
+ size_t opts_size;
276
+ uint64_t raw_size, effective_size;
277
+
278
+ r = rbd_get_size(image, &raw_size);
279
+ if (r < 0) {
280
+ error_setg_errno(errp, -r, "cannot get raw image size");
281
+ return r;
282
+ }
283
+
284
+ switch (encrypt->format) {
285
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
286
+ memset(&luks_opts, 0, sizeof(luks_opts));
287
+ format = RBD_ENCRYPTION_FORMAT_LUKS1;
288
+ opts = &luks_opts;
289
+ opts_size = sizeof(luks_opts);
290
+ r = qemu_rbd_convert_luks_create_options(
291
+ qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
292
+ &luks_opts.alg, &passphrase, &passphrase_len, errp);
293
+ if (r < 0) {
294
+ return r;
295
+ }
296
+ luks_opts.passphrase = passphrase;
297
+ luks_opts.passphrase_size = passphrase_len;
298
+ break;
299
+ }
300
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
301
+ memset(&luks2_opts, 0, sizeof(luks2_opts));
302
+ format = RBD_ENCRYPTION_FORMAT_LUKS2;
303
+ opts = &luks2_opts;
304
+ opts_size = sizeof(luks2_opts);
305
+ r = qemu_rbd_convert_luks_create_options(
306
+ qapi_RbdEncryptionCreateOptionsLUKS2_base(
307
+ &encrypt->u.luks2),
308
+ &luks2_opts.alg, &passphrase, &passphrase_len, errp);
309
+ if (r < 0) {
310
+ return r;
311
+ }
312
+ luks2_opts.passphrase = passphrase;
313
+ luks2_opts.passphrase_size = passphrase_len;
314
+ break;
315
+ }
316
+ default: {
317
+ r = -ENOTSUP;
318
+ error_setg_errno(
319
+ errp, -r, "unknown image encryption format: %u",
320
+ encrypt->format);
321
+ return r;
322
+ }
323
+ }
324
+
325
+ r = rbd_encryption_format(image, format, opts, opts_size);
326
+ if (r < 0) {
327
+ error_setg_errno(errp, -r, "encryption format fail");
328
+ return r;
329
+ }
330
+
331
+ r = rbd_get_size(image, &effective_size);
332
+ if (r < 0) {
333
+ error_setg_errno(errp, -r, "cannot get effective image size");
334
+ return r;
335
+ }
336
+
337
+ r = rbd_resize(image, raw_size + (raw_size - effective_size));
338
+ if (r < 0) {
339
+ error_setg_errno(errp, -r, "cannot resize image after format");
340
+ return r;
341
+ }
342
+
343
+ return 0;
344
+}
345
+
346
+static int qemu_rbd_encryption_load(rbd_image_t image,
347
+ RbdEncryptionOptions *encrypt,
348
+ Error **errp)
349
+{
350
+ int r = 0;
351
+ g_autofree char *passphrase = NULL;
352
+ size_t passphrase_len;
353
+ rbd_encryption_luks1_format_options_t luks_opts;
354
+ rbd_encryption_luks2_format_options_t luks2_opts;
355
+ rbd_encryption_format_t format;
356
+ rbd_encryption_options_t opts;
357
+ size_t opts_size;
358
+
359
+ switch (encrypt->format) {
360
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
361
+ memset(&luks_opts, 0, sizeof(luks_opts));
362
+ format = RBD_ENCRYPTION_FORMAT_LUKS1;
363
+ opts = &luks_opts;
364
+ opts_size = sizeof(luks_opts);
365
+ r = qemu_rbd_convert_luks_options(
366
+ qapi_RbdEncryptionOptionsLUKS_base(&encrypt->u.luks),
367
+ &passphrase, &passphrase_len, errp);
368
+ if (r < 0) {
369
+ return r;
370
+ }
371
+ luks_opts.passphrase = passphrase;
372
+ luks_opts.passphrase_size = passphrase_len;
373
+ break;
374
+ }
375
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
376
+ memset(&luks2_opts, 0, sizeof(luks2_opts));
377
+ format = RBD_ENCRYPTION_FORMAT_LUKS2;
378
+ opts = &luks2_opts;
379
+ opts_size = sizeof(luks2_opts);
380
+ r = qemu_rbd_convert_luks_options(
381
+ qapi_RbdEncryptionOptionsLUKS2_base(&encrypt->u.luks2),
382
+ &passphrase, &passphrase_len, errp);
383
+ if (r < 0) {
384
+ return r;
385
+ }
386
+ luks2_opts.passphrase = passphrase;
387
+ luks2_opts.passphrase_size = passphrase_len;
388
+ break;
389
+ }
390
+ default: {
391
+ r = -ENOTSUP;
392
+ error_setg_errno(
393
+ errp, -r, "unknown image encryption format: %u",
394
+ encrypt->format);
395
+ return r;
396
+ }
397
+ }
398
+
399
+ r = rbd_encryption_load(image, format, opts, opts_size);
400
+ if (r < 0) {
401
+ error_setg_errno(errp, -r, "encryption load fail");
402
+ return r;
403
+ }
404
+
405
+ return 0;
406
+}
407
+#endif
408
+
409
/* FIXME Deprecate and remove keypairs or make it available in QMP. */
410
static int qemu_rbd_do_create(BlockdevCreateOptions *options,
411
const char *keypairs, const char *password_secret,
412
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
413
return -EINVAL;
414
}
415
416
+#ifndef LIBRBD_SUPPORTS_ENCRYPTION
417
+ if (opts->has_encrypt) {
418
+ error_setg(errp, "RBD library does not support image encryption");
419
+ return -ENOTSUP;
420
+ }
421
+#endif
422
+
423
if (opts->has_cluster_size) {
424
int64_t objsize = opts->cluster_size;
425
if ((objsize - 1) & objsize) { /* not a power of 2? */
426
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
427
goto out;
428
}
429
430
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
431
+ if (opts->has_encrypt) {
432
+ rbd_image_t image;
433
+
434
+ ret = rbd_open(io_ctx, opts->location->image, &image, NULL);
435
+ if (ret < 0) {
436
+ error_setg_errno(errp, -ret,
437
+ "error opening image '%s' for encryption format",
438
+ opts->location->image);
439
+ goto out;
440
+ }
441
+
442
+ ret = qemu_rbd_encryption_format(image, opts->encrypt, errp);
443
+ rbd_close(image);
444
+ if (ret < 0) {
445
+ /* encryption format fail, try removing the image */
446
+ rbd_remove(io_ctx, opts->location->image);
447
+ goto out;
448
+ }
449
+ }
450
+#endif
451
+
452
ret = 0;
453
out:
454
rados_ioctx_destroy(io_ctx);
455
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_co_create(BlockdevCreateOptions *options, Error **errp)
456
return qemu_rbd_do_create(options, NULL, NULL, errp);
457
}
458
459
+static int qemu_rbd_extract_encryption_create_options(
460
+ QemuOpts *opts,
461
+ RbdEncryptionCreateOptions **spec,
462
+ Error **errp)
463
+{
464
+ QDict *opts_qdict;
465
+ QDict *encrypt_qdict;
466
+ Visitor *v;
467
+ int ret = 0;
468
+
469
+ opts_qdict = qemu_opts_to_qdict(opts, NULL);
470
+ qdict_extract_subqdict(opts_qdict, &encrypt_qdict, "encrypt.");
471
+ qobject_unref(opts_qdict);
472
+ if (!qdict_size(encrypt_qdict)) {
473
+ *spec = NULL;
474
+ goto exit;
475
+ }
476
+
477
+ /* Convert options into a QAPI object */
478
+ v = qobject_input_visitor_new_flat_confused(encrypt_qdict, errp);
479
+ if (!v) {
480
+ ret = -EINVAL;
481
+ goto exit;
482
+ }
483
+
484
+ visit_type_RbdEncryptionCreateOptions(v, NULL, spec, errp);
485
+ visit_free(v);
486
+ if (!*spec) {
487
+ ret = -EINVAL;
488
+ goto exit;
489
+ }
490
+
491
+exit:
492
+ qobject_unref(encrypt_qdict);
493
+ return ret;
494
+}
495
+
496
static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
497
const char *filename,
498
QemuOpts *opts,
499
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
500
BlockdevCreateOptions *create_options;
501
BlockdevCreateOptionsRbd *rbd_opts;
502
BlockdevOptionsRbd *loc;
503
+ RbdEncryptionCreateOptions *encrypt = NULL;
504
Error *local_err = NULL;
505
const char *keypairs, *password_secret;
506
QDict *options = NULL;
507
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_create_opts(BlockDriver *drv,
508
goto exit;
509
}
510
511
+ ret = qemu_rbd_extract_encryption_create_options(opts, &encrypt, errp);
512
+ if (ret < 0) {
513
+ goto exit;
514
+ }
515
+ rbd_opts->encrypt = encrypt;
516
+ rbd_opts->has_encrypt = !!encrypt;
517
+
518
/*
519
* Caution: while qdict_get_try_str() is fine, getting non-string
520
* types would require more care. When @options come from -blockdev
521
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
522
goto failed_open;
523
}
524
525
+ if (opts->has_encrypt) {
526
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
527
+ r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp);
528
+ if (r < 0) {
529
+ goto failed_post_open;
530
+ }
531
+#else
532
+ r = -ENOTSUP;
533
+ error_setg(errp, "RBD library does not support image encryption");
534
+ goto failed_post_open;
535
+#endif
536
+ }
537
+
538
r = rbd_get_size(s->image, &s->image_size);
539
if (r < 0) {
540
error_setg_errno(errp, -r, "error getting image size from %s",
541
s->image_name);
542
- rbd_close(s->image);
543
- goto failed_open;
544
+ goto failed_post_open;
545
}
546
547
/* If we are using an rbd snapshot, we must be r/o, otherwise
548
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
549
if (s->snap != NULL) {
550
r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
551
if (r < 0) {
552
- rbd_close(s->image);
553
- goto failed_open;
554
+ goto failed_post_open;
249
}
555
}
250
556
}
251
- aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
557
252
- vxhs_complete_aio_bh, acb);
558
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
253
+ replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs),
559
r = 0;
254
+ vxhs_complete_aio_bh, acb);
560
goto out;
255
break;
561
256
562
+failed_post_open:
257
default:
563
+ rbd_close(s->image);
258
diff --git a/replay/replay-events.c b/replay/replay-events.c
564
failed_open:
259
index XXXXXXX..XXXXXXX 100644
565
rados_ioctx_destroy(s->io_ctx);
260
--- a/replay/replay-events.c
566
g_free(s->snap);
261
+++ b/replay/replay-events.c
567
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
262
@@ -XXX,XX +XXX,XX @@ static void replay_run_event(Event *event)
568
return 0;
263
case REPLAY_ASYNC_EVENT_BH:
264
aio_bh_call(event->opaque);
265
break;
266
+ case REPLAY_ASYNC_EVENT_BH_ONESHOT:
267
+ ((QEMUBHFunc *)event->opaque)(event->opaque2);
268
+ break;
269
case REPLAY_ASYNC_EVENT_INPUT:
270
qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
271
qapi_free_InputEvent((InputEvent *)event->opaque);
272
@@ -XXX,XX +XXX,XX @@ void replay_bh_schedule_event(QEMUBH *bh)
273
}
274
}
569
}
275
570
276
+void replay_bh_schedule_oneshot_event(AioContext *ctx,
571
+static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
277
+ QEMUBHFunc *cb, void *opaque)
572
+ Error **errp)
278
+{
573
+{
279
+ if (events_enabled) {
574
+ BDRVRBDState *s = bs->opaque;
280
+ uint64_t id = replay_get_current_icount();
575
+ ImageInfoSpecific *spec_info;
281
+ replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id);
576
+ char buf[RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {0};
577
+ int r;
578
+
579
+ if (s->image_size >= RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) {
580
+ r = rbd_read(s->image, 0,
581
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN, buf);
582
+ if (r < 0) {
583
+ error_setg_errno(errp, -r, "cannot read image start for probe");
584
+ return NULL;
585
+ }
586
+ }
587
+
588
+ spec_info = g_new(ImageInfoSpecific, 1);
589
+ *spec_info = (ImageInfoSpecific){
590
+ .type = IMAGE_INFO_SPECIFIC_KIND_RBD,
591
+ .u.rbd.data = g_new0(ImageInfoSpecificRbd, 1),
592
+ };
593
+
594
+ if (memcmp(buf, rbd_luks_header_verification,
595
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
596
+ spec_info->u.rbd.data->encryption_format =
597
+ RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
598
+ spec_info->u.rbd.data->has_encryption_format = true;
599
+ } else if (memcmp(buf, rbd_luks2_header_verification,
600
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
601
+ spec_info->u.rbd.data->encryption_format =
602
+ RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
603
+ spec_info->u.rbd.data->has_encryption_format = true;
282
+ } else {
604
+ } else {
283
+ aio_bh_schedule_oneshot(ctx, cb, opaque);
605
+ spec_info->u.rbd.data->has_encryption_format = false;
284
+ }
606
+ }
607
+
608
+ return spec_info;
285
+}
609
+}
286
+
610
+
287
void replay_add_input_event(struct InputEvent *event)
611
static int64_t qemu_rbd_getlength(BlockDriverState *bs)
288
{
612
{
289
replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
613
BDRVRBDState *s = bs->opaque;
290
@@ -XXX,XX +XXX,XX @@ static void replay_save_event(Event *event, int checkpoint)
614
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qemu_rbd_create_opts = {
291
/* save event-specific data */
615
.type = QEMU_OPT_STRING,
292
switch (event->event_kind) {
616
.help = "ID of secret providing the password",
293
case REPLAY_ASYNC_EVENT_BH:
617
},
294
+ case REPLAY_ASYNC_EVENT_BH_ONESHOT:
618
+ {
295
replay_put_qword(event->id);
619
+ .name = "encrypt.format",
296
break;
620
+ .type = QEMU_OPT_STRING,
297
case REPLAY_ASYNC_EVENT_INPUT:
621
+ .help = "Encrypt the image, format choices: 'luks', 'luks2'",
298
@@ -XXX,XX +XXX,XX @@ static Event *replay_read_event(int checkpoint)
622
+ },
299
/* Events that has not to be in the queue */
623
+ {
300
switch (replay_state.read_event_kind) {
624
+ .name = "encrypt.cipher-alg",
301
case REPLAY_ASYNC_EVENT_BH:
625
+ .type = QEMU_OPT_STRING,
302
+ case REPLAY_ASYNC_EVENT_BH_ONESHOT:
626
+ .help = "Name of encryption cipher algorithm"
303
if (replay_state.read_event_id == -1) {
627
+ " (allowed values: aes-128, aes-256)",
304
replay_state.read_event_id = replay_get_qword();
628
+ },
305
}
629
+ {
306
diff --git a/stubs/replay-user.c b/stubs/replay-user.c
630
+ .name = "encrypt.key-secret",
307
new file mode 100644
631
+ .type = QEMU_OPT_STRING,
308
index XXXXXXX..XXXXXXX
632
+ .help = "ID of secret providing LUKS passphrase",
309
--- /dev/null
633
+ },
310
+++ b/stubs/replay-user.c
634
{ /* end of list */ }
311
@@ -XXX,XX +XXX,XX @@
635
}
312
+#include "qemu/osdep.h"
636
};
313
+#include "sysemu/replay.h"
637
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
314
+#include "sysemu/sysemu.h"
638
.bdrv_co_create_opts = qemu_rbd_co_create_opts,
315
+
639
.bdrv_has_zero_init = bdrv_has_zero_init_1,
316
+void replay_bh_schedule_oneshot_event(AioContext *ctx,
640
.bdrv_get_info = qemu_rbd_getinfo,
317
+ QEMUBHFunc *cb, void *opaque)
641
+ .bdrv_get_specific_info = qemu_rbd_get_specific_info,
318
+{
642
.create_opts = &qemu_rbd_create_opts,
319
+ aio_bh_schedule_oneshot(ctx, cb, opaque);
643
.bdrv_getlength = qemu_rbd_getlength,
320
+}
644
.bdrv_co_truncate = qemu_rbd_co_truncate,
321
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
322
index XXXXXXX..XXXXXXX 100644
323
--- a/stubs/Makefile.objs
324
+++ b/stubs/Makefile.objs
325
@@ -XXX,XX +XXX,XX @@ stub-obj-y += monitor.o
326
stub-obj-y += notify-event.o
327
stub-obj-y += qtest.o
328
stub-obj-y += replay.o
329
+stub-obj-y += replay-user.o
330
stub-obj-y += runstate-check.o
331
stub-obj-y += set-fd-handler.o
332
stub-obj-y += sysbus.o
333
--
645
--
334
2.20.1
646
2.31.1
335
647
336
648
diff view generated by jsdifflib
New patch
1
1
From: Peter Lieven <pl@kamp.de>
2
3
Ceph Luminous (version 12.2.z) is almost 4 years old at this point.
4
Bump the requirement to get rid of the ifdef'ry in the code.
5
Qemu 6.1 dropped the support for RHEL-7 which was the last supported
6
OS that required an older librbd.
7
8
Signed-off-by: Peter Lieven <pl@kamp.de>
9
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
10
Message-Id: <20210702172356.11574-2-idryomov@gmail.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block/rbd.c | 120 ++++------------------------------------------------
14
meson.build | 7 ++-
15
2 files changed, 13 insertions(+), 114 deletions(-)
16
17
diff --git a/block/rbd.c b/block/rbd.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/rbd.c
20
+++ b/block/rbd.c
21
@@ -XXX,XX +XXX,XX @@
22
* leading "\".
23
*/
24
25
-/* rbd_aio_discard added in 0.1.2 */
26
-#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 2)
27
-#define LIBRBD_SUPPORTS_DISCARD
28
-#else
29
-#undef LIBRBD_SUPPORTS_DISCARD
30
-#endif
31
-
32
#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
33
34
#define RBD_MAX_SNAPS 100
35
36
-/* The LIBRBD_SUPPORTS_IOVEC is defined in librbd.h */
37
-#ifdef LIBRBD_SUPPORTS_IOVEC
38
-#define LIBRBD_USE_IOVEC 1
39
-#else
40
-#define LIBRBD_USE_IOVEC 0
41
-#endif
42
-
43
#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
44
45
static const char rbd_luks_header_verification[
46
@@ -XXX,XX +XXX,XX @@ typedef struct RBDAIOCB {
47
BlockAIOCB common;
48
int64_t ret;
49
QEMUIOVector *qiov;
50
- char *bounce;
51
RBDAIOCmd cmd;
52
int error;
53
struct BDRVRBDState *s;
54
@@ -XXX,XX +XXX,XX @@ typedef struct RADOSCB {
55
RBDAIOCB *acb;
56
struct BDRVRBDState *s;
57
int64_t size;
58
- char *buf;
59
int64_t ret;
60
} RADOSCB;
61
62
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
63
64
static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
65
{
66
- if (LIBRBD_USE_IOVEC) {
67
- RBDAIOCB *acb = rcb->acb;
68
- iov_memset(acb->qiov->iov, acb->qiov->niov, offs, 0,
69
- acb->qiov->size - offs);
70
- } else {
71
- memset(rcb->buf + offs, 0, rcb->size - offs);
72
- }
73
+ RBDAIOCB *acb = rcb->acb;
74
+ iov_memset(acb->qiov->iov, acb->qiov->niov, offs, 0,
75
+ acb->qiov->size - offs);
76
}
77
78
#ifdef LIBRBD_SUPPORTS_ENCRYPTION
79
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
80
81
g_free(rcb);
82
83
- if (!LIBRBD_USE_IOVEC) {
84
- if (acb->cmd == RBD_AIO_READ) {
85
- qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
86
- }
87
- qemu_vfree(acb->bounce);
88
- }
89
-
90
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
91
92
qemu_aio_unref(acb);
93
@@ -XXX,XX +XXX,XX @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
94
rbd_finish_bh, rcb);
95
}
96
97
-static int rbd_aio_discard_wrapper(rbd_image_t image,
98
- uint64_t off,
99
- uint64_t len,
100
- rbd_completion_t comp)
101
-{
102
-#ifdef LIBRBD_SUPPORTS_DISCARD
103
- return rbd_aio_discard(image, off, len, comp);
104
-#else
105
- return -ENOTSUP;
106
-#endif
107
-}
108
-
109
-static int rbd_aio_flush_wrapper(rbd_image_t image,
110
- rbd_completion_t comp)
111
-{
112
-#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
113
- return rbd_aio_flush(image, comp);
114
-#else
115
- return -ENOTSUP;
116
-#endif
117
-}
118
-
119
static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
120
int64_t off,
121
QEMUIOVector *qiov,
122
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
123
124
rcb = g_new(RADOSCB, 1);
125
126
- if (!LIBRBD_USE_IOVEC) {
127
- if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
128
- acb->bounce = NULL;
129
- } else {
130
- acb->bounce = qemu_try_blockalign(bs, qiov->size);
131
- if (acb->bounce == NULL) {
132
- goto failed;
133
- }
134
- }
135
- if (cmd == RBD_AIO_WRITE) {
136
- qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
137
- }
138
- rcb->buf = acb->bounce;
139
- }
140
-
141
acb->ret = 0;
142
acb->error = 0;
143
acb->s = s;
144
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
145
}
146
147
switch (cmd) {
148
- case RBD_AIO_WRITE: {
149
+ case RBD_AIO_WRITE:
150
/*
151
* RBD APIs don't allow us to write more than actual size, so in order
152
* to support growing images, we resize the image before write
153
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
154
goto failed_completion;
155
}
156
}
157
-#ifdef LIBRBD_SUPPORTS_IOVEC
158
- r = rbd_aio_writev(s->image, qiov->iov, qiov->niov, off, c);
159
-#else
160
- r = rbd_aio_write(s->image, off, size, rcb->buf, c);
161
-#endif
162
+ r = rbd_aio_writev(s->image, qiov->iov, qiov->niov, off, c);
163
break;
164
- }
165
case RBD_AIO_READ:
166
-#ifdef LIBRBD_SUPPORTS_IOVEC
167
- r = rbd_aio_readv(s->image, qiov->iov, qiov->niov, off, c);
168
-#else
169
- r = rbd_aio_read(s->image, off, size, rcb->buf, c);
170
-#endif
171
+ r = rbd_aio_readv(s->image, qiov->iov, qiov->niov, off, c);
172
break;
173
case RBD_AIO_DISCARD:
174
- r = rbd_aio_discard_wrapper(s->image, off, size, c);
175
+ r = rbd_aio_discard(s->image, off, size, c);
176
break;
177
case RBD_AIO_FLUSH:
178
- r = rbd_aio_flush_wrapper(s->image, c);
179
+ r = rbd_aio_flush(s->image, c);
180
break;
181
default:
182
r = -EINVAL;
183
@@ -XXX,XX +XXX,XX @@ failed_completion:
184
rbd_aio_release(c);
185
failed:
186
g_free(rcb);
187
- if (!LIBRBD_USE_IOVEC) {
188
- qemu_vfree(acb->bounce);
189
- }
190
191
qemu_aio_unref(acb);
192
return NULL;
193
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qemu_rbd_aio_pwritev(BlockDriverState *bs,
194
RBD_AIO_WRITE);
195
}
196
197
-#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
198
static BlockAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
199
BlockCompletionFunc *cb,
200
void *opaque)
201
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
202
return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
203
}
204
205
-#else
206
-
207
-static int qemu_rbd_co_flush(BlockDriverState *bs)
208
-{
209
-#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
210
- /* rbd_flush added in 0.1.1 */
211
- BDRVRBDState *s = bs->opaque;
212
- return rbd_flush(s->image);
213
-#else
214
- return 0;
215
-#endif
216
-}
217
-#endif
218
-
219
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
220
{
221
BDRVRBDState *s = bs->opaque;
222
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
223
return snap_count;
224
}
225
226
-#ifdef LIBRBD_SUPPORTS_DISCARD
227
static BlockAIOCB *qemu_rbd_aio_pdiscard(BlockDriverState *bs,
228
int64_t offset,
229
int bytes,
230
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qemu_rbd_aio_pdiscard(BlockDriverState *bs,
231
return rbd_start_aio(bs, offset, NULL, bytes, cb, opaque,
232
RBD_AIO_DISCARD);
233
}
234
-#endif
235
236
-#ifdef LIBRBD_SUPPORTS_INVALIDATE
237
static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
238
Error **errp)
239
{
240
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
241
error_setg_errno(errp, -r, "Failed to invalidate the cache");
242
}
243
}
244
-#endif
245
246
static QemuOptsList qemu_rbd_create_opts = {
247
.name = "rbd-create-opts",
248
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
249
.bdrv_aio_preadv = qemu_rbd_aio_preadv,
250
.bdrv_aio_pwritev = qemu_rbd_aio_pwritev,
251
252
-#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
253
.bdrv_aio_flush = qemu_rbd_aio_flush,
254
-#else
255
- .bdrv_co_flush_to_disk = qemu_rbd_co_flush,
256
-#endif
257
-
258
-#ifdef LIBRBD_SUPPORTS_DISCARD
259
.bdrv_aio_pdiscard = qemu_rbd_aio_pdiscard,
260
-#endif
261
262
.bdrv_snapshot_create = qemu_rbd_snap_create,
263
.bdrv_snapshot_delete = qemu_rbd_snap_remove,
264
.bdrv_snapshot_list = qemu_rbd_snap_list,
265
.bdrv_snapshot_goto = qemu_rbd_snap_rollback,
266
-#ifdef LIBRBD_SUPPORTS_INVALIDATE
267
.bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache,
268
-#endif
269
270
.strong_runtime_opts = qemu_rbd_strong_runtime_opts,
271
};
272
diff --git a/meson.build b/meson.build
273
index XXXXXXX..XXXXXXX 100644
274
--- a/meson.build
275
+++ b/meson.build
276
@@ -XXX,XX +XXX,XX @@ if not get_option('rbd').auto() or have_block
277
int main(void) {
278
rados_t cluster;
279
rados_create(&cluster, NULL);
280
+ #if LIBRBD_VERSION_CODE < LIBRBD_VERSION(1, 12, 0)
281
+ #error
282
+ #endif
283
return 0;
284
}''', dependencies: [librbd, librados])
285
rbd = declare_dependency(dependencies: [librbd, librados])
286
elif get_option('rbd').enabled()
287
- error('could not link librados')
288
+ error('librbd >= 1.12.0 required')
289
else
290
- warning('could not link librados, disabling')
291
+ warning('librbd >= 1.12.0 not found, disabling')
292
endif
293
endif
294
endif
295
--
296
2.31.1
297
298
diff view generated by jsdifflib
New patch
1
From: Peter Lieven <pl@kamp.de>
1
2
3
Signed-off-by: Peter Lieven <pl@kamp.de>
4
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
5
Message-Id: <20210702172356.11574-3-idryomov@gmail.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
block/rbd.c | 18 +++++++-----------
9
1 file changed, 7 insertions(+), 11 deletions(-)
10
11
diff --git a/block/rbd.c b/block/rbd.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/rbd.c
14
+++ b/block/rbd.c
15
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRBDState {
16
char *snap;
17
char *namespace;
18
uint64_t image_size;
19
+ uint64_t object_size;
20
} BDRVRBDState;
21
22
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
23
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
24
const QDictEntry *e;
25
Error *local_err = NULL;
26
char *keypairs, *secretid;
27
+ rbd_image_info_t info;
28
int r;
29
30
keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
31
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
32
#endif
33
}
34
35
- r = rbd_get_size(s->image, &s->image_size);
36
+ r = rbd_stat(s->image, &info, sizeof(info));
37
if (r < 0) {
38
- error_setg_errno(errp, -r, "error getting image size from %s",
39
+ error_setg_errno(errp, -r, "error getting image info from %s",
40
s->image_name);
41
goto failed_post_open;
42
}
43
+ s->image_size = info.size;
44
+ s->object_size = info.obj_size;
45
46
/* If we are using an rbd snapshot, we must be r/o, otherwise
47
* leave as-is */
48
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
49
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
50
{
51
BDRVRBDState *s = bs->opaque;
52
- rbd_image_info_t info;
53
- int r;
54
-
55
- r = rbd_stat(s->image, &info, sizeof(info));
56
- if (r < 0) {
57
- return r;
58
- }
59
-
60
- bdi->cluster_size = info.obj_size;
61
+ bdi->cluster_size = s->object_size;
62
return 0;
63
}
64
65
--
66
2.31.1
67
68
diff view generated by jsdifflib
New patch
1
From: Peter Lieven <pl@kamp.de>
1
2
3
While at it just call rbd_get_size and avoid rbd_image_info_t.
4
5
Signed-off-by: Peter Lieven <pl@kamp.de>
6
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
7
Message-Id: <20210702172356.11574-4-idryomov@gmail.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
block/rbd.c | 5 ++---
11
1 file changed, 2 insertions(+), 3 deletions(-)
12
13
diff --git a/block/rbd.c b/block/rbd.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/rbd.c
16
+++ b/block/rbd.c
17
@@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
18
static int64_t qemu_rbd_getlength(BlockDriverState *bs)
19
{
20
BDRVRBDState *s = bs->opaque;
21
- rbd_image_info_t info;
22
int r;
23
24
- r = rbd_stat(s->image, &info, sizeof(info));
25
+ r = rbd_get_size(s->image, &s->image_size);
26
if (r < 0) {
27
return r;
28
}
29
30
- return info.size;
31
+ return s->image_size;
32
}
33
34
static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
35
--
36
2.31.1
37
38
diff view generated by jsdifflib
1
From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
1
From: Peter Lieven <pl@kamp.de>
2
2
3
This patch enables making snapshots with blkreplay used in
3
Signed-off-by: Peter Lieven <pl@kamp.de>
4
block devices.
4
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
5
This function is required to make bdrv_snapshot_goto without
5
Message-Id: <20210702172356.11574-5-idryomov@gmail.com>
6
calling .bdrv_open which is not implemented.
7
8
Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
9
Acked-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
7
---
12
block/blkreplay.c | 8 ++++++++
8
block/rbd.c | 252 +++++++++++++++++++---------------------------------
13
1 file changed, 8 insertions(+)
9
1 file changed, 90 insertions(+), 162 deletions(-)
14
10
15
diff --git a/block/blkreplay.c b/block/blkreplay.c
11
diff --git a/block/rbd.c b/block/rbd.c
16
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
17
--- a/block/blkreplay.c
13
--- a/block/rbd.c
18
+++ b/block/blkreplay.c
14
+++ b/block/rbd.c
19
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
15
@@ -XXX,XX +XXX,XX @@ typedef enum {
16
RBD_AIO_FLUSH
17
} RBDAIOCmd;
18
19
-typedef struct RBDAIOCB {
20
- BlockAIOCB common;
21
- int64_t ret;
22
- QEMUIOVector *qiov;
23
- RBDAIOCmd cmd;
24
- int error;
25
- struct BDRVRBDState *s;
26
-} RBDAIOCB;
27
-
28
-typedef struct RADOSCB {
29
- RBDAIOCB *acb;
30
- struct BDRVRBDState *s;
31
- int64_t size;
32
- int64_t ret;
33
-} RADOSCB;
34
-
35
typedef struct BDRVRBDState {
36
rados_t cluster;
37
rados_ioctx_t io_ctx;
38
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRBDState {
39
uint64_t object_size;
40
} BDRVRBDState;
41
42
+typedef struct RBDTask {
43
+ BlockDriverState *bs;
44
+ Coroutine *co;
45
+ bool complete;
46
+ int64_t ret;
47
+} RBDTask;
48
+
49
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
50
BlockdevOptionsRbd *opts, bool cache,
51
const char *keypairs, const char *secretid,
52
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
20
return ret;
53
return ret;
21
}
54
}
22
55
23
+static int blkreplay_snapshot_goto(BlockDriverState *bs,
56
-static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
24
+ const char *snapshot_id)
57
-{
25
+{
58
- RBDAIOCB *acb = rcb->acb;
26
+ return bdrv_snapshot_goto(bs->file->bs, snapshot_id, NULL);
59
- iov_memset(acb->qiov->iov, acb->qiov->niov, offs, 0,
60
- acb->qiov->size - offs);
61
-}
62
-
63
#ifdef LIBRBD_SUPPORTS_ENCRYPTION
64
static int qemu_rbd_convert_luks_options(
65
RbdEncryptionOptionsLUKSBase *luks_opts,
66
@@ -XXX,XX +XXX,XX @@ exit:
67
return ret;
68
}
69
70
-/*
71
- * This aio completion is being called from rbd_finish_bh() and runs in qemu
72
- * BH context.
73
- */
74
-static void qemu_rbd_complete_aio(RADOSCB *rcb)
75
-{
76
- RBDAIOCB *acb = rcb->acb;
77
- int64_t r;
78
-
79
- r = rcb->ret;
80
-
81
- if (acb->cmd != RBD_AIO_READ) {
82
- if (r < 0) {
83
- acb->ret = r;
84
- acb->error = 1;
85
- } else if (!acb->error) {
86
- acb->ret = rcb->size;
87
- }
88
- } else {
89
- if (r < 0) {
90
- qemu_rbd_memset(rcb, 0);
91
- acb->ret = r;
92
- acb->error = 1;
93
- } else if (r < rcb->size) {
94
- qemu_rbd_memset(rcb, r);
95
- if (!acb->error) {
96
- acb->ret = rcb->size;
97
- }
98
- } else if (!acb->error) {
99
- acb->ret = r;
100
- }
101
- }
102
-
103
- g_free(rcb);
104
-
105
- acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
106
-
107
- qemu_aio_unref(acb);
108
-}
109
-
110
static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
111
{
112
const char **vals;
113
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_resize(BlockDriverState *bs, uint64_t size)
114
return 0;
115
}
116
117
-static const AIOCBInfo rbd_aiocb_info = {
118
- .aiocb_size = sizeof(RBDAIOCB),
119
-};
120
-
121
-static void rbd_finish_bh(void *opaque)
122
+static void qemu_rbd_finish_bh(void *opaque)
123
{
124
- RADOSCB *rcb = opaque;
125
- qemu_rbd_complete_aio(rcb);
126
+ RBDTask *task = opaque;
127
+ task->complete = 1;
128
+ aio_co_wake(task->co);
129
}
130
131
/*
132
- * This is the callback function for rbd_aio_read and _write
133
+ * This is the completion callback function for all rbd aio calls
134
+ * started from qemu_rbd_start_co().
135
*
136
* Note: this function is being called from a non qemu thread so
137
* we need to be careful about what we do here. Generally we only
138
* schedule a BH, and do the rest of the io completion handling
139
- * from rbd_finish_bh() which runs in a qemu context.
140
+ * from qemu_rbd_finish_bh() which runs in a qemu context.
141
*/
142
-static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
143
+static void qemu_rbd_completion_cb(rbd_completion_t c, RBDTask *task)
144
{
145
- RBDAIOCB *acb = rcb->acb;
146
-
147
- rcb->ret = rbd_aio_get_return_value(c);
148
+ task->ret = rbd_aio_get_return_value(c);
149
rbd_aio_release(c);
150
-
151
- replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs),
152
- rbd_finish_bh, rcb);
153
+ aio_bh_schedule_oneshot(bdrv_get_aio_context(task->bs),
154
+ qemu_rbd_finish_bh, task);
155
}
156
157
-static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
158
- int64_t off,
159
- QEMUIOVector *qiov,
160
- int64_t size,
161
- BlockCompletionFunc *cb,
162
- void *opaque,
163
- RBDAIOCmd cmd)
164
+static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,
165
+ uint64_t offset,
166
+ uint64_t bytes,
167
+ QEMUIOVector *qiov,
168
+ int flags,
169
+ RBDAIOCmd cmd)
170
{
171
- RBDAIOCB *acb;
172
- RADOSCB *rcb = NULL;
173
+ BDRVRBDState *s = bs->opaque;
174
+ RBDTask task = { .bs = bs, .co = qemu_coroutine_self() };
175
rbd_completion_t c;
176
int r;
177
178
- BDRVRBDState *s = bs->opaque;
179
-
180
- acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
181
- acb->cmd = cmd;
182
- acb->qiov = qiov;
183
- assert(!qiov || qiov->size == size);
184
-
185
- rcb = g_new(RADOSCB, 1);
186
+ assert(!qiov || qiov->size == bytes);
187
188
- acb->ret = 0;
189
- acb->error = 0;
190
- acb->s = s;
191
-
192
- rcb->acb = acb;
193
- rcb->s = acb->s;
194
- rcb->size = size;
195
- r = rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
196
+ r = rbd_aio_create_completion(&task,
197
+ (rbd_callback_t) qemu_rbd_completion_cb, &c);
198
if (r < 0) {
199
- goto failed;
200
+ return r;
201
}
202
203
switch (cmd) {
204
- case RBD_AIO_WRITE:
205
- /*
206
- * RBD APIs don't allow us to write more than actual size, so in order
207
- * to support growing images, we resize the image before write
208
- * operations that exceed the current size.
209
- */
210
- if (off + size > s->image_size) {
211
- r = qemu_rbd_resize(bs, off + size);
212
- if (r < 0) {
213
- goto failed_completion;
214
- }
215
- }
216
- r = rbd_aio_writev(s->image, qiov->iov, qiov->niov, off, c);
217
- break;
218
case RBD_AIO_READ:
219
- r = rbd_aio_readv(s->image, qiov->iov, qiov->niov, off, c);
220
+ r = rbd_aio_readv(s->image, qiov->iov, qiov->niov, offset, c);
221
+ break;
222
+ case RBD_AIO_WRITE:
223
+ r = rbd_aio_writev(s->image, qiov->iov, qiov->niov, offset, c);
224
break;
225
case RBD_AIO_DISCARD:
226
- r = rbd_aio_discard(s->image, off, size, c);
227
+ r = rbd_aio_discard(s->image, offset, bytes, c);
228
break;
229
case RBD_AIO_FLUSH:
230
r = rbd_aio_flush(s->image, c);
231
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
232
}
233
234
if (r < 0) {
235
- goto failed_completion;
236
+ error_report("rbd request failed early: cmd %d offset %" PRIu64
237
+ " bytes %" PRIu64 " flags %d r %d (%s)", cmd, offset,
238
+ bytes, flags, r, strerror(-r));
239
+ rbd_aio_release(c);
240
+ return r;
241
}
242
- return &acb->common;
243
244
-failed_completion:
245
- rbd_aio_release(c);
246
-failed:
247
- g_free(rcb);
248
+ while (!task.complete) {
249
+ qemu_coroutine_yield();
250
+ }
251
252
- qemu_aio_unref(acb);
253
- return NULL;
254
+ if (task.ret < 0) {
255
+ error_report("rbd request failed: cmd %d offset %" PRIu64 " bytes %"
256
+ PRIu64 " flags %d task.ret %" PRIi64 " (%s)", cmd, offset,
257
+ bytes, flags, task.ret, strerror(-task.ret));
258
+ return task.ret;
259
+ }
260
+
261
+ /* zero pad short reads */
262
+ if (cmd == RBD_AIO_READ && task.ret < qiov->size) {
263
+ qemu_iovec_memset(qiov, task.ret, 0, qiov->size - task.ret);
264
+ }
265
+
266
+ return 0;
27
+}
267
+}
28
+
268
+
29
static BlockDriver bdrv_blkreplay = {
269
+static int
30
.format_name = "blkreplay",
270
+coroutine_fn qemu_rbd_co_preadv(BlockDriverState *bs, uint64_t offset,
31
.instance_size = 0,
271
+ uint64_t bytes, QEMUIOVector *qiov,
32
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkreplay = {
272
+ int flags)
33
.bdrv_co_pwrite_zeroes = blkreplay_co_pwrite_zeroes,
273
+{
34
.bdrv_co_pdiscard = blkreplay_co_pdiscard,
274
+ return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_READ);
35
.bdrv_co_flush = blkreplay_co_flush,
275
}
36
+
276
37
+ .bdrv_snapshot_goto = blkreplay_snapshot_goto,
277
-static BlockAIOCB *qemu_rbd_aio_preadv(BlockDriverState *bs,
38
};
278
- uint64_t offset, uint64_t bytes,
39
279
- QEMUIOVector *qiov, int flags,
40
static void bdrv_blkreplay_init(void)
280
- BlockCompletionFunc *cb,
281
- void *opaque)
282
+static int
283
+coroutine_fn qemu_rbd_co_pwritev(BlockDriverState *bs, uint64_t offset,
284
+ uint64_t bytes, QEMUIOVector *qiov,
285
+ int flags)
286
{
287
- return rbd_start_aio(bs, offset, qiov, bytes, cb, opaque,
288
- RBD_AIO_READ);
289
+ BDRVRBDState *s = bs->opaque;
290
+ /*
291
+ * RBD APIs don't allow us to write more than actual size, so in order
292
+ * to support growing images, we resize the image before write
293
+ * operations that exceed the current size.
294
+ */
295
+ if (offset + bytes > s->image_size) {
296
+ int r = qemu_rbd_resize(bs, offset + bytes);
297
+ if (r < 0) {
298
+ return r;
299
+ }
300
+ }
301
+ return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_WRITE);
302
}
303
304
-static BlockAIOCB *qemu_rbd_aio_pwritev(BlockDriverState *bs,
305
- uint64_t offset, uint64_t bytes,
306
- QEMUIOVector *qiov, int flags,
307
- BlockCompletionFunc *cb,
308
- void *opaque)
309
+static int coroutine_fn qemu_rbd_co_flush(BlockDriverState *bs)
310
{
311
- return rbd_start_aio(bs, offset, qiov, bytes, cb, opaque,
312
- RBD_AIO_WRITE);
313
+ return qemu_rbd_start_co(bs, 0, 0, NULL, 0, RBD_AIO_FLUSH);
314
}
315
316
-static BlockAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
317
- BlockCompletionFunc *cb,
318
- void *opaque)
319
+static int coroutine_fn qemu_rbd_co_pdiscard(BlockDriverState *bs,
320
+ int64_t offset, int count)
321
{
322
- return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
323
+ return qemu_rbd_start_co(bs, offset, count, NULL, 0, RBD_AIO_DISCARD);
324
}
325
326
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
327
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
328
return snap_count;
329
}
330
331
-static BlockAIOCB *qemu_rbd_aio_pdiscard(BlockDriverState *bs,
332
- int64_t offset,
333
- int bytes,
334
- BlockCompletionFunc *cb,
335
- void *opaque)
336
-{
337
- return rbd_start_aio(bs, offset, NULL, bytes, cb, opaque,
338
- RBD_AIO_DISCARD);
339
-}
340
-
341
static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
342
Error **errp)
343
{
344
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
345
.bdrv_co_truncate = qemu_rbd_co_truncate,
346
.protocol_name = "rbd",
347
348
- .bdrv_aio_preadv = qemu_rbd_aio_preadv,
349
- .bdrv_aio_pwritev = qemu_rbd_aio_pwritev,
350
-
351
- .bdrv_aio_flush = qemu_rbd_aio_flush,
352
- .bdrv_aio_pdiscard = qemu_rbd_aio_pdiscard,
353
+ .bdrv_co_preadv = qemu_rbd_co_preadv,
354
+ .bdrv_co_pwritev = qemu_rbd_co_pwritev,
355
+ .bdrv_co_flush_to_disk = qemu_rbd_co_flush,
356
+ .bdrv_co_pdiscard = qemu_rbd_co_pdiscard,
357
358
.bdrv_snapshot_create = qemu_rbd_snap_create,
359
.bdrv_snapshot_delete = qemu_rbd_snap_remove,
41
--
360
--
42
2.20.1
361
2.31.1
43
362
44
363
diff view generated by jsdifflib
New patch
1
From: Peter Lieven <pl@kamp.de>
1
2
3
This patch wittingly sets BDRV_REQ_NO_FALLBACK and silently ignores
4
BDRV_REQ_MAY_UNMAP for older librbd versions.
5
6
The rationale for this is as follows (citing Ilya Dryomov current RBD
7
maintainer):
8
9
---8<---
10
a) remove the BDRV_REQ_MAY_UNMAP check in qemu_rbd_co_pwrite_zeroes()
11
and as a consequence always unmap if librbd is too old
12
13
It's not clear what qemu's expectation is but in general Write
14
Zeroes is allowed to unmap. The only guarantee is that subsequent
15
reads return zeroes, everything else is a hint. This is how it is
16
specified in the kernel and in the NVMe spec.
17
18
In particular, block/nvme.c implements it as follows:
19
20
if (flags & BDRV_REQ_MAY_UNMAP) {
21
cdw12 |= (1 << 25);
22
}
23
24
This sets the Deallocate bit. But if it's not set, the device may
25
still deallocate:
26
27
"""
28
If the Deallocate bit (CDW12.DEAC) is set to '1' in a Write Zeroes
29
command, and the namespace supports clearing all bytes to 0h in the
30
values read (e.g., bits 2:0 in the DLFEAT field are set to 001b)
31
from a deallocated logical block and its metadata (excluding
32
protection information), then for each specified logical block, the
33
controller:
34
- should deallocate that logical block;
35
36
...
37
38
If the Deallocate bit is cleared to '0' in a Write Zeroes command,
39
and the namespace supports clearing all bytes to 0h in the values
40
read (e.g., bits 2:0 in the DLFEAT field are set to 001b) from
41
a deallocated logical block and its metadata (excluding protection
42
information), then, for each specified logical block, the
43
controller:
44
- may deallocate that logical block;
45
"""
46
47
https://nvmexpress.org/wp-content/uploads/NVM-Express-NVM-Command-Set-Specification-2021.06.02-Ratified-1.pdf
48
49
b) set BDRV_REQ_NO_FALLBACK in supported_zero_flags
50
51
Again, it's not clear what qemu expects here, but without it we end
52
up in a ridiculous situation where specifying the "don't allow slow
53
fallback" switch immediately fails all efficient zeroing requests on
54
a device where Write Zeroes is always efficient:
55
56
$ qemu-io -c 'help write' | grep -- '-[zun]'
57
-n, -- with -z, don't allow slow fallback
58
-u, -- with -z, allow unmapping
59
-z, -- write zeroes using blk_co_pwrite_zeroes
60
61
$ qemu-io -f rbd -c 'write -z -u -n 0 1M' rbd:foo/bar
62
write failed: Operation not supported
63
--->8---
64
65
Signed-off-by: Peter Lieven <pl@kamp.de>
66
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
67
Message-Id: <20210702172356.11574-6-idryomov@gmail.com>
68
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
69
---
70
block/rbd.c | 32 +++++++++++++++++++++++++++++++-
71
1 file changed, 31 insertions(+), 1 deletion(-)
72
73
diff --git a/block/rbd.c b/block/rbd.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/rbd.c
76
+++ b/block/rbd.c
77
@@ -XXX,XX +XXX,XX @@ typedef enum {
78
RBD_AIO_READ,
79
RBD_AIO_WRITE,
80
RBD_AIO_DISCARD,
81
- RBD_AIO_FLUSH
82
+ RBD_AIO_FLUSH,
83
+ RBD_AIO_WRITE_ZEROES
84
} RBDAIOCmd;
85
86
typedef struct BDRVRBDState {
87
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
88
}
89
}
90
91
+#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
92
+ bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
93
+#endif
94
+
95
/* When extending regular files, we get zeros from the OS */
96
bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
97
98
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,
99
case RBD_AIO_FLUSH:
100
r = rbd_aio_flush(s->image, c);
101
break;
102
+#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
103
+ case RBD_AIO_WRITE_ZEROES: {
104
+ int zero_flags = 0;
105
+#ifdef RBD_WRITE_ZEROES_FLAG_THICK_PROVISION
106
+ if (!(flags & BDRV_REQ_MAY_UNMAP)) {
107
+ zero_flags = RBD_WRITE_ZEROES_FLAG_THICK_PROVISION;
108
+ }
109
+#endif
110
+ r = rbd_aio_write_zeroes(s->image, offset, bytes, c, zero_flags, 0);
111
+ break;
112
+ }
113
+#endif
114
default:
115
r = -EINVAL;
116
}
117
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_pdiscard(BlockDriverState *bs,
118
return qemu_rbd_start_co(bs, offset, count, NULL, 0, RBD_AIO_DISCARD);
119
}
120
121
+#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
122
+static int
123
+coroutine_fn qemu_rbd_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
124
+ int count, BdrvRequestFlags flags)
125
+{
126
+ return qemu_rbd_start_co(bs, offset, count, NULL, flags,
127
+ RBD_AIO_WRITE_ZEROES);
128
+}
129
+#endif
130
+
131
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
132
{
133
BDRVRBDState *s = bs->opaque;
134
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
135
.bdrv_co_pwritev = qemu_rbd_co_pwritev,
136
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
137
.bdrv_co_pdiscard = qemu_rbd_co_pdiscard,
138
+#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
139
+ .bdrv_co_pwrite_zeroes = qemu_rbd_co_pwrite_zeroes,
140
+#endif
141
142
.bdrv_snapshot_create = qemu_rbd_snap_create,
143
.bdrv_snapshot_delete = qemu_rbd_snap_remove,
144
--
145
2.31.1
146
147
diff view generated by jsdifflib
New patch
1
From: Peter Lieven <pl@kamp.de>
1
2
3
librbd supports 1 byte alignment for all aio operations.
4
5
Currently, there is no API call to query limits from the Ceph
6
ObjectStore backend. So drop the bdrv_refresh_limits completely
7
until there is such an API call.
8
9
Signed-off-by: Peter Lieven <pl@kamp.de>
10
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
11
Message-Id: <20210702172356.11574-7-idryomov@gmail.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
block/rbd.c | 9 ---------
15
1 file changed, 9 deletions(-)
16
17
diff --git a/block/rbd.c b/block/rbd.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/rbd.c
20
+++ b/block/rbd.c
21
@@ -XXX,XX +XXX,XX @@ done:
22
return;
23
}
24
25
-
26
-static void qemu_rbd_refresh_limits(BlockDriverState *bs, Error **errp)
27
-{
28
- /* XXX Does RBD support AIO on less than 512-byte alignment? */
29
- bs->bl.request_alignment = 512;
30
-}
31
-
32
-
33
static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts,
34
Error **errp)
35
{
36
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
37
.format_name = "rbd",
38
.instance_size = sizeof(BDRVRBDState),
39
.bdrv_parse_filename = qemu_rbd_parse_filename,
40
- .bdrv_refresh_limits = qemu_rbd_refresh_limits,
41
.bdrv_file_open = qemu_rbd_open,
42
.bdrv_close = qemu_rbd_close,
43
.bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
44
--
45
2.31.1
46
47
diff view generated by jsdifflib
New patch
1
From: Heinrich Schuchardt <xypron.glpk@gmx.de>
1
2
3
uri_free() checks if its argument is NULL in uri_clean() and g_free().
4
There is no need to check the argument before the call.
5
6
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
7
Message-Id: <20210629063602.4239-1-xypron.glpk@gmx.de>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block/nfs.c | 4 +---
13
block/ssh.c | 4 +---
14
util/uri.c | 22 ++++++----------------
15
3 files changed, 8 insertions(+), 22 deletions(-)
16
17
diff --git a/block/nfs.c b/block/nfs.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/nfs.c
20
+++ b/block/nfs.c
21
@@ -XXX,XX +XXX,XX @@ out:
22
if (qp) {
23
query_params_free(qp);
24
}
25
- if (uri) {
26
- uri_free(uri);
27
- }
28
+ uri_free(uri);
29
return ret;
30
}
31
32
diff --git a/block/ssh.c b/block/ssh.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block/ssh.c
35
+++ b/block/ssh.c
36
@@ -XXX,XX +XXX,XX @@ static int parse_uri(const char *filename, QDict *options, Error **errp)
37
return 0;
38
39
err:
40
- if (uri) {
41
- uri_free(uri);
42
- }
43
+ uri_free(uri);
44
return -EINVAL;
45
}
46
47
diff --git a/util/uri.c b/util/uri.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/util/uri.c
50
+++ b/util/uri.c
51
@@ -XXX,XX +XXX,XX @@ static void uri_clean(URI *uri)
52
53
/**
54
* uri_free:
55
- * @uri: pointer to an URI
56
+ * @uri: pointer to an URI, NULL is ignored
57
*
58
* Free up the URI struct
59
*/
60
@@ -XXX,XX +XXX,XX @@ step_7:
61
val = uri_to_string(res);
62
63
done:
64
- if (ref != NULL) {
65
- uri_free(ref);
66
- }
67
- if (bas != NULL) {
68
- uri_free(bas);
69
- }
70
- if (res != NULL) {
71
- uri_free(res);
72
- }
73
+ uri_free(ref);
74
+ uri_free(bas);
75
+ uri_free(res);
76
return val;
77
}
78
79
@@ -XXX,XX +XXX,XX @@ done:
80
if (remove_path != 0) {
81
ref->path = NULL;
82
}
83
- if (ref != NULL) {
84
- uri_free(ref);
85
- }
86
- if (bas != NULL) {
87
- uri_free(bas);
88
- }
89
+ uri_free(ref);
90
+ uri_free(bas);
91
92
return val;
93
}
94
--
95
2.31.1
96
97
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
We do not do any permission checks in fuse_open(), so let the kernel do
4
them. We already let fuse_getattr() report the proper UNIX permissions,
5
so this should work the way we want.
6
7
This causes a change in 308's reference output, because now opening a
8
non-writable export with O_RDWR fails already, instead of only actually
9
attempting to write to it. (That is an improvement.)
10
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Message-Id: <20210625142317.271673-2-mreitz@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
block/export/fuse.c | 8 ++++++--
16
tests/qemu-iotests/308 | 3 ++-
17
tests/qemu-iotests/308.out | 2 +-
18
3 files changed, 9 insertions(+), 4 deletions(-)
19
20
diff --git a/block/export/fuse.c b/block/export/fuse.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/export/fuse.c
23
+++ b/block/export/fuse.c
24
@@ -XXX,XX +XXX,XX @@ static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
25
struct fuse_args fuse_args;
26
int ret;
27
28
- /* Needs to match what fuse_init() sets. Only max_read must be supplied. */
29
- mount_opts = g_strdup_printf("max_read=%zu", FUSE_MAX_BOUNCE_BYTES);
30
+ /*
31
+ * max_read needs to match what fuse_init() sets.
32
+ * max_write need not be supplied.
33
+ */
34
+ mount_opts = g_strdup_printf("max_read=%zu,default_permissions",
35
+ FUSE_MAX_BOUNCE_BYTES);
36
37
fuse_argv[0] = ""; /* Dummy program name */
38
fuse_argv[1] = "-o";
39
diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308
40
index XXXXXXX..XXXXXXX 100755
41
--- a/tests/qemu-iotests/308
42
+++ b/tests/qemu-iotests/308
43
@@ -XXX,XX +XXX,XX @@ echo '=== Writable export ==='
44
fuse_export_add 'export-mp' "'mountpoint': '$EXT_MP', 'writable': true"
45
46
# Check that writing to the read-only export fails
47
-$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" | _filter_qemu_io
48
+$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \
49
+ | _filter_qemu_io | _filter_testdir | _filter_imgfmt
50
51
# But here it should work
52
$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$EXT_MP" | _filter_qemu_io
53
diff --git a/tests/qemu-iotests/308.out b/tests/qemu-iotests/308.out
54
index XXXXXXX..XXXXXXX 100644
55
--- a/tests/qemu-iotests/308.out
56
+++ b/tests/qemu-iotests/308.out
57
@@ -XXX,XX +XXX,XX @@ virtual size: 0 B (0 bytes)
58
'mountpoint': 'TEST_DIR/t.IMGFMT.fuse', 'writable': true
59
} }
60
{"return": {}}
61
-write failed: Permission denied
62
+qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
63
wrote 65536/65536 bytes at offset 1048576
64
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
65
wrote 65536/65536 bytes at offset 1048576
66
--
67
2.31.1
68
69
diff view generated by jsdifflib
New patch
1
1
From: Max Reitz <mreitz@redhat.com>
2
3
Without the allow_other mount option, no user (not even root) but the
4
one who started qemu/the storage daemon can access the export. Allow
5
users to configure the export such that such accesses are possible.
6
7
While allow_other is probably what users want, we cannot make it an
8
unconditional default, because passing it is only possible (for non-root
9
users) if the global fuse.conf configuration file allows it. Thus, the
10
default is an 'auto' mode, in which we first try with allow_other, and
11
then fall back to without.
12
13
FuseExport.allow_other reports whether allow_other was actually used as
14
a mount option or not. Currently, this information is not used, but a
15
future patch will let this field decide whether e.g. an export's UID and
16
GID can be changed through chmod.
17
18
One notable thing about 'auto' mode is that libfuse may print error
19
messages directly to stderr, and so may fusermount (which it executes).
20
Our export code cannot really filter or hide them. Therefore, if 'auto'
21
fails its first attempt and has to fall back, fusermount will print an
22
error message that mounting with allow_other failed.
23
24
This behavior necessitates a change to iotest 308, namely we need to
25
filter out this error message (because if the first attempt at mounting
26
with allow_other succeeds, there will be no such message).
27
28
Furthermore, common.rc's _make_test_img should use allow-other=off for
29
FUSE exports, because iotests generally do not need to access images
30
from other users, so allow-other=on or allow-other=auto have no
31
advantage. OTOH, allow-other=on will not work on systems where
32
user_allow_other is disabled, and with allow-other=auto, we get said
33
error message that we would need to filter out again. Just disabling
34
allow-other is simplest.
35
36
Signed-off-by: Max Reitz <mreitz@redhat.com>
37
Message-Id: <20210625142317.271673-3-mreitz@redhat.com>
38
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
39
---
40
qapi/block-export.json | 33 ++++++++++++++++++++++++++++++++-
41
block/export/fuse.c | 28 +++++++++++++++++++++++-----
42
tests/qemu-iotests/308 | 6 +++++-
43
tests/qemu-iotests/common.rc | 6 +++++-
44
4 files changed, 65 insertions(+), 8 deletions(-)
45
46
diff --git a/qapi/block-export.json b/qapi/block-export.json
47
index XXXXXXX..XXXXXXX 100644
48
--- a/qapi/block-export.json
49
+++ b/qapi/block-export.json
50
@@ -XXX,XX +XXX,XX @@
51
     '*logical-block-size': 'size',
52
'*num-queues': 'uint16'} }
53
54
+##
55
+# @FuseExportAllowOther:
56
+#
57
+# Possible allow_other modes for FUSE exports.
58
+#
59
+# @off: Do not pass allow_other as a mount option.
60
+#
61
+# @on: Pass allow_other as a mount option.
62
+#
63
+# @auto: Try mounting with allow_other first, and if that fails, retry
64
+# without allow_other.
65
+#
66
+# Since: 6.1
67
+##
68
+{ 'enum': 'FuseExportAllowOther',
69
+ 'data': ['off', 'on', 'auto'] }
70
+
71
##
72
# @BlockExportOptionsFuse:
73
#
74
@@ -XXX,XX +XXX,XX @@
75
# @growable: Whether writes beyond the EOF should grow the block node
76
# accordingly. (default: false)
77
#
78
+# @allow-other: If this is off, only qemu's user is allowed access to
79
+# this export. That cannot be changed even with chmod or
80
+# chown.
81
+# Enabling this option will allow other users access to
82
+# the export with the FUSE mount option "allow_other".
83
+# Note that using allow_other as a non-root user requires
84
+# user_allow_other to be enabled in the global fuse.conf
85
+# configuration file.
86
+# In auto mode (the default), the FUSE export driver will
87
+# first attempt to mount the export with allow_other, and
88
+# if that fails, try again without.
89
+# (since 6.1; default: auto)
90
+#
91
# Since: 6.0
92
##
93
{ 'struct': 'BlockExportOptionsFuse',
94
'data': { 'mountpoint': 'str',
95
- '*growable': 'bool' },
96
+ '*growable': 'bool',
97
+ '*allow-other': 'FuseExportAllowOther' },
98
'if': 'defined(CONFIG_FUSE)' }
99
100
##
101
diff --git a/block/export/fuse.c b/block/export/fuse.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/block/export/fuse.c
104
+++ b/block/export/fuse.c
105
@@ -XXX,XX +XXX,XX @@ typedef struct FuseExport {
106
char *mountpoint;
107
bool writable;
108
bool growable;
109
+ /* Whether allow_other was used as a mount option or not */
110
+ bool allow_other;
111
} FuseExport;
112
113
static GHashTable *exports;
114
@@ -XXX,XX +XXX,XX @@ static void fuse_export_delete(BlockExport *exp);
115
static void init_exports_table(void);
116
117
static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
118
- Error **errp);
119
+ bool allow_other, Error **errp);
120
static void read_from_fuse_export(void *opaque);
121
122
static bool is_regular_file(const char *path, Error **errp);
123
@@ -XXX,XX +XXX,XX @@ static int fuse_export_create(BlockExport *blk_exp,
124
exp->writable = blk_exp_args->writable;
125
exp->growable = args->growable;
126
127
- ret = setup_fuse_export(exp, args->mountpoint, errp);
128
+ /* set default */
129
+ if (!args->has_allow_other) {
130
+ args->allow_other = FUSE_EXPORT_ALLOW_OTHER_AUTO;
131
+ }
132
+
133
+ if (args->allow_other == FUSE_EXPORT_ALLOW_OTHER_AUTO) {
134
+ /* Ignore errors on our first attempt */
135
+ ret = setup_fuse_export(exp, args->mountpoint, true, NULL);
136
+ exp->allow_other = ret == 0;
137
+ if (ret < 0) {
138
+ ret = setup_fuse_export(exp, args->mountpoint, false, errp);
139
+ }
140
+ } else {
141
+ exp->allow_other = args->allow_other == FUSE_EXPORT_ALLOW_OTHER_ON;
142
+ ret = setup_fuse_export(exp, args->mountpoint, exp->allow_other, errp);
143
+ }
144
if (ret < 0) {
145
goto fail;
146
}
147
@@ -XXX,XX +XXX,XX @@ static void init_exports_table(void)
148
* Create exp->fuse_session and mount it.
149
*/
150
static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
151
- Error **errp)
152
+ bool allow_other, Error **errp)
153
{
154
const char *fuse_argv[4];
155
char *mount_opts;
156
@@ -XXX,XX +XXX,XX @@ static int setup_fuse_export(FuseExport *exp, const char *mountpoint,
157
* max_read needs to match what fuse_init() sets.
158
* max_write need not be supplied.
159
*/
160
- mount_opts = g_strdup_printf("max_read=%zu,default_permissions",
161
- FUSE_MAX_BOUNCE_BYTES);
162
+ mount_opts = g_strdup_printf("max_read=%zu,default_permissions%s",
163
+ FUSE_MAX_BOUNCE_BYTES,
164
+ allow_other ? ",allow_other" : "");
165
166
fuse_argv[0] = ""; /* Dummy program name */
167
fuse_argv[1] = "-o";
168
diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308
169
index XXXXXXX..XXXXXXX 100755
170
--- a/tests/qemu-iotests/308
171
+++ b/tests/qemu-iotests/308
172
@@ -XXX,XX +XXX,XX @@ _supported_os Linux # We need /dev/urandom
173
# $4: Node to export (defaults to 'node-format')
174
fuse_export_add()
175
{
176
+ # The grep -v is a filter for errors when /etc/fuse.conf does not contain
177
+ # user_allow_other. (The error is benign, but it is printed by fusermount
178
+ # on the first mount attempt, so our export code cannot hide it.)
179
_send_qemu_cmd $QEMU_HANDLE \
180
"{'execute': 'block-export-add',
181
'arguments': {
182
@@ -XXX,XX +XXX,XX @@ fuse_export_add()
183
$2
184
} }" \
185
"${3:-return}" \
186
- | _filter_imgfmt
187
+ | _filter_imgfmt \
188
+ | grep -v 'option allow_other only allowed if'
189
}
190
191
# $1: Export ID
192
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
193
index XXXXXXX..XXXXXXX 100644
194
--- a/tests/qemu-iotests/common.rc
195
+++ b/tests/qemu-iotests/common.rc
196
@@ -XXX,XX +XXX,XX @@ _make_test_img()
197
# Usually, users would export formatted nodes. But we present fuse as a
198
# protocol-level driver here, so we have to leave the format to the
199
# client.
200
+ # Switch off allow-other, because in general we do not need it for
201
+ # iotests. The default allow-other=auto has the downside of printing a
202
+ # fusermount error on its first attempt if allow_other is not
203
+ # permissible, which we would need to filter.
204
QSD_NEED_PID=y $QSD \
205
--blockdev file,node-name=export-node,filename=$img_name,discard=unmap \
206
- --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=on \
207
+ --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=on,allow-other=off \
208
&
209
210
pidfile="$QEMU_TEST_DIR/qemu-storage-daemon.pid"
211
--
212
2.31.1
213
214
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
In order to support changing other attributes than the file size in
4
fuse_setattr(), we have to give each its own independent branch. This
5
also applies to the only attribute we do support right now.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20210625142317.271673-4-mreitz@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block/export/fuse.c | 20 +++++++++++---------
13
1 file changed, 11 insertions(+), 9 deletions(-)
14
15
diff --git a/block/export/fuse.c b/block/export/fuse.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/export/fuse.c
18
+++ b/block/export/fuse.c
19
@@ -XXX,XX +XXX,XX @@ static void fuse_setattr(fuse_req_t req, fuse_ino_t inode, struct stat *statbuf,
20
FuseExport *exp = fuse_req_userdata(req);
21
int ret;
22
23
- if (!exp->writable) {
24
- fuse_reply_err(req, EACCES);
25
- return;
26
- }
27
-
28
if (to_set & ~FUSE_SET_ATTR_SIZE) {
29
fuse_reply_err(req, ENOTSUP);
30
return;
31
}
32
33
- ret = fuse_do_truncate(exp, statbuf->st_size, true, PREALLOC_MODE_OFF);
34
- if (ret < 0) {
35
- fuse_reply_err(req, -ret);
36
- return;
37
+ if (to_set & FUSE_SET_ATTR_SIZE) {
38
+ if (!exp->writable) {
39
+ fuse_reply_err(req, EACCES);
40
+ return;
41
+ }
42
+
43
+ ret = fuse_do_truncate(exp, statbuf->st_size, true, PREALLOC_MODE_OFF);
44
+ if (ret < 0) {
45
+ fuse_reply_err(req, -ret);
46
+ return;
47
+ }
48
}
49
50
fuse_getattr(req, inode, fi);
51
--
52
2.31.1
53
54
diff view generated by jsdifflib
1
From: Peter Lieven <pl@kamp.de>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
qemu is currently not able to detect truncated vhdx image files.
3
Allow changing the file mode, UID, and GID through SETATTR.
4
Add a basic check if all allocated blocks are reachable at open and
5
report all errors during bdrv_co_check.
6
4
7
Signed-off-by: Peter Lieven <pl@kamp.de>
5
Without allow_other, UID and GID are not allowed to be changed, because
6
it would not make sense. Also, changing group or others' permissions
7
is not allowed either.
8
9
For read-only exports, +w cannot be set.
10
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Message-Id: <20210625142317.271673-5-mreitz@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
14
---
10
block/vhdx.c | 120 +++++++++++++++++++++++++++++++++++++++++++--------
15
block/export/fuse.c | 73 ++++++++++++++++++++++++++++++++++++++-------
11
1 file changed, 103 insertions(+), 17 deletions(-)
16
1 file changed, 62 insertions(+), 11 deletions(-)
12
17
13
diff --git a/block/vhdx.c b/block/vhdx.c
18
diff --git a/block/export/fuse.c b/block/export/fuse.c
14
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
15
--- a/block/vhdx.c
20
--- a/block/export/fuse.c
16
+++ b/block/vhdx.c
21
+++ b/block/export/fuse.c
17
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@ typedef struct FuseExport {
18
#include "qemu/option.h"
23
bool growable;
19
#include "qemu/crc32c.h"
24
/* Whether allow_other was used as a mount option or not */
20
#include "qemu/bswap.h"
25
bool allow_other;
21
+#include "qemu/error-report.h"
26
+
22
#include "vhdx.h"
27
+ mode_t st_mode;
23
#include "migration/blocker.h"
28
+ uid_t st_uid;
24
#include "qemu/uuid.h"
29
+ gid_t st_gid;
25
@@ -XXX,XX +XXX,XX @@ static int vhdx_region_check(BDRVVHDXState *s, uint64_t start, uint64_t length)
30
} FuseExport;
26
end = start + length;
31
27
QLIST_FOREACH(r, &s->regions, entries) {
32
static GHashTable *exports;
28
if (!((start >= r->end) || (end <= r->start))) {
33
@@ -XXX,XX +XXX,XX @@ static int fuse_export_create(BlockExport *blk_exp,
29
+ error_report("VHDX region %" PRIu64 "-%" PRIu64 " overlaps with "
34
args->allow_other = FUSE_EXPORT_ALLOW_OTHER_AUTO;
30
+ "region %" PRIu64 "-%." PRIu64, start, end, r->start,
35
}
31
+ r->end);
36
32
ret = -EINVAL;
37
+ exp->st_mode = S_IFREG | S_IRUSR;
33
goto exit;
38
+ if (exp->writable) {
34
}
39
+ exp->st_mode |= S_IWUSR;
35
@@ -XXX,XX +XXX,XX @@ static void vhdx_calc_bat_entries(BDRVVHDXState *s)
40
+ }
36
41
+ exp->st_uid = getuid();
42
+ exp->st_gid = getgid();
43
+
44
if (args->allow_other == FUSE_EXPORT_ALLOW_OTHER_AUTO) {
45
/* Ignore errors on our first attempt */
46
ret = setup_fuse_export(exp, args->mountpoint, true, NULL);
47
@@ -XXX,XX +XXX,XX @@ static void fuse_getattr(fuse_req_t req, fuse_ino_t inode,
48
int64_t length, allocated_blocks;
49
time_t now = time(NULL);
50
FuseExport *exp = fuse_req_userdata(req);
51
- mode_t mode;
52
53
length = blk_getlength(exp->common.blk);
54
if (length < 0) {
55
@@ -XXX,XX +XXX,XX @@ static void fuse_getattr(fuse_req_t req, fuse_ino_t inode,
56
allocated_blocks = DIV_ROUND_UP(allocated_blocks, 512);
57
}
58
59
- mode = S_IFREG | S_IRUSR;
60
- if (exp->writable) {
61
- mode |= S_IWUSR;
62
- }
63
-
64
statbuf = (struct stat) {
65
.st_ino = inode,
66
- .st_mode = mode,
67
+ .st_mode = exp->st_mode,
68
.st_nlink = 1,
69
- .st_uid = getuid(),
70
- .st_gid = getgid(),
71
+ .st_uid = exp->st_uid,
72
+ .st_gid = exp->st_gid,
73
.st_size = length,
74
.st_blksize = blk_bs(exp->common.blk)->bl.request_alignment,
75
.st_blocks = allocated_blocks,
76
@@ -XXX,XX +XXX,XX @@ static int fuse_do_truncate(const FuseExport *exp, int64_t size,
37
}
77
}
38
78
39
+static int vhdx_check_bat_entries(BlockDriverState *bs, int *errcnt)
79
/**
40
+{
80
- * Let clients set file attributes. Only resizing is supported.
41
+ BDRVVHDXState *s = bs->opaque;
81
+ * Let clients set file attributes. Only resizing and changing
42
+ int64_t image_file_size = bdrv_getlength(bs->file->bs);
82
+ * permissions (st_mode, st_uid, st_gid) is allowed.
43
+ uint64_t payblocks = s->chunk_ratio;
83
+ * Changing permissions is only allowed as far as it will actually
44
+ uint64_t i;
84
+ * permit access: Read-only exports cannot be given +w, and exports
45
+ int ret = 0;
85
+ * without allow_other cannot be given a different UID or GID, and
46
+
86
+ * they cannot be given non-owner access.
47
+ if (image_file_size < 0) {
87
*/
48
+ error_report("Could not determinate VHDX image file size.");
88
static void fuse_setattr(fuse_req_t req, fuse_ino_t inode, struct stat *statbuf,
49
+ return image_file_size;
89
int to_set, struct fuse_file_info *fi)
90
{
91
FuseExport *exp = fuse_req_userdata(req);
92
+ int supported_attrs;
93
int ret;
94
95
- if (to_set & ~FUSE_SET_ATTR_SIZE) {
96
+ supported_attrs = FUSE_SET_ATTR_SIZE | FUSE_SET_ATTR_MODE;
97
+ if (exp->allow_other) {
98
+ supported_attrs |= FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID;
50
+ }
99
+ }
51
+
100
+
52
+ for (i = 0; i < s->bat_entries; i++) {
101
+ if (to_set & ~supported_attrs) {
53
+ if ((s->bat[i] & VHDX_BAT_STATE_BIT_MASK) ==
102
fuse_reply_err(req, ENOTSUP);
54
+ PAYLOAD_BLOCK_FULLY_PRESENT) {
103
return;
55
+ uint64_t offset = s->bat[i] & VHDX_BAT_FILE_OFF_MASK;
104
}
56
+ /*
105
57
+ * Allow that the last block exists only partially. The VHDX spec
106
+ /* Do some argument checks first before committing to anything */
58
+ * states that the image file can only grow in blocksize increments,
107
+ if (to_set & FUSE_SET_ATTR_MODE) {
59
+ * but QEMU created images with partial last blocks in the past.
108
+ /*
60
+ */
109
+ * Without allow_other, non-owners can never access the export, so do
61
+ uint32_t block_length = MIN(s->block_size,
110
+ * not allow setting permissions for them
62
+ bs->total_sectors * BDRV_SECTOR_SIZE - i * s->block_size);
111
+ */
63
+ /*
112
+ if (!exp->allow_other &&
64
+ * Check for BAT entry overflow.
113
+ (statbuf->st_mode & (S_IRWXG | S_IRWXO)) != 0)
65
+ */
114
+ {
66
+ if (offset > INT64_MAX - s->block_size) {
115
+ fuse_reply_err(req, EPERM);
67
+ error_report("VHDX BAT entry %" PRIu64 " offset overflow.", i);
116
+ return;
68
+ ret = -EINVAL;
117
+ }
69
+ if (!errcnt) {
70
+ break;
71
+ }
72
+ (*errcnt)++;
73
+ }
74
+ /*
75
+ * Check if fully allocated BAT entries do not reside after
76
+ * end of the image file.
77
+ */
78
+ if (offset >= image_file_size) {
79
+ error_report("VHDX BAT entry %" PRIu64 " start offset %" PRIu64
80
+ " points after end of file (%" PRIi64 "). Image"
81
+ " has probably been truncated.",
82
+ i, offset, image_file_size);
83
+ ret = -EINVAL;
84
+ if (!errcnt) {
85
+ break;
86
+ }
87
+ (*errcnt)++;
88
+ } else if (offset + block_length > image_file_size) {
89
+ error_report("VHDX BAT entry %" PRIu64 " end offset %" PRIu64
90
+ " points after end of file (%" PRIi64 "). Image"
91
+ " has probably been truncated.",
92
+ i, offset + block_length - 1, image_file_size);
93
+ ret = -EINVAL;
94
+ if (!errcnt) {
95
+ break;
96
+ }
97
+ (*errcnt)++;
98
+ }
99
+
118
+
100
+ /*
119
+ /* +w for read-only exports makes no sense, disallow it */
101
+ * verify populated BAT field file offsets against
120
+ if (!exp->writable &&
102
+ * region table and log entries
121
+ (statbuf->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
103
+ */
122
+ {
104
+ if (payblocks--) {
123
+ fuse_reply_err(req, EROFS);
105
+ /* payload bat entries */
124
+ return;
106
+ int ret2;
107
+ ret2 = vhdx_region_check(s, offset, s->block_size);
108
+ if (ret2 < 0) {
109
+ ret = -EINVAL;
110
+ if (!errcnt) {
111
+ break;
112
+ }
113
+ (*errcnt)++;
114
+ }
115
+ } else {
116
+ payblocks = s->chunk_ratio;
117
+ /*
118
+ * Once differencing files are supported, verify sector bitmap
119
+ * blocks here
120
+ */
121
+ }
122
+ }
125
+ }
123
+ }
126
+ }
124
+
127
+
125
+ return ret;
128
if (to_set & FUSE_SET_ATTR_SIZE) {
126
+}
129
if (!exp->writable) {
127
+
130
fuse_reply_err(req, EACCES);
128
static void vhdx_close(BlockDriverState *bs)
131
@@ -XXX,XX +XXX,XX @@ static void fuse_setattr(fuse_req_t req, fuse_ino_t inode, struct stat *statbuf,
129
{
132
}
130
BDRVVHDXState *s = bs->opaque;
131
@@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
132
goto fail;
133
}
133
}
134
134
135
- uint64_t payblocks = s->chunk_ratio;
135
+ if (to_set & FUSE_SET_ATTR_MODE) {
136
- /* endian convert, and verify populated BAT field file offsets against
136
+ /* Ignore FUSE-supplied file type, only change the mode */
137
- * region table and log entries */
137
+ exp->st_mode = (statbuf->st_mode & 07777) | S_IFREG;
138
+ /* endian convert populated BAT field entires */
139
for (i = 0; i < s->bat_entries; i++) {
140
s->bat[i] = le64_to_cpu(s->bat[i]);
141
- if (payblocks--) {
142
- /* payload bat entries */
143
- if ((s->bat[i] & VHDX_BAT_STATE_BIT_MASK) ==
144
- PAYLOAD_BLOCK_FULLY_PRESENT) {
145
- ret = vhdx_region_check(s, s->bat[i] & VHDX_BAT_FILE_OFF_MASK,
146
- s->block_size);
147
- if (ret < 0) {
148
- goto fail;
149
- }
150
- }
151
- } else {
152
- payblocks = s->chunk_ratio;
153
- /* Once differencing files are supported, verify sector bitmap
154
- * blocks here */
155
+ }
138
+ }
156
+
139
+
157
+ if (!(flags & BDRV_O_CHECK)) {
140
+ if (to_set & FUSE_SET_ATTR_UID) {
158
+ ret = vhdx_check_bat_entries(bs, NULL);
141
+ exp->st_uid = statbuf->st_uid;
159
+ if (ret < 0) {
142
+ }
160
+ goto fail;
161
}
162
}
163
164
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_check(BlockDriverState *bs,
165
if (s->log_replayed_on_open) {
166
result->corruptions_fixed++;
167
}
168
+
143
+
169
+ vhdx_check_bat_entries(bs, &result->corruptions);
144
+ if (to_set & FUSE_SET_ATTR_GID) {
145
+ exp->st_gid = statbuf->st_gid;
146
+ }
170
+
147
+
171
return 0;
148
fuse_getattr(req, inode, fi);
172
}
149
}
173
150
174
--
151
--
175
2.20.1
152
2.31.1
176
153
177
154
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
For long test image paths, the order of the "Formatting" line and the
3
Test that +w on read-only FUSE exports returns an EROFS error. u+x on
4
"(qemu)" prompt after a drive_backup HMP command may be reversed. In
4
the other hand should work. (There is no special reason to choose u+x
5
fact, the interaction between the prompt and the line may lead to the
5
here, it simply is like +w another flag that is not set by default.)
6
"Formatting" to being greppable at all after "read"-ing it (if the
7
prompt injects an IFS character into the "Formatting" string).
8
6
9
So just wait until we get a prompt. At that point, the block job must
10
have been started, so "info block-jobs" will only return "No active
11
jobs" once it is done.
12
13
Reported-by: Thomas Huth <thuth@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: John Snow <jsnow@redhat.com>
8
Message-Id: <20210625142317.271673-6-mreitz@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
10
---
18
tests/qemu-iotests/028 | 11 ++++++++---
11
tests/qemu-iotests/308 | 11 +++++++++++
19
tests/qemu-iotests/028.out | 1 -
12
tests/qemu-iotests/308.out | 4 ++++
20
2 files changed, 8 insertions(+), 4 deletions(-)
13
2 files changed, 15 insertions(+)
21
14
22
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
15
diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308
23
index XXXXXXX..XXXXXXX 100755
16
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/028
17
--- a/tests/qemu-iotests/308
25
+++ b/tests/qemu-iotests/028
18
+++ b/tests/qemu-iotests/308
26
@@ -XXX,XX +XXX,XX @@ fi
19
@@ -XXX,XX +XXX,XX @@ fuse_export_add 'export-mp' "'mountpoint': '$EXT_MP'"
27
# Silence output since it contains the disk image path and QEMU's readline
20
# Check that the export presents the same data as the original image
28
# character echoing makes it very hard to filter the output. Plus, there
21
$QEMU_IMG compare -f raw -F $IMGFMT -U "$EXT_MP" "$TEST_IMG"
29
# is no telling how many times the command will repeat before succeeding.
22
30
-_send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)" >/dev/null
23
+# Some quick chmod tests
31
-_send_qemu_cmd $h "" "Formatting" | _filter_img_create
24
+stat -c 'Permissions pre-chmod: %a' "$EXT_MP"
32
-qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs" >/dev/null
25
+
33
+# (Note that creating the image results in a "Formatting..." message over
26
+# Verify that we cannot set +w
34
+# stdout, which is the same channel the monitor uses. We cannot reliably
27
+chmod u+w "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt
35
+# wait for it because the monitor output may interact with it in such a
28
+stat -c 'Permissions post-+w: %a' "$EXT_MP"
36
+# way that _timed_wait_for cannot read it. However, once the block job is
29
+
37
+# done, we know that the "Formatting..." message must have appeared
30
+# But that we can set, say, +x (if we are so inclined)
38
+# already, so the output is still deterministic.)
31
+chmod u+x "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt
39
+silent=y _send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)"
32
+stat -c 'Permissions post-+x: %a' "$EXT_MP"
40
+silent=y qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs"
33
+
41
_send_qemu_cmd $h "info block-jobs" "No active jobs"
34
echo
42
_send_qemu_cmd $h 'quit' ""
35
echo '=== Mount over existing file ==='
43
36
44
diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out
37
diff --git a/tests/qemu-iotests/308.out b/tests/qemu-iotests/308.out
45
index XXXXXXX..XXXXXXX 100644
38
index XXXXXXX..XXXXXXX 100644
46
--- a/tests/qemu-iotests/028.out
39
--- a/tests/qemu-iotests/308.out
47
+++ b/tests/qemu-iotests/028.out
40
+++ b/tests/qemu-iotests/308.out
48
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
41
@@ -XXX,XX +XXX,XX @@ wrote 67108864/67108864 bytes at offset 0
49
42
} }
50
block-backup
43
{"return": {}}
51
44
Images are identical.
52
-Formatting 'TEST_DIR/t.IMGFMT.copy', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
45
+Permissions pre-chmod: 400
53
(qemu) info block-jobs
46
+chmod: changing permissions of 'TEST_DIR/t.IMGFMT.fuse': Read-only file system
54
No active jobs
47
+Permissions post-+w: 400
55
=== IO: pattern 195
48
+Permissions post-+x: 500
49
50
=== Mount over existing file ===
51
{'execute': 'block-export-add',
56
--
52
--
57
2.20.1
53
2.31.1
58
54
59
55
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
The BDRV_REQ_NO_FALLBACK flag means that an operation should only be
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
performed if it can be offloaded or otherwise performed efficiently.
4
Message-Id: <20210625142317.271673-7-mreitz@redhat.com>
5
6
However a misaligned write request requires a RMW so we should return
7
an error and let the caller decide how to proceed.
8
9
This hits an assertion since commit c8bb23cbdb if the required
10
alignment is larger than the cluster size:
11
12
qemu-img create -f qcow2 -o cluster_size=2k img.qcow2 4G
13
qemu-io -c "open -o driver=qcow2,file.align=4k blkdebug::img.qcow2" \
14
-c 'write 0 512'
15
qemu-io: block/io.c:1127: bdrv_driver_pwritev: Assertion `!(flags & BDRV_REQ_NO_FALLBACK)' failed.
16
Aborted
17
18
The reason is that when writing to an unallocated cluster we try to
19
skip the copy-on-write part and zeroize it using BDRV_REQ_NO_FALLBACK
20
instead, resulting in a write request that is too small (2KB cluster
21
size vs 4KB required alignment).
22
23
Signed-off-by: Alberto Garcia <berto@igalia.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
6
---
26
block/io.c | 7 +++++
7
tests/qemu-iotests/tests/fuse-allow-other | 168 ++++++++++++++++++
27
tests/qemu-iotests/268 | 55 ++++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/tests/fuse-allow-other.out | 88 +++++++++
28
tests/qemu-iotests/268.out | 7 +++++
9
2 files changed, 256 insertions(+)
29
tests/qemu-iotests/group | 1 +
10
create mode 100755 tests/qemu-iotests/tests/fuse-allow-other
30
4 files changed, 70 insertions(+)
11
create mode 100644 tests/qemu-iotests/tests/fuse-allow-other.out
31
create mode 100755 tests/qemu-iotests/268
12
32
create mode 100644 tests/qemu-iotests/268.out
13
diff --git a/tests/qemu-iotests/tests/fuse-allow-other b/tests/qemu-iotests/tests/fuse-allow-other
33
34
diff --git a/block/io.c b/block/io.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/io.c
37
+++ b/block/io.c
38
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
39
return ret;
40
}
41
42
+ /* If the request is misaligned then we can't make it efficient */
43
+ if ((flags & BDRV_REQ_NO_FALLBACK) &&
44
+ !QEMU_IS_ALIGNED(offset | bytes, align))
45
+ {
46
+ return -ENOTSUP;
47
+ }
48
+
49
bdrv_inc_in_flight(bs);
50
/*
51
* Align write if necessary by performing a read-modify-write cycle.
52
diff --git a/tests/qemu-iotests/268 b/tests/qemu-iotests/268
53
new file mode 100755
14
new file mode 100755
54
index XXXXXXX..XXXXXXX
15
index XXXXXXX..XXXXXXX
55
--- /dev/null
16
--- /dev/null
56
+++ b/tests/qemu-iotests/268
17
+++ b/tests/qemu-iotests/tests/fuse-allow-other
57
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@
58
+#!/usr/bin/env bash
19
+#!/usr/bin/env bash
59
+#
20
+# group: rw
60
+# Test write request with required alignment larger than the cluster size
21
+#
61
+#
22
+# Test FUSE exports' allow-other option
62
+# Copyright (C) 2019 Igalia, S.L.
23
+#
63
+# Author: Alberto Garcia <berto@igalia.com>
24
+# Copyright (C) 2021 Red Hat, Inc.
64
+#
25
+#
65
+# This program is free software; you can redistribute it and/or modify
26
+# This program is free software; you can redistribute it and/or modify
66
+# it under the terms of the GNU General Public License as published by
27
+# it under the terms of the GNU General Public License as published by
67
+# the Free Software Foundation; either version 2 of the License, or
28
+# the Free Software Foundation; either version 2 of the License, or
68
+# (at your option) any later version.
29
+# (at your option) any later version.
...
...
74
+#
35
+#
75
+# You should have received a copy of the GNU General Public License
36
+# You should have received a copy of the GNU General Public License
76
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
37
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
77
+#
38
+#
78
+
39
+
79
+# creator
40
+seq=$(basename "$0")
80
+owner=berto@igalia.com
81
+
82
+seq=`basename $0`
83
+echo "QA output created by $seq"
41
+echo "QA output created by $seq"
84
+
42
+
85
+status=1    # failure is the default!
43
+status=1    # failure is the default!
86
+
44
+
87
+_cleanup()
45
+_cleanup()
88
+{
46
+{
47
+ _cleanup_qemu
89
+ _cleanup_test_img
48
+ _cleanup_test_img
49
+ rm -f "$EXT_MP"
90
+}
50
+}
91
+trap "_cleanup; exit \$status" 0 1 2 3 15
51
+trap "_cleanup; exit \$status" 0 1 2 3 15
92
+
52
+
93
+# get standard environment, filters and checks
53
+# get standard environment, filters and checks
94
+. ./common.rc
54
+. ../common.rc
95
+. ./common.filter
55
+. ../common.filter
96
+
56
+. ../common.qemu
97
+_supported_fmt qcow2
57
+
98
+_supported_proto file
58
+_supported_fmt generic
59
+
60
+_supported_proto file # We create the FUSE export manually
61
+
62
+sudo -n -u nobody true || \
63
+ _notrun 'Password-less sudo as nobody required to test allow_other'
64
+
65
+# $1: Export ID
66
+# $2: Options (beyond the node-name and ID)
67
+# $3: Expected return value (defaults to 'return')
68
+# $4: Node to export (defaults to 'node-format')
69
+fuse_export_add()
70
+{
71
+ allow_other_not_supported='option allow_other only allowed if'
72
+
73
+ output=$(
74
+ success_or_failure=yes _send_qemu_cmd $QEMU_HANDLE \
75
+ "{'execute': 'block-export-add',
76
+ 'arguments': {
77
+ 'type': 'fuse',
78
+ 'id': '$1',
79
+ 'node-name': '${4:-node-format}',
80
+ $2
81
+ } }" \
82
+ "${3:-return}" \
83
+ "$allow_other_not_supported" \
84
+ | _filter_imgfmt
85
+ )
86
+
87
+ if echo "$output" | grep -q "$allow_other_not_supported"; then
88
+ # Shut down qemu gracefully so it can unmount the export
89
+ _send_qemu_cmd $QEMU_HANDLE \
90
+ "{'execute': 'quit'}" \
91
+ 'return'
92
+
93
+ wait=yes _cleanup_qemu
94
+
95
+ _notrun "allow_other not supported"
96
+ fi
97
+
98
+ echo "$output"
99
+}
100
+
101
+EXT_MP="$TEST_DIR/fuse-export"
102
+
103
+_make_test_img 64k
104
+touch "$EXT_MP"
99
+
105
+
100
+echo
106
+echo
101
+echo "== Required alignment larger than cluster size =="
107
+echo '=== Test permissions ==='
102
+
108
+
103
+CLUSTER_SIZE=2k _make_test_img 1M
109
+# $1: allow-other value ('on'/'off'/'auto')
104
+# Since commit c8bb23cbdb writing to an unallocated cluster fills the
110
+run_permission_test()
105
+# empty COW areas with bdrv_write_zeroes(flags=BDRV_REQ_NO_FALLBACK)
111
+{
106
+$QEMU_IO -c "open -o driver=$IMGFMT,file.align=4k blkdebug::$TEST_IMG" \
112
+ _launch_qemu \
107
+ -c "write 0 512" | _filter_qemu_io
113
+ -blockdev \
114
+ "$IMGFMT,node-name=node-format,file.driver=file,file.filename=$TEST_IMG"
115
+
116
+ _send_qemu_cmd $QEMU_HANDLE \
117
+ "{'execute': 'qmp_capabilities'}" \
118
+ 'return'
119
+
120
+ fuse_export_add 'export' \
121
+ "'mountpoint': '$EXT_MP',
122
+ 'allow-other': '$1'"
123
+
124
+ # Should always work
125
+ echo '(Removing all permissions)'
126
+ chmod 000 "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt
127
+ stat -c 'Permissions post-chmod: %a' "$EXT_MP"
128
+
129
+ # Should always work
130
+ echo '(Granting u+r)'
131
+ chmod u+r "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt
132
+ stat -c 'Permissions post-chmod: %a' "$EXT_MP"
133
+
134
+ # Should only work with allow-other: Otherwise, no permissions can be
135
+ # granted to the group or others
136
+ echo '(Granting read permissions for everyone)'
137
+ chmod 444 "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt
138
+ stat -c 'Permissions post-chmod: %a' "$EXT_MP"
139
+
140
+ echo 'Doing operations as nobody:'
141
+ # Change to TEST_DIR, so nobody will not have to attempt a lookup
142
+ pushd "$TEST_DIR" >/dev/null
143
+
144
+ # This is already prevented by the permissions (without allow-other, FUSE
145
+ # exports always have o-r), but test it anyway
146
+ sudo -n -u nobody cat fuse-export >/dev/null
147
+
148
+ # If the only problem were the lack of permissions, we should still be able
149
+ # to stat the export as nobody; it should not work without allow-other,
150
+ # though
151
+ sudo -n -u nobody \
152
+ stat -c 'Permissions seen by nobody: %a' fuse-export 2>&1 \
153
+ | _filter_imgfmt
154
+
155
+ # To prove the point, revoke read permissions for others and try again
156
+ chmod o-r fuse-export 2>&1 | _filter_testdir | _filter_imgfmt
157
+
158
+ # Should fail
159
+ sudo -n -u nobody cat fuse-export >/dev/null
160
+ # Should work with allow_other
161
+ sudo -n -u nobody \
162
+ stat -c 'Permissions seen by nobody: %a' fuse-export 2>&1 \
163
+ | _filter_imgfmt
164
+
165
+ popd >/dev/null
166
+
167
+ _send_qemu_cmd $QEMU_HANDLE \
168
+ "{'execute': 'quit'}" \
169
+ 'return'
170
+
171
+ wait=yes _cleanup_qemu
172
+}
173
+
174
+# 'auto' should behave exactly like 'on', because 'on' tests that
175
+# allow_other works (otherwise, this test is skipped)
176
+for ao in off on auto; do
177
+ echo
178
+ echo "--- allow-other=$ao ---"
179
+
180
+ run_permission_test "$ao"
181
+done
108
+
182
+
109
+# success, all done
183
+# success, all done
110
+echo "*** done"
184
+echo "*** done"
111
+rm -f $seq.full
185
+rm -f $seq.full
112
+status=0
186
+status=0
113
diff --git a/tests/qemu-iotests/268.out b/tests/qemu-iotests/268.out
187
diff --git a/tests/qemu-iotests/tests/fuse-allow-other.out b/tests/qemu-iotests/tests/fuse-allow-other.out
114
new file mode 100644
188
new file mode 100644
115
index XXXXXXX..XXXXXXX
189
index XXXXXXX..XXXXXXX
116
--- /dev/null
190
--- /dev/null
117
+++ b/tests/qemu-iotests/268.out
191
+++ b/tests/qemu-iotests/tests/fuse-allow-other.out
118
@@ -XXX,XX +XXX,XX @@
192
@@ -XXX,XX +XXX,XX @@
119
+QA output created by 268
193
+QA output created by fuse-allow-other
120
+
194
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
121
+== Required alignment larger than cluster size ==
195
+
122
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
196
+=== Test permissions ===
123
+wrote 512/512 bytes at offset 0
197
+
124
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
198
+--- allow-other=off ---
199
+{'execute': 'qmp_capabilities'}
200
+{"return": {}}
201
+{'execute': 'block-export-add',
202
+ 'arguments': {
203
+ 'type': 'fuse',
204
+ 'id': 'export',
205
+ 'node-name': 'node-format',
206
+ 'mountpoint': 'TEST_DIR/fuse-export',
207
+ 'allow-other': 'off'
208
+ } }
209
+{"return": {}}
210
+(Removing all permissions)
211
+Permissions post-chmod: 0
212
+(Granting u+r)
213
+Permissions post-chmod: 400
214
+(Granting read permissions for everyone)
215
+chmod: changing permissions of 'TEST_DIR/fuse-export': Operation not permitted
216
+Permissions post-chmod: 400
217
+Doing operations as nobody:
218
+cat: fuse-export: Permission denied
219
+stat: cannot statx 'fuse-export': Permission denied
220
+cat: fuse-export: Permission denied
221
+stat: cannot statx 'fuse-export': Permission denied
222
+{'execute': 'quit'}
223
+{"return": {}}
224
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
225
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
226
+
227
+--- allow-other=on ---
228
+{'execute': 'qmp_capabilities'}
229
+{"return": {}}
230
+{'execute': 'block-export-add',
231
+ 'arguments': {
232
+ 'type': 'fuse',
233
+ 'id': 'export',
234
+ 'node-name': 'node-format',
235
+ 'mountpoint': 'TEST_DIR/fuse-export',
236
+ 'allow-other': 'on'
237
+ } }
238
+{"return": {}}
239
+(Removing all permissions)
240
+Permissions post-chmod: 0
241
+(Granting u+r)
242
+Permissions post-chmod: 400
243
+(Granting read permissions for everyone)
244
+Permissions post-chmod: 444
245
+Doing operations as nobody:
246
+Permissions seen by nobody: 444
247
+cat: fuse-export: Permission denied
248
+Permissions seen by nobody: 440
249
+{'execute': 'quit'}
250
+{"return": {}}
251
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
252
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
253
+
254
+--- allow-other=auto ---
255
+{'execute': 'qmp_capabilities'}
256
+{"return": {}}
257
+{'execute': 'block-export-add',
258
+ 'arguments': {
259
+ 'type': 'fuse',
260
+ 'id': 'export',
261
+ 'node-name': 'node-format',
262
+ 'mountpoint': 'TEST_DIR/fuse-export',
263
+ 'allow-other': 'auto'
264
+ } }
265
+{"return": {}}
266
+(Removing all permissions)
267
+Permissions post-chmod: 0
268
+(Granting u+r)
269
+Permissions post-chmod: 400
270
+(Granting read permissions for everyone)
271
+Permissions post-chmod: 444
272
+Doing operations as nobody:
273
+Permissions seen by nobody: 444
274
+cat: fuse-export: Permission denied
275
+Permissions seen by nobody: 440
276
+{'execute': 'quit'}
277
+{"return": {}}
278
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
279
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export"}}
125
+*** done
280
+*** done
126
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
127
index XXXXXXX..XXXXXXX 100644
128
--- a/tests/qemu-iotests/group
129
+++ b/tests/qemu-iotests/group
130
@@ -XXX,XX +XXX,XX @@
131
265 rw auto quick
132
266 rw quick
133
267 rw auto quick snapshot
134
+268 rw auto quick
135
--
281
--
136
2.20.1
282
2.31.1
137
283
138
284
diff view generated by jsdifflib
1
From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
1
From: Peter Lieven <pl@kamp.de>
2
2
3
After recent updates block devices cannot be closed on qemu exit.
3
task->complete is a bool not an integer.
4
This happens due to the block request polling when replay is not finished.
5
Therefore now we stop execution recording before closing the block devices.
6
4
7
Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
5
Signed-off-by: Peter Lieven <pl@kamp.de>
6
Message-Id: <20210707180449.32665-1-pl@kamp.de>
7
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
9
---
10
replay/replay.c | 2 ++
10
block/rbd.c | 2 +-
11
vl.c | 1 +
11
1 file changed, 1 insertion(+), 1 deletion(-)
12
2 files changed, 3 insertions(+)
13
12
14
diff --git a/replay/replay.c b/replay/replay.c
13
diff --git a/block/rbd.c b/block/rbd.c
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/replay/replay.c
15
--- a/block/rbd.c
17
+++ b/replay/replay.c
16
+++ b/block/rbd.c
18
@@ -XXX,XX +XXX,XX @@ void replay_finish(void)
17
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_resize(BlockDriverState *bs, uint64_t size)
19
g_free(replay_snapshot);
18
static void qemu_rbd_finish_bh(void *opaque)
20
replay_snapshot = NULL;
19
{
21
20
RBDTask *task = opaque;
22
+ replay_mode = REPLAY_MODE_NONE;
21
- task->complete = 1;
23
+
22
+ task->complete = true;
24
replay_finish_events();
23
aio_co_wake(task->co);
25
}
24
}
26
25
27
diff --git a/vl.c b/vl.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/vl.c
30
+++ b/vl.c
31
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
32
33
/* No more vcpu or device emulation activity beyond this point */
34
vm_shutdown();
35
+ replay_finish();
36
37
job_cancel_sync_all();
38
bdrv_close_all();
39
--
26
--
40
2.20.1
27
2.31.1
41
28
42
29
diff view generated by jsdifflib
New patch
1
From: Peter Lieven <pl@kamp.de>
1
2
3
adding myself as a designated reviewer.
4
5
Signed-off-by: Peter Lieven <pl@kamp.de>
6
Message-Id: <20210707180449.32665-2-pl@kamp.de>
7
Acked-by: Ilya Dryomov <idryomov@gmail.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
MAINTAINERS | 1 +
11
1 file changed, 1 insertion(+)
12
13
diff --git a/MAINTAINERS b/MAINTAINERS
14
index XXXXXXX..XXXXXXX 100644
15
--- a/MAINTAINERS
16
+++ b/MAINTAINERS
17
@@ -XXX,XX +XXX,XX @@ F: block/vmdk.c
18
19
RBD
20
M: Ilya Dryomov <idryomov@gmail.com>
21
+R: Peter Lieven <pl@kamp.de>
22
L: qemu-block@nongnu.org
23
S: Supported
24
F: block/rbd.c
25
--
26
2.31.1
27
28
diff view generated by jsdifflib
New patch
1
dev->max_queues was never initialised for backends that don't support
2
VHOST_USER_PROTOCOL_F_MQ, so it would use 0 as the maximum number of
3
queues to check against and consequently fail for any such backend.
1
4
5
Set it to 1 if the backend doesn't have multiqueue support.
6
7
Fixes: c90bd505a3e8210c23d69fecab9ee6f56ec4a161
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20210705171429.29286-1-kwolf@redhat.com>
10
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
11
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
hw/virtio/vhost-user.c | 3 +++
15
1 file changed, 3 insertions(+)
16
17
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/virtio/vhost-user.c
20
+++ b/hw/virtio/vhost-user.c
21
@@ -XXX,XX +XXX,XX @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque,
22
if (err < 0) {
23
return -EPROTO;
24
}
25
+ } else {
26
+ dev->max_queues = 1;
27
}
28
+
29
if (dev->num_queues && dev->max_queues < dev->num_queues) {
30
error_setg(errp, "The maximum number of queues supported by the "
31
"backend is %" PRIu64, dev->max_queues);
32
--
33
2.31.1
34
35
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
drive_backup_prepare() does bdrv_drained_begin() in hope that
4
bdrv_drained_end() will be called in drive_backup_clean(). Still we
5
need to set state->bs for this to work. That's done too late: a lot of
6
failure paths in drive_backup_prepare() miss setting state->bs. Fix
7
that.
8
9
Fixes: 2288ccfac96281c316db942d10e3f921c1373064
10
Fixes: https://gitlab.com/qemu-project/qemu/-/issues/399
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Message-Id: <20210608171852.250775-1-vsementsov@virtuozzo.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
blockdev.c | 3 +--
17
1 file changed, 1 insertion(+), 2 deletions(-)
18
19
diff --git a/blockdev.c b/blockdev.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/blockdev.c
22
+++ b/blockdev.c
23
@@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
24
aio_context = bdrv_get_aio_context(bs);
25
aio_context_acquire(aio_context);
26
27
+ state->bs = bs;
28
/* Paired with .clean() */
29
bdrv_drained_begin(bs);
30
31
@@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
32
}
33
}
34
35
- state->bs = bs;
36
-
37
state->job = do_backup_common(qapi_DriveBackup_base(backup),
38
bs, target_bs, aio_context,
39
common->block_job_txn, errp);
40
--
41
2.31.1
42
43
diff view generated by jsdifflib
New patch
1
From: Eric Blake <eblake@redhat.com>
1
2
3
This was deprecated back in bc5ee6da7 (qcow2: Deprecate use of
4
qemu-img amend to change backing file), and no one in the meantime has
5
given any reasons why it should be supported. Time to make change
6
attempts a hard error (but for convenience, specifying the _same_
7
backing chain is not forbidden). Update a couple of iotests to match.
8
9
Signed-off-by: Eric Blake <eblake@redhat.com>
10
Message-Id: <20210503213600.569128-2-eblake@redhat.com>
11
Reviewed-by: Connor Kuehl <ckuehl@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
docs/system/deprecated.rst | 12 ------------
15
docs/system/removed-features.rst | 12 ++++++++++++
16
block/qcow2.c | 13 ++++---------
17
tests/qemu-iotests/061 | 3 +++
18
tests/qemu-iotests/061.out | 3 ++-
19
tests/qemu-iotests/082.out | 6 ++++--
20
6 files changed, 25 insertions(+), 24 deletions(-)
21
22
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
23
index XXXXXXX..XXXXXXX 100644
24
--- a/docs/system/deprecated.rst
25
+++ b/docs/system/deprecated.rst
26
@@ -XXX,XX +XXX,XX @@ this CPU is also deprecated.
27
Related binaries
28
----------------
29
30
-qemu-img amend to adjust backing file (since 5.1)
31
-'''''''''''''''''''''''''''''''''''''''''''''''''
32
-
33
-The use of ``qemu-img amend`` to modify the name or format of a qcow2
34
-backing image is deprecated; this functionality was never fully
35
-documented or tested, and interferes with other amend operations that
36
-need access to the original backing image (such as deciding whether a
37
-v3 zero cluster may be left unallocated when converting to a v2
38
-image). Rather, any changes to the backing chain should be performed
39
-with ``qemu-img rebase -u`` either before or after the remaining
40
-changes being performed by amend, as appropriate.
41
-
42
qemu-img backing file without format (since 5.1)
43
''''''''''''''''''''''''''''''''''''''''''''''''
44
45
diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst
46
index XXXXXXX..XXXXXXX 100644
47
--- a/docs/system/removed-features.rst
48
+++ b/docs/system/removed-features.rst
49
@@ -XXX,XX +XXX,XX @@ topologies described with -smp include all possible cpus, i.e.
50
The ``enforce-config-section`` property was replaced by the
51
``-global migration.send-configuration={on|off}`` option.
52
53
+qemu-img amend to adjust backing file (removed in 6.1)
54
+''''''''''''''''''''''''''''''''''''''''''''''''''''''
55
+
56
+The use of ``qemu-img amend`` to modify the name or format of a qcow2
57
+backing image was never fully documented or tested, and interferes
58
+with other amend operations that need access to the original backing
59
+image (such as deciding whether a v3 zero cluster may be left
60
+unallocated when converting to a v2 image). Any changes to the
61
+backing chain should be performed with ``qemu-img rebase -u`` either
62
+before or after the remaining changes being performed by amend, as
63
+appropriate.
64
+
65
Block devices
66
-------------
67
68
diff --git a/block/qcow2.c b/block/qcow2.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/block/qcow2.c
71
+++ b/block/qcow2.c
72
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
73
if (backing_file || backing_format) {
74
if (g_strcmp0(backing_file, s->image_backing_file) ||
75
g_strcmp0(backing_format, s->image_backing_format)) {
76
- warn_report("Deprecated use of amend to alter the backing file; "
77
- "use qemu-img rebase instead");
78
- }
79
- ret = qcow2_change_backing_file(bs,
80
- backing_file ?: s->image_backing_file,
81
- backing_format ?: s->image_backing_format);
82
- if (ret < 0) {
83
- error_setg_errno(errp, -ret, "Failed to change the backing file");
84
- return ret;
85
+ error_setg(errp, "Cannot amend the backing file");
86
+ error_append_hint(errp,
87
+ "You can use 'qemu-img rebase' instead.\n");
88
+ return -EINVAL;
89
}
90
}
91
92
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
93
index XXXXXXX..XXXXXXX 100755
94
--- a/tests/qemu-iotests/061
95
+++ b/tests/qemu-iotests/061
96
@@ -XXX,XX +XXX,XX @@ _make_test_img -o "compat=1.1" 64M
97
TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
98
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
99
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
100
+$QEMU_IMG amend -o "backing_file=$TEST_IMG.base,backing_fmt=qcow2" \
101
+     "$TEST_IMG" && echo "unexpected pass"
102
+$QEMU_IMG rebase -u -b "$TEST_IMG.base" -F qcow2 "$TEST_IMG"
103
$QEMU_IMG amend -o "backing_file=$TEST_IMG.base,backing_fmt=qcow2" "$TEST_IMG"
104
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
105
_check_test_img
106
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
107
index XXXXXXX..XXXXXXX 100644
108
--- a/tests/qemu-iotests/061.out
109
+++ b/tests/qemu-iotests/061.out
110
@@ -XXX,XX +XXX,XX @@ wrote 131072/131072 bytes at offset 0
111
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
112
read 131072/131072 bytes at offset 0
113
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
114
-qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead
115
+qemu-img: Cannot amend the backing file
116
+You can use 'qemu-img rebase' instead.
117
read 131072/131072 bytes at offset 0
118
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
119
No errors were found on the image.
120
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
121
index XXXXXXX..XXXXXXX 100644
122
--- a/tests/qemu-iotests/082.out
123
+++ b/tests/qemu-iotests/082.out
124
@@ -XXX,XX +XXX,XX @@ Amend options for 'qcow2':
125
size=<size> - Virtual disk size
126
127
Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2
128
-qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead
129
+qemu-img: Cannot amend the backing file
130
+You can use 'qemu-img rebase' instead.
131
132
Testing: rebase -u -b -f qcow2 TEST_DIR/t.qcow2
133
134
Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2
135
-qemu-img: warning: Deprecated use of amend to alter the backing file; use qemu-img rebase instead
136
+qemu-img: Cannot amend the backing file
137
+You can use 'qemu-img rebase' instead.
138
139
Testing: rebase -u -b -f qcow2 TEST_DIR/t.qcow2
140
141
--
142
2.31.1
143
144
diff view generated by jsdifflib
New patch
1
1
From: Eric Blake <eblake@redhat.com>
2
3
Back in commit d9f059aa6c (qemu-img: Deprecate use of -b without -F),
4
we deprecated the ability to create a file with a backing image that
5
requires qemu to perform format probing. Qemu can still probe older
6
files for backwards compatibility, but it is time to finish off the
7
ability to create such images, due to the potential security risk they
8
present. Update a couple of iotests affected by the change.
9
10
Signed-off-by: Eric Blake <eblake@redhat.com>
11
Message-Id: <20210503213600.569128-3-eblake@redhat.com>
12
Reviewed-by: Connor Kuehl <ckuehl@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
docs/system/deprecated.rst | 20 -----------------
16
docs/system/removed-features.rst | 19 ++++++++++++++++
17
block.c | 37 ++++++++++----------------------
18
qemu-img.c | 6 ++++--
19
tests/qemu-iotests/040 | 4 ++--
20
tests/qemu-iotests/041 | 6 ++++--
21
tests/qemu-iotests/114 | 18 ++++++++--------
22
tests/qemu-iotests/114.out | 11 ++++------
23
tests/qemu-iotests/301 | 4 +---
24
tests/qemu-iotests/301.out | 16 ++------------
25
10 files changed, 56 insertions(+), 85 deletions(-)
26
27
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
28
index XXXXXXX..XXXXXXX 100644
29
--- a/docs/system/deprecated.rst
30
+++ b/docs/system/deprecated.rst
31
@@ -XXX,XX +XXX,XX @@ this CPU is also deprecated.
32
Related binaries
33
----------------
34
35
-qemu-img backing file without format (since 5.1)
36
-''''''''''''''''''''''''''''''''''''''''''''''''
37
-
38
-The use of ``qemu-img create``, ``qemu-img rebase``, or ``qemu-img
39
-convert`` to create or modify an image that depends on a backing file
40
-now recommends that an explicit backing format be provided. This is
41
-for safety: if QEMU probes a different format than what you thought,
42
-the data presented to the guest will be corrupt; similarly, presenting
43
-a raw image to a guest allows a potential security exploit if a future
44
-probe sees a non-raw image based on guest writes.
45
-
46
-To avoid the warning message, or even future refusal to create an
47
-unsafe image, you must pass ``-o backing_fmt=`` (or the shorthand
48
-``-F`` during create) to specify the intended backing format. You may
49
-use ``qemu-img rebase -u`` to retroactively add a backing format to an
50
-existing image. However, be aware that there are already potential
51
-security risks to blindly using ``qemu-img info`` to probe the format
52
-of an untrusted backing image, when deciding what format to add into
53
-an existing image.
54
-
55
Backwards compatibility
56
-----------------------
57
58
diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst
59
index XXXXXXX..XXXXXXX 100644
60
--- a/docs/system/removed-features.rst
61
+++ b/docs/system/removed-features.rst
62
@@ -XXX,XX +XXX,XX @@ backing chain should be performed with ``qemu-img rebase -u`` either
63
before or after the remaining changes being performed by amend, as
64
appropriate.
65
66
+qemu-img backing file without format (removed in 6.1)
67
+'''''''''''''''''''''''''''''''''''''''''''''''''''''
68
+
69
+The use of ``qemu-img create``, ``qemu-img rebase``, or ``qemu-img
70
+convert`` to create or modify an image that depends on a backing file
71
+now requires that an explicit backing format be provided. This is
72
+for safety: if QEMU probes a different format than what you thought,
73
+the data presented to the guest will be corrupt; similarly, presenting
74
+a raw image to a guest allows a potential security exploit if a future
75
+probe sees a non-raw image based on guest writes.
76
+
77
+To avoid creating unsafe backing chains, you must pass ``-o
78
+backing_fmt=`` (or the shorthand ``-F`` during create) to specify the
79
+intended backing format. You may use ``qemu-img rebase -u`` to
80
+retroactively add a backing format to an existing image. However, be
81
+aware that there are already potential security risks to blindly using
82
+``qemu-img info`` to probe the format of an untrusted backing image,
83
+when deciding what format to add into an existing image.
84
+
85
Block devices
86
-------------
87
88
diff --git a/block.c b/block.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/block.c
91
+++ b/block.c
92
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
93
* -ENOTSUP - format driver doesn't support changing the backing file
94
*/
95
int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
96
- const char *backing_fmt, bool warn)
97
+ const char *backing_fmt, bool require)
98
{
99
BlockDriver *drv = bs->drv;
100
int ret;
101
@@ -XXX,XX +XXX,XX @@ int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
102
return -EINVAL;
103
}
104
105
- if (warn && backing_file && !backing_fmt) {
106
- warn_report("Deprecated use of backing file without explicit "
107
- "backing format, use of this image requires "
108
- "potentially unsafe format probing");
109
+ if (require && backing_file && !backing_fmt) {
110
+ return -EINVAL;
111
}
112
113
if (drv->bdrv_change_backing_file != NULL) {
114
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
115
goto out;
116
} else {
117
if (!backing_fmt) {
118
- warn_report("Deprecated use of backing file without explicit "
119
- "backing format (detected format of %s)",
120
- bs->drv->format_name);
121
- if (bs->drv != &bdrv_raw) {
122
- /*
123
- * A probe of raw deserves the most attention:
124
- * leaving the backing format out of the image
125
- * will ensure bs->probed is set (ensuring we
126
- * don't accidentally commit into the backing
127
- * file), and allow more spots to warn the users
128
- * to fix their toolchain when opening this image
129
- * later. For other images, we can safely record
130
- * the format that we probed.
131
- */
132
- backing_fmt = bs->drv->format_name;
133
- qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, backing_fmt,
134
- NULL);
135
- }
136
+ error_setg(&local_err,
137
+ "Backing file specified without backing format");
138
+ error_append_hint(&local_err, "Detected format of %s.",
139
+ bs->drv->format_name);
140
+ goto out;
141
}
142
if (size == -1) {
143
/* Opened BS, have no size */
144
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
145
}
146
/* (backing_file && !(flags & BDRV_O_NO_BACKING)) */
147
} else if (backing_file && !backing_fmt) {
148
- warn_report("Deprecated use of unopened backing file without "
149
- "explicit backing format, use of this image requires "
150
- "potentially unsafe format probing");
151
+ error_setg(&local_err,
152
+ "Backing file specified without backing format");
153
+ goto out;
154
}
155
156
if (size == -1) {
157
diff --git a/qemu-img.c b/qemu-img.c
158
index XXXXXXX..XXXXXXX 100644
159
--- a/qemu-img.c
160
+++ b/qemu-img.c
161
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
162
163
if (out_baseimg_param) {
164
if (!qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT)) {
165
- warn_report("Deprecated use of backing file without explicit "
166
- "backing format");
167
+ error_report("Use of backing file requires explicit "
168
+ "backing format");
169
+ ret = -1;
170
+ goto out;
171
}
172
}
173
174
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
175
index XXXXXXX..XXXXXXX 100755
176
--- a/tests/qemu-iotests/040
177
+++ b/tests/qemu-iotests/040
178
@@ -XXX,XX +XXX,XX @@ class TestCommitWithOverriddenBacking(iotests.QMPTestCase):
179
def setUp(self):
180
qemu_img('create', '-f', iotests.imgfmt, self.img_base_a, '1M')
181
qemu_img('create', '-f', iotests.imgfmt, self.img_base_b, '1M')
182
- qemu_img('create', '-f', iotests.imgfmt, '-b', self.img_base_a, \
183
- self.img_top)
184
+ qemu_img('create', '-f', iotests.imgfmt, '-b', self.img_base_a,
185
+ '-F', iotests.imgfmt, self.img_top)
186
187
self.vm = iotests.VM()
188
self.vm.launch()
189
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
190
index XXXXXXX..XXXXXXX 100755
191
--- a/tests/qemu-iotests/041
192
+++ b/tests/qemu-iotests/041
193
@@ -XXX,XX +XXX,XX @@ class TestReplaces(iotests.QMPTestCase):
194
class TestFilters(iotests.QMPTestCase):
195
def setUp(self):
196
qemu_img('create', '-f', iotests.imgfmt, backing_img, '1M')
197
- qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img, test_img)
198
- qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img, target_img)
199
+ qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img,
200
+ '-F', iotests.imgfmt, test_img)
201
+ qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img,
202
+ '-F', iotests.imgfmt, target_img)
203
204
qemu_io('-c', 'write -P 1 0 512k', backing_img)
205
qemu_io('-c', 'write -P 2 512k 512k', test_img)
206
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
207
index XXXXXXX..XXXXXXX 100755
208
--- a/tests/qemu-iotests/114
209
+++ b/tests/qemu-iotests/114
210
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
211
# qcow2.py does not work too well with external data files
212
_unsupported_imgopts data_file
213
214
-# Intentionally specify backing file without backing format; demonstrate
215
-# the difference in warning messages when backing file could be probed.
216
-# Note that only a non-raw probe result will affect the resulting image.
217
+# Older qemu-img could set up backing file without backing format; modern
218
+# qemu can't but we can use qcow2.py to simulate older files.
219
truncate -s $((64 * 1024 * 1024)) "$TEST_IMG.orig"
220
-_make_test_img -b "$TEST_IMG.orig" 64M
221
+_make_test_img -b "$TEST_IMG.orig" -F raw 64M
222
+$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0xE2792ACA
223
224
TEST_IMG="$TEST_IMG.base" _make_test_img 64M
225
$QEMU_IMG convert -O qcow2 -B "$TEST_IMG.orig" "$TEST_IMG.orig" "$TEST_IMG"
226
-_make_test_img -b "$TEST_IMG.base" 64M
227
-_make_test_img -u -b "$TEST_IMG.base" 64M
228
+_make_test_img -b "$TEST_IMG.base" -F $IMGFMT 64M
229
+_make_test_img -u -b "$TEST_IMG.base" -F $IMGFMT 64M
230
231
# Set an invalid backing file format
232
$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0xE2792ACA "foo"
233
@@ -XXX,XX +XXX,XX @@ _img_info
234
$QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir
235
$QEMU_IO -c "open -o backing.driver=$IMGFMT $TEST_IMG" -c "read 0 4k" | _filter_qemu_io
236
237
-# Rebase the image, to show that omitting backing format triggers a warning,
238
-# but probing now lets us use the backing file.
239
-$QEMU_IMG rebase -u -b "$TEST_IMG.base" "$TEST_IMG"
240
+# Rebase the image, to show that backing format is required.
241
+($QEMU_IMG rebase -u -b "$TEST_IMG.base" "$TEST_IMG" 2>&1 && echo "unexpected pass") | _filter_testdir
242
+$QEMU_IMG rebase -u -b "$TEST_IMG.base" -F $IMGFMT "$TEST_IMG"
243
$QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir
244
245
# success, all done
246
diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out
247
index XXXXXXX..XXXXXXX 100644
248
--- a/tests/qemu-iotests/114.out
249
+++ b/tests/qemu-iotests/114.out
250
@@ -XXX,XX +XXX,XX @@
251
QA output created by 114
252
-qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of raw)
253
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig
254
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig backing_fmt=raw
255
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
256
-qemu-img: warning: Deprecated use of backing file without explicit backing format
257
-qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of IMGFMT)
258
+qemu-img: Use of backing file requires explicit backing format
259
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
260
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
261
-qemu-img: warning: Deprecated use of unopened backing file without explicit backing format, use of this image requires potentially unsafe format probing
262
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
263
image: TEST_DIR/t.IMGFMT
264
file format: IMGFMT
265
virtual size: 64 MiB (67108864 bytes)
266
@@ -XXX,XX +XXX,XX @@ qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknow
267
no file open, try 'help open'
268
read 4096/4096 bytes at offset 0
269
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
270
-qemu-img: warning: Deprecated use of backing file without explicit backing format, use of this image requires potentially unsafe format probing
271
+qemu-img: Could not change the backing file to 'TEST_DIR/t.qcow2.base': Invalid argument
272
read 4096/4096 bytes at offset 0
273
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
274
*** done
275
diff --git a/tests/qemu-iotests/301 b/tests/qemu-iotests/301
276
index XXXXXXX..XXXXXXX 100755
277
--- a/tests/qemu-iotests/301
278
+++ b/tests/qemu-iotests/301
279
@@ -XXX,XX +XXX,XX @@
280
#
281
# Test qcow backing file warnings
282
#
283
-# Copyright (C) 2020 Red Hat, Inc.
284
+# Copyright (C) 2020-2021 Red Hat, Inc.
285
#
286
# This program is free software; you can redistribute it and/or modify
287
# it under the terms of the GNU General Public License as published by
288
@@ -XXX,XX +XXX,XX @@ echo "== qcow backed by qcow =="
289
290
TEST_IMG="$TEST_IMG.base" _make_test_img $size
291
_make_test_img -b "$TEST_IMG.base" $size
292
-_img_info
293
_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size
294
_img_info
295
296
@@ -XXX,XX +XXX,XX @@ echo "== qcow backed by raw =="
297
rm "$TEST_IMG.base"
298
truncate --size=$size "$TEST_IMG.base"
299
_make_test_img -b "$TEST_IMG.base" $size
300
-_img_info
301
_make_test_img -b "$TEST_IMG.base" -F raw $size
302
_img_info
303
304
diff --git a/tests/qemu-iotests/301.out b/tests/qemu-iotests/301.out
305
index XXXXXXX..XXXXXXX 100644
306
--- a/tests/qemu-iotests/301.out
307
+++ b/tests/qemu-iotests/301.out
308
@@ -XXX,XX +XXX,XX @@ QA output created by 301
309
310
== qcow backed by qcow ==
311
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432
312
-qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of IMGFMT)
313
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
314
-image: TEST_DIR/t.IMGFMT
315
-file format: IMGFMT
316
-virtual size: 32 MiB (33554432 bytes)
317
-cluster_size: 512
318
-backing file: TEST_DIR/t.IMGFMT.base
319
+qemu-img: TEST_DIR/t.IMGFMT: Backing file specified without backing format
320
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
321
image: TEST_DIR/t.IMGFMT
322
file format: IMGFMT
323
@@ -XXX,XX +XXX,XX @@ cluster_size: 512
324
backing file: TEST_DIR/t.IMGFMT.base
325
326
== qcow backed by raw ==
327
-qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of raw)
328
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base
329
-image: TEST_DIR/t.IMGFMT
330
-file format: IMGFMT
331
-virtual size: 32 MiB (33554432 bytes)
332
-cluster_size: 512
333
-backing file: TEST_DIR/t.IMGFMT.base
334
+qemu-img: TEST_DIR/t.IMGFMT: Backing file specified without backing format
335
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
336
image: TEST_DIR/t.IMGFMT
337
file format: IMGFMT
338
--
339
2.31.1
340
341
diff view generated by jsdifflib
New patch
1
From: Eric Blake <eblake@redhat.com>
1
2
3
When removeing support for qemu-img being able to create backing
4
chains without embedded backing formats, we caused a poor error
5
message as caught by iotest 114. Improve the situation to inform the
6
user what went wrong.
7
8
Suggested-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Eric Blake <eblake@redhat.com>
10
Message-Id: <20210708155228.2666172-1-eblake@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
qemu-img.c | 3 +++
14
tests/qemu-iotests/114.out | 2 +-
15
2 files changed, 4 insertions(+), 1 deletion(-)
16
17
diff --git a/qemu-img.c b/qemu-img.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/qemu-img.c
20
+++ b/qemu-img.c
21
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
22
if (ret == -ENOSPC) {
23
error_report("Could not change the backing file to '%s': No "
24
"space left in the file header", out_baseimg);
25
+ } else if (ret == -EINVAL && out_baseimg && !out_basefmt) {
26
+ error_report("Could not change the backing file to '%s': backing "
27
+ "format must be specified", out_baseimg);
28
} else if (ret < 0) {
29
error_report("Could not change the backing file to '%s': %s",
30
out_baseimg, strerror(-ret));
31
diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out
32
index XXXXXXX..XXXXXXX 100644
33
--- a/tests/qemu-iotests/114.out
34
+++ b/tests/qemu-iotests/114.out
35
@@ -XXX,XX +XXX,XX @@ qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknow
36
no file open, try 'help open'
37
read 4096/4096 bytes at offset 0
38
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
39
-qemu-img: Could not change the backing file to 'TEST_DIR/t.qcow2.base': Invalid argument
40
+qemu-img: Could not change the backing file to 'TEST_DIR/t.qcow2.base': backing format must be specified
41
read 4096/4096 bytes at offset 0
42
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
43
*** done
44
--
45
2.31.1
46
47
diff view generated by jsdifflib
1
From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
1
Without an external data file, s->data_file is a second pointer with the
2
same value as bs->file. When changing bs->file to a different BdrvChild
3
and freeing the old BdrvChild, s->data_file must also be updated,
4
otherwise it points to freed memory and causes crashes.
2
5
3
In record/replay mode bdrv queue is controlled by replay mechanism.
6
This problem was caught by iotests case 245.
4
It does not allow saving or loading the snapshots
5
when bdrv queue is not empty. Stopping the VM is not blocked by nonempty
6
queue, but flushing the queue is still impossible there,
7
because it may cause deadlocks in replay mode.
8
This patch disables bdrv_drain_all and bdrv_flush_all in
9
record/replay mode.
10
7
11
Stopping the machine when the IO requests are not finished is needed
8
Fixes: df2b7086f169239ebad5d150efa29c9bb6d4f820
12
for the debugging. E.g., breakpoint may be set at the specified step,
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
and forcing the IO requests to finish may break the determinism
10
Message-Id: <20210708114709.206487-2-kwolf@redhat.com>
14
of the execution.
11
Reviewed-by: Eric Blake <eblake@redhat.com>
15
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
17
Acked-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
14
---
20
block/io.c | 28 ++++++++++++++++++++++++++++
15
block/qcow2.c | 29 +++++++++++++++++++++++++++++
21
cpus.c | 2 --
16
1 file changed, 29 insertions(+)
22
2 files changed, 28 insertions(+), 2 deletions(-)
23
17
24
diff --git a/block/io.c b/block/io.c
18
diff --git a/block/qcow2.c b/block/qcow2.c
25
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
26
--- a/block/io.c
20
--- a/block/qcow2.c
27
+++ b/block/io.c
21
+++ b/block/qcow2.c
28
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
29
#include "qapi/error.h"
23
static int qcow2_reopen_prepare(BDRVReopenState *state,
30
#include "qemu/error-report.h"
24
BlockReopenQueue *queue, Error **errp)
31
#include "qemu/main-loop.h"
25
{
32
+#include "sysemu/replay.h"
26
+ BDRVQcow2State *s = state->bs->opaque;
33
27
Qcow2ReopenState *r;
34
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
28
int ret;
35
29
36
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
30
@@ -XXX,XX +XXX,XX @@ static int qcow2_reopen_prepare(BDRVReopenState *state,
37
return;
31
}
38
}
32
}
39
33
40
+ /*
34
+ /*
41
+ * bdrv queue is managed by record/replay,
35
+ * Without an external data file, s->data_file points to the same BdrvChild
42
+ * waiting for finishing the I/O requests may
36
+ * as bs->file. It needs to be resynced after reopen because bs->file may
43
+ * be infinite
37
+ * be changed. We can't use it in the meantime.
44
+ */
38
+ */
45
+ if (replay_events_enabled()) {
39
+ if (!has_data_file(state->bs)) {
46
+ return;
40
+ assert(s->data_file == state->bs->file);
41
+ s->data_file = NULL;
47
+ }
42
+ }
48
+
43
+
49
/* AIO_WAIT_WHILE() with a NULL context can only be called from the main
44
return 0;
50
* loop AioContext, so make sure we're in the main context. */
45
51
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
46
fail:
52
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
47
@@ -XXX,XX +XXX,XX @@ fail:
53
BlockDriverState *bs = NULL;
48
54
int drained_end_counter = 0;
49
static void qcow2_reopen_commit(BDRVReopenState *state)
55
50
{
56
+ /*
51
+ BDRVQcow2State *s = state->bs->opaque;
57
+ * bdrv queue is managed by record/replay,
52
+
58
+ * waiting for finishing the I/O requests may
53
qcow2_update_options_commit(state->bs, state->opaque);
59
+ * be endless
54
+ if (!s->data_file) {
60
+ */
55
+ /*
61
+ if (replay_events_enabled()) {
56
+ * If we don't have an external data file, s->data_file was cleared by
62
+ return;
57
+ * qcow2_reopen_prepare() and needs to be updated.
58
+ */
59
+ s->data_file = state->bs->file;
63
+ }
60
+ }
61
g_free(state->opaque);
62
}
63
64
@@ -XXX,XX +XXX,XX @@ static void qcow2_reopen_commit_post(BDRVReopenState *state)
65
66
static void qcow2_reopen_abort(BDRVReopenState *state)
67
{
68
+ BDRVQcow2State *s = state->bs->opaque;
64
+
69
+
65
while ((bs = bdrv_next_all_states(bs))) {
70
+ if (!s->data_file) {
66
AioContext *aio_context = bdrv_get_aio_context(bs);
71
+ /*
67
72
+ * If we don't have an external data file, s->data_file was cleared by
68
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
73
+ * qcow2_reopen_prepare() and needs to be restored.
69
BlockDriverState *bs = NULL;
74
+ */
70
int result = 0;
75
+ s->data_file = state->bs->file;
71
72
+ /*
73
+ * bdrv queue is managed by record/replay,
74
+ * creating new flush request for stopping
75
+ * the VM may break the determinism
76
+ */
77
+ if (replay_events_enabled()) {
78
+ return result;
79
+ }
76
+ }
80
+
77
qcow2_update_options_abort(state->bs, state->opaque);
81
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
78
g_free(state->opaque);
82
AioContext *aio_context = bdrv_get_aio_context(bs);
79
}
83
int ret;
84
diff --git a/cpus.c b/cpus.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/cpus.c
87
+++ b/cpus.c
88
@@ -XXX,XX +XXX,XX @@ static int do_vm_stop(RunState state, bool send_stop)
89
}
90
91
bdrv_drain_all();
92
- replay_disable_events();
93
ret = bdrv_flush_all();
94
95
return ret;
96
@@ -XXX,XX +XXX,XX @@ int vm_prepare_start(void)
97
/* We are sending this now, but the CPUs will be resumed shortly later */
98
qapi_event_send_resume();
99
100
- replay_enable_events();
101
cpu_enable_ticks();
102
runstate_set(RUN_STATE_RUNNING);
103
vm_state_notify(1, RUN_STATE_RUNNING);
104
--
80
--
105
2.20.1
81
2.31.1
106
82
107
83
diff view generated by jsdifflib
1
From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
This patch updates the description of the command lines for using
3
Move the code to free a BlockReopenQueue to a separate function.
4
record/replay with attached block devices.
4
It will be used in a subsequent patch.
5
5
6
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
6
[ kwolf: Also free explicit_options and options, and explicitly
7
qobject_ref() the value when it continues to be used. This makes
8
future memory leaks less likely. ]
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Message-Id: <20210708114709.206487-3-kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
15
---
9
docs/replay.txt | 12 +++++++++---
16
include/block/block.h | 1 +
10
1 file changed, 9 insertions(+), 3 deletions(-)
17
block.c | 22 ++++++++++++++++------
18
2 files changed, 17 insertions(+), 6 deletions(-)
11
19
12
diff --git a/docs/replay.txt b/docs/replay.txt
20
diff --git a/include/block/block.h b/include/block/block.h
13
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
14
--- a/docs/replay.txt
22
--- a/include/block/block.h
15
+++ b/docs/replay.txt
23
+++ b/include/block/block.h
16
@@ -XXX,XX +XXX,XX @@ Usage of the record/replay:
24
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
17
* First, record the execution with the following command line:
25
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
18
qemu-system-i386 \
26
BlockDriverState *bs, QDict *options,
19
-icount shift=7,rr=record,rrfile=replay.bin \
27
bool keep_old_opts);
20
- -drive file=disk.qcow2,if=none,id=img-direct \
28
+void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue);
21
+ -drive file=disk.qcow2,if=none,snapshot,id=img-direct \
29
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
22
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \
30
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
23
-device ide-hd,drive=img-blkreplay \
31
Error **errp);
24
-netdev user,id=net1 -device rtl8139,netdev=net1 \
32
diff --git a/block.c b/block.c
25
@@ -XXX,XX +XXX,XX @@ Usage of the record/replay:
33
index XXXXXXX..XXXXXXX 100644
26
* After recording, you can replay it by using another command line:
34
--- a/block.c
27
qemu-system-i386 \
35
+++ b/block.c
28
-icount shift=7,rr=replay,rrfile=replay.bin \
36
@@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
29
- -drive file=disk.qcow2,if=none,id=img-direct \
37
NULL, 0, keep_old_opts);
30
+ -drive file=disk.qcow2,if=none,snapshot,id=img-direct \
38
}
31
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \
39
32
-device ide-hd,drive=img-blkreplay \
40
+void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue)
33
-netdev user,id=net1 -device rtl8139,netdev=net1 \
41
+{
34
@@ -XXX,XX +XXX,XX @@ Block devices record/replay module intercepts calls of
42
+ if (bs_queue) {
35
bdrv coroutine functions at the top of block drivers stack.
43
+ BlockReopenQueueEntry *bs_entry, *next;
36
To record and replay block operations the drive must be configured
44
+ QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
37
as following:
45
+ qobject_unref(bs_entry->state.explicit_options);
38
- -drive file=disk.qcow2,if=none,id=img-direct
46
+ qobject_unref(bs_entry->state.options);
39
+ -drive file=disk.qcow2,if=none,snapshot,id=img-direct
47
+ g_free(bs_entry);
40
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
48
+ }
41
-device ide-hd,drive=img-blkreplay
49
+ g_free(bs_queue);
42
50
+ }
43
@@ -XXX,XX +XXX,XX @@ This snapshot is created at start of recording and restored at start
51
+}
44
of replaying. It also can be loaded while replaying to roll back
45
the execution.
46
47
+'snapshot' flag of the disk image must be removed to save the snapshots
48
+in the overlay (or original image) instead of using the temporary overlay.
49
+ -drive file=disk.ovl,if=none,id=img-direct
50
+ -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
51
+ -device ide-hd,drive=img-blkreplay
52
+
52
+
53
Use QEMU monitor to create additional snapshots. 'savevm <name>' command
53
/*
54
created the snapshot and 'loadvm <name>' restores it. To prevent corruption
54
* Reopen multiple BlockDriverStates atomically & transactionally.
55
of the original disk image, use overlay files linked to the original images.
55
*
56
@@ -XXX,XX +XXX,XX @@ abort:
57
if (bs_entry->prepared) {
58
bdrv_reopen_abort(&bs_entry->state);
59
}
60
- qobject_unref(bs_entry->state.explicit_options);
61
- qobject_unref(bs_entry->state.options);
62
}
63
64
cleanup:
65
- QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
66
- g_free(bs_entry);
67
- }
68
- g_free(bs_queue);
69
+ bdrv_reopen_queue_free(bs_queue);
70
71
return ret;
72
}
73
@@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
74
/* set BDS specific flags now */
75
qobject_unref(bs->explicit_options);
76
qobject_unref(bs->options);
77
+ qobject_ref(reopen_state->explicit_options);
78
+ qobject_ref(reopen_state->options);
79
80
bs->explicit_options = reopen_state->explicit_options;
81
bs->options = reopen_state->options;
56
--
82
--
57
2.20.1
83
2.31.1
58
84
59
85
diff view generated by jsdifflib
New patch
1
1
As the BlockReopenQueue can contain nodes in multiple AioContexts, only
2
one of which may be locked when AIO_WAIT_WHILE() can be called, we can't
3
let the caller lock the right contexts. Instead, individually lock the
4
AioContext of a single node when iterating the queue.
5
6
Reintroduce bdrv_reopen() as a wrapper for reopening a single node that
7
drains the node and temporarily drops the AioContext lock for
8
bdrv_reopen_multiple().
9
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Message-Id: <20210708114709.206487-4-kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
include/block/block.h | 2 ++
16
block.c | 49 ++++++++++++++++++++++++++++++++++++-------
17
block/replication.c | 7 +++++++
18
blockdev.c | 5 +++++
19
qemu-io-cmds.c | 7 +------
20
5 files changed, 57 insertions(+), 13 deletions(-)
21
22
diff --git a/include/block/block.h b/include/block/block.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/block.h
25
+++ b/include/block/block.h
26
@@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
27
bool keep_old_opts);
28
void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue);
29
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
30
+int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts,
31
+ Error **errp);
32
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
33
Error **errp);
34
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
35
diff --git a/block.c b/block.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block.c
38
+++ b/block.c
39
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue)
40
*
41
* All affected nodes must be drained between bdrv_reopen_queue() and
42
* bdrv_reopen_multiple().
43
+ *
44
+ * To be called from the main thread, with all other AioContexts unlocked.
45
*/
46
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
47
{
48
int ret = -1;
49
BlockReopenQueueEntry *bs_entry, *next;
50
+ AioContext *ctx;
51
Transaction *tran = tran_new();
52
g_autoptr(GHashTable) found = NULL;
53
g_autoptr(GSList) refresh_list = NULL;
54
55
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
56
assert(bs_queue != NULL);
57
58
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
59
+ ctx = bdrv_get_aio_context(bs_entry->state.bs);
60
+ aio_context_acquire(ctx);
61
ret = bdrv_flush(bs_entry->state.bs);
62
+ aio_context_release(ctx);
63
if (ret < 0) {
64
error_setg_errno(errp, -ret, "Error flushing drive");
65
goto abort;
66
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
67
68
QTAILQ_FOREACH(bs_entry, bs_queue, entry) {
69
assert(bs_entry->state.bs->quiesce_counter > 0);
70
+ ctx = bdrv_get_aio_context(bs_entry->state.bs);
71
+ aio_context_acquire(ctx);
72
ret = bdrv_reopen_prepare(&bs_entry->state, bs_queue, tran, errp);
73
+ aio_context_release(ctx);
74
if (ret < 0) {
75
goto abort;
76
}
77
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
78
* to first element.
79
*/
80
QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
81
+ ctx = bdrv_get_aio_context(bs_entry->state.bs);
82
+ aio_context_acquire(ctx);
83
bdrv_reopen_commit(&bs_entry->state);
84
+ aio_context_release(ctx);
85
}
86
87
tran_commit(tran);
88
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
89
BlockDriverState *bs = bs_entry->state.bs;
90
91
if (bs->drv->bdrv_reopen_commit_post) {
92
+ ctx = bdrv_get_aio_context(bs);
93
+ aio_context_acquire(ctx);
94
bs->drv->bdrv_reopen_commit_post(&bs_entry->state);
95
+ aio_context_release(ctx);
96
}
97
}
98
99
@@ -XXX,XX +XXX,XX @@ abort:
100
tran_abort(tran);
101
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
102
if (bs_entry->prepared) {
103
+ ctx = bdrv_get_aio_context(bs_entry->state.bs);
104
+ aio_context_acquire(ctx);
105
bdrv_reopen_abort(&bs_entry->state);
106
+ aio_context_release(ctx);
107
}
108
}
109
110
@@ -XXX,XX +XXX,XX @@ cleanup:
111
return ret;
112
}
113
114
-int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
115
- Error **errp)
116
+int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts,
117
+ Error **errp)
118
{
119
- int ret;
120
+ AioContext *ctx = bdrv_get_aio_context(bs);
121
BlockReopenQueue *queue;
122
- QDict *opts = qdict_new();
123
-
124
- qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
125
+ int ret;
126
127
bdrv_subtree_drained_begin(bs);
128
- queue = bdrv_reopen_queue(NULL, bs, opts, true);
129
+ if (ctx != qemu_get_aio_context()) {
130
+ aio_context_release(ctx);
131
+ }
132
+
133
+ queue = bdrv_reopen_queue(NULL, bs, opts, keep_old_opts);
134
ret = bdrv_reopen_multiple(queue, errp);
135
+
136
+ if (ctx != qemu_get_aio_context()) {
137
+ aio_context_acquire(ctx);
138
+ }
139
bdrv_subtree_drained_end(bs);
140
141
return ret;
142
}
143
144
+int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
145
+ Error **errp)
146
+{
147
+ QDict *opts = qdict_new();
148
+
149
+ qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
150
+
151
+ return bdrv_reopen(bs, opts, true, errp);
152
+}
153
+
154
/*
155
* Take a BDRVReopenState and check if the value of 'backing' in the
156
* reopen_state->options QDict is valid or not.
157
diff --git a/block/replication.c b/block/replication.c
158
index XXXXXXX..XXXXXXX 100644
159
--- a/block/replication.c
160
+++ b/block/replication.c
161
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
162
}
163
164
if (reopen_queue) {
165
+ AioContext *ctx = bdrv_get_aio_context(bs);
166
+ if (ctx != qemu_get_aio_context()) {
167
+ aio_context_release(ctx);
168
+ }
169
bdrv_reopen_multiple(reopen_queue, errp);
170
+ if (ctx != qemu_get_aio_context()) {
171
+ aio_context_acquire(ctx);
172
+ }
173
}
174
175
bdrv_subtree_drained_end(s->hidden_disk->bs);
176
diff --git a/blockdev.c b/blockdev.c
177
index XXXXXXX..XXXXXXX 100644
178
--- a/blockdev.c
179
+++ b/blockdev.c
180
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_reopen(BlockdevOptions *options, Error **errp)
181
ctx = bdrv_get_aio_context(bs);
182
aio_context_acquire(ctx);
183
bdrv_subtree_drained_begin(bs);
184
+ aio_context_release(ctx);
185
+
186
queue = bdrv_reopen_queue(NULL, bs, qdict, false);
187
bdrv_reopen_multiple(queue, errp);
188
+
189
+ ctx = bdrv_get_aio_context(bs);
190
+ aio_context_acquire(ctx);
191
bdrv_subtree_drained_end(bs);
192
aio_context_release(ctx);
193
194
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
195
index XXXXXXX..XXXXXXX 100644
196
--- a/qemu-io-cmds.c
197
+++ b/qemu-io-cmds.c
198
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
199
bool writethrough = !blk_enable_write_cache(blk);
200
bool has_rw_option = false;
201
bool has_cache_option = false;
202
-
203
- BlockReopenQueue *brq;
204
Error *local_err = NULL;
205
206
while ((c = getopt(argc, argv, "c:o:rw")) != -1) {
207
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
208
qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH);
209
}
210
211
- bdrv_subtree_drained_begin(bs);
212
- brq = bdrv_reopen_queue(NULL, bs, opts, true);
213
- bdrv_reopen_multiple(brq, &local_err);
214
- bdrv_subtree_drained_end(bs);
215
+ bdrv_reopen(bs, opts, true, &local_err);
216
217
if (local_err) {
218
error_report_err(local_err);
219
--
220
2.31.1
221
222
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
[ kwolf: Fixed AioContext locking ]
4
5
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20210708114709.206487-5-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
qapi/block-core.json | 18 +++--
12
blockdev.c | 81 ++++++++++---------
13
tests/qemu-iotests/155 | 9 ++-
14
tests/qemu-iotests/165 | 4 +-
15
tests/qemu-iotests/245 | 27 ++++---
16
tests/qemu-iotests/248 | 2 +-
17
tests/qemu-iotests/248.out | 2 +-
18
tests/qemu-iotests/296 | 9 ++-
19
tests/qemu-iotests/298 | 4 +-
20
.../tests/remove-bitmap-from-backing | 18 +++--
21
10 files changed, 99 insertions(+), 75 deletions(-)
22
23
diff --git a/qapi/block-core.json b/qapi/block-core.json
24
index XXXXXXX..XXXXXXX 100644
25
--- a/qapi/block-core.json
26
+++ b/qapi/block-core.json
27
@@ -XXX,XX +XXX,XX @@
28
##
29
# @x-blockdev-reopen:
30
#
31
-# Reopens a block device using the given set of options. Any option
32
-# not specified will be reset to its default value regardless of its
33
-# previous status. If an option cannot be changed or a particular
34
+# Reopens one or more block devices using the given set of options.
35
+# Any option not specified will be reset to its default value regardless
36
+# of its previous status. If an option cannot be changed or a particular
37
# driver does not support reopening then the command will return an
38
-# error.
39
+# error. All devices in the list are reopened in one transaction, so
40
+# if one of them fails then the whole transaction is cancelled.
41
#
42
-# The top-level @node-name option (from BlockdevOptions) must be
43
+# The command receives a list of block devices to reopen. For each one
44
+# of them, the top-level @node-name option (from BlockdevOptions) must be
45
# specified and is used to select the block device to be reopened.
46
# Other @node-name options must be either omitted or set to the
47
# current name of the appropriate node. This command won't change any
48
@@ -XXX,XX +XXX,XX @@
49
#
50
# 4) NULL: the current child (if any) is detached.
51
#
52
-# Options (1) and (2) are supported in all cases, but at the moment
53
-# only @backing allows replacing or detaching an existing child.
54
+# Options (1) and (2) are supported in all cases. Option (3) is
55
+# supported for @file and @backing, and option (4) for @backing only.
56
#
57
# Unlike with blockdev-add, the @backing option must always be present
58
# unless the node being reopened does not have a backing file and its
59
@@ -XXX,XX +XXX,XX @@
60
# Since: 4.0
61
##
62
{ 'command': 'x-blockdev-reopen',
63
- 'data': 'BlockdevOptions', 'boxed': true }
64
+ 'data': { 'options': ['BlockdevOptions'] } }
65
66
##
67
# @blockdev-del:
68
diff --git a/blockdev.c b/blockdev.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/blockdev.c
71
+++ b/blockdev.c
72
@@ -XXX,XX +XXX,XX @@ fail:
73
visit_free(v);
74
}
75
76
-void qmp_x_blockdev_reopen(BlockdevOptions *options, Error **errp)
77
-{
78
- BlockDriverState *bs;
79
- AioContext *ctx;
80
- QObject *obj;
81
- Visitor *v = qobject_output_visitor_new(&obj);
82
- BlockReopenQueue *queue;
83
- QDict *qdict;
84
+void qmp_x_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
85
+{
86
+ BlockReopenQueue *queue = NULL;
87
+ GSList *drained = NULL;
88
+
89
+ /* Add each one of the BDS that we want to reopen to the queue */
90
+ for (; reopen_list != NULL; reopen_list = reopen_list->next) {
91
+ BlockdevOptions *options = reopen_list->value;
92
+ BlockDriverState *bs;
93
+ AioContext *ctx;
94
+ QObject *obj;
95
+ Visitor *v;
96
+ QDict *qdict;
97
+
98
+ /* Check for the selected node name */
99
+ if (!options->has_node_name) {
100
+ error_setg(errp, "node-name not specified");
101
+ goto fail;
102
+ }
103
104
- /* Check for the selected node name */
105
- if (!options->has_node_name) {
106
- error_setg(errp, "node-name not specified");
107
- goto fail;
108
- }
109
+ bs = bdrv_find_node(options->node_name);
110
+ if (!bs) {
111
+ error_setg(errp, "Failed to find node with node-name='%s'",
112
+ options->node_name);
113
+ goto fail;
114
+ }
115
116
- bs = bdrv_find_node(options->node_name);
117
- if (!bs) {
118
- error_setg(errp, "Failed to find node with node-name='%s'",
119
- options->node_name);
120
- goto fail;
121
- }
122
+ /* Put all options in a QDict and flatten it */
123
+ v = qobject_output_visitor_new(&obj);
124
+ visit_type_BlockdevOptions(v, NULL, &options, &error_abort);
125
+ visit_complete(v, &obj);
126
+ visit_free(v);
127
128
- /* Put all options in a QDict and flatten it */
129
- visit_type_BlockdevOptions(v, NULL, &options, &error_abort);
130
- visit_complete(v, &obj);
131
- qdict = qobject_to(QDict, obj);
132
+ qdict = qobject_to(QDict, obj);
133
134
- qdict_flatten(qdict);
135
+ qdict_flatten(qdict);
136
137
- /* Perform the reopen operation */
138
- ctx = bdrv_get_aio_context(bs);
139
- aio_context_acquire(ctx);
140
- bdrv_subtree_drained_begin(bs);
141
- aio_context_release(ctx);
142
+ ctx = bdrv_get_aio_context(bs);
143
+ aio_context_acquire(ctx);
144
145
- queue = bdrv_reopen_queue(NULL, bs, qdict, false);
146
- bdrv_reopen_multiple(queue, errp);
147
+ bdrv_subtree_drained_begin(bs);
148
+ queue = bdrv_reopen_queue(queue, bs, qdict, false);
149
+ drained = g_slist_prepend(drained, bs);
150
151
- ctx = bdrv_get_aio_context(bs);
152
- aio_context_acquire(ctx);
153
- bdrv_subtree_drained_end(bs);
154
- aio_context_release(ctx);
155
+ aio_context_release(ctx);
156
+ }
157
+
158
+ /* Perform the reopen operation */
159
+ bdrv_reopen_multiple(queue, errp);
160
+ queue = NULL;
161
162
fail:
163
- visit_free(v);
164
+ bdrv_reopen_queue_free(queue);
165
+ g_slist_free_full(drained, (GDestroyNotify) bdrv_subtree_drained_end);
166
}
167
168
void qmp_blockdev_del(const char *node_name, Error **errp)
169
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
170
index XXXXXXX..XXXXXXX 100755
171
--- a/tests/qemu-iotests/155
172
+++ b/tests/qemu-iotests/155
173
@@ -XXX,XX +XXX,XX @@ class TestBlockdevMirrorReopen(MirrorBaseClass):
174
result = self.vm.qmp('blockdev-add', node_name="backing",
175
driver="null-co")
176
self.assert_qmp(result, 'return', {})
177
- result = self.vm.qmp('x-blockdev-reopen', node_name="target",
178
- driver=iotests.imgfmt, file="target-file",
179
- backing="backing")
180
+ result = self.vm.qmp('x-blockdev-reopen', options=[{
181
+ 'node-name': "target",
182
+ 'driver': iotests.imgfmt,
183
+ 'file': "target-file",
184
+ 'backing': "backing"
185
+ }])
186
self.assert_qmp(result, 'return', {})
187
188
class TestBlockdevMirrorReopenIothread(TestBlockdevMirrorReopen):
189
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
190
index XXXXXXX..XXXXXXX 100755
191
--- a/tests/qemu-iotests/165
192
+++ b/tests/qemu-iotests/165
193
@@ -XXX,XX +XXX,XX @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
194
assert sha256_1 == self.getSha256()
195
196
# Reopen to RW
197
- result = self.vm.qmp('x-blockdev-reopen', **{
198
+ result = self.vm.qmp('x-blockdev-reopen', options=[{
199
'node-name': 'node0',
200
'driver': iotests.imgfmt,
201
'file': {
202
@@ -XXX,XX +XXX,XX @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
203
'filename': disk
204
},
205
'read-only': False
206
- })
207
+ }])
208
self.assert_qmp(result, 'return', {})
209
210
# Check that bitmap is reopened to RW and we can write to it.
211
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
212
index XXXXXXX..XXXXXXX 100755
213
--- a/tests/qemu-iotests/245
214
+++ b/tests/qemu-iotests/245
215
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
216
"Expected output of %d qemu-io commands, found %d" %
217
(found, self.total_io_cmds))
218
219
- # Run x-blockdev-reopen with 'opts' but applying 'newopts'
220
- # on top of it. The original 'opts' dict is unmodified
221
+ # Run x-blockdev-reopen on a list of block devices
222
+ def reopenMultiple(self, opts, errmsg = None):
223
+ result = self.vm.qmp('x-blockdev-reopen', conv_keys=False, options=opts)
224
+ if errmsg:
225
+ self.assert_qmp(result, 'error/class', 'GenericError')
226
+ self.assert_qmp(result, 'error/desc', errmsg)
227
+ else:
228
+ self.assert_qmp(result, 'return', {})
229
+
230
+ # Run x-blockdev-reopen on a single block device (specified by
231
+ # 'opts') but applying 'newopts' on top of it. The original 'opts'
232
+ # dict is unmodified
233
def reopen(self, opts, newopts = {}, errmsg = None):
234
opts = copy.deepcopy(opts)
235
236
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
237
subdict = opts[prefix]
238
subdict[key] = value
239
240
- result = self.vm.qmp('x-blockdev-reopen', conv_keys = False, **opts)
241
- if errmsg:
242
- self.assert_qmp(result, 'error/class', 'GenericError')
243
- self.assert_qmp(result, 'error/desc', errmsg)
244
- else:
245
- self.assert_qmp(result, 'return', {})
246
+ self.reopenMultiple([ opts ], errmsg)
247
248
249
# Run query-named-block-nodes and return the specified entry
250
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
251
# We cannot change any of these
252
self.reopen(opts, {'node-name': 'not-found'}, "Failed to find node with node-name='not-found'")
253
self.reopen(opts, {'node-name': ''}, "Failed to find node with node-name=''")
254
- self.reopen(opts, {'node-name': None}, "Invalid parameter type for 'node-name', expected: string")
255
+ self.reopen(opts, {'node-name': None}, "Invalid parameter type for 'options[0].node-name', expected: string")
256
self.reopen(opts, {'driver': 'raw'}, "Cannot change the option 'driver'")
257
self.reopen(opts, {'driver': ''}, "Invalid parameter ''")
258
- self.reopen(opts, {'driver': None}, "Invalid parameter type for 'driver', expected: string")
259
+ self.reopen(opts, {'driver': None}, "Invalid parameter type for 'options[0].driver', expected: string")
260
self.reopen(opts, {'file': 'not-found'}, "Cannot find device='' nor node-name='not-found'")
261
self.reopen(opts, {'file': ''}, "Cannot find device='' nor node-name=''")
262
self.reopen(opts, {'file': None}, "Invalid parameter type for 'file', expected: BlockdevRef")
263
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
264
self.reopen(opts, {'file.filename': hd_path[1]}, "Cannot change the option 'filename'")
265
self.reopen(opts, {'file.aio': 'native'}, "Cannot change the option 'aio'")
266
self.reopen(opts, {'file.locking': 'off'}, "Cannot change the option 'locking'")
267
- self.reopen(opts, {'file.filename': None}, "Invalid parameter type for 'file.filename', expected: string")
268
+ self.reopen(opts, {'file.filename': None}, "Invalid parameter type for 'options[0].file.filename', expected: string")
269
270
# node-name is optional in BlockdevOptions, but x-blockdev-reopen needs it
271
del opts['node-name']
272
diff --git a/tests/qemu-iotests/248 b/tests/qemu-iotests/248
273
index XXXXXXX..XXXXXXX 100755
274
--- a/tests/qemu-iotests/248
275
+++ b/tests/qemu-iotests/248
276
@@ -XXX,XX +XXX,XX @@ vm.get_qmp_events()
277
278
del blockdev_opts['file']['size']
279
vm.qmp_log('x-blockdev-reopen', filters=[filter_qmp_testfiles],
280
- **blockdev_opts)
281
+ options = [ blockdev_opts ])
282
283
vm.qmp_log('block-job-resume', device='drive0')
284
vm.event_wait('JOB_STATUS_CHANGE', timeout=1.0,
285
diff --git a/tests/qemu-iotests/248.out b/tests/qemu-iotests/248.out
286
index XXXXXXX..XXXXXXX 100644
287
--- a/tests/qemu-iotests/248.out
288
+++ b/tests/qemu-iotests/248.out
289
@@ -XXX,XX +XXX,XX @@
290
{"return": {}}
291
{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "on-target-error": "enospc", "sync": "full", "target": "target"}}
292
{"return": {}}
293
-{"execute": "x-blockdev-reopen", "arguments": {"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}}, "node-name": "target"}}
294
+{"execute": "x-blockdev-reopen", "arguments": {"options": [{"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}}, "node-name": "target"}]}}
295
{"return": {}}
296
{"execute": "block-job-resume", "arguments": {"device": "drive0"}}
297
{"return": {}}
298
diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296
299
index XXXXXXX..XXXXXXX 100755
300
--- a/tests/qemu-iotests/296
301
+++ b/tests/qemu-iotests/296
302
@@ -XXX,XX +XXX,XX @@ class EncryptionSetupTestCase(iotests.QMPTestCase):
303
304
command = 'x-blockdev-reopen' if reOpen else 'blockdev-add'
305
306
- result = vm.qmp(command, **
307
- {
308
+ opts = {
309
'driver': iotests.imgfmt,
310
'node-name': id,
311
'read-only': readOnly,
312
@@ -XXX,XX +XXX,XX @@ class EncryptionSetupTestCase(iotests.QMPTestCase):
313
'filename': test_img,
314
}
315
}
316
- )
317
+
318
+ if reOpen:
319
+ result = vm.qmp(command, options=[opts])
320
+ else:
321
+ result = vm.qmp(command, **opts)
322
self.assert_qmp(result, 'return', {})
323
324
325
diff --git a/tests/qemu-iotests/298 b/tests/qemu-iotests/298
326
index XXXXXXX..XXXXXXX 100755
327
--- a/tests/qemu-iotests/298
328
+++ b/tests/qemu-iotests/298
329
@@ -XXX,XX +XXX,XX @@ class TestPreallocateFilter(TestPreallocateBase):
330
self.check_big()
331
332
def test_reopen_opts(self):
333
- result = self.vm.qmp('x-blockdev-reopen', **{
334
+ result = self.vm.qmp('x-blockdev-reopen', options=[{
335
'node-name': 'disk',
336
'driver': iotests.imgfmt,
337
'file': {
338
@@ -XXX,XX +XXX,XX @@ class TestPreallocateFilter(TestPreallocateBase):
339
'filename': disk
340
}
341
}
342
- })
343
+ }])
344
self.assert_qmp(result, 'return', {})
345
346
self.vm.hmp_qemu_io('drive0', 'write 0 1M')
347
diff --git a/tests/qemu-iotests/tests/remove-bitmap-from-backing b/tests/qemu-iotests/tests/remove-bitmap-from-backing
348
index XXXXXXX..XXXXXXX 100755
349
--- a/tests/qemu-iotests/tests/remove-bitmap-from-backing
350
+++ b/tests/qemu-iotests/tests/remove-bitmap-from-backing
351
@@ -XXX,XX +XXX,XX @@ log('Trying to remove persistent bitmap from r-o base node, should fail:')
352
vm.qmp_log('block-dirty-bitmap-remove', node='base', name='bitmap0')
353
354
new_base_opts = {
355
- 'node-name': 'base',
356
- 'driver': 'qcow2',
357
- 'file': {
358
- 'driver': 'file',
359
- 'filename': base
360
- },
361
- 'read-only': False
362
+ 'options': [{
363
+ 'node-name': 'base',
364
+ 'driver': 'qcow2',
365
+ 'file': {
366
+ 'driver': 'file',
367
+ 'filename': base
368
+ },
369
+ 'read-only': False
370
+ }]
371
}
372
373
# Don't want to bother with filtering qmp_log for reopen command
374
@@ -XXX,XX +XXX,XX @@ if result != {'return': {}}:
375
log('Remove persistent bitmap from base node reopened to RW:')
376
vm.qmp_log('block-dirty-bitmap-remove', node='base', name='bitmap0')
377
378
-new_base_opts['read-only'] = True
379
+new_base_opts['options'][0]['read-only'] = True
380
result = vm.qmp('x-blockdev-reopen', **new_base_opts)
381
if result != {'return': {}}:
382
log('Failed to reopen: ' + str(result))
383
--
384
2.31.1
385
386
diff view generated by jsdifflib
1
From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
This patch disables setting '-snapshot' option on by default
3
This test swaps the images used by two active block devices.
4
in record/replay mode. This is needed for creating vmstates in record
5
and replay modes.
6
4
7
Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
5
This is now possible thanks to the new ability to run
8
Acked-by: Kevin Wolf <kwolf@redhat.com>
6
x-blockdev-reopen on multiple devices at the same time.
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Message-Id: <20210708114709.206487-6-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
13
---
11
vl.c | 10 ++++++++--
14
tests/qemu-iotests/245 | 47 ++++++++++++++++++++++++++++++++++++++
12
1 file changed, 8 insertions(+), 2 deletions(-)
15
tests/qemu-iotests/245.out | 4 ++--
16
2 files changed, 49 insertions(+), 2 deletions(-)
13
17
14
diff --git a/vl.c b/vl.c
18
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/245
21
+++ b/tests/qemu-iotests/245
22
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
23
'-c', 'read -P 0x40 0x40008 1',
24
'-c', 'read -P 0x80 0x40010 1', hd_path[0])
25
26
+ # Swap the disk images of two active block devices
27
+ def test_swap_files(self):
28
+ # Add hd0 and hd2 (none of them with backing files)
29
+ opts0 = hd_opts(0)
30
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts0)
31
+ self.assert_qmp(result, 'return', {})
32
+
33
+ opts2 = hd_opts(2)
34
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts2)
35
+ self.assert_qmp(result, 'return', {})
36
+
37
+ # Write different data to both block devices
38
+ self.run_qemu_io("hd0", "write -P 0xa0 0 1k")
39
+ self.run_qemu_io("hd2", "write -P 0xa2 0 1k")
40
+
41
+ # Check that the data reads correctly
42
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1k")
43
+ self.run_qemu_io("hd2", "read -P 0xa2 0 1k")
44
+
45
+ # It's not possible to make a block device use an image that
46
+ # is already being used by the other device.
47
+ self.reopen(opts0, {'file': 'hd2-file'},
48
+ "Permission conflict on node 'hd2-file': permissions "
49
+ "'write, resize' are both required by node 'hd2' (uses "
50
+ "node 'hd2-file' as 'file' child) and unshared by node "
51
+ "'hd0' (uses node 'hd2-file' as 'file' child).")
52
+ self.reopen(opts2, {'file': 'hd0-file'},
53
+ "Permission conflict on node 'hd0-file': permissions "
54
+ "'write, resize' are both required by node 'hd0' (uses "
55
+ "node 'hd0-file' as 'file' child) and unshared by node "
56
+ "'hd2' (uses node 'hd0-file' as 'file' child).")
57
+
58
+ # But we can swap the images if we reopen both devices at the
59
+ # same time
60
+ opts0['file'] = 'hd2-file'
61
+ opts2['file'] = 'hd0-file'
62
+ self.reopenMultiple([opts0, opts2])
63
+ self.run_qemu_io("hd0", "read -P 0xa2 0 1k")
64
+ self.run_qemu_io("hd2", "read -P 0xa0 0 1k")
65
+
66
+ # And we can of course come back to the original state
67
+ opts0['file'] = 'hd0-file'
68
+ opts2['file'] = 'hd2-file'
69
+ self.reopenMultiple([opts0, opts2])
70
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1k")
71
+ self.run_qemu_io("hd2", "read -P 0xa2 0 1k")
72
+
73
# Misc reopen tests with different block drivers
74
@iotests.skip_if_unsupported(['quorum', 'throttle'])
75
def test_misc_drivers(self):
76
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
15
index XXXXXXX..XXXXXXX 100644
77
index XXXXXXX..XXXXXXX 100644
16
--- a/vl.c
78
--- a/tests/qemu-iotests/245.out
17
+++ b/vl.c
79
+++ b/tests/qemu-iotests/245.out
18
@@ -XXX,XX +XXX,XX @@ static void configure_blockdev(BlockdevOptionsQueue *bdo_queue,
80
@@ -XXX,XX +XXX,XX @@ read 1/1 bytes at offset 262152
19
qapi_free_BlockdevOptions(bdo->bdo);
81
read 1/1 bytes at offset 262160
20
g_free(bdo);
82
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
21
}
83
22
- if (snapshot || replay_mode != REPLAY_MODE_NONE) {
84
-..............
23
+ if (snapshot) {
85
+...............
24
qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,
86
----------------------------------------------------------------------
25
NULL, NULL);
87
-Ran 24 tests
26
}
88
+Ran 25 tests
27
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
89
28
drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
90
OK
29
break;
30
case QEMU_OPTION_snapshot:
31
- snapshot = 1;
32
+ {
33
+ Error *blocker = NULL;
34
+ snapshot = 1;
35
+ error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED,
36
+ "-snapshot");
37
+ replay_add_blocker(blocker);
38
+ }
39
break;
40
case QEMU_OPTION_numa:
41
opts = qemu_opts_parse_noisily(qemu_find_opts("numa"),
42
--
91
--
43
2.20.1
92
2.31.1
44
93
45
94
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
This patch drops the 'x-' prefix from x-blockdev-reopen.
4
5
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20210708114709.206487-7-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
qapi/block-core.json | 6 +++---
12
blockdev.c | 2 +-
13
tests/qemu-iotests/155 | 2 +-
14
tests/qemu-iotests/165 | 2 +-
15
tests/qemu-iotests/245 | 10 +++++-----
16
tests/qemu-iotests/248 | 2 +-
17
tests/qemu-iotests/248.out | 2 +-
18
tests/qemu-iotests/296 | 2 +-
19
tests/qemu-iotests/298 | 2 +-
20
tests/qemu-iotests/tests/remove-bitmap-from-backing | 4 ++--
21
10 files changed, 17 insertions(+), 17 deletions(-)
22
23
diff --git a/qapi/block-core.json b/qapi/block-core.json
24
index XXXXXXX..XXXXXXX 100644
25
--- a/qapi/block-core.json
26
+++ b/qapi/block-core.json
27
@@ -XXX,XX +XXX,XX @@
28
{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true }
29
30
##
31
-# @x-blockdev-reopen:
32
+# @blockdev-reopen:
33
#
34
# Reopens one or more block devices using the given set of options.
35
# Any option not specified will be reset to its default value regardless
36
@@ -XXX,XX +XXX,XX @@
37
# image does not have a default backing file name as part of its
38
# metadata.
39
#
40
-# Since: 4.0
41
+# Since: 6.1
42
##
43
-{ 'command': 'x-blockdev-reopen',
44
+{ 'command': 'blockdev-reopen',
45
'data': { 'options': ['BlockdevOptions'] } }
46
47
##
48
diff --git a/blockdev.c b/blockdev.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/blockdev.c
51
+++ b/blockdev.c
52
@@ -XXX,XX +XXX,XX @@ fail:
53
visit_free(v);
54
}
55
56
-void qmp_x_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
57
+void qmp_blockdev_reopen(BlockdevOptionsList *reopen_list, Error **errp)
58
{
59
BlockReopenQueue *queue = NULL;
60
GSList *drained = NULL;
61
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
62
index XXXXXXX..XXXXXXX 100755
63
--- a/tests/qemu-iotests/155
64
+++ b/tests/qemu-iotests/155
65
@@ -XXX,XX +XXX,XX @@ class TestBlockdevMirrorReopen(MirrorBaseClass):
66
result = self.vm.qmp('blockdev-add', node_name="backing",
67
driver="null-co")
68
self.assert_qmp(result, 'return', {})
69
- result = self.vm.qmp('x-blockdev-reopen', options=[{
70
+ result = self.vm.qmp('blockdev-reopen', options=[{
71
'node-name': "target",
72
'driver': iotests.imgfmt,
73
'file': "target-file",
74
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
75
index XXXXXXX..XXXXXXX 100755
76
--- a/tests/qemu-iotests/165
77
+++ b/tests/qemu-iotests/165
78
@@ -XXX,XX +XXX,XX @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
79
assert sha256_1 == self.getSha256()
80
81
# Reopen to RW
82
- result = self.vm.qmp('x-blockdev-reopen', options=[{
83
+ result = self.vm.qmp('blockdev-reopen', options=[{
84
'node-name': 'node0',
85
'driver': iotests.imgfmt,
86
'file': {
87
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
88
index XXXXXXX..XXXXXXX 100755
89
--- a/tests/qemu-iotests/245
90
+++ b/tests/qemu-iotests/245
91
@@ -XXX,XX +XXX,XX @@
92
#!/usr/bin/env python3
93
# group: rw
94
#
95
-# Test cases for the QMP 'x-blockdev-reopen' command
96
+# Test cases for the QMP 'blockdev-reopen' command
97
#
98
# Copyright (C) 2018-2019 Igalia, S.L.
99
# Author: Alberto Garcia <berto@igalia.com>
100
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
101
"Expected output of %d qemu-io commands, found %d" %
102
(found, self.total_io_cmds))
103
104
- # Run x-blockdev-reopen on a list of block devices
105
+ # Run blockdev-reopen on a list of block devices
106
def reopenMultiple(self, opts, errmsg = None):
107
- result = self.vm.qmp('x-blockdev-reopen', conv_keys=False, options=opts)
108
+ result = self.vm.qmp('blockdev-reopen', conv_keys=False, options=opts)
109
if errmsg:
110
self.assert_qmp(result, 'error/class', 'GenericError')
111
self.assert_qmp(result, 'error/desc', errmsg)
112
else:
113
self.assert_qmp(result, 'return', {})
114
115
- # Run x-blockdev-reopen on a single block device (specified by
116
+ # Run blockdev-reopen on a single block device (specified by
117
# 'opts') but applying 'newopts' on top of it. The original 'opts'
118
# dict is unmodified
119
def reopen(self, opts, newopts = {}, errmsg = None):
120
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
121
self.reopen(opts, {'file.locking': 'off'}, "Cannot change the option 'locking'")
122
self.reopen(opts, {'file.filename': None}, "Invalid parameter type for 'options[0].file.filename', expected: string")
123
124
- # node-name is optional in BlockdevOptions, but x-blockdev-reopen needs it
125
+ # node-name is optional in BlockdevOptions, but blockdev-reopen needs it
126
del opts['node-name']
127
self.reopen(opts, {}, "node-name not specified")
128
129
diff --git a/tests/qemu-iotests/248 b/tests/qemu-iotests/248
130
index XXXXXXX..XXXXXXX 100755
131
--- a/tests/qemu-iotests/248
132
+++ b/tests/qemu-iotests/248
133
@@ -XXX,XX +XXX,XX @@ vm.event_wait('JOB_STATUS_CHANGE', timeout=3.0,
134
vm.get_qmp_events()
135
136
del blockdev_opts['file']['size']
137
-vm.qmp_log('x-blockdev-reopen', filters=[filter_qmp_testfiles],
138
+vm.qmp_log('blockdev-reopen', filters=[filter_qmp_testfiles],
139
options = [ blockdev_opts ])
140
141
vm.qmp_log('block-job-resume', device='drive0')
142
diff --git a/tests/qemu-iotests/248.out b/tests/qemu-iotests/248.out
143
index XXXXXXX..XXXXXXX 100644
144
--- a/tests/qemu-iotests/248.out
145
+++ b/tests/qemu-iotests/248.out
146
@@ -XXX,XX +XXX,XX @@
147
{"return": {}}
148
{"execute": "blockdev-mirror", "arguments": {"device": "drive0", "on-target-error": "enospc", "sync": "full", "target": "target"}}
149
{"return": {}}
150
-{"execute": "x-blockdev-reopen", "arguments": {"options": [{"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}}, "node-name": "target"}]}}
151
+{"execute": "blockdev-reopen", "arguments": {"options": [{"driver": "qcow2", "file": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-target"}}, "node-name": "target"}]}}
152
{"return": {}}
153
{"execute": "block-job-resume", "arguments": {"device": "drive0"}}
154
{"return": {}}
155
diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296
156
index XXXXXXX..XXXXXXX 100755
157
--- a/tests/qemu-iotests/296
158
+++ b/tests/qemu-iotests/296
159
@@ -XXX,XX +XXX,XX @@ class EncryptionSetupTestCase(iotests.QMPTestCase):
160
def openImageQmp(self, vm, id, file, secret,
161
readOnly = False, reOpen = False):
162
163
- command = 'x-blockdev-reopen' if reOpen else 'blockdev-add'
164
+ command = 'blockdev-reopen' if reOpen else 'blockdev-add'
165
166
opts = {
167
'driver': iotests.imgfmt,
168
diff --git a/tests/qemu-iotests/298 b/tests/qemu-iotests/298
169
index XXXXXXX..XXXXXXX 100755
170
--- a/tests/qemu-iotests/298
171
+++ b/tests/qemu-iotests/298
172
@@ -XXX,XX +XXX,XX @@ class TestPreallocateFilter(TestPreallocateBase):
173
self.check_big()
174
175
def test_reopen_opts(self):
176
- result = self.vm.qmp('x-blockdev-reopen', options=[{
177
+ result = self.vm.qmp('blockdev-reopen', options=[{
178
'node-name': 'disk',
179
'driver': iotests.imgfmt,
180
'file': {
181
diff --git a/tests/qemu-iotests/tests/remove-bitmap-from-backing b/tests/qemu-iotests/tests/remove-bitmap-from-backing
182
index XXXXXXX..XXXXXXX 100755
183
--- a/tests/qemu-iotests/tests/remove-bitmap-from-backing
184
+++ b/tests/qemu-iotests/tests/remove-bitmap-from-backing
185
@@ -XXX,XX +XXX,XX @@ new_base_opts = {
186
}
187
188
# Don't want to bother with filtering qmp_log for reopen command
189
-result = vm.qmp('x-blockdev-reopen', **new_base_opts)
190
+result = vm.qmp('blockdev-reopen', **new_base_opts)
191
if result != {'return': {}}:
192
log('Failed to reopen: ' + str(result))
193
194
@@ -XXX,XX +XXX,XX @@ log('Remove persistent bitmap from base node reopened to RW:')
195
vm.qmp_log('block-dirty-bitmap-remove', node='base', name='bitmap0')
196
197
new_base_opts['options'][0]['read-only'] = True
198
-result = vm.qmp('x-blockdev-reopen', **new_base_opts)
199
+result = vm.qmp('blockdev-reopen', **new_base_opts)
200
if result != {'return': {}}:
201
log('Failed to reopen: ' + str(result))
202
203
--
204
2.31.1
205
206
diff view generated by jsdifflib