1
The following changes since commit b2f7a038bb4c4fc5ce6b8486e8513dfd97665e2a:
1
The following changes since commit 3a821c52e1a30ecd9a436f2c67cc66b5628c829f:
2
2
3
Merge remote-tracking branch 'remotes/rth/tags/pull-softfloat-20181104' into staging (2018-11-05 10:32:49 +0000)
3
Merge tag 'nvme-next-pull-request' of git://git.infradead.org/qemu-nvme into staging (2022-06-23 14:52:30 -0700)
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 1240ac558d348f6c7a5752b1a57c1da58e4efe3e:
9
for you to fetch changes up to 779d82e1d305f2a9cbd7f48cf6555ad58145e04a:
10
10
11
include: Add a comment to explain the origin of sizes' lookup table (2018-11-05 15:29:59 +0100)
11
vduse-blk: Add name option (2022-06-24 17:07:06 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- auto-read-only option to fix commit job when used with -blockdev
16
- Add vduse-blk export
17
- Fix help text related qemu-iotests failure (by improving the help text
17
- Dirty bitmaps: Fix and improve bitmap merge
18
and updating the reference output)
18
- gluster: correctly set max_pdiscard
19
- quorum: Add missing checks when adding/removing child nodes
19
- rbd: report a better error when namespace does not exist
20
- Don't take address of fields in packed structs
20
- aio_wait_kick: add missing memory barrier
21
- vvfat: Fix crash when reporting error about too many files in directory
21
- Code cleanups
22
22
23
----------------------------------------------------------------
23
----------------------------------------------------------------
24
Alberto Garcia (7):
24
Emanuele Giuseppe Esposito (1):
25
block: replace "discard" literal with BDRV_OPT_DISCARD macro
25
aio_wait_kick: add missing memory barrier
26
qcow2: Get the request alignment for encrypted images from QCryptoBlock
27
quorum: Remove quorum_err()
28
quorum: Return an error if the blkverify mode has invalid settings
29
iotest: Test the blkverify mode of the Quorum driver
30
quorum: Forbid adding children in blkverify mode
31
iotest: Test x-blockdev-change on a Quorum
32
26
33
Cleber Rosa (1):
27
Eric Blake (1):
34
iotests: make 083 specific to raw
28
nbd: Drop dead code spotted by Coverity
35
29
36
Daniel P. Berrangé (1):
30
Fabian Ebner (1):
37
crypto: initialize sector size even when opening with no IO flag
31
block/gluster: correctly set max_pdiscard
38
32
39
Kevin Wolf (12):
33
Stefan Hajnoczi (3):
40
vpc: Don't leak opts in vpc_open()
34
block: drop unused bdrv_co_drain() API
41
block: Update flags in bdrv_set_read_only()
35
block: get rid of blk->guest_block_size
42
block: Add auto-read-only option
36
qsd: document vduse-blk exports
43
rbd: Close image in qemu_rbd_open() error path
44
block: Require auto-read-only for existing fallbacks
45
nbd: Support auto-read-only option
46
file-posix: Support auto-read-only option
47
curl: Support auto-read-only option
48
gluster: Support auto-read-only option
49
iscsi: Support auto-read-only option
50
block: Make auto-read-only=on default for -drive
51
qemu-iotests: Test auto-read-only with -drive and -blockdev
52
37
53
Leonid Bloch (2):
38
Stefano Garzarella (1):
54
vdi: Use a literal number of bytes for DEFAULT_CLUSTER_SIZE
39
block/rbd: report a better error when namespace does not exist
55
include: Add a comment to explain the origin of sizes' lookup table
56
40
57
Li Qiang (1):
41
Vladimir Sementsov-Ogievskiy (3):
58
block: change some function return type to bool
42
block: block_dirty_bitmap_merge(): fix error path
43
block: improve block_dirty_bitmap_merge(): don't allocate extra bitmap
44
block: simplify handling of try to merge different sized bitmaps
59
45
60
Max Reitz (5):
46
Xie Yongji (10):
61
option: Make option help nicer to read
47
block: Support passing NULL ops to blk_set_dev_ops()
62
chardev: Indent list of chardevs
48
block/export: Fix incorrect length passed to vu_queue_push()
63
qdev-monitor: Make device options help nicer
49
block/export: Abstract out the logic of virtio-blk I/O process
64
object: Make option help nicer to read
50
linux-headers: Add vduse.h
65
fw_cfg: Drop newline in @file description
51
libvduse: Add VDUSE (vDPA Device in Userspace) library
52
vduse-blk: Implement vduse-blk export
53
vduse-blk: Add vduse-blk resize support
54
libvduse: Add support for reconnecting
55
vduse-blk: Add serial option
56
vduse-blk: Add name option
66
57
67
Peter Maydell (5):
58
qapi/block-export.json | 29 +-
68
block/qcow2: Don't take address of fields in packed structs
59
docs/tools/qemu-storage-daemon.rst | 22 +
69
block/qcow: Don't take address of fields in packed structs
60
meson_options.txt | 4 +
70
block/qcow2-bitmap: Don't take address of fields in packed structs
61
block/export/vduse-blk.h | 20 +
71
block/vhdx: Don't take address of fields in packed structs
62
block/export/virtio-blk-handler.h | 37 +
72
block/vdi: Don't take address of fields in packed structs
63
include/block/aio-wait.h | 2 +
73
64
include/block/block-io.h | 1 -
74
Stefan Weil (1):
65
include/block/block_int-io.h | 2 +-
75
qemu-io-cmds: Fix two format strings
66
include/qemu/hbitmap.h | 15 +-
76
67
include/sysemu/block-backend-io.h | 1 -
77
Thomas Huth (1):
68
linux-headers/linux/vduse.h | 306 ++++++
78
block/vvfat: Fix crash when reporting error about too many files in directory
69
subprojects/libvduse/include/atomic.h | 1 +
79
70
subprojects/libvduse/include/compiler.h | 1 +
80
qapi/block-core.json | 7 +
71
subprojects/libvduse/libvduse.h | 247 +++++
81
block/vhdx.h | 12 +-
72
block/backup.c | 6 +-
82
include/block/block.h | 5 +-
73
block/block-backend.c | 12 +-
83
include/qemu/option.h | 2 +-
74
block/dirty-bitmap.c | 26 +-
84
include/qemu/units.h | 18 +
75
block/export/export.c | 6 +
85
include/sysemu/block-backend.h | 6 +-
76
block/export/vduse-blk.c | 374 ++++++++
86
block.c | 60 ++-
77
block/export/vhost-user-blk-server.c | 263 +----
87
block/block-backend.c | 8 +-
78
block/export/virtio-blk-handler.c | 240 +++++
88
block/bochs.c | 17 +-
79
block/gluster.c | 2 +-
89
block/cloop.c | 16 +-
80
block/io.c | 15 -
90
block/curl.c | 8 +-
81
block/monitor/bitmap-qmp-cmds.c | 40 +-
91
block/dmg.c | 16 +-
82
block/nbd.c | 8 +-
92
block/file-posix.c | 19 +-
83
block/rbd.c | 24 +
93
block/gluster.c | 12 +-
84
hw/block/virtio-blk.c | 1 -
94
block/iscsi.c | 8 +-
85
hw/block/xen-block.c | 1 -
95
block/nbd-client.c | 10 +-
86
hw/ide/core.c | 1 -
96
block/qcow.c | 18 +-
87
hw/scsi/scsi-disk.c | 1 -
97
block/qcow2-bitmap.c | 24 +-
88
hw/scsi/scsi-generic.c | 1 -
98
block/qcow2.c | 66 +--
89
storage-daemon/qemu-storage-daemon.c | 10 +
99
block/quorum.c | 45 +-
90
subprojects/libvduse/libvduse.c | 1375 +++++++++++++++++++++++++++
100
block/rbd.c | 14 +-
91
util/aio-wait.c | 16 +-
101
block/vdi.c | 68 +--
92
util/hbitmap.c | 25 +-
102
block/vhdx-endian.c | 118 ++---
93
MAINTAINERS | 9 +
103
block/vhdx-log.c | 4 +-
94
block/export/meson.build | 7 +-
104
block/vhdx.c | 18 +-
95
meson.build | 34 +
105
block/vpc.c | 2 +
96
scripts/meson-buildoptions.sh | 7 +
106
block/vvfat.c | 15 +-
97
scripts/update-linux-headers.sh | 2 +-
107
blockdev.c | 3 +-
98
subprojects/libvduse/linux-headers/linux | 1 +
108
chardev/char.c | 2 +-
99
subprojects/libvduse/meson.build | 10 +
109
crypto/block-qcow.c | 2 +
100
subprojects/libvduse/standard-headers/linux | 1 +
110
qdev-monitor.c | 13 +-
101
43 files changed, 2852 insertions(+), 354 deletions(-)
111
qemu-img.c | 4 +-
102
create mode 100644 block/export/vduse-blk.h
112
qemu-io-cmds.c | 4 +-
103
create mode 100644 block/export/virtio-blk-handler.h
113
util/qemu-option.c | 32 +-
104
create mode 100644 linux-headers/linux/vduse.h
114
vl.c | 15 +-
105
create mode 120000 subprojects/libvduse/include/atomic.h
115
tests/qemu-iotests/081 | 116 +++++
106
create mode 120000 subprojects/libvduse/include/compiler.h
116
tests/qemu-iotests/081.out | 70 +++
107
create mode 100644 subprojects/libvduse/libvduse.h
117
tests/qemu-iotests/082.out | 956 ++++++++++++++++++++---------------------
108
create mode 100644 block/export/vduse-blk.c
118
tests/qemu-iotests/083 | 2 +-
109
create mode 100644 block/export/virtio-blk-handler.c
119
tests/qemu-iotests/232 | 147 +++++++
110
create mode 100644 subprojects/libvduse/libvduse.c
120
tests/qemu-iotests/232.out | 59 +++
111
create mode 120000 subprojects/libvduse/linux-headers/linux
121
tests/qemu-iotests/group | 1 +
112
create mode 100644 subprojects/libvduse/meson.build
122
42 files changed, 1266 insertions(+), 776 deletions(-)
113
create mode 120000 subprojects/libvduse/standard-headers/linux
123
create mode 100755 tests/qemu-iotests/232
124
create mode 100644 tests/qemu-iotests/232.out
125
diff view generated by jsdifflib
Deleted patch
1
From: Thomas Huth <thuth@redhat.com>
2
1
3
When using the vvfat driver with a directory that contains too many files,
4
QEMU currently crashes. This can be triggered like this for example:
5
6
mkdir /tmp/vvfattest
7
cd /tmp/vvfattest
8
for ((x=0;x<=513;x++)); do mkdir $x; done
9
qemu-system-x86_64 -drive \
10
file.driver=vvfat,file.dir=.,read-only=on,media=cdrom
11
12
Seems like read_directory() is changing the mapping->path variable. Make
13
sure we use the right pointer instead.
14
15
Signed-off-by: Thomas Huth <thuth@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
block/vvfat.c | 4 ++--
19
1 file changed, 2 insertions(+), 2 deletions(-)
20
21
diff --git a/block/vvfat.c b/block/vvfat.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/vvfat.c
24
+++ b/block/vvfat.c
25
@@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s,
26
mapping = array_get(&(s->mapping), i);
27
28
if (mapping->mode & MODE_DIRECTORY) {
29
+ char *path = mapping->path;
30
mapping->begin = cluster;
31
if(read_directory(s, i)) {
32
- error_setg(errp, "Could not read directory %s",
33
- mapping->path);
34
+ error_setg(errp, "Could not read directory %s", path);
35
return -1;
36
}
37
mapping = array_get(&(s->mapping), i);
38
--
39
2.19.1
40
41
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This is a static function with only one caller, so there's no need to
3
bdrv_co_drain() has not been used since commit 9a0cec664eef ("mirror:
4
keep it. Inlining the code in quorum_compare() makes it much simpler.
4
use bdrv_drained_begin/bdrv_drained_end") in 2016. Remove it so there
5
are fewer drain scenarios to worry about.
5
6
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Use bdrv_drained_begin()/bdrv_drained_end() instead. They are "mixed"
7
Reported-by: Markus Armbruster <armbru@redhat.com>
8
functions that can be called from coroutine context. Unlike
9
bdrv_co_drain(), these functions provide control of the length of the
10
drained section, which is usually the right thing.
11
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Message-Id: <20220521122714.3837731-1-stefanha@redhat.com>
14
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
15
Reviewed-by: Alberto Faria <afaria@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
17
---
10
block/quorum.c | 24 +++++-------------------
18
include/block/block-io.h | 1 -
11
1 file changed, 5 insertions(+), 19 deletions(-)
19
block/io.c | 15 ---------------
20
2 files changed, 16 deletions(-)
12
21
13
diff --git a/block/quorum.c b/block/quorum.c
22
diff --git a/include/block/block-io.h b/include/block/block-io.h
14
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
15
--- a/block/quorum.c
24
--- a/include/block/block-io.h
16
+++ b/block/quorum.c
25
+++ b/include/block/block-io.h
17
@@ -XXX,XX +XXX,XX @@ static bool quorum_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
26
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter);
18
return true;
27
cond); })
28
29
void bdrv_drain(BlockDriverState *bs);
30
-void coroutine_fn bdrv_co_drain(BlockDriverState *bs);
31
32
int generated_co_wrapper
33
bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
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 @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
39
BDRV_POLL_WHILE(child->bs, qatomic_read(&drained_end_counter) > 0);
19
}
40
}
20
41
21
-static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb,
42
-/*
22
- const char *fmt, ...)
43
- * Wait for pending requests to complete on a single BlockDriverState subtree,
44
- * and suspend block driver's internal I/O until next request arrives.
45
- *
46
- * Note that unlike bdrv_drain_all(), the caller must hold the BlockDriverState
47
- * AioContext.
48
- */
49
-void coroutine_fn bdrv_co_drain(BlockDriverState *bs)
23
-{
50
-{
24
- va_list ap;
51
- IO_OR_GS_CODE();
25
-
52
- assert(qemu_in_coroutine());
26
- va_start(ap, fmt);
53
- bdrv_drained_begin(bs);
27
- fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64 " ",
54
- bdrv_drained_end(bs);
28
- acb->offset, acb->bytes);
29
- vfprintf(stderr, fmt, ap);
30
- fprintf(stderr, "\n");
31
- va_end(ap);
32
- exit(1);
33
-}
55
-}
34
-
56
-
35
-static bool quorum_compare(QuorumAIOCB *acb,
57
void bdrv_drain(BlockDriverState *bs)
36
- QEMUIOVector *a,
37
- QEMUIOVector *b)
38
+static bool quorum_compare(QuorumAIOCB *acb, QEMUIOVector *a, QEMUIOVector *b)
39
{
58
{
40
BDRVQuorumState *s = acb->bs->opaque;
59
IO_OR_GS_CODE();
41
ssize_t offset;
42
@@ -XXX,XX +XXX,XX @@ static bool quorum_compare(QuorumAIOCB *acb,
43
if (s->is_blkverify) {
44
offset = qemu_iovec_compare(a, b);
45
if (offset != -1) {
46
- quorum_err(acb, "contents mismatch at offset %" PRIu64,
47
- acb->offset + offset);
48
+ fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64
49
+ " contents mismatch at offset %" PRIu64 "\n",
50
+ acb->offset, acb->bytes, acb->offset + offset);
51
+ exit(1);
52
}
53
return true;
54
}
55
--
60
--
56
2.19.1
61
2.35.3
57
58
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This adds some whitespace into the option help (including indentation)
3
Commit 1b7fd729559c ("block: rename buffer_alignment to
4
and puts angle brackets around the type names. Furthermore, the list
4
guest_block_size") noted:
5
name is no longer printed as part of every line, but only once in
6
advance, and only if the caller did not print a caption already.
7
5
8
This patch also restores the description alignment we had before commit
6
At this point, the field is set by the device emulation, but completely
9
9cbef9d68ee1d8d0, just at 24 instead of 16 characters like we used to.
7
ignored by the block layer.
10
This increase is because now we have the type and two spaces of
11
indentation before the description, and with a usual type name length of
12
three chracters, this sums up to eight additional characters -- which
13
means that we now need 24 characters to get the same amount of padding
14
for most options. Also, 24 is a third of 80, which makes it kind of a
15
round number in terminal terms.
16
8
17
Finally, this patch amends the reference output of iotest 082 to match
9
The last time the value of buffer_alignment/guest_block_size was
18
the changes (and thus makes it pass again).
10
actually used was before commit 339064d50639 ("block: Don't use guest
11
sector size for qemu_blockalign()").
19
12
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
This value has not been used since 2013. Get rid of it.
21
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
14
15
Cc: Xie Yongji <xieyongji@bytedance.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Message-Id: <20220518130945.2657905-1-stefanha@redhat.com>
18
Reviewed-by: Paul Durrant <paul@xen.org>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Reviewed-by: Alberto Faria <afaria@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
22
---
24
include/qemu/option.h | 2 +-
23
include/sysemu/block-backend-io.h | 1 -
25
qemu-img.c | 4 +-
24
block/block-backend.c | 10 ----------
26
util/qemu-option.c | 32 +-
25
block/export/vhost-user-blk-server.c | 1 -
27
tests/qemu-iotests/082.out | 956 ++++++++++++++++++-------------------
26
hw/block/virtio-blk.c | 1 -
28
4 files changed, 507 insertions(+), 487 deletions(-)
27
hw/block/xen-block.c | 1 -
28
hw/ide/core.c | 1 -
29
hw/scsi/scsi-disk.c | 1 -
30
hw/scsi/scsi-generic.c | 1 -
31
8 files changed, 17 deletions(-)
29
32
30
diff --git a/include/qemu/option.h b/include/qemu/option.h
33
diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h
31
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
32
--- a/include/qemu/option.h
35
--- a/include/sysemu/block-backend-io.h
33
+++ b/include/qemu/option.h
36
+++ b/include/sysemu/block-backend-io.h
34
@@ -XXX,XX +XXX,XX @@ typedef int (*qemu_opts_loopfunc)(void *opaque, QemuOpts *opts, Error **errp);
37
@@ -XXX,XX +XXX,XX @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
35
int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
38
void blk_iostatus_set_err(BlockBackend *blk, int error);
36
void *opaque, Error **errp);
39
int blk_get_max_iov(BlockBackend *blk);
37
void qemu_opts_print(QemuOpts *opts, const char *sep);
40
int blk_get_max_hw_iov(BlockBackend *blk);
38
-void qemu_opts_print_help(QemuOptsList *list);
41
-void blk_set_guest_block_size(BlockBackend *blk, int align);
39
+void qemu_opts_print_help(QemuOptsList *list, bool print_caption);
42
40
void qemu_opts_free(QemuOptsList *list);
43
void blk_io_plug(BlockBackend *blk);
41
QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list);
44
void blk_io_unplug(BlockBackend *blk);
42
45
diff --git a/block/block-backend.c b/block/block-backend.c
43
diff --git a/qemu-img.c b/qemu-img.c
44
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
45
--- a/qemu-img.c
47
--- a/block/block-backend.c
46
+++ b/qemu-img.c
48
+++ b/block/block-backend.c
47
@@ -XXX,XX +XXX,XX @@ static int print_block_option_help(const char *filename, const char *fmt)
49
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
50
const BlockDevOps *dev_ops;
51
void *dev_opaque;
52
53
- /* the block size for which the guest device expects atomicity */
54
- int guest_block_size;
55
-
56
/* If the BDS tree is removed, some of its options are stored here (which
57
* can be used to restore those options in the new BDS on insert) */
58
BlockBackendRootState root_state;
59
@@ -XXX,XX +XXX,XX @@ void blk_detach_dev(BlockBackend *blk, DeviceState *dev)
60
blk->dev = NULL;
61
blk->dev_ops = NULL;
62
blk->dev_opaque = NULL;
63
- blk->guest_block_size = 512;
64
blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort);
65
blk_unref(blk);
66
}
67
@@ -XXX,XX +XXX,XX @@ int blk_get_max_iov(BlockBackend *blk)
68
return blk->root->bs->bl.max_iov;
69
}
70
71
-void blk_set_guest_block_size(BlockBackend *blk, int align)
72
-{
73
- IO_CODE();
74
- blk->guest_block_size = align;
75
-}
76
-
77
void *blk_try_blockalign(BlockBackend *blk, size_t size)
78
{
79
IO_CODE();
80
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/block/export/vhost-user-blk-server.c
83
+++ b/block/export/vhost-user-blk-server.c
84
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
85
return -EINVAL;
48
}
86
}
49
87
vexp->blk_size = logical_block_size;
50
printf("Supported options:\n");
88
- blk_set_guest_block_size(exp->blk, logical_block_size);
51
- qemu_opts_print_help(create_opts);
89
52
+ qemu_opts_print_help(create_opts, false);
90
if (vu_opts->has_num_queues) {
53
qemu_opts_free(create_opts);
91
num_queues = vu_opts->num_queues;
54
return 0;
92
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
55
}
56
@@ -XXX,XX +XXX,XX @@ static int print_amend_option_help(const char *format)
57
assert(drv->create_opts);
58
59
printf("Creation options for '%s':\n", format);
60
- qemu_opts_print_help(drv->create_opts);
61
+ qemu_opts_print_help(drv->create_opts, false);
62
printf("\nNote that not all of these options may be amendable.\n");
63
return 0;
64
}
65
diff --git a/util/qemu-option.c b/util/qemu-option.c
66
index XXXXXXX..XXXXXXX 100644
93
index XXXXXXX..XXXXXXX 100644
67
--- a/util/qemu-option.c
94
--- a/hw/block/virtio-blk.c
68
+++ b/util/qemu-option.c
95
+++ b/hw/block/virtio-blk.c
69
@@ -XXX,XX +XXX,XX @@ static const char *opt_type_to_string(enum QemuOptType type)
96
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
70
g_assert_not_reached();
97
71
}
98
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
72
99
blk_set_dev_ops(s->blk, &virtio_block_ops, s);
73
-void qemu_opts_print_help(QemuOptsList *list)
100
- blk_set_guest_block_size(s->blk, s->conf.conf.logical_block_size);
74
+/**
101
75
+ * Print the list of options available in the given list. If
102
blk_iostatus_enable(s->blk);
76
+ * @print_caption is true, a caption (including the list name, if it
103
77
+ * exists) is printed. The options itself will be indented, so
104
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
78
+ * @print_caption should only be set to false if the caller prints its
105
index XXXXXXX..XXXXXXX 100644
79
+ * own custom caption (so that the indentation makes sense).
106
--- a/hw/block/xen-block.c
80
+ */
107
+++ b/hw/block/xen-block.c
81
+void qemu_opts_print_help(QemuOptsList *list, bool print_caption)
108
@@ -XXX,XX +XXX,XX @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
82
{
83
QemuOptDesc *desc;
84
int i;
85
@@ -XXX,XX +XXX,XX @@ void qemu_opts_print_help(QemuOptsList *list)
86
desc = list->desc;
87
while (desc && desc->name) {
88
GString *str = g_string_new(NULL);
89
- if (list->name) {
90
- g_string_append_printf(str, "%s.", list->name);
91
- }
92
- g_string_append_printf(str, "%s=%s", desc->name,
93
+ g_string_append_printf(str, " %s=<%s>", desc->name,
94
opt_type_to_string(desc->type));
95
if (desc->help) {
96
+ if (str->len < 24) {
97
+ g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
98
+ }
99
g_string_append_printf(str, " - %s", desc->help);
100
}
101
g_ptr_array_add(array, g_string_free(str, false));
102
@@ -XXX,XX +XXX,XX @@ void qemu_opts_print_help(QemuOptsList *list)
103
}
109
}
104
110
105
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
111
blk_set_dev_ops(blk, &xen_block_dev_ops, blockdev);
106
+ if (print_caption && array->len > 0) {
112
- blk_set_guest_block_size(blk, conf->logical_block_size);
107
+ if (list->name) {
113
108
+ printf("%s options:\n", list->name);
114
if (conf->discard_granularity == -1) {
109
+ } else {
115
conf->discard_granularity = conf->physical_block_size;
110
+ printf("Options:\n");
116
diff --git a/hw/ide/core.c b/hw/ide/core.c
111
+ }
117
index XXXXXXX..XXXXXXX 100644
112
+ } else if (array->len == 0) {
118
--- a/hw/ide/core.c
113
+ if (list->name) {
119
+++ b/hw/ide/core.c
114
+ printf("There are no options for %s.\n", list->name);
120
@@ -XXX,XX +XXX,XX @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
115
+ } else {
121
s->smart_selftest_count = 0;
116
+ printf("No options available.\n");
122
if (kind == IDE_CD) {
117
+ }
123
blk_set_dev_ops(blk, &ide_cd_block_ops, s);
118
+ }
124
- blk_set_guest_block_size(blk, 2048);
119
for (i = 0; i < array->len; i++) {
125
} else {
120
printf("%s\n", (char *)array->pdata[i]);
126
if (!blk_is_inserted(s->blk)) {
127
error_setg(errp, "Device needs media, but drive is empty");
128
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
129
index XXXXXXX..XXXXXXX 100644
130
--- a/hw/scsi/scsi-disk.c
131
+++ b/hw/scsi/scsi-disk.c
132
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
133
} else {
134
blk_set_dev_ops(s->qdev.conf.blk, &scsi_disk_block_ops, s);
121
}
135
}
122
@@ -XXX,XX +XXX,XX @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
136
- blk_set_guest_block_size(s->qdev.conf.blk, s->qdev.blocksize);
123
opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err);
137
124
if (err) {
138
blk_iostatus_enable(s->qdev.conf.blk);
125
if (invalidp && has_help_option(params)) {
139
126
- qemu_opts_print_help(list);
140
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
127
+ qemu_opts_print_help(list, true);
128
error_free(err);
129
} else {
130
error_report_err(err);
131
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
132
index XXXXXXX..XXXXXXX 100644
141
index XXXXXXX..XXXXXXX 100644
133
--- a/tests/qemu-iotests/082.out
142
--- a/hw/scsi/scsi-generic.c
134
+++ b/tests/qemu-iotests/082.out
143
+++ b/hw/scsi/scsi-generic.c
135
@@ -XXX,XX +XXX,XX @@ cluster_size: 8192
144
@@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void * opaque, int ret)
136
145
s->blocksize = ldl_be_p(&r->buf[8]);
137
Testing: create -f qcow2 -o help TEST_DIR/t.qcow2 128M
146
s->max_lba = ldq_be_p(&r->buf[0]);
138
Supported options:
147
}
139
-size Virtual disk size
148
- blk_set_guest_block_size(s->conf.blk, s->blocksize);
140
-compat Compatibility level (0.10 or 1.1)
149
141
-backing_file File name of a base image
150
/*
142
-backing_fmt Image format of the base image
151
* Patch MODE SENSE device specific parameters if the BDS is opened
143
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
144
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
145
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
146
-encrypt.cipher-alg Name of encryption cipher algorithm
147
-encrypt.cipher-mode Name of encryption cipher mode
148
-encrypt.ivgen-alg Name of IV generator algorithm
149
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
150
-encrypt.hash-alg Name of encryption hash algorithm
151
-encrypt.iter-time Time to spend in PBKDF in milliseconds
152
-cluster_size qcow2 cluster size
153
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
154
-lazy_refcounts Postpone refcount updates
155
-refcount_bits Width of a reference count entry in bits
156
-nocow Turn off copy-on-write (valid only on btrfs)
157
+ backing_file=<str> - File name of a base image
158
+ backing_fmt=<str> - Image format of the base image
159
+ cluster_size=<size> - qcow2 cluster size
160
+ compat=<str> - Compatibility level (0.10 or 1.1)
161
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
162
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
163
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
164
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
165
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
166
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
167
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
168
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
169
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
170
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
171
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
172
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
173
+ refcount_bits=<num> - Width of a reference count entry in bits
174
+ size=<size> - Virtual disk size
175
176
Testing: create -f qcow2 -o ? TEST_DIR/t.qcow2 128M
177
Supported options:
178
-size Virtual disk size
179
-compat Compatibility level (0.10 or 1.1)
180
-backing_file File name of a base image
181
-backing_fmt Image format of the base image
182
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
183
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
184
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
185
-encrypt.cipher-alg Name of encryption cipher algorithm
186
-encrypt.cipher-mode Name of encryption cipher mode
187
-encrypt.ivgen-alg Name of IV generator algorithm
188
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
189
-encrypt.hash-alg Name of encryption hash algorithm
190
-encrypt.iter-time Time to spend in PBKDF in milliseconds
191
-cluster_size qcow2 cluster size
192
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
193
-lazy_refcounts Postpone refcount updates
194
-refcount_bits Width of a reference count entry in bits
195
-nocow Turn off copy-on-write (valid only on btrfs)
196
+ backing_file=<str> - File name of a base image
197
+ backing_fmt=<str> - Image format of the base image
198
+ cluster_size=<size> - qcow2 cluster size
199
+ compat=<str> - Compatibility level (0.10 or 1.1)
200
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
201
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
202
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
203
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
204
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
205
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
206
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
207
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
208
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
209
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
210
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
211
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
212
+ refcount_bits=<num> - Width of a reference count entry in bits
213
+ size=<size> - Virtual disk size
214
215
Testing: create -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 128M
216
Supported options:
217
-size Virtual disk size
218
-compat Compatibility level (0.10 or 1.1)
219
-backing_file File name of a base image
220
-backing_fmt Image format of the base image
221
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
222
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
223
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
224
-encrypt.cipher-alg Name of encryption cipher algorithm
225
-encrypt.cipher-mode Name of encryption cipher mode
226
-encrypt.ivgen-alg Name of IV generator algorithm
227
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
228
-encrypt.hash-alg Name of encryption hash algorithm
229
-encrypt.iter-time Time to spend in PBKDF in milliseconds
230
-cluster_size qcow2 cluster size
231
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
232
-lazy_refcounts Postpone refcount updates
233
-refcount_bits Width of a reference count entry in bits
234
-nocow Turn off copy-on-write (valid only on btrfs)
235
+ backing_file=<str> - File name of a base image
236
+ backing_fmt=<str> - Image format of the base image
237
+ cluster_size=<size> - qcow2 cluster size
238
+ compat=<str> - Compatibility level (0.10 or 1.1)
239
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
240
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
241
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
242
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
243
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
244
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
245
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
246
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
247
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
248
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
249
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
250
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
251
+ refcount_bits=<num> - Width of a reference count entry in bits
252
+ size=<size> - Virtual disk size
253
254
Testing: create -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 128M
255
Supported options:
256
-size Virtual disk size
257
-compat Compatibility level (0.10 or 1.1)
258
-backing_file File name of a base image
259
-backing_fmt Image format of the base image
260
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
261
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
262
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
263
-encrypt.cipher-alg Name of encryption cipher algorithm
264
-encrypt.cipher-mode Name of encryption cipher mode
265
-encrypt.ivgen-alg Name of IV generator algorithm
266
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
267
-encrypt.hash-alg Name of encryption hash algorithm
268
-encrypt.iter-time Time to spend in PBKDF in milliseconds
269
-cluster_size qcow2 cluster size
270
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
271
-lazy_refcounts Postpone refcount updates
272
-refcount_bits Width of a reference count entry in bits
273
-nocow Turn off copy-on-write (valid only on btrfs)
274
+ backing_file=<str> - File name of a base image
275
+ backing_fmt=<str> - Image format of the base image
276
+ cluster_size=<size> - qcow2 cluster size
277
+ compat=<str> - Compatibility level (0.10 or 1.1)
278
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
279
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
280
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
281
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
282
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
283
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
284
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
285
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
286
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
287
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
288
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
289
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
290
+ refcount_bits=<num> - Width of a reference count entry in bits
291
+ size=<size> - Virtual disk size
292
293
Testing: create -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 128M
294
Supported options:
295
-size Virtual disk size
296
-compat Compatibility level (0.10 or 1.1)
297
-backing_file File name of a base image
298
-backing_fmt Image format of the base image
299
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
300
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
301
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
302
-encrypt.cipher-alg Name of encryption cipher algorithm
303
-encrypt.cipher-mode Name of encryption cipher mode
304
-encrypt.ivgen-alg Name of IV generator algorithm
305
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
306
-encrypt.hash-alg Name of encryption hash algorithm
307
-encrypt.iter-time Time to spend in PBKDF in milliseconds
308
-cluster_size qcow2 cluster size
309
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
310
-lazy_refcounts Postpone refcount updates
311
-refcount_bits Width of a reference count entry in bits
312
-nocow Turn off copy-on-write (valid only on btrfs)
313
+ backing_file=<str> - File name of a base image
314
+ backing_fmt=<str> - Image format of the base image
315
+ cluster_size=<size> - qcow2 cluster size
316
+ compat=<str> - Compatibility level (0.10 or 1.1)
317
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
318
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
319
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
320
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
321
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
322
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
323
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
324
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
325
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
326
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
327
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
328
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
329
+ refcount_bits=<num> - Width of a reference count entry in bits
330
+ size=<size> - Virtual disk size
331
332
Testing: create -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 128M
333
Supported options:
334
-size Virtual disk size
335
-compat Compatibility level (0.10 or 1.1)
336
-backing_file File name of a base image
337
-backing_fmt Image format of the base image
338
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
339
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
340
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
341
-encrypt.cipher-alg Name of encryption cipher algorithm
342
-encrypt.cipher-mode Name of encryption cipher mode
343
-encrypt.ivgen-alg Name of IV generator algorithm
344
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
345
-encrypt.hash-alg Name of encryption hash algorithm
346
-encrypt.iter-time Time to spend in PBKDF in milliseconds
347
-cluster_size qcow2 cluster size
348
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
349
-lazy_refcounts Postpone refcount updates
350
-refcount_bits Width of a reference count entry in bits
351
-nocow Turn off copy-on-write (valid only on btrfs)
352
+ backing_file=<str> - File name of a base image
353
+ backing_fmt=<str> - Image format of the base image
354
+ cluster_size=<size> - qcow2 cluster size
355
+ compat=<str> - Compatibility level (0.10 or 1.1)
356
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
357
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
358
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
359
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
360
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
361
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
362
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
363
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
364
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
365
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
366
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
367
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
368
+ refcount_bits=<num> - Width of a reference count entry in bits
369
+ size=<size> - Virtual disk size
370
371
Testing: create -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 128M
372
Supported options:
373
-size Virtual disk size
374
-compat Compatibility level (0.10 or 1.1)
375
-backing_file File name of a base image
376
-backing_fmt Image format of the base image
377
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
378
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
379
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
380
-encrypt.cipher-alg Name of encryption cipher algorithm
381
-encrypt.cipher-mode Name of encryption cipher mode
382
-encrypt.ivgen-alg Name of IV generator algorithm
383
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
384
-encrypt.hash-alg Name of encryption hash algorithm
385
-encrypt.iter-time Time to spend in PBKDF in milliseconds
386
-cluster_size qcow2 cluster size
387
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
388
-lazy_refcounts Postpone refcount updates
389
-refcount_bits Width of a reference count entry in bits
390
-nocow Turn off copy-on-write (valid only on btrfs)
391
+ backing_file=<str> - File name of a base image
392
+ backing_fmt=<str> - Image format of the base image
393
+ cluster_size=<size> - qcow2 cluster size
394
+ compat=<str> - Compatibility level (0.10 or 1.1)
395
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
396
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
397
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
398
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
399
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
400
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
401
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
402
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
403
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
404
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
405
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
406
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
407
+ refcount_bits=<num> - Width of a reference count entry in bits
408
+ size=<size> - Virtual disk size
409
410
Testing: create -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 128M
411
Supported options:
412
-size Virtual disk size
413
-compat Compatibility level (0.10 or 1.1)
414
-backing_file File name of a base image
415
-backing_fmt Image format of the base image
416
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
417
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
418
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
419
-encrypt.cipher-alg Name of encryption cipher algorithm
420
-encrypt.cipher-mode Name of encryption cipher mode
421
-encrypt.ivgen-alg Name of IV generator algorithm
422
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
423
-encrypt.hash-alg Name of encryption hash algorithm
424
-encrypt.iter-time Time to spend in PBKDF in milliseconds
425
-cluster_size qcow2 cluster size
426
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
427
-lazy_refcounts Postpone refcount updates
428
-refcount_bits Width of a reference count entry in bits
429
-nocow Turn off copy-on-write (valid only on btrfs)
430
+ backing_file=<str> - File name of a base image
431
+ backing_fmt=<str> - Image format of the base image
432
+ cluster_size=<size> - qcow2 cluster size
433
+ compat=<str> - Compatibility level (0.10 or 1.1)
434
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
435
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
436
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
437
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
438
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
439
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
440
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
441
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
442
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
443
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
444
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
445
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
446
+ refcount_bits=<num> - Width of a reference count entry in bits
447
+ size=<size> - Virtual disk size
448
449
Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
450
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16
451
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
452
453
Testing: create -f qcow2 -o help
454
Supported options:
455
-size Virtual disk size
456
-compat Compatibility level (0.10 or 1.1)
457
-backing_file File name of a base image
458
-backing_fmt Image format of the base image
459
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
460
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
461
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
462
-encrypt.cipher-alg Name of encryption cipher algorithm
463
-encrypt.cipher-mode Name of encryption cipher mode
464
-encrypt.ivgen-alg Name of IV generator algorithm
465
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
466
-encrypt.hash-alg Name of encryption hash algorithm
467
-encrypt.iter-time Time to spend in PBKDF in milliseconds
468
-cluster_size qcow2 cluster size
469
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
470
-lazy_refcounts Postpone refcount updates
471
-refcount_bits Width of a reference count entry in bits
472
+ backing_file=<str> - File name of a base image
473
+ backing_fmt=<str> - Image format of the base image
474
+ cluster_size=<size> - qcow2 cluster size
475
+ compat=<str> - Compatibility level (0.10 or 1.1)
476
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
477
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
478
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
479
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
480
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
481
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
482
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
483
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
484
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
485
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
486
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
487
+ refcount_bits=<num> - Width of a reference count entry in bits
488
+ size=<size> - Virtual disk size
489
490
Testing: create -o help
491
Supported options:
492
-size Virtual disk size
493
+ size=<size> - Virtual disk size
494
495
Testing: create -f bochs -o help
496
qemu-img: Format driver 'bochs' does not support image creation
497
@@ -XXX,XX +XXX,XX @@ cluster_size: 8192
498
499
Testing: convert -O qcow2 -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
500
Supported options:
501
-size Virtual disk size
502
-compat Compatibility level (0.10 or 1.1)
503
-backing_file File name of a base image
504
-backing_fmt Image format of the base image
505
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
506
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
507
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
508
-encrypt.cipher-alg Name of encryption cipher algorithm
509
-encrypt.cipher-mode Name of encryption cipher mode
510
-encrypt.ivgen-alg Name of IV generator algorithm
511
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
512
-encrypt.hash-alg Name of encryption hash algorithm
513
-encrypt.iter-time Time to spend in PBKDF in milliseconds
514
-cluster_size qcow2 cluster size
515
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
516
-lazy_refcounts Postpone refcount updates
517
-refcount_bits Width of a reference count entry in bits
518
-nocow Turn off copy-on-write (valid only on btrfs)
519
+ backing_file=<str> - File name of a base image
520
+ backing_fmt=<str> - Image format of the base image
521
+ cluster_size=<size> - qcow2 cluster size
522
+ compat=<str> - Compatibility level (0.10 or 1.1)
523
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
524
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
525
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
526
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
527
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
528
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
529
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
530
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
531
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
532
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
533
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
534
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
535
+ refcount_bits=<num> - Width of a reference count entry in bits
536
+ size=<size> - Virtual disk size
537
538
Testing: convert -O qcow2 -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
539
Supported options:
540
-size Virtual disk size
541
-compat Compatibility level (0.10 or 1.1)
542
-backing_file File name of a base image
543
-backing_fmt Image format of the base image
544
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
545
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
546
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
547
-encrypt.cipher-alg Name of encryption cipher algorithm
548
-encrypt.cipher-mode Name of encryption cipher mode
549
-encrypt.ivgen-alg Name of IV generator algorithm
550
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
551
-encrypt.hash-alg Name of encryption hash algorithm
552
-encrypt.iter-time Time to spend in PBKDF in milliseconds
553
-cluster_size qcow2 cluster size
554
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
555
-lazy_refcounts Postpone refcount updates
556
-refcount_bits Width of a reference count entry in bits
557
-nocow Turn off copy-on-write (valid only on btrfs)
558
+ backing_file=<str> - File name of a base image
559
+ backing_fmt=<str> - Image format of the base image
560
+ cluster_size=<size> - qcow2 cluster size
561
+ compat=<str> - Compatibility level (0.10 or 1.1)
562
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
563
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
564
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
565
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
566
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
567
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
568
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
569
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
570
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
571
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
572
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
573
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
574
+ refcount_bits=<num> - Width of a reference count entry in bits
575
+ size=<size> - Virtual disk size
576
577
Testing: convert -O qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
578
Supported options:
579
-size Virtual disk size
580
-compat Compatibility level (0.10 or 1.1)
581
-backing_file File name of a base image
582
-backing_fmt Image format of the base image
583
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
584
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
585
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
586
-encrypt.cipher-alg Name of encryption cipher algorithm
587
-encrypt.cipher-mode Name of encryption cipher mode
588
-encrypt.ivgen-alg Name of IV generator algorithm
589
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
590
-encrypt.hash-alg Name of encryption hash algorithm
591
-encrypt.iter-time Time to spend in PBKDF in milliseconds
592
-cluster_size qcow2 cluster size
593
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
594
-lazy_refcounts Postpone refcount updates
595
-refcount_bits Width of a reference count entry in bits
596
-nocow Turn off copy-on-write (valid only on btrfs)
597
+ backing_file=<str> - File name of a base image
598
+ backing_fmt=<str> - Image format of the base image
599
+ cluster_size=<size> - qcow2 cluster size
600
+ compat=<str> - Compatibility level (0.10 or 1.1)
601
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
602
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
603
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
604
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
605
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
606
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
607
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
608
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
609
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
610
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
611
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
612
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
613
+ refcount_bits=<num> - Width of a reference count entry in bits
614
+ size=<size> - Virtual disk size
615
616
Testing: convert -O qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
617
Supported options:
618
-size Virtual disk size
619
-compat Compatibility level (0.10 or 1.1)
620
-backing_file File name of a base image
621
-backing_fmt Image format of the base image
622
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
623
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
624
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
625
-encrypt.cipher-alg Name of encryption cipher algorithm
626
-encrypt.cipher-mode Name of encryption cipher mode
627
-encrypt.ivgen-alg Name of IV generator algorithm
628
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
629
-encrypt.hash-alg Name of encryption hash algorithm
630
-encrypt.iter-time Time to spend in PBKDF in milliseconds
631
-cluster_size qcow2 cluster size
632
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
633
-lazy_refcounts Postpone refcount updates
634
-refcount_bits Width of a reference count entry in bits
635
-nocow Turn off copy-on-write (valid only on btrfs)
636
+ backing_file=<str> - File name of a base image
637
+ backing_fmt=<str> - Image format of the base image
638
+ cluster_size=<size> - qcow2 cluster size
639
+ compat=<str> - Compatibility level (0.10 or 1.1)
640
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
641
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
642
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
643
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
644
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
645
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
646
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
647
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
648
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
649
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
650
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
651
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
652
+ refcount_bits=<num> - Width of a reference count entry in bits
653
+ size=<size> - Virtual disk size
654
655
Testing: convert -O qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
656
Supported options:
657
-size Virtual disk size
658
-compat Compatibility level (0.10 or 1.1)
659
-backing_file File name of a base image
660
-backing_fmt Image format of the base image
661
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
662
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
663
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
664
-encrypt.cipher-alg Name of encryption cipher algorithm
665
-encrypt.cipher-mode Name of encryption cipher mode
666
-encrypt.ivgen-alg Name of IV generator algorithm
667
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
668
-encrypt.hash-alg Name of encryption hash algorithm
669
-encrypt.iter-time Time to spend in PBKDF in milliseconds
670
-cluster_size qcow2 cluster size
671
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
672
-lazy_refcounts Postpone refcount updates
673
-refcount_bits Width of a reference count entry in bits
674
-nocow Turn off copy-on-write (valid only on btrfs)
675
+ backing_file=<str> - File name of a base image
676
+ backing_fmt=<str> - Image format of the base image
677
+ cluster_size=<size> - qcow2 cluster size
678
+ compat=<str> - Compatibility level (0.10 or 1.1)
679
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
680
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
681
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
682
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
683
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
684
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
685
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
686
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
687
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
688
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
689
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
690
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
691
+ refcount_bits=<num> - Width of a reference count entry in bits
692
+ size=<size> - Virtual disk size
693
694
Testing: convert -O qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
695
Supported options:
696
-size Virtual disk size
697
-compat Compatibility level (0.10 or 1.1)
698
-backing_file File name of a base image
699
-backing_fmt Image format of the base image
700
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
701
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
702
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
703
-encrypt.cipher-alg Name of encryption cipher algorithm
704
-encrypt.cipher-mode Name of encryption cipher mode
705
-encrypt.ivgen-alg Name of IV generator algorithm
706
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
707
-encrypt.hash-alg Name of encryption hash algorithm
708
-encrypt.iter-time Time to spend in PBKDF in milliseconds
709
-cluster_size qcow2 cluster size
710
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
711
-lazy_refcounts Postpone refcount updates
712
-refcount_bits Width of a reference count entry in bits
713
-nocow Turn off copy-on-write (valid only on btrfs)
714
+ backing_file=<str> - File name of a base image
715
+ backing_fmt=<str> - Image format of the base image
716
+ cluster_size=<size> - qcow2 cluster size
717
+ compat=<str> - Compatibility level (0.10 or 1.1)
718
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
719
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
720
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
721
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
722
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
723
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
724
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
725
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
726
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
727
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
728
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
729
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
730
+ refcount_bits=<num> - Width of a reference count entry in bits
731
+ size=<size> - Virtual disk size
732
733
Testing: convert -O qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
734
Supported options:
735
-size Virtual disk size
736
-compat Compatibility level (0.10 or 1.1)
737
-backing_file File name of a base image
738
-backing_fmt Image format of the base image
739
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
740
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
741
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
742
-encrypt.cipher-alg Name of encryption cipher algorithm
743
-encrypt.cipher-mode Name of encryption cipher mode
744
-encrypt.ivgen-alg Name of IV generator algorithm
745
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
746
-encrypt.hash-alg Name of encryption hash algorithm
747
-encrypt.iter-time Time to spend in PBKDF in milliseconds
748
-cluster_size qcow2 cluster size
749
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
750
-lazy_refcounts Postpone refcount updates
751
-refcount_bits Width of a reference count entry in bits
752
-nocow Turn off copy-on-write (valid only on btrfs)
753
+ backing_file=<str> - File name of a base image
754
+ backing_fmt=<str> - Image format of the base image
755
+ cluster_size=<size> - qcow2 cluster size
756
+ compat=<str> - Compatibility level (0.10 or 1.1)
757
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
758
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
759
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
760
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
761
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
762
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
763
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
764
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
765
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
766
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
767
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
768
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
769
+ refcount_bits=<num> - Width of a reference count entry in bits
770
+ size=<size> - Virtual disk size
771
772
Testing: convert -O qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
773
Supported options:
774
-size Virtual disk size
775
-compat Compatibility level (0.10 or 1.1)
776
-backing_file File name of a base image
777
-backing_fmt Image format of the base image
778
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
779
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
780
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
781
-encrypt.cipher-alg Name of encryption cipher algorithm
782
-encrypt.cipher-mode Name of encryption cipher mode
783
-encrypt.ivgen-alg Name of IV generator algorithm
784
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
785
-encrypt.hash-alg Name of encryption hash algorithm
786
-encrypt.iter-time Time to spend in PBKDF in milliseconds
787
-cluster_size qcow2 cluster size
788
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
789
-lazy_refcounts Postpone refcount updates
790
-refcount_bits Width of a reference count entry in bits
791
-nocow Turn off copy-on-write (valid only on btrfs)
792
+ backing_file=<str> - File name of a base image
793
+ backing_fmt=<str> - Image format of the base image
794
+ cluster_size=<size> - qcow2 cluster size
795
+ compat=<str> - Compatibility level (0.10 or 1.1)
796
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
797
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
798
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
799
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
800
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
801
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
802
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
803
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
804
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
805
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
806
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
807
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
808
+ refcount_bits=<num> - Width of a reference count entry in bits
809
+ size=<size> - Virtual disk size
810
811
Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
812
qemu-img: Could not open 'TEST_DIR/t.qcow2.base': Could not open backing file: Could not open 'TEST_DIR/t.qcow2,help': No such file or directory
813
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
814
815
Testing: convert -O qcow2 -o help
816
Supported options:
817
-size Virtual disk size
818
-compat Compatibility level (0.10 or 1.1)
819
-backing_file File name of a base image
820
-backing_fmt Image format of the base image
821
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
822
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
823
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
824
-encrypt.cipher-alg Name of encryption cipher algorithm
825
-encrypt.cipher-mode Name of encryption cipher mode
826
-encrypt.ivgen-alg Name of IV generator algorithm
827
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
828
-encrypt.hash-alg Name of encryption hash algorithm
829
-encrypt.iter-time Time to spend in PBKDF in milliseconds
830
-cluster_size qcow2 cluster size
831
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
832
-lazy_refcounts Postpone refcount updates
833
-refcount_bits Width of a reference count entry in bits
834
+ backing_file=<str> - File name of a base image
835
+ backing_fmt=<str> - Image format of the base image
836
+ cluster_size=<size> - qcow2 cluster size
837
+ compat=<str> - Compatibility level (0.10 or 1.1)
838
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
839
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
840
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
841
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
842
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
843
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
844
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
845
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
846
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
847
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
848
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
849
+ refcount_bits=<num> - Width of a reference count entry in bits
850
+ size=<size> - Virtual disk size
851
852
Testing: convert -o help
853
Supported options:
854
-size Virtual disk size
855
+ size=<size> - Virtual disk size
856
857
Testing: convert -O bochs -o help
858
qemu-img: Format driver 'bochs' does not support image creation
859
@@ -XXX,XX +XXX,XX @@ cluster_size: 65536
860
861
Testing: amend -f qcow2 -o help TEST_DIR/t.qcow2
862
Creation options for 'qcow2':
863
-size Virtual disk size
864
-compat Compatibility level (0.10 or 1.1)
865
-backing_file File name of a base image
866
-backing_fmt Image format of the base image
867
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
868
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
869
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
870
-encrypt.cipher-alg Name of encryption cipher algorithm
871
-encrypt.cipher-mode Name of encryption cipher mode
872
-encrypt.ivgen-alg Name of IV generator algorithm
873
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
874
-encrypt.hash-alg Name of encryption hash algorithm
875
-encrypt.iter-time Time to spend in PBKDF in milliseconds
876
-cluster_size qcow2 cluster size
877
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
878
-lazy_refcounts Postpone refcount updates
879
-refcount_bits Width of a reference count entry in bits
880
+ backing_file=<str> - File name of a base image
881
+ backing_fmt=<str> - Image format of the base image
882
+ cluster_size=<size> - qcow2 cluster size
883
+ compat=<str> - Compatibility level (0.10 or 1.1)
884
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
885
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
886
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
887
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
888
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
889
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
890
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
891
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
892
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
893
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
894
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
895
+ refcount_bits=<num> - Width of a reference count entry in bits
896
+ size=<size> - Virtual disk size
897
898
Note that not all of these options may be amendable.
899
900
Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2
901
Creation options for 'qcow2':
902
-size Virtual disk size
903
-compat Compatibility level (0.10 or 1.1)
904
-backing_file File name of a base image
905
-backing_fmt Image format of the base image
906
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
907
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
908
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
909
-encrypt.cipher-alg Name of encryption cipher algorithm
910
-encrypt.cipher-mode Name of encryption cipher mode
911
-encrypt.ivgen-alg Name of IV generator algorithm
912
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
913
-encrypt.hash-alg Name of encryption hash algorithm
914
-encrypt.iter-time Time to spend in PBKDF in milliseconds
915
-cluster_size qcow2 cluster size
916
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
917
-lazy_refcounts Postpone refcount updates
918
-refcount_bits Width of a reference count entry in bits
919
+ backing_file=<str> - File name of a base image
920
+ backing_fmt=<str> - Image format of the base image
921
+ cluster_size=<size> - qcow2 cluster size
922
+ compat=<str> - Compatibility level (0.10 or 1.1)
923
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
924
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
925
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
926
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
927
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
928
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
929
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
930
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
931
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
932
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
933
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
934
+ refcount_bits=<num> - Width of a reference count entry in bits
935
+ size=<size> - Virtual disk size
936
937
Note that not all of these options may be amendable.
938
939
Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2
940
Creation options for 'qcow2':
941
-size Virtual disk size
942
-compat Compatibility level (0.10 or 1.1)
943
-backing_file File name of a base image
944
-backing_fmt Image format of the base image
945
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
946
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
947
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
948
-encrypt.cipher-alg Name of encryption cipher algorithm
949
-encrypt.cipher-mode Name of encryption cipher mode
950
-encrypt.ivgen-alg Name of IV generator algorithm
951
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
952
-encrypt.hash-alg Name of encryption hash algorithm
953
-encrypt.iter-time Time to spend in PBKDF in milliseconds
954
-cluster_size qcow2 cluster size
955
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
956
-lazy_refcounts Postpone refcount updates
957
-refcount_bits Width of a reference count entry in bits
958
+ backing_file=<str> - File name of a base image
959
+ backing_fmt=<str> - Image format of the base image
960
+ cluster_size=<size> - qcow2 cluster size
961
+ compat=<str> - Compatibility level (0.10 or 1.1)
962
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
963
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
964
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
965
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
966
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
967
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
968
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
969
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
970
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
971
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
972
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
973
+ refcount_bits=<num> - Width of a reference count entry in bits
974
+ size=<size> - Virtual disk size
975
976
Note that not all of these options may be amendable.
977
978
Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2
979
Creation options for 'qcow2':
980
-size Virtual disk size
981
-compat Compatibility level (0.10 or 1.1)
982
-backing_file File name of a base image
983
-backing_fmt Image format of the base image
984
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
985
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
986
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
987
-encrypt.cipher-alg Name of encryption cipher algorithm
988
-encrypt.cipher-mode Name of encryption cipher mode
989
-encrypt.ivgen-alg Name of IV generator algorithm
990
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
991
-encrypt.hash-alg Name of encryption hash algorithm
992
-encrypt.iter-time Time to spend in PBKDF in milliseconds
993
-cluster_size qcow2 cluster size
994
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
995
-lazy_refcounts Postpone refcount updates
996
-refcount_bits Width of a reference count entry in bits
997
+ backing_file=<str> - File name of a base image
998
+ backing_fmt=<str> - Image format of the base image
999
+ cluster_size=<size> - qcow2 cluster size
1000
+ compat=<str> - Compatibility level (0.10 or 1.1)
1001
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1002
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1003
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1004
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1005
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1006
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1007
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1008
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1009
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1010
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1011
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1012
+ refcount_bits=<num> - Width of a reference count entry in bits
1013
+ size=<size> - Virtual disk size
1014
1015
Note that not all of these options may be amendable.
1016
1017
Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2
1018
Creation options for 'qcow2':
1019
-size Virtual disk size
1020
-compat Compatibility level (0.10 or 1.1)
1021
-backing_file File name of a base image
1022
-backing_fmt Image format of the base image
1023
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1024
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1025
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1026
-encrypt.cipher-alg Name of encryption cipher algorithm
1027
-encrypt.cipher-mode Name of encryption cipher mode
1028
-encrypt.ivgen-alg Name of IV generator algorithm
1029
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1030
-encrypt.hash-alg Name of encryption hash algorithm
1031
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1032
-cluster_size qcow2 cluster size
1033
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1034
-lazy_refcounts Postpone refcount updates
1035
-refcount_bits Width of a reference count entry in bits
1036
+ backing_file=<str> - File name of a base image
1037
+ backing_fmt=<str> - Image format of the base image
1038
+ cluster_size=<size> - qcow2 cluster size
1039
+ compat=<str> - Compatibility level (0.10 or 1.1)
1040
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1041
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1042
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1043
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1044
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1045
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1046
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1047
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1048
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1049
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1050
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1051
+ refcount_bits=<num> - Width of a reference count entry in bits
1052
+ size=<size> - Virtual disk size
1053
1054
Note that not all of these options may be amendable.
1055
1056
Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2
1057
Creation options for 'qcow2':
1058
-size Virtual disk size
1059
-compat Compatibility level (0.10 or 1.1)
1060
-backing_file File name of a base image
1061
-backing_fmt Image format of the base image
1062
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1063
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1064
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1065
-encrypt.cipher-alg Name of encryption cipher algorithm
1066
-encrypt.cipher-mode Name of encryption cipher mode
1067
-encrypt.ivgen-alg Name of IV generator algorithm
1068
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1069
-encrypt.hash-alg Name of encryption hash algorithm
1070
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1071
-cluster_size qcow2 cluster size
1072
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1073
-lazy_refcounts Postpone refcount updates
1074
-refcount_bits Width of a reference count entry in bits
1075
+ backing_file=<str> - File name of a base image
1076
+ backing_fmt=<str> - Image format of the base image
1077
+ cluster_size=<size> - qcow2 cluster size
1078
+ compat=<str> - Compatibility level (0.10 or 1.1)
1079
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1080
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1081
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1082
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1083
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1084
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1085
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1086
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1087
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1088
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1089
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1090
+ refcount_bits=<num> - Width of a reference count entry in bits
1091
+ size=<size> - Virtual disk size
1092
1093
Note that not all of these options may be amendable.
1094
1095
Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2
1096
Creation options for 'qcow2':
1097
-size Virtual disk size
1098
-compat Compatibility level (0.10 or 1.1)
1099
-backing_file File name of a base image
1100
-backing_fmt Image format of the base image
1101
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1102
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1103
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1104
-encrypt.cipher-alg Name of encryption cipher algorithm
1105
-encrypt.cipher-mode Name of encryption cipher mode
1106
-encrypt.ivgen-alg Name of IV generator algorithm
1107
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1108
-encrypt.hash-alg Name of encryption hash algorithm
1109
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1110
-cluster_size qcow2 cluster size
1111
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1112
-lazy_refcounts Postpone refcount updates
1113
-refcount_bits Width of a reference count entry in bits
1114
+ backing_file=<str> - File name of a base image
1115
+ backing_fmt=<str> - Image format of the base image
1116
+ cluster_size=<size> - qcow2 cluster size
1117
+ compat=<str> - Compatibility level (0.10 or 1.1)
1118
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1119
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1120
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1121
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1122
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1123
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1124
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1125
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1126
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1127
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1128
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1129
+ refcount_bits=<num> - Width of a reference count entry in bits
1130
+ size=<size> - Virtual disk size
1131
1132
Note that not all of these options may be amendable.
1133
1134
Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2
1135
Creation options for 'qcow2':
1136
-size Virtual disk size
1137
-compat Compatibility level (0.10 or 1.1)
1138
-backing_file File name of a base image
1139
-backing_fmt Image format of the base image
1140
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1141
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1142
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1143
-encrypt.cipher-alg Name of encryption cipher algorithm
1144
-encrypt.cipher-mode Name of encryption cipher mode
1145
-encrypt.ivgen-alg Name of IV generator algorithm
1146
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1147
-encrypt.hash-alg Name of encryption hash algorithm
1148
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1149
-cluster_size qcow2 cluster size
1150
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1151
-lazy_refcounts Postpone refcount updates
1152
-refcount_bits Width of a reference count entry in bits
1153
+ backing_file=<str> - File name of a base image
1154
+ backing_fmt=<str> - Image format of the base image
1155
+ cluster_size=<size> - qcow2 cluster size
1156
+ compat=<str> - Compatibility level (0.10 or 1.1)
1157
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1158
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1159
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1160
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1161
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1162
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1163
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1164
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1165
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1166
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1167
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1168
+ refcount_bits=<num> - Width of a reference count entry in bits
1169
+ size=<size> - Virtual disk size
1170
1171
Note that not all of these options may be amendable.
1172
1173
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
1174
1175
Testing: amend -f qcow2 -o help
1176
Creation options for 'qcow2':
1177
-size Virtual disk size
1178
-compat Compatibility level (0.10 or 1.1)
1179
-backing_file File name of a base image
1180
-backing_fmt Image format of the base image
1181
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1182
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1183
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1184
-encrypt.cipher-alg Name of encryption cipher algorithm
1185
-encrypt.cipher-mode Name of encryption cipher mode
1186
-encrypt.ivgen-alg Name of IV generator algorithm
1187
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1188
-encrypt.hash-alg Name of encryption hash algorithm
1189
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1190
-cluster_size qcow2 cluster size
1191
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1192
-lazy_refcounts Postpone refcount updates
1193
-refcount_bits Width of a reference count entry in bits
1194
+ backing_file=<str> - File name of a base image
1195
+ backing_fmt=<str> - Image format of the base image
1196
+ cluster_size=<size> - qcow2 cluster size
1197
+ compat=<str> - Compatibility level (0.10 or 1.1)
1198
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1199
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1200
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1201
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1202
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1203
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1204
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1205
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1206
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1207
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1208
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1209
+ refcount_bits=<num> - Width of a reference count entry in bits
1210
+ size=<size> - Virtual disk size
1211
1212
Note that not all of these options may be amendable.
1213
1214
Testing: convert -o help
1215
Supported options:
1216
-size Virtual disk size
1217
+ size=<size> - Virtual disk size
1218
1219
Testing: amend -f bochs -o help
1220
qemu-img: Format driver 'bochs' does not support option amendment
1221
--
152
--
1222
2.19.1
153
2.35.3
1223
1224
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
2
2
3
Just like in qemu_opts_print_help(), print the device name as a caption
3
At the end we ignore failure of bdrv_merge_dirty_bitmap() and report
4
instead of on every single line, indent all options, add angle brackets
4
success. And still set errp. That's wrong.
5
around types, and align the descriptions after 24 characters. Also,
6
separate the descriptions with " - " instead of putting them in
7
parentheses, because that is what we do everywhere else. This does look
8
a bit funny here because basically all bits have the description
9
"on/off", but funny does not mean it is less readable.
10
5
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
12
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
7
Reviewed-by: Nikita Lapshin <nikita.lapshin@virtuozzo.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20220517111206.23585-2-v.sementsov-og@mail.ru>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
11
---
15
qdev-monitor.c | 13 +++++++++++--
12
block/monitor/bitmap-qmp-cmds.c | 5 ++++-
16
1 file changed, 11 insertions(+), 2 deletions(-)
13
1 file changed, 4 insertions(+), 1 deletion(-)
17
14
18
diff --git a/qdev-monitor.c b/qdev-monitor.c
15
diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c
19
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
20
--- a/qdev-monitor.c
17
--- a/block/monitor/bitmap-qmp-cmds.c
21
+++ b/qdev-monitor.c
18
+++ b/block/monitor/bitmap-qmp-cmds.c
22
@@ -XXX,XX +XXX,XX @@ int qdev_device_help(QemuOpts *opts)
19
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
23
goto error;
24
}
20
}
25
21
26
+ if (prop_list) {
22
/* Merge into dst; dst is unchanged on failure. */
27
+ out_printf("%s options:\n", driver);
23
- bdrv_merge_dirty_bitmap(dst, anon, backup, errp);
28
+ } else {
24
+ if (!bdrv_merge_dirty_bitmap(dst, anon, backup, errp)) {
29
+ out_printf("There are no options for %s.\n", driver);
25
+ dst = NULL;
26
+ goto out;
30
+ }
27
+ }
31
for (prop = prop_list; prop; prop = prop->next) {
28
32
- out_printf("%s.%s=%s", driver, prop->value->name, prop->value->type);
29
out:
33
+ int len;
30
bdrv_release_dirty_bitmap(anon);
34
+ out_printf(" %s=<%s>%n", prop->value->name, prop->value->type, &len);
35
if (prop->value->has_description) {
36
- out_printf(" (%s)\n", prop->value->description);
37
+ if (len < 24) {
38
+ out_printf("%*s", 24 - len, "");
39
+ }
40
+ out_printf(" - %s\n", prop->value->description);
41
} else {
42
out_printf("\n");
43
}
44
--
31
--
45
2.19.1
32
2.35.3
46
47
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
We don't need extra bitmap. All we need is to backup the original
4
it might not be actually aligned enough for that pointer type (and
4
bitmap when we do first merge. So, drop extra temporary bitmap and work
5
thus cause a crash on dereference on some host architectures). Newer
5
directly with target and backup.
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
6
9
There are a few places where the in-place swap function is
7
Still to keep old semantics, that on failure target is unchanged and
10
used on something other than a packed struct field; we convert
8
user don't need to restore, we need a local_backup variable and do
11
those anyway, for consistency.
9
restore ourselves on failure path.
12
10
13
This patch was produced with the following spatch script
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
14
(and hand-editing to fold a few resulting overlength lines):
12
Message-Id: <20220517111206.23585-3-v.sementsov-og@mail.ru>
15
13
Reviewed-by: Eric Blake <eblake@redhat.com>
16
@@
17
expression E;
18
@@
19
-be16_to_cpus(&E);
20
+E = be16_to_cpu(E);
21
@@
22
expression E;
23
@@
24
-be32_to_cpus(&E);
25
+E = be32_to_cpu(E);
26
@@
27
expression E;
28
@@
29
-be64_to_cpus(&E);
30
+E = be64_to_cpu(E);
31
@@
32
expression E;
33
@@
34
-cpu_to_be16s(&E);
35
+E = cpu_to_be16(E);
36
@@
37
expression E;
38
@@
39
-cpu_to_be32s(&E);
40
+E = cpu_to_be32(E);
41
@@
42
expression E;
43
@@
44
-cpu_to_be64s(&E);
45
+E = cpu_to_be64(E);
46
47
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
48
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
49
Tested-by: John Snow <jsnow@redhat.com>
50
Reviewed-by: John Snow <jsnow@redhat.com>
51
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
52
---
15
---
53
block/qcow2.c | 64 +++++++++++++++++++++++++++------------------------
16
block/monitor/bitmap-qmp-cmds.c | 41 +++++++++++++++++----------------
54
1 file changed, 34 insertions(+), 30 deletions(-)
17
1 file changed, 21 insertions(+), 20 deletions(-)
55
18
56
diff --git a/block/qcow2.c b/block/qcow2.c
19
diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c
57
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
58
--- a/block/qcow2.c
21
--- a/block/monitor/bitmap-qmp-cmds.c
59
+++ b/block/qcow2.c
22
+++ b/block/monitor/bitmap-qmp-cmds.c
60
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
23
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
61
"pread fail from offset %" PRIu64, offset);
24
HBitmap **backup, Error **errp)
62
return 1;
25
{
26
BlockDriverState *bs;
27
- BdrvDirtyBitmap *dst, *src, *anon;
28
+ BdrvDirtyBitmap *dst, *src;
29
BlockDirtyBitmapOrStrList *lst;
30
+ HBitmap *local_backup = NULL;
31
32
GLOBAL_STATE_CODE();
33
34
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
35
return NULL;
36
}
37
38
- anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst),
39
- NULL, errp);
40
- if (!anon) {
41
- return NULL;
42
- }
43
-
44
for (lst = bms; lst; lst = lst->next) {
45
switch (lst->value->type) {
46
const char *name, *node;
47
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
48
src = bdrv_find_dirty_bitmap(bs, name);
49
if (!src) {
50
error_setg(errp, "Dirty bitmap '%s' not found", name);
51
- dst = NULL;
52
- goto out;
53
+ goto fail;
54
}
55
break;
56
case QTYPE_QDICT:
57
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
58
name = lst->value->u.external.name;
59
src = block_dirty_bitmap_lookup(node, name, NULL, errp);
60
if (!src) {
61
- dst = NULL;
62
- goto out;
63
+ goto fail;
64
}
65
break;
66
default:
67
abort();
63
}
68
}
64
- be32_to_cpus(&ext.magic);
69
65
- be32_to_cpus(&ext.len);
70
- if (!bdrv_merge_dirty_bitmap(anon, src, NULL, errp)) {
66
+ ext.magic = be32_to_cpu(ext.magic);
71
- dst = NULL;
67
+ ext.len = be32_to_cpu(ext.len);
72
- goto out;
68
offset += sizeof(ext);
73
+ /* We do backup only for first merge operation */
69
#ifdef DEBUG_EXT
74
+ if (!bdrv_merge_dirty_bitmap(dst, src,
70
printf("ext.magic = 0x%x\n", ext.magic);
75
+ local_backup ? NULL : &local_backup,
71
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
76
+ errp))
72
"Unable to read CRYPTO header extension");
77
+ {
73
return ret;
78
+ goto fail;
74
}
75
- be64_to_cpus(&s->crypto_header.offset);
76
- be64_to_cpus(&s->crypto_header.length);
77
+ s->crypto_header.offset = be64_to_cpu(s->crypto_header.offset);
78
+ s->crypto_header.length = be64_to_cpu(s->crypto_header.length);
79
80
if ((s->crypto_header.offset % s->cluster_size) != 0) {
81
error_setg(errp, "Encryption header offset '%" PRIu64 "' is "
82
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
83
return -EINVAL;
84
}
85
86
- be32_to_cpus(&bitmaps_ext.nb_bitmaps);
87
- be64_to_cpus(&bitmaps_ext.bitmap_directory_size);
88
- be64_to_cpus(&bitmaps_ext.bitmap_directory_offset);
89
+ bitmaps_ext.nb_bitmaps = be32_to_cpu(bitmaps_ext.nb_bitmaps);
90
+ bitmaps_ext.bitmap_directory_size =
91
+ be64_to_cpu(bitmaps_ext.bitmap_directory_size);
92
+ bitmaps_ext.bitmap_directory_offset =
93
+ be64_to_cpu(bitmaps_ext.bitmap_directory_offset);
94
95
if (bitmaps_ext.nb_bitmaps > QCOW2_MAX_BITMAPS) {
96
error_setg(errp,
97
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
98
error_setg_errno(errp, -ret, "Could not read qcow2 header");
99
goto fail;
100
}
101
- be32_to_cpus(&header.magic);
102
- be32_to_cpus(&header.version);
103
- be64_to_cpus(&header.backing_file_offset);
104
- be32_to_cpus(&header.backing_file_size);
105
- be64_to_cpus(&header.size);
106
- be32_to_cpus(&header.cluster_bits);
107
- be32_to_cpus(&header.crypt_method);
108
- be64_to_cpus(&header.l1_table_offset);
109
- be32_to_cpus(&header.l1_size);
110
- be64_to_cpus(&header.refcount_table_offset);
111
- be32_to_cpus(&header.refcount_table_clusters);
112
- be64_to_cpus(&header.snapshots_offset);
113
- be32_to_cpus(&header.nb_snapshots);
114
+ header.magic = be32_to_cpu(header.magic);
115
+ header.version = be32_to_cpu(header.version);
116
+ header.backing_file_offset = be64_to_cpu(header.backing_file_offset);
117
+ header.backing_file_size = be32_to_cpu(header.backing_file_size);
118
+ header.size = be64_to_cpu(header.size);
119
+ header.cluster_bits = be32_to_cpu(header.cluster_bits);
120
+ header.crypt_method = be32_to_cpu(header.crypt_method);
121
+ header.l1_table_offset = be64_to_cpu(header.l1_table_offset);
122
+ header.l1_size = be32_to_cpu(header.l1_size);
123
+ header.refcount_table_offset = be64_to_cpu(header.refcount_table_offset);
124
+ header.refcount_table_clusters =
125
+ be32_to_cpu(header.refcount_table_clusters);
126
+ header.snapshots_offset = be64_to_cpu(header.snapshots_offset);
127
+ header.nb_snapshots = be32_to_cpu(header.nb_snapshots);
128
129
if (header.magic != QCOW_MAGIC) {
130
error_setg(errp, "Image is not in qcow2 format");
131
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
132
header.refcount_order = 4;
133
header.header_length = 72;
134
} else {
135
- be64_to_cpus(&header.incompatible_features);
136
- be64_to_cpus(&header.compatible_features);
137
- be64_to_cpus(&header.autoclear_features);
138
- be32_to_cpus(&header.refcount_order);
139
- be32_to_cpus(&header.header_length);
140
+ header.incompatible_features =
141
+ be64_to_cpu(header.incompatible_features);
142
+ header.compatible_features = be64_to_cpu(header.compatible_features);
143
+ header.autoclear_features = be64_to_cpu(header.autoclear_features);
144
+ header.refcount_order = be32_to_cpu(header.refcount_order);
145
+ header.header_length = be32_to_cpu(header.header_length);
146
147
if (header.header_length < 104) {
148
error_setg(errp, "qcow2 header too short");
149
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
150
goto fail;
151
}
152
for(i = 0;i < s->l1_size; i++) {
153
- be64_to_cpus(&s->l1_table[i]);
154
+ s->l1_table[i] = be64_to_cpu(s->l1_table[i]);
155
}
79
}
156
}
80
}
157
81
158
@@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs)
82
- /* Merge into dst; dst is unchanged on failure. */
159
83
- if (!bdrv_merge_dirty_bitmap(dst, anon, backup, errp)) {
160
/* Full disk encryption header pointer extension */
84
- dst = NULL;
161
if (s->crypto_header.offset != 0) {
85
- goto out;
162
- cpu_to_be64s(&s->crypto_header.offset);
86
+ if (backup) {
163
- cpu_to_be64s(&s->crypto_header.length);
87
+ *backup = local_backup;
164
+ s->crypto_header.offset = cpu_to_be64(s->crypto_header.offset);
88
+ } else {
165
+ s->crypto_header.length = cpu_to_be64(s->crypto_header.length);
89
+ hbitmap_free(local_backup);
166
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_CRYPTO_HEADER,
90
}
167
&s->crypto_header, sizeof(s->crypto_header),
91
168
buflen);
92
- out:
169
- be64_to_cpus(&s->crypto_header.offset);
93
- bdrv_release_dirty_bitmap(anon);
170
- be64_to_cpus(&s->crypto_header.length);
94
return dst;
171
+ s->crypto_header.offset = be64_to_cpu(s->crypto_header.offset);
95
+
172
+ s->crypto_header.length = be64_to_cpu(s->crypto_header.length);
96
+fail:
173
if (ret < 0) {
97
+ if (local_backup) {
174
goto fail;
98
+ bdrv_restore_dirty_bitmap(dst, local_backup);
175
}
99
+ }
100
+
101
+ return NULL;
102
}
103
104
void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
176
--
105
--
177
2.19.1
106
2.35.3
178
179
diff view generated by jsdifflib
1
If a management application builds the block graph node by node, the
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
2
protocol layer doesn't inherit its read-only option from the format
2
3
layer any more, so it must be set explicitly.
3
We have too much logic to simply check that bitmaps are of the same
4
4
size. Let's just define that hbitmap_merge() and
5
Backing files should work on read-only storage, but at the same time, a
5
bdrv_dirty_bitmap_merge_internal() require their argument bitmaps be of
6
block job like commit should be able to reopen them read-write if they
6
same size, this simplifies things.
7
are on read-write storage. However, without option inheritance, reopen
7
8
only changes the read-only option for the root node (typically the
8
Let's look through the callers:
9
format layer), but not the protocol layer, so reopening fails (the
9
10
format layer wants to get write permissions, but the protocol layer is
10
For backup_init_bcs_bitmap() we already assert that merge can't fail.
11
still read-only).
11
12
12
In bdrv_reclaim_dirty_bitmap_locked() we gracefully handle the error
13
A simple workaround for the problem in the management tool would be to
13
that can't happen: successor always has same size as its parent, drop
14
open the protocol layer always read-write and to make only the format
14
this logic.
15
layer read-only for backing files. However, sometimes the file is
15
16
actually stored on read-only storage and we don't know whether the image
16
In bdrv_merge_dirty_bitmap() we already has assertion and separate
17
can be opened read-write (for example, for NBD it depends on the server
17
check. Make the check explicit and improve error message.
18
we're trying to connect to). This adds an option that makes QEMU try to
18
19
open the image read-write, but allows it to degrade to a read-only mode
19
Signed-off-by: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
20
without returning an error.
20
Reviewed-by: Nikita Lapshin <nikita.lapshin@virtuozzo.com>
21
21
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
22
The documentation for this option is consciously phrased in a way that
22
Message-Id: <20220517111206.23585-4-v.sementsov-og@mail.ru>
23
allows QEMU to switch to a better model eventually: Instead of trying
24
when the image is first opened, making the read-only flag dynamic and
25
changing it automatically whenever the first BLK_PERM_WRITE user is
26
attached or the last one is detached would be much more useful
27
behaviour.
28
29
Unfortunately, this more useful behaviour is also a lot harder to
30
implement, and libvirt needs a solution now before it can switch to
31
-blockdev, so let's start with this easier approach for now.
32
33
Instead of adding a new auto-read-only option, turning the existing
34
read-only into an enum (with a bool alternate for compatibility) was
35
considered, but it complicated the implementation to the point that it
36
didn't seem to be worth it.
37
38
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
39
Reviewed-by: Eric Blake <eblake@redhat.com>
40
---
24
---
41
qapi/block-core.json | 7 +++++++
25
include/block/block_int-io.h | 2 +-
42
include/block/block.h | 2 ++
26
include/qemu/hbitmap.h | 15 ++-------------
43
block.c | 17 +++++++++++++++++
27
block/backup.c | 6 ++----
44
block/vvfat.c | 1 +
28
block/dirty-bitmap.c | 26 +++++++++++---------------
45
blockdev.c | 2 +-
29
util/hbitmap.c | 25 +++++++------------------
46
5 files changed, 28 insertions(+), 1 deletion(-)
30
5 files changed, 23 insertions(+), 51 deletions(-)
47
31
48
diff --git a/qapi/block-core.json b/qapi/block-core.json
32
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
49
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
50
--- a/qapi/block-core.json
34
--- a/include/block/block_int-io.h
51
+++ b/qapi/block-core.json
35
+++ b/include/block/block_int-io.h
52
@@ -XXX,XX +XXX,XX @@
36
@@ -XXX,XX +XXX,XX @@ bool blk_dev_is_tray_open(BlockBackend *blk);
53
# either generally or in certain configurations. In this case,
37
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
54
# the default value does not work and the option must be
38
55
# specified explicitly.
39
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
56
+# @auto-read-only: if true and @read-only is false, QEMU may automatically
40
-bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
57
+# decide not to open the image read-write as requested, but
41
+void bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
58
+# fall back to read-only instead (and switch between the modes
42
const BdrvDirtyBitmap *src,
59
+# later), e.g. depending on whether the image file is writable
43
HBitmap **backup, bool lock);
60
+# or whether a writing user is attached to the node
44
61
+# (default: false, since 3.1)
45
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
62
# @detect-zeroes: detect and optimize zero writes (Since 2.1)
46
index XXXXXXX..XXXXXXX 100644
63
# (default: off)
47
--- a/include/qemu/hbitmap.h
64
# @force-share: force share all permission on added nodes.
48
+++ b/include/qemu/hbitmap.h
65
@@ -XXX,XX +XXX,XX @@
49
@@ -XXX,XX +XXX,XX @@ void hbitmap_truncate(HBitmap *hb, uint64_t size);
66
'*discard': 'BlockdevDiscardOptions',
50
*
67
'*cache': 'BlockdevCacheOptions',
51
* Store result of merging @a and @b into @result.
68
'*read-only': 'bool',
52
* @result is allowed to be equal to @a or @b.
69
+ '*auto-read-only': 'bool',
53
- *
70
'*force-share': 'bool',
54
- * Return true if the merge was successful,
71
'*detect-zeroes': 'BlockdevDetectZeroesOptions' },
55
- * false if it was not attempted.
72
'discriminator': 'driver',
56
- */
73
diff --git a/include/block/block.h b/include/block/block.h
57
-bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result);
74
index XXXXXXX..XXXXXXX 100644
58
-
75
--- a/include/block/block.h
59
-/**
76
+++ b/include/block/block.h
60
- * hbitmap_can_merge:
77
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
61
- *
78
select an appropriate protocol driver,
62
- * hbitmap_can_merge(a, b) && hbitmap_can_merge(a, result) is sufficient and
79
ignoring the format layer */
63
- * necessary for hbitmap_merge will not fail.
80
#define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */
64
- *
81
+#define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening read-write fails */
65
+ * All bitmaps must have same size.
82
66
*/
83
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)
67
-bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b);
84
68
+void hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result);
85
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
69
86
#define BDRV_OPT_CACHE_DIRECT "cache.direct"
70
/**
87
#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
71
* hbitmap_empty:
88
#define BDRV_OPT_READ_ONLY "read-only"
72
diff --git a/block/backup.c b/block/backup.c
89
+#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only"
73
index XXXXXXX..XXXXXXX 100644
90
#define BDRV_OPT_DISCARD "discard"
74
--- a/block/backup.c
91
#define BDRV_OPT_FORCE_SHARE "force-share"
75
+++ b/block/backup.c
92
76
@@ -XXX,XX +XXX,XX @@ out:
93
diff --git a/block.c b/block.c
77
94
index XXXXXXX..XXXXXXX 100644
78
static void backup_init_bcs_bitmap(BackupBlockJob *job)
95
--- a/block.c
79
{
96
+++ b/block.c
80
- bool ret;
97
@@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
81
uint64_t estimate;
98
82
BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
99
/* Inherit the read-only option from the parent if it's not set */
83
100
qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
84
if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
101
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY);
85
bdrv_clear_dirty_bitmap(bcs_bitmap, NULL);
102
86
- ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap,
103
/* Our block drivers take care to send flushes and respect unmap policy,
87
- NULL, true);
104
* so we can default to enable both on lower layers regardless of the
88
- assert(ret);
105
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
89
+ bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap, NULL,
106
90
+ true);
107
/* backing files always opened read-only */
91
} else if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
108
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
92
/*
109
+ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
93
* We can't hog the coroutine to initialize this thoroughly.
110
flags &= ~BDRV_O_COPY_ON_READ;
94
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
111
95
index XXXXXXX..XXXXXXX 100644
112
/* snapshot=on is handled on the top layer */
96
--- a/block/dirty-bitmap.c
113
@@ -XXX,XX +XXX,XX @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
97
+++ b/block/dirty-bitmap.c
114
*flags |= BDRV_O_RDWR;
98
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BdrvDirtyBitmap *parent,
115
}
99
return NULL;
116
100
}
117
+ assert(qemu_opt_find(opts, BDRV_OPT_AUTO_READ_ONLY));
101
118
+ if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
102
- if (!hbitmap_merge(parent->bitmap, successor->bitmap, parent->bitmap)) {
119
+ *flags |= BDRV_O_AUTO_RDONLY;
103
- error_setg(errp, "Merging of parent and successor bitmap failed");
120
+ }
104
- return NULL;
105
- }
106
+ hbitmap_merge(parent->bitmap, successor->bitmap, parent->bitmap);
107
108
parent->disabled = successor->disabled;
109
parent->busy = false;
110
@@ -XXX,XX +XXX,XX @@ bool bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
111
goto out;
112
}
113
114
- if (!hbitmap_can_merge(dest->bitmap, src->bitmap)) {
115
- error_setg(errp, "Bitmaps are incompatible and can't be merged");
116
+ if (bdrv_dirty_bitmap_size(src) != bdrv_dirty_bitmap_size(dest)) {
117
+ error_setg(errp, "Bitmaps are of different sizes (destination size is %"
118
+ PRId64 ", source size is %" PRId64 ") and can't be merged",
119
+ bdrv_dirty_bitmap_size(dest), bdrv_dirty_bitmap_size(src));
120
goto out;
121
}
122
123
- ret = bdrv_dirty_bitmap_merge_internal(dest, src, backup, false);
124
- assert(ret);
125
+ bdrv_dirty_bitmap_merge_internal(dest, src, backup, false);
126
+ ret = true;
127
128
out:
129
bdrv_dirty_bitmaps_unlock(dest->bs);
130
@@ -XXX,XX +XXX,XX @@ out:
131
/**
132
* bdrv_dirty_bitmap_merge_internal: merge src into dest.
133
* Does NOT check bitmap permissions; not suitable for use as public API.
134
+ * @dest, @src and @backup (if not NULL) must have same size.
135
*
136
* @backup: If provided, make a copy of dest here prior to merge.
137
* @lock: If true, lock and unlock bitmaps on the way in/out.
138
- * returns true if the merge succeeded; false if unattempted.
139
*/
140
-bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
141
+void bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
142
const BdrvDirtyBitmap *src,
143
HBitmap **backup,
144
bool lock)
145
{
146
- bool ret;
147
IO_CODE();
148
149
assert(!bdrv_dirty_bitmap_readonly(dest));
150
@@ -XXX,XX +XXX,XX @@ bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
151
if (backup) {
152
*backup = dest->bitmap;
153
dest->bitmap = hbitmap_alloc(dest->size, hbitmap_granularity(*backup));
154
- ret = hbitmap_merge(*backup, src->bitmap, dest->bitmap);
155
+ hbitmap_merge(*backup, src->bitmap, dest->bitmap);
156
} else {
157
- ret = hbitmap_merge(dest->bitmap, src->bitmap, dest->bitmap);
158
+ hbitmap_merge(dest->bitmap, src->bitmap, dest->bitmap);
159
}
160
161
if (lock) {
162
@@ -XXX,XX +XXX,XX @@ bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
163
bdrv_dirty_bitmaps_unlock(src->bs);
164
}
165
}
166
-
167
- return ret;
121
}
168
}
122
169
diff --git a/util/hbitmap.c b/util/hbitmap.c
123
static void update_options_from_flags(QDict *options, int flags)
170
index XXXXXXX..XXXXXXX 100644
124
@@ -XXX,XX +XXX,XX @@ static void update_options_from_flags(QDict *options, int flags)
171
--- a/util/hbitmap.c
125
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
172
+++ b/util/hbitmap.c
126
qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
173
@@ -XXX,XX +XXX,XX @@ void hbitmap_truncate(HBitmap *hb, uint64_t size)
127
}
174
}
128
+ if (!qdict_haskey(options, BDRV_OPT_AUTO_READ_ONLY)) {
129
+ qdict_put_bool(options, BDRV_OPT_AUTO_READ_ONLY,
130
+ flags & BDRV_O_AUTO_RDONLY);
131
+ }
132
}
175
}
133
176
134
static void bdrv_assign_node_name(BlockDriverState *bs,
177
-bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b)
135
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
178
-{
136
.type = QEMU_OPT_BOOL,
179
- return (a->orig_size == b->orig_size);
137
.help = "Node is opened in read-only mode",
180
-}
138
},
181
-
139
+ {
182
/**
140
+ .name = BDRV_OPT_AUTO_READ_ONLY,
183
* hbitmap_sparse_merge: performs dst = dst | src
141
+ .type = QEMU_OPT_BOOL,
184
* works with differing granularities.
142
+ .help = "Node can become read-only if opening read-write fails",
185
@@ -XXX,XX +XXX,XX @@ static void hbitmap_sparse_merge(HBitmap *dst, const HBitmap *src)
143
+ },
186
* Given HBitmaps A and B, let R := A (BITOR) B.
144
{
187
* Bitmaps A and B will not be modified,
145
.name = "detect-zeroes",
188
* except when bitmap R is an alias of A or B.
146
.type = QEMU_OPT_STRING,
189
- *
147
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
190
- * @return true if the merge was successful,
148
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
191
- * false if it was not attempted.
149
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
192
+ * Bitmaps must have same size.
150
qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
193
*/
151
+ qdict_set_default_str(qdict, BDRV_OPT_AUTO_READ_ONLY, "off");
194
-bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result)
152
+
195
+void hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result)
153
}
154
155
bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
156
diff --git a/block/vvfat.c b/block/vvfat.c
157
index XXXXXXX..XXXXXXX 100644
158
--- a/block/vvfat.c
159
+++ b/block/vvfat.c
160
@@ -XXX,XX +XXX,XX @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options,
161
int parent_flags, QDict *parent_options)
162
{
196
{
163
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
197
int i;
164
+ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
198
uint64_t j;
165
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
199
200
- if (!hbitmap_can_merge(a, b) || !hbitmap_can_merge(a, result)) {
201
- return false;
202
- }
203
- assert(hbitmap_can_merge(b, result));
204
+ assert(a->orig_size == result->orig_size);
205
+ assert(b->orig_size == result->orig_size);
206
207
if ((!hbitmap_count(a) && result == b) ||
208
(!hbitmap_count(b) && result == a)) {
209
- return true;
210
+ return;
211
}
212
213
if (!hbitmap_count(a) && !hbitmap_count(b)) {
214
hbitmap_reset_all(result);
215
- return true;
216
+ return;
217
}
218
219
if (a->granularity != b->granularity) {
220
@@ -XXX,XX +XXX,XX @@ bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result)
221
if (b != result) {
222
hbitmap_sparse_merge(result, b);
223
}
224
- return true;
225
+ return;
226
}
227
228
/* This merge is O(size), as BITS_PER_LONG and HBITMAP_LEVELS are constant.
229
@@ -XXX,XX +XXX,XX @@ bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result)
230
231
/* Recompute the dirty count */
232
result->count = hb_count_between(result, 0, result->size - 1);
233
-
234
- return true;
166
}
235
}
167
236
168
diff --git a/blockdev.c b/blockdev.c
237
char *hbitmap_sha256(const HBitmap *bitmap, Error **errp)
169
index XXXXXXX..XXXXXXX 100644
170
--- a/blockdev.c
171
+++ b/blockdev.c
172
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
173
174
bdrv_flags = blk_get_open_flags_from_root_state(blk);
175
bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
176
- BDRV_O_PROTOCOL);
177
+ BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
178
179
if (!has_read_only) {
180
read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
181
--
238
--
182
2.19.1
239
2.35.3
183
184
diff view generated by jsdifflib
1
From: Li Qiang <liq3ea@163.com>
1
From: Xie Yongji <xieyongji@bytedance.com>
2
2
3
Signed-off-by: Li Qiang <liq3ea@163.com>
3
This supports passing NULL ops to blk_set_dev_ops()
4
Reviewed-by: Alberto Garcia <berto@igalia.com>
4
so that we can remove stale ops in some cases.
5
6
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20220523084611.91-2-xieyongji@bytedance.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
10
---
7
include/sysemu/block-backend.h | 6 +++---
11
block/block-backend.c | 2 +-
8
block/block-backend.c | 8 ++++----
12
1 file changed, 1 insertion(+), 1 deletion(-)
9
2 files changed, 7 insertions(+), 7 deletions(-)
10
13
11
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
12
index XXXXXXX..XXXXXXX 100644
13
--- a/include/sysemu/block-backend.h
14
+++ b/include/sysemu/block-backend.h
15
@@ -XXX,XX +XXX,XX @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
16
int error);
17
void blk_error_action(BlockBackend *blk, BlockErrorAction action,
18
bool is_read, int error);
19
-int blk_is_read_only(BlockBackend *blk);
20
-int blk_is_sg(BlockBackend *blk);
21
-int blk_enable_write_cache(BlockBackend *blk);
22
+bool blk_is_read_only(BlockBackend *blk);
23
+bool blk_is_sg(BlockBackend *blk);
24
+bool blk_enable_write_cache(BlockBackend *blk);
25
void blk_set_enable_write_cache(BlockBackend *blk, bool wce);
26
void blk_invalidate_cache(BlockBackend *blk, Error **errp);
27
bool blk_is_inserted(BlockBackend *blk);
28
diff --git a/block/block-backend.c b/block/block-backend.c
14
diff --git a/block/block-backend.c b/block/block-backend.c
29
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
30
--- a/block/block-backend.c
16
--- a/block/block-backend.c
31
+++ b/block/block-backend.c
17
+++ b/block/block-backend.c
32
@@ -XXX,XX +XXX,XX @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
18
@@ -XXX,XX +XXX,XX @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
19
blk->dev_opaque = opaque;
20
21
/* Are we currently quiesced? Should we enforce this right now? */
22
- if (blk->quiesce_counter && ops->drained_begin) {
23
+ if (blk->quiesce_counter && ops && ops->drained_begin) {
24
ops->drained_begin(opaque);
33
}
25
}
34
}
26
}
35
36
-int blk_is_read_only(BlockBackend *blk)
37
+bool blk_is_read_only(BlockBackend *blk)
38
{
39
BlockDriverState *bs = blk_bs(blk);
40
41
@@ -XXX,XX +XXX,XX @@ int blk_is_read_only(BlockBackend *blk)
42
}
43
}
44
45
-int blk_is_sg(BlockBackend *blk)
46
+bool blk_is_sg(BlockBackend *blk)
47
{
48
BlockDriverState *bs = blk_bs(blk);
49
50
if (!bs) {
51
- return 0;
52
+ return false;
53
}
54
55
return bdrv_is_sg(bs);
56
}
57
58
-int blk_enable_write_cache(BlockBackend *blk)
59
+bool blk_enable_write_cache(BlockBackend *blk)
60
{
61
return blk->enable_write_cache;
62
}
63
--
27
--
64
2.19.1
28
2.35.3
65
66
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Xie Yongji <xieyongji@bytedance.com>
2
2
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
3
Now the req->size is set to the correct value only
4
when handling VIRTIO_BLK_T_GET_ID request. This patch
5
fixes it.
6
7
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
8
Message-Id: <20220523084611.91-3-xieyongji@bytedance.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
11
---
6
block.c | 6 +++---
12
block/export/vhost-user-blk-server.c | 5 ++---
7
1 file changed, 3 insertions(+), 3 deletions(-)
13
1 file changed, 2 insertions(+), 3 deletions(-)
8
14
9
diff --git a/block.c b/block.c
15
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
10
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
11
--- a/block.c
17
--- a/block/export/vhost-user-blk-server.c
12
+++ b/block.c
18
+++ b/block/export/vhost-user-blk-server.c
13
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
19
@@ -XXX,XX +XXX,XX @@ static void vu_blk_req_complete(VuBlkReq *req)
14
.help = "try to optimize zero writes (off, on, unmap)",
20
{
15
},
21
VuDev *vu_dev = &req->server->vu_dev;
16
{
22
17
- .name = "discard",
23
- /* IO size with 1 extra status byte */
18
+ .name = BDRV_OPT_DISCARD,
24
- vu_queue_push(vu_dev, req->vq, &req->elem, req->size + 1);
19
.type = QEMU_OPT_STRING,
25
+ vu_queue_push(vu_dev, req->vq, &req->elem, req->size);
20
.help = "discard operation (ignore/off, unmap/on)",
26
vu_queue_notify(vu_dev, req->vq);
21
},
27
22
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
28
free(req);
23
}
29
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
30
goto err;
24
}
31
}
25
32
26
- discard = qemu_opt_get(opts, "discard");
33
+ req->size = iov_size(in_iov, in_num);
27
+ discard = qemu_opt_get(opts, BDRV_OPT_DISCARD);
34
/* We always touch the last byte, so just see how big in_iov is. */
28
if (discard != NULL) {
35
req->in = (void *)in_iov[in_num - 1].iov_base
29
if (bdrv_parse_discard_flags(discard, &bs->open_flags) != 0) {
36
+ in_iov[in_num - 1].iov_len
30
error_setg(errp, "Invalid discard option");
37
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
31
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
38
VIRTIO_BLK_ID_BYTES);
32
39
snprintf(elem->in_sg[0].iov_base, size, "%s", "vhost_user_blk");
33
update_flags_from_options(&reopen_state->flags, opts);
40
req->in->status = VIRTIO_BLK_S_OK;
34
41
- req->size = elem->in_sg[0].iov_len;
35
- discard = qemu_opt_get_del(opts, "discard");
42
break;
36
+ discard = qemu_opt_get_del(opts, BDRV_OPT_DISCARD);
43
}
37
if (discard != NULL) {
44
case VIRTIO_BLK_T_DISCARD:
38
if (bdrv_parse_discard_flags(discard, &reopen_state->flags) != 0) {
39
error_setg(errp, "Invalid discard option");
40
--
45
--
41
2.19.1
46
2.35.3
42
43
diff view generated by jsdifflib
1
Some block drivers have traditionally changed their node to read-only
1
From: Xie Yongji <xieyongji@bytedance.com>
2
mode without asking the user. This behaviour has been marked deprecated
3
since 2.11, expecting users to provide an explicit read-only=on option.
4
2
5
Now that we have auto-read-only=on, enable these drivers to make use of
3
Abstract the common logic of virtio-blk I/O process to a function
6
the option.
4
named virtio_blk_process_req(). It's needed for the following commit.
7
5
8
This is the only use of bdrv_set_read_only(), so we can make it a bit
6
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
9
more specific and turn it into a bdrv_apply_auto_read_only() that is
7
Message-Id: <20220523084611.91-4-xieyongji@bytedance.com>
10
more convenient for drivers to use.
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block/export/virtio-blk-handler.h | 37 ++++
12
block/export/vhost-user-blk-server.c | 259 +++------------------------
13
block/export/virtio-blk-handler.c | 240 +++++++++++++++++++++++++
14
MAINTAINERS | 2 +
15
block/export/meson.build | 2 +-
16
5 files changed, 301 insertions(+), 239 deletions(-)
17
create mode 100644 block/export/virtio-blk-handler.h
18
create mode 100644 block/export/virtio-blk-handler.c
11
19
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
diff --git a/block/export/virtio-blk-handler.h b/block/export/virtio-blk-handler.h
13
Reviewed-by: Eric Blake <eblake@redhat.com>
21
new file mode 100644
14
---
22
index XXXXXXX..XXXXXXX
15
include/block/block.h | 3 ++-
23
--- /dev/null
16
block.c | 42 +++++++++++++++++++++++++++---------------
24
+++ b/block/export/virtio-blk-handler.h
17
block/bochs.c | 17 ++++++-----------
25
@@ -XXX,XX +XXX,XX @@
18
block/cloop.c | 16 +++++-----------
26
+/*
19
block/dmg.c | 16 +++++-----------
27
+ * Handler for virtio-blk I/O
20
block/rbd.c | 15 ++++-----------
28
+ *
21
block/vvfat.c | 10 ++--------
29
+ * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved.
22
7 files changed, 51 insertions(+), 68 deletions(-)
30
+ *
23
31
+ * Author:
24
diff --git a/include/block/block.h b/include/block/block.h
32
+ * Xie Yongji <xieyongji@bytedance.com>
33
+ *
34
+ * This work is licensed under the terms of the GNU GPL, version 2 or
35
+ * later. See the COPYING file in the top-level directory.
36
+ */
37
+
38
+#ifndef VIRTIO_BLK_HANDLER_H
39
+#define VIRTIO_BLK_HANDLER_H
40
+
41
+#include "sysemu/block-backend.h"
42
+
43
+#define VIRTIO_BLK_SECTOR_BITS 9
44
+#define VIRTIO_BLK_SECTOR_SIZE (1ULL << VIRTIO_BLK_SECTOR_BITS)
45
+
46
+#define VIRTIO_BLK_MAX_DISCARD_SECTORS 32768
47
+#define VIRTIO_BLK_MAX_WRITE_ZEROES_SECTORS 32768
48
+
49
+typedef struct {
50
+ BlockBackend *blk;
51
+ const char *serial;
52
+ uint32_t logical_block_size;
53
+ bool writable;
54
+} VirtioBlkHandler;
55
+
56
+int coroutine_fn virtio_blk_process_req(VirtioBlkHandler *handler,
57
+ struct iovec *in_iov,
58
+ struct iovec *out_iov,
59
+ unsigned int in_num,
60
+ unsigned int out_num);
61
+
62
+#endif /* VIRTIO_BLK_HANDLER_H */
63
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
25
index XXXXXXX..XXXXXXX 100644
64
index XXXXXXX..XXXXXXX 100644
26
--- a/include/block/block.h
65
--- a/block/export/vhost-user-blk-server.c
27
+++ b/include/block/block.h
66
+++ b/block/export/vhost-user-blk-server.c
28
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
67
@@ -XXX,XX +XXX,XX @@
29
bool bdrv_is_read_only(BlockDriverState *bs);
68
#include "vhost-user-blk-server.h"
30
int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
69
#include "qapi/error.h"
31
bool ignore_allow_rdw, Error **errp);
70
#include "qom/object_interfaces.h"
32
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
71
-#include "sysemu/block-backend.h"
33
+int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
72
#include "util/block-helpers.h"
34
+ Error **errp);
73
-
35
bool bdrv_is_writable(BlockDriverState *bs);
74
-/*
36
bool bdrv_is_sg(BlockDriverState *bs);
75
- * Sector units are 512 bytes regardless of the
37
bool bdrv_is_inserted(BlockDriverState *bs);
76
- * virtio_blk_config->blk_size value.
38
diff --git a/block.c b/block.c
77
- */
39
index XXXXXXX..XXXXXXX 100644
78
-#define VIRTIO_BLK_SECTOR_BITS 9
40
--- a/block.c
79
-#define VIRTIO_BLK_SECTOR_SIZE (1ull << VIRTIO_BLK_SECTOR_BITS)
41
+++ b/block.c
80
+#include "virtio-blk-handler.h"
42
@@ -XXX,XX +XXX,XX @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
81
43
return 0;
82
enum {
83
VHOST_USER_BLK_NUM_QUEUES_DEFAULT = 1,
84
- VHOST_USER_BLK_MAX_DISCARD_SECTORS = 32768,
85
- VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS = 32768,
86
-};
87
-struct virtio_blk_inhdr {
88
- unsigned char status;
89
};
90
91
typedef struct VuBlkReq {
92
VuVirtqElement elem;
93
- int64_t sector_num;
94
- size_t size;
95
- struct virtio_blk_inhdr *in;
96
- struct virtio_blk_outhdr out;
97
VuServer *server;
98
struct VuVirtq *vq;
99
} VuBlkReq;
100
@@ -XXX,XX +XXX,XX @@ typedef struct VuBlkReq {
101
typedef struct {
102
BlockExport export;
103
VuServer vu_server;
104
- uint32_t blk_size;
105
+ VirtioBlkHandler handler;
106
QIOChannelSocket *sioc;
107
struct virtio_blk_config blkcfg;
108
- bool writable;
109
} VuBlkExport;
110
111
-static void vu_blk_req_complete(VuBlkReq *req)
112
+static void vu_blk_req_complete(VuBlkReq *req, size_t in_len)
113
{
114
VuDev *vu_dev = &req->server->vu_dev;
115
116
- vu_queue_push(vu_dev, req->vq, &req->elem, req->size);
117
+ vu_queue_push(vu_dev, req->vq, &req->elem, in_len);
118
vu_queue_notify(vu_dev, req->vq);
119
120
free(req);
44
}
121
}
45
122
46
-/* TODO Remove (deprecated since 2.11)
123
-static bool vu_blk_sect_range_ok(VuBlkExport *vexp, uint64_t sector,
47
- * Block drivers are not supposed to automatically change bs->read_only.
124
- size_t size)
48
- * Instead, they should just check whether they can provide what the user
125
-{
49
- * explicitly requested and error out if read-write is requested, but they can
126
- uint64_t nb_sectors;
50
- * only provide read-only access. */
127
- uint64_t total_sectors;
51
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
128
-
52
+/*
129
- if (size % VIRTIO_BLK_SECTOR_SIZE) {
53
+ * Called by a driver that can only provide a read-only image.
130
- return false;
54
+ *
131
- }
55
+ * Returns 0 if the node is already read-only or it could switch the node to
132
-
56
+ * read-only because BDRV_O_AUTO_RDONLY is set.
133
- nb_sectors = size >> VIRTIO_BLK_SECTOR_BITS;
57
+ *
134
-
58
+ * Returns -EACCES if the node is read-write and BDRV_O_AUTO_RDONLY is not set
135
- QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != VIRTIO_BLK_SECTOR_SIZE);
59
+ * or bdrv_can_set_read_only() forbids making the node read-only. If @errmsg
136
- if (nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
60
+ * is not NULL, it is used as the error message for the Error object.
137
- return false;
61
+ */
138
- }
62
+int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
139
- if ((sector << VIRTIO_BLK_SECTOR_BITS) % vexp->blk_size) {
63
+ Error **errp)
140
- return false;
141
- }
142
- blk_get_geometry(vexp->export.blk, &total_sectors);
143
- if (sector > total_sectors || nb_sectors > total_sectors - sector) {
144
- return false;
145
- }
146
- return true;
147
-}
148
-
149
-static int coroutine_fn
150
-vu_blk_discard_write_zeroes(VuBlkExport *vexp, struct iovec *iov,
151
- uint32_t iovcnt, uint32_t type)
152
-{
153
- BlockBackend *blk = vexp->export.blk;
154
- struct virtio_blk_discard_write_zeroes desc;
155
- ssize_t size;
156
- uint64_t sector;
157
- uint32_t num_sectors;
158
- uint32_t max_sectors;
159
- uint32_t flags;
160
- int bytes;
161
-
162
- /* Only one desc is currently supported */
163
- if (unlikely(iov_size(iov, iovcnt) > sizeof(desc))) {
164
- return VIRTIO_BLK_S_UNSUPP;
165
- }
166
-
167
- size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc));
168
- if (unlikely(size != sizeof(desc))) {
169
- error_report("Invalid size %zd, expected %zu", size, sizeof(desc));
170
- return VIRTIO_BLK_S_IOERR;
171
- }
172
-
173
- sector = le64_to_cpu(desc.sector);
174
- num_sectors = le32_to_cpu(desc.num_sectors);
175
- flags = le32_to_cpu(desc.flags);
176
- max_sectors = (type == VIRTIO_BLK_T_WRITE_ZEROES) ?
177
- VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS :
178
- VHOST_USER_BLK_MAX_DISCARD_SECTORS;
179
-
180
- /* This check ensures that 'bytes' fits in an int */
181
- if (unlikely(num_sectors > max_sectors)) {
182
- return VIRTIO_BLK_S_IOERR;
183
- }
184
-
185
- bytes = num_sectors << VIRTIO_BLK_SECTOR_BITS;
186
-
187
- if (unlikely(!vu_blk_sect_range_ok(vexp, sector, bytes))) {
188
- return VIRTIO_BLK_S_IOERR;
189
- }
190
-
191
- /*
192
- * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard
193
- * and write zeroes commands if any unknown flag is set.
194
- */
195
- if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
196
- return VIRTIO_BLK_S_UNSUPP;
197
- }
198
-
199
- if (type == VIRTIO_BLK_T_WRITE_ZEROES) {
200
- int blk_flags = 0;
201
-
202
- if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
203
- blk_flags |= BDRV_REQ_MAY_UNMAP;
204
- }
205
-
206
- if (blk_co_pwrite_zeroes(blk, sector << VIRTIO_BLK_SECTOR_BITS,
207
- bytes, blk_flags) == 0) {
208
- return VIRTIO_BLK_S_OK;
209
- }
210
- } else if (type == VIRTIO_BLK_T_DISCARD) {
211
- /*
212
- * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for
213
- * discard commands if the unmap flag is set.
214
- */
215
- if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
216
- return VIRTIO_BLK_S_UNSUPP;
217
- }
218
-
219
- if (blk_co_pdiscard(blk, sector << VIRTIO_BLK_SECTOR_BITS,
220
- bytes) == 0) {
221
- return VIRTIO_BLK_S_OK;
222
- }
223
- }
224
-
225
- return VIRTIO_BLK_S_IOERR;
226
-}
227
-
228
/* Called with server refcount increased, must decrease before returning */
229
static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
64
{
230
{
65
int ret = 0;
231
VuBlkReq *req = opaque;
66
232
VuServer *server = req->server;
67
- ret = bdrv_can_set_read_only(bs, read_only, false, errp);
233
VuVirtqElement *elem = &req->elem;
68
- if (ret < 0) {
234
- uint32_t type;
69
- return ret;
235
-
70
+ if (!(bs->open_flags & BDRV_O_RDWR)) {
236
VuBlkExport *vexp = container_of(server, VuBlkExport, vu_server);
71
+ return 0;
237
- BlockBackend *blk = vexp->export.blk;
72
+ }
238
-
73
+ if (!(bs->open_flags & BDRV_O_AUTO_RDONLY)) {
239
+ VirtioBlkHandler *handler = &vexp->handler;
74
+ goto fail;
240
struct iovec *in_iov = elem->in_sg;
241
struct iovec *out_iov = elem->out_sg;
242
unsigned in_num = elem->in_num;
243
unsigned out_num = elem->out_num;
244
-
245
- /* refer to hw/block/virtio_blk.c */
246
- if (elem->out_num < 1 || elem->in_num < 1) {
247
- error_report("virtio-blk request missing headers");
248
- goto err;
249
- }
250
-
251
- if (unlikely(iov_to_buf(out_iov, out_num, 0, &req->out,
252
- sizeof(req->out)) != sizeof(req->out))) {
253
- error_report("virtio-blk request outhdr too short");
254
- goto err;
255
- }
256
-
257
- iov_discard_front(&out_iov, &out_num, sizeof(req->out));
258
-
259
- if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
260
- error_report("virtio-blk request inhdr too short");
261
- goto err;
262
- }
263
-
264
- req->size = iov_size(in_iov, in_num);
265
- /* We always touch the last byte, so just see how big in_iov is. */
266
- req->in = (void *)in_iov[in_num - 1].iov_base
267
- + in_iov[in_num - 1].iov_len
268
- - sizeof(struct virtio_blk_inhdr);
269
- iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
270
-
271
- type = le32_to_cpu(req->out.type);
272
- switch (type & ~VIRTIO_BLK_T_BARRIER) {
273
- case VIRTIO_BLK_T_IN:
274
- case VIRTIO_BLK_T_OUT: {
275
- QEMUIOVector qiov;
276
- int64_t offset;
277
- ssize_t ret = 0;
278
- bool is_write = type & VIRTIO_BLK_T_OUT;
279
- req->sector_num = le64_to_cpu(req->out.sector);
280
-
281
- if (is_write && !vexp->writable) {
282
- req->in->status = VIRTIO_BLK_S_IOERR;
283
- break;
284
- }
285
-
286
- if (is_write) {
287
- qemu_iovec_init_external(&qiov, out_iov, out_num);
288
- } else {
289
- qemu_iovec_init_external(&qiov, in_iov, in_num);
290
- }
291
-
292
- if (unlikely(!vu_blk_sect_range_ok(vexp,
293
- req->sector_num,
294
- qiov.size))) {
295
- req->in->status = VIRTIO_BLK_S_IOERR;
296
- break;
297
- }
298
-
299
- offset = req->sector_num << VIRTIO_BLK_SECTOR_BITS;
300
-
301
- if (is_write) {
302
- ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0);
303
- } else {
304
- ret = blk_co_preadv(blk, offset, qiov.size, &qiov, 0);
305
- }
306
- if (ret >= 0) {
307
- req->in->status = VIRTIO_BLK_S_OK;
308
- } else {
309
- req->in->status = VIRTIO_BLK_S_IOERR;
310
- }
311
- break;
312
- }
313
- case VIRTIO_BLK_T_FLUSH:
314
- if (blk_co_flush(blk) == 0) {
315
- req->in->status = VIRTIO_BLK_S_OK;
316
- } else {
317
- req->in->status = VIRTIO_BLK_S_IOERR;
318
- }
319
- break;
320
- case VIRTIO_BLK_T_GET_ID: {
321
- size_t size = MIN(iov_size(&elem->in_sg[0], in_num),
322
- VIRTIO_BLK_ID_BYTES);
323
- snprintf(elem->in_sg[0].iov_base, size, "%s", "vhost_user_blk");
324
- req->in->status = VIRTIO_BLK_S_OK;
325
- break;
326
+ int in_len;
327
+
328
+ in_len = virtio_blk_process_req(handler, in_iov, out_iov,
329
+ in_num, out_num);
330
+ if (in_len < 0) {
331
+ free(req);
332
+ vhost_user_server_unref(server);
333
+ return;
75
}
334
}
76
335
- case VIRTIO_BLK_T_DISCARD:
77
- bs->read_only = read_only;
336
- case VIRTIO_BLK_T_WRITE_ZEROES: {
78
-
337
- if (!vexp->writable) {
79
- if (read_only) {
338
- req->in->status = VIRTIO_BLK_S_IOERR;
80
- bs->open_flags &= ~BDRV_O_RDWR;
339
- break;
81
- } else {
340
- }
82
- bs->open_flags |= BDRV_O_RDWR;
341
-
83
+ ret = bdrv_can_set_read_only(bs, true, false, NULL);
342
- req->in->status = vu_blk_discard_write_zeroes(vexp, out_iov, out_num,
84
+ if (ret < 0) {
343
- type);
85
+ goto fail;
344
- break;
345
- }
346
- default:
347
- req->in->status = VIRTIO_BLK_S_UNSUPP;
348
- break;
349
- }
350
-
351
- vu_blk_req_complete(req);
352
- vhost_user_server_unref(server);
353
- return;
354
355
-err:
356
- free(req);
357
+ vu_blk_req_complete(req, in_len);
358
vhost_user_server_unref(server);
359
}
360
361
@@ -XXX,XX +XXX,XX @@ static uint64_t vu_blk_get_features(VuDev *dev)
362
1ull << VIRTIO_RING_F_EVENT_IDX |
363
1ull << VHOST_USER_F_PROTOCOL_FEATURES;
364
365
- if (!vexp->writable) {
366
+ if (!vexp->handler.writable) {
367
features |= 1ull << VIRTIO_BLK_F_RO;
86
}
368
}
87
369
88
+ bs->read_only = true;
370
@@ -XXX,XX +XXX,XX @@ vu_blk_initialize_config(BlockDriverState *bs,
89
+ bs->open_flags &= ~BDRV_O_RDWR;
371
config->opt_io_size = cpu_to_le32(1);
90
+
372
config->num_queues = cpu_to_le16(num_queues);
91
return 0;
373
config->max_discard_sectors =
92
+
374
- cpu_to_le32(VHOST_USER_BLK_MAX_DISCARD_SECTORS);
93
+fail:
375
+ cpu_to_le32(VIRTIO_BLK_MAX_DISCARD_SECTORS);
94
+ error_setg(errp, "%s", errmsg ?: "Image is read-only");
376
config->max_discard_seg = cpu_to_le32(1);
95
+ return -EACCES;
377
config->discard_sector_alignment =
378
cpu_to_le32(blk_size >> VIRTIO_BLK_SECTOR_BITS);
379
config->max_write_zeroes_sectors
380
- = cpu_to_le32(VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS);
381
+ = cpu_to_le32(VIRTIO_BLK_MAX_WRITE_ZEROES_SECTORS);
382
config->max_write_zeroes_seg = cpu_to_le32(1);
96
}
383
}
97
384
98
void bdrv_get_full_backing_filename_from_filename(const char *backed,
385
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
99
diff --git a/block/bochs.c b/block/bochs.c
386
uint64_t logical_block_size;
100
index XXXXXXX..XXXXXXX 100644
387
uint16_t num_queues = VHOST_USER_BLK_NUM_QUEUES_DEFAULT;
101
--- a/block/bochs.c
388
102
+++ b/block/bochs.c
389
- vexp->writable = opts->writable;
103
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
390
vexp->blkcfg.wce = 0;
104
struct bochs_header bochs;
391
105
int ret;
392
if (vu_opts->has_logical_block_size) {
106
393
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
107
+ /* No write support yet */
394
error_propagate(errp, local_err);
108
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
109
+ if (ret < 0) {
110
+ return ret;
111
+ }
112
+
113
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
114
false, errp);
115
if (!bs->file) {
116
return -EINVAL;
395
return -EINVAL;
117
}
396
}
118
397
- vexp->blk_size = logical_block_size;
119
- if (!bdrv_is_read_only(bs)) {
398
120
- error_report("Opening bochs images without an explicit read-only=on "
399
if (vu_opts->has_num_queues) {
121
- "option is deprecated. Future versions will refuse to "
400
num_queues = vu_opts->num_queues;
122
- "open the image instead of automatically marking the "
401
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
123
- "image read-only.");
402
error_setg(errp, "num-queues must be greater than 0");
124
- ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
125
- if (ret < 0) {
126
- return ret;
127
- }
128
- }
129
-
130
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
131
if (ret < 0) {
132
return ret;
133
diff --git a/block/cloop.c b/block/cloop.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/block/cloop.c
136
+++ b/block/cloop.c
137
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
138
uint32_t offsets_size, max_compressed_block_size = 1, i;
139
int ret;
140
141
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
142
+ if (ret < 0) {
143
+ return ret;
144
+ }
145
+
146
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
147
false, errp);
148
if (!bs->file) {
149
return -EINVAL;
403
return -EINVAL;
150
}
404
}
151
405
+ vexp->handler.blk = exp->blk;
152
- if (!bdrv_is_read_only(bs)) {
406
+ vexp->handler.serial = "vhost_user_blk";
153
- error_report("Opening cloop images without an explicit read-only=on "
407
+ vexp->handler.logical_block_size = logical_block_size;
154
- "option is deprecated. Future versions will refuse to "
408
+ vexp->handler.writable = opts->writable;
155
- "open the image instead of automatically marking the "
409
156
- "image read-only.");
410
vu_blk_initialize_config(blk_bs(exp->blk), &vexp->blkcfg,
157
- ret = bdrv_set_read_only(bs, true, errp);
411
logical_block_size, num_queues);
158
- if (ret < 0) {
412
diff --git a/block/export/virtio-blk-handler.c b/block/export/virtio-blk-handler.c
159
- return ret;
413
new file mode 100644
160
- }
414
index XXXXXXX..XXXXXXX
161
- }
415
--- /dev/null
162
-
416
+++ b/block/export/virtio-blk-handler.c
163
/* read header */
417
@@ -XXX,XX +XXX,XX @@
164
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
418
+/*
165
if (ret < 0) {
419
+ * Handler for virtio-blk I/O
166
diff --git a/block/dmg.c b/block/dmg.c
420
+ *
421
+ * Copyright (c) 2020 Red Hat, Inc.
422
+ * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved.
423
+ *
424
+ * Author:
425
+ * Coiby Xu <coiby.xu@gmail.com>
426
+ * Xie Yongji <xieyongji@bytedance.com>
427
+ *
428
+ * This work is licensed under the terms of the GNU GPL, version 2 or
429
+ * later. See the COPYING file in the top-level directory.
430
+ */
431
+
432
+#include "qemu/osdep.h"
433
+#include "qemu/error-report.h"
434
+#include "virtio-blk-handler.h"
435
+
436
+#include "standard-headers/linux/virtio_blk.h"
437
+
438
+struct virtio_blk_inhdr {
439
+ unsigned char status;
440
+};
441
+
442
+static bool virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
443
+ uint64_t sector, size_t size)
444
+{
445
+ uint64_t nb_sectors;
446
+ uint64_t total_sectors;
447
+
448
+ if (size % VIRTIO_BLK_SECTOR_SIZE) {
449
+ return false;
450
+ }
451
+
452
+ nb_sectors = size >> VIRTIO_BLK_SECTOR_BITS;
453
+
454
+ QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != VIRTIO_BLK_SECTOR_SIZE);
455
+ if (nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
456
+ return false;
457
+ }
458
+ if ((sector << VIRTIO_BLK_SECTOR_BITS) % block_size) {
459
+ return false;
460
+ }
461
+ blk_get_geometry(blk, &total_sectors);
462
+ if (sector > total_sectors || nb_sectors > total_sectors - sector) {
463
+ return false;
464
+ }
465
+ return true;
466
+}
467
+
468
+static int coroutine_fn
469
+virtio_blk_discard_write_zeroes(VirtioBlkHandler *handler, struct iovec *iov,
470
+ uint32_t iovcnt, uint32_t type)
471
+{
472
+ BlockBackend *blk = handler->blk;
473
+ struct virtio_blk_discard_write_zeroes desc;
474
+ ssize_t size;
475
+ uint64_t sector;
476
+ uint32_t num_sectors;
477
+ uint32_t max_sectors;
478
+ uint32_t flags;
479
+ int bytes;
480
+
481
+ /* Only one desc is currently supported */
482
+ if (unlikely(iov_size(iov, iovcnt) > sizeof(desc))) {
483
+ return VIRTIO_BLK_S_UNSUPP;
484
+ }
485
+
486
+ size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc));
487
+ if (unlikely(size != sizeof(desc))) {
488
+ error_report("Invalid size %zd, expected %zu", size, sizeof(desc));
489
+ return VIRTIO_BLK_S_IOERR;
490
+ }
491
+
492
+ sector = le64_to_cpu(desc.sector);
493
+ num_sectors = le32_to_cpu(desc.num_sectors);
494
+ flags = le32_to_cpu(desc.flags);
495
+ max_sectors = (type == VIRTIO_BLK_T_WRITE_ZEROES) ?
496
+ VIRTIO_BLK_MAX_WRITE_ZEROES_SECTORS :
497
+ VIRTIO_BLK_MAX_DISCARD_SECTORS;
498
+
499
+ /* This check ensures that 'bytes' fits in an int */
500
+ if (unlikely(num_sectors > max_sectors)) {
501
+ return VIRTIO_BLK_S_IOERR;
502
+ }
503
+
504
+ bytes = num_sectors << VIRTIO_BLK_SECTOR_BITS;
505
+
506
+ if (unlikely(!virtio_blk_sect_range_ok(blk, handler->logical_block_size,
507
+ sector, bytes))) {
508
+ return VIRTIO_BLK_S_IOERR;
509
+ }
510
+
511
+ /*
512
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard
513
+ * and write zeroes commands if any unknown flag is set.
514
+ */
515
+ if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
516
+ return VIRTIO_BLK_S_UNSUPP;
517
+ }
518
+
519
+ if (type == VIRTIO_BLK_T_WRITE_ZEROES) {
520
+ int blk_flags = 0;
521
+
522
+ if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
523
+ blk_flags |= BDRV_REQ_MAY_UNMAP;
524
+ }
525
+
526
+ if (blk_co_pwrite_zeroes(blk, sector << VIRTIO_BLK_SECTOR_BITS,
527
+ bytes, blk_flags) == 0) {
528
+ return VIRTIO_BLK_S_OK;
529
+ }
530
+ } else if (type == VIRTIO_BLK_T_DISCARD) {
531
+ /*
532
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for
533
+ * discard commands if the unmap flag is set.
534
+ */
535
+ if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
536
+ return VIRTIO_BLK_S_UNSUPP;
537
+ }
538
+
539
+ if (blk_co_pdiscard(blk, sector << VIRTIO_BLK_SECTOR_BITS,
540
+ bytes) == 0) {
541
+ return VIRTIO_BLK_S_OK;
542
+ }
543
+ }
544
+
545
+ return VIRTIO_BLK_S_IOERR;
546
+}
547
+
548
+int coroutine_fn virtio_blk_process_req(VirtioBlkHandler *handler,
549
+ struct iovec *in_iov,
550
+ struct iovec *out_iov,
551
+ unsigned int in_num,
552
+ unsigned int out_num)
553
+{
554
+ BlockBackend *blk = handler->blk;
555
+ struct virtio_blk_inhdr *in;
556
+ struct virtio_blk_outhdr out;
557
+ uint32_t type;
558
+ int in_len;
559
+
560
+ if (out_num < 1 || in_num < 1) {
561
+ error_report("virtio-blk request missing headers");
562
+ return -EINVAL;
563
+ }
564
+
565
+ if (unlikely(iov_to_buf(out_iov, out_num, 0, &out,
566
+ sizeof(out)) != sizeof(out))) {
567
+ error_report("virtio-blk request outhdr too short");
568
+ return -EINVAL;
569
+ }
570
+
571
+ iov_discard_front(&out_iov, &out_num, sizeof(out));
572
+
573
+ if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
574
+ error_report("virtio-blk request inhdr too short");
575
+ return -EINVAL;
576
+ }
577
+
578
+ /* We always touch the last byte, so just see how big in_iov is. */
579
+ in_len = iov_size(in_iov, in_num);
580
+ in = (void *)in_iov[in_num - 1].iov_base
581
+ + in_iov[in_num - 1].iov_len
582
+ - sizeof(struct virtio_blk_inhdr);
583
+ iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
584
+
585
+ type = le32_to_cpu(out.type);
586
+ switch (type & ~VIRTIO_BLK_T_BARRIER) {
587
+ case VIRTIO_BLK_T_IN:
588
+ case VIRTIO_BLK_T_OUT: {
589
+ QEMUIOVector qiov;
590
+ int64_t offset;
591
+ ssize_t ret = 0;
592
+ bool is_write = type & VIRTIO_BLK_T_OUT;
593
+ int64_t sector_num = le64_to_cpu(out.sector);
594
+
595
+ if (is_write && !handler->writable) {
596
+ in->status = VIRTIO_BLK_S_IOERR;
597
+ break;
598
+ }
599
+
600
+ if (is_write) {
601
+ qemu_iovec_init_external(&qiov, out_iov, out_num);
602
+ } else {
603
+ qemu_iovec_init_external(&qiov, in_iov, in_num);
604
+ }
605
+
606
+ if (unlikely(!virtio_blk_sect_range_ok(blk,
607
+ handler->logical_block_size,
608
+ sector_num, qiov.size))) {
609
+ in->status = VIRTIO_BLK_S_IOERR;
610
+ break;
611
+ }
612
+
613
+ offset = sector_num << VIRTIO_BLK_SECTOR_BITS;
614
+
615
+ if (is_write) {
616
+ ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0);
617
+ } else {
618
+ ret = blk_co_preadv(blk, offset, qiov.size, &qiov, 0);
619
+ }
620
+ if (ret >= 0) {
621
+ in->status = VIRTIO_BLK_S_OK;
622
+ } else {
623
+ in->status = VIRTIO_BLK_S_IOERR;
624
+ }
625
+ break;
626
+ }
627
+ case VIRTIO_BLK_T_FLUSH:
628
+ if (blk_co_flush(blk) == 0) {
629
+ in->status = VIRTIO_BLK_S_OK;
630
+ } else {
631
+ in->status = VIRTIO_BLK_S_IOERR;
632
+ }
633
+ break;
634
+ case VIRTIO_BLK_T_GET_ID: {
635
+ size_t size = MIN(strlen(handler->serial) + 1,
636
+ MIN(iov_size(in_iov, in_num),
637
+ VIRTIO_BLK_ID_BYTES));
638
+ iov_from_buf(in_iov, in_num, 0, handler->serial, size);
639
+ in->status = VIRTIO_BLK_S_OK;
640
+ break;
641
+ }
642
+ case VIRTIO_BLK_T_DISCARD:
643
+ case VIRTIO_BLK_T_WRITE_ZEROES:
644
+ if (!handler->writable) {
645
+ in->status = VIRTIO_BLK_S_IOERR;
646
+ break;
647
+ }
648
+ in->status = virtio_blk_discard_write_zeroes(handler, out_iov,
649
+ out_num, type);
650
+ break;
651
+ default:
652
+ in->status = VIRTIO_BLK_S_UNSUPP;
653
+ break;
654
+ }
655
+
656
+ return in_len;
657
+}
658
diff --git a/MAINTAINERS b/MAINTAINERS
167
index XXXXXXX..XXXXXXX 100644
659
index XXXXXXX..XXXXXXX 100644
168
--- a/block/dmg.c
660
--- a/MAINTAINERS
169
+++ b/block/dmg.c
661
+++ b/MAINTAINERS
170
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
662
@@ -XXX,XX +XXX,XX @@ M: Coiby Xu <Coiby.Xu@gmail.com>
171
int64_t offset;
663
S: Maintained
172
int ret;
664
F: block/export/vhost-user-blk-server.c
173
665
F: block/export/vhost-user-blk-server.h
174
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
666
+F: block/export/virtio-blk-handler.c
175
+ if (ret < 0) {
667
+F: block/export/virtio-blk-handler.h
176
+ return ret;
668
F: include/qemu/vhost-user-server.h
177
+ }
669
F: tests/qtest/libqos/vhost-user-blk.c
178
+
670
F: tests/qtest/libqos/vhost-user-blk.h
179
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
671
diff --git a/block/export/meson.build b/block/export/meson.build
180
false, errp);
181
if (!bs->file) {
182
return -EINVAL;
183
}
184
185
- if (!bdrv_is_read_only(bs)) {
186
- error_report("Opening dmg images without an explicit read-only=on "
187
- "option is deprecated. Future versions will refuse to "
188
- "open the image instead of automatically marking the "
189
- "image read-only.");
190
- ret = bdrv_set_read_only(bs, true, errp);
191
- if (ret < 0) {
192
- return ret;
193
- }
194
- }
195
-
196
block_module_load_one("dmg-bz2");
197
198
s->n_chunks = 0;
199
diff --git a/block/rbd.c b/block/rbd.c
200
index XXXXXXX..XXXXXXX 100644
672
index XXXXXXX..XXXXXXX 100644
201
--- a/block/rbd.c
673
--- a/block/export/meson.build
202
+++ b/block/rbd.c
674
+++ b/block/export/meson.build
203
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
675
@@ -XXX,XX +XXX,XX @@
204
/* If we are using an rbd snapshot, we must be r/o, otherwise
676
blockdev_ss.add(files('export.c'))
205
* leave as-is */
677
206
if (s->snap != NULL) {
678
if have_vhost_user_blk_server
207
- if (!bdrv_is_read_only(bs)) {
679
- blockdev_ss.add(files('vhost-user-blk-server.c'))
208
- error_report("Opening rbd snapshots without an explicit "
680
+ blockdev_ss.add(files('vhost-user-blk-server.c', 'virtio-blk-handler.c'))
209
- "read-only=on option is deprecated. Future versions "
681
endif
210
- "will refuse to open the image instead of "
682
211
- "automatically marking the image read-only.");
683
blockdev_ss.add(when: fuse, if_true: files('fuse.c'))
212
- r = bdrv_set_read_only(bs, true, &local_err);
213
- if (r < 0) {
214
- rbd_close(s->image);
215
- error_propagate(errp, local_err);
216
- goto failed_open;
217
- }
218
+ r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
219
+ if (r < 0) {
220
+ rbd_close(s->image);
221
+ goto failed_open;
222
}
223
}
224
225
diff --git a/block/vvfat.c b/block/vvfat.c
226
index XXXXXXX..XXXXXXX 100644
227
--- a/block/vvfat.c
228
+++ b/block/vvfat.c
229
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
230
"Unable to set VVFAT to 'rw' when drive is read-only");
231
goto fail;
232
}
233
- } else if (!bdrv_is_read_only(bs)) {
234
- error_report("Opening non-rw vvfat images without an explicit "
235
- "read-only=on option is deprecated. Future versions "
236
- "will refuse to open the image instead of "
237
- "automatically marking the image read-only.");
238
- /* read only is the default for safety */
239
- ret = bdrv_set_read_only(bs, true, &local_err);
240
+ } else {
241
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
242
if (ret < 0) {
243
- error_propagate(errp, local_err);
244
goto fail;
245
}
246
}
247
--
684
--
248
2.19.1
685
2.35.3
249
250
diff view generated by jsdifflib
1
From: Xie Yongji <xieyongji@bytedance.com>
2
3
This adds vduse header to linux headers so that the
4
relevant VDUSE API can be used in subsequent patches.
5
6
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20220523084611.91-5-xieyongji@bytedance.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
---
10
---
4
tests/qemu-iotests/232 | 147 +++++++++++++++++++++++++++++++++++++
11
linux-headers/linux/vduse.h | 306 ++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/232.out | 59 +++++++++++++++
12
scripts/update-linux-headers.sh | 2 +-
6
tests/qemu-iotests/group | 1 +
13
2 files changed, 307 insertions(+), 1 deletion(-)
7
3 files changed, 207 insertions(+)
14
create mode 100644 linux-headers/linux/vduse.h
8
create mode 100755 tests/qemu-iotests/232
9
create mode 100644 tests/qemu-iotests/232.out
10
15
11
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
16
diff --git a/linux-headers/linux/vduse.h b/linux-headers/linux/vduse.h
12
new file mode 100755
13
index XXXXXXX..XXXXXXX
14
--- /dev/null
15
+++ b/tests/qemu-iotests/232
16
@@ -XXX,XX +XXX,XX @@
17
+#!/bin/bash
18
+#
19
+# Test for auto-read-only
20
+#
21
+# Copyright (C) 2018 Red Hat, Inc.
22
+#
23
+# This program is free software; you can redistribute it and/or modify
24
+# it under the terms of the GNU General Public License as published by
25
+# the Free Software Foundation; either version 2 of the License, or
26
+# (at your option) any later version.
27
+#
28
+# This program is distributed in the hope that it will be useful,
29
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
30
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
+# GNU General Public License for more details.
32
+#
33
+# You should have received a copy of the GNU General Public License
34
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+#
36
+
37
+# creator
38
+owner=kwolf@redhat.com
39
+
40
+seq=`basename $0`
41
+echo "QA output created by $seq"
42
+
43
+here=`pwd`
44
+status=1    # failure is the default!
45
+
46
+_cleanup()
47
+{
48
+ _cleanup_test_img
49
+ rm -f $TEST_IMG.snap
50
+}
51
+trap "_cleanup; exit \$status" 0 1 2 3 15
52
+
53
+# get standard environment, filters and checks
54
+. ./common.rc
55
+. ./common.filter
56
+
57
+_supported_fmt generic
58
+_supported_proto file
59
+_supported_os Linux
60
+
61
+function do_run_qemu()
62
+{
63
+ echo Testing: "$@"
64
+ (
65
+ if ! test -t 0; then
66
+ while read cmd; do
67
+ echo $cmd
68
+ done
69
+ fi
70
+ echo quit
71
+ ) | $QEMU -nographic -monitor stdio -nodefaults "$@"
72
+ echo
73
+}
74
+
75
+function run_qemu()
76
+{
77
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp |
78
+ _filter_generated_node_ids | _filter_imgfmt
79
+}
80
+
81
+function run_qemu_info_block()
82
+{
83
+ echo "info block -n" | run_qemu "$@" | grep -e "(file" -e "QEMU_PROG"
84
+}
85
+
86
+size=128M
87
+
88
+_make_test_img $size
89
+
90
+echo
91
+echo "=== -drive with read-write image: read-only/auto-read-only combinations ==="
92
+echo
93
+
94
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off
95
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on
96
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on
97
+echo
98
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=off
99
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=on
100
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off
101
+echo
102
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=off
103
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=on
104
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none
105
+
106
+echo
107
+echo "=== -drive with read-only image: read-only/auto-read-only combinations ==="
108
+echo
109
+
110
+chmod a-w $TEST_IMG
111
+
112
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off
113
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on
114
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on
115
+echo
116
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=off
117
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=on
118
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off
119
+echo
120
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=off
121
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=on
122
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none
123
+
124
+echo
125
+echo "=== -blockdev with read-write image: read-only/auto-read-only combinations ==="
126
+echo
127
+
128
+chmod a+w $TEST_IMG
129
+
130
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=off
131
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=on
132
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on
133
+echo
134
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=off
135
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=on
136
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off
137
+echo
138
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=off
139
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
140
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
141
+
142
+echo
143
+echo "=== -blockdev with read-only image: read-only/auto-read-only combinations ==="
144
+echo
145
+
146
+chmod a-w $TEST_IMG
147
+
148
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=off
149
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=on
150
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on
151
+echo
152
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=off
153
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=on
154
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off
155
+echo
156
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=off
157
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
158
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
159
+
160
+# success, all done
161
+echo "*** done"
162
+rm -f $seq.full
163
+status=0
164
diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out
165
new file mode 100644
17
new file mode 100644
166
index XXXXXXX..XXXXXXX
18
index XXXXXXX..XXXXXXX
167
--- /dev/null
19
--- /dev/null
168
+++ b/tests/qemu-iotests/232.out
20
+++ b/linux-headers/linux/vduse.h
169
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@
170
+QA output created by 232
22
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
171
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
23
+#ifndef _VDUSE_H_
172
+
24
+#define _VDUSE_H_
173
+=== -drive with read-write image: read-only/auto-read-only combinations ===
25
+
174
+
26
+#include <linux/types.h>
175
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
27
+
176
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
28
+#define VDUSE_BASE    0x81
177
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
29
+
178
+
30
+/* The ioctls for control device (/dev/vduse/control) */
179
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
31
+
180
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
32
+#define VDUSE_API_VERSION    0
181
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
33
+
182
+
34
+/*
183
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
35
+ * Get the version of VDUSE API that kernel supported (VDUSE_API_VERSION).
184
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
36
+ * This is used for future extension.
185
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
37
+ */
186
+
38
+#define VDUSE_GET_API_VERSION    _IOR(VDUSE_BASE, 0x00, __u64)
187
+=== -drive with read-only image: read-only/auto-read-only combinations ===
39
+
188
+
40
+/* Set the version of VDUSE API that userspace supported. */
189
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
41
+#define VDUSE_SET_API_VERSION    _IOW(VDUSE_BASE, 0x01, __u64)
190
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
42
+
191
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
43
+/**
192
+
44
+ * struct vduse_dev_config - basic configuration of a VDUSE device
193
+QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
45
+ * @name: VDUSE device name, needs to be NUL terminated
194
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
46
+ * @vendor_id: virtio vendor id
195
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
47
+ * @device_id: virtio device id
196
+
48
+ * @features: virtio features
197
+QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
49
+ * @vq_num: the number of virtqueues
198
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
50
+ * @vq_align: the allocation alignment of virtqueue's metadata
199
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
51
+ * @reserved: for future use, needs to be initialized to zero
200
+
52
+ * @config_size: the size of the configuration space
201
+=== -blockdev with read-write image: read-only/auto-read-only combinations ===
53
+ * @config: the buffer of the configuration space
202
+
54
+ *
203
+node0: TEST_DIR/t.IMGFMT (file, read-only)
55
+ * Structure used by VDUSE_CREATE_DEV ioctl to create VDUSE device.
204
+node0: TEST_DIR/t.IMGFMT (file, read-only)
56
+ */
205
+node0: TEST_DIR/t.IMGFMT (file, read-only)
57
+struct vduse_dev_config {
206
+
58
+#define VDUSE_NAME_MAX    256
207
+node0: TEST_DIR/t.IMGFMT (file)
59
+    char name[VDUSE_NAME_MAX];
208
+node0: TEST_DIR/t.IMGFMT (file)
60
+    __u32 vendor_id;
209
+node0: TEST_DIR/t.IMGFMT (file)
61
+    __u32 device_id;
210
+
62
+    __u64 features;
211
+node0: TEST_DIR/t.IMGFMT (file)
63
+    __u32 vq_num;
212
+node0: TEST_DIR/t.IMGFMT (file)
64
+    __u32 vq_align;
213
+node0: TEST_DIR/t.IMGFMT (file)
65
+    __u32 reserved[13];
214
+
66
+    __u32 config_size;
215
+=== -blockdev with read-only image: read-only/auto-read-only combinations ===
67
+    __u8 config[];
216
+
68
+};
217
+node0: TEST_DIR/t.IMGFMT (file, read-only)
69
+
218
+node0: TEST_DIR/t.IMGFMT (file, read-only)
70
+/* Create a VDUSE device which is represented by a char device (/dev/vduse/$NAME) */
219
+node0: TEST_DIR/t.IMGFMT (file, read-only)
71
+#define VDUSE_CREATE_DEV    _IOW(VDUSE_BASE, 0x02, struct vduse_dev_config)
220
+
72
+
221
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
73
+/*
222
+node0: TEST_DIR/t.IMGFMT (file, read-only)
74
+ * Destroy a VDUSE device. Make sure there are no more references
223
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
75
+ * to the char device (/dev/vduse/$NAME).
224
+
76
+ */
225
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
77
+#define VDUSE_DESTROY_DEV    _IOW(VDUSE_BASE, 0x03, char[VDUSE_NAME_MAX])
226
+node0: TEST_DIR/t.IMGFMT (file, read-only)
78
+
227
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
79
+/* The ioctls for VDUSE device (/dev/vduse/$NAME) */
228
+*** done
80
+
229
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
81
+/**
230
index XXXXXXX..XXXXXXX 100644
82
+ * struct vduse_iotlb_entry - entry of IOTLB to describe one IOVA region [start, last]
231
--- a/tests/qemu-iotests/group
83
+ * @offset: the mmap offset on returned file descriptor
232
+++ b/tests/qemu-iotests/group
84
+ * @start: start of the IOVA region
233
@@ -XXX,XX +XXX,XX @@
85
+ * @last: last of the IOVA region
234
227 auto quick
86
+ * @perm: access permission of the IOVA region
235
229 auto quick
87
+ *
236
231 auto quick
88
+ * Structure used by VDUSE_IOTLB_GET_FD ioctl to find an overlapped IOVA region.
237
+232 auto quick
89
+ */
90
+struct vduse_iotlb_entry {
91
+    __u64 offset;
92
+    __u64 start;
93
+    __u64 last;
94
+#define VDUSE_ACCESS_RO 0x1
95
+#define VDUSE_ACCESS_WO 0x2
96
+#define VDUSE_ACCESS_RW 0x3
97
+    __u8 perm;
98
+};
99
+
100
+/*
101
+ * Find the first IOVA region that overlaps with the range [start, last]
102
+ * and return the corresponding file descriptor. Return -EINVAL means the
103
+ * IOVA region doesn't exist. Caller should set start and last fields.
104
+ */
105
+#define VDUSE_IOTLB_GET_FD    _IOWR(VDUSE_BASE, 0x10, struct vduse_iotlb_entry)
106
+
107
+/*
108
+ * Get the negotiated virtio features. It's a subset of the features in
109
+ * struct vduse_dev_config which can be accepted by virtio driver. It's
110
+ * only valid after FEATURES_OK status bit is set.
111
+ */
112
+#define VDUSE_DEV_GET_FEATURES    _IOR(VDUSE_BASE, 0x11, __u64)
113
+
114
+/**
115
+ * struct vduse_config_data - data used to update configuration space
116
+ * @offset: the offset from the beginning of configuration space
117
+ * @length: the length to write to configuration space
118
+ * @buffer: the buffer used to write from
119
+ *
120
+ * Structure used by VDUSE_DEV_SET_CONFIG ioctl to update device
121
+ * configuration space.
122
+ */
123
+struct vduse_config_data {
124
+    __u32 offset;
125
+    __u32 length;
126
+    __u8 buffer[];
127
+};
128
+
129
+/* Set device configuration space */
130
+#define VDUSE_DEV_SET_CONFIG    _IOW(VDUSE_BASE, 0x12, struct vduse_config_data)
131
+
132
+/*
133
+ * Inject a config interrupt. It's usually used to notify virtio driver
134
+ * that device configuration space has changed.
135
+ */
136
+#define VDUSE_DEV_INJECT_CONFIG_IRQ    _IO(VDUSE_BASE, 0x13)
137
+
138
+/**
139
+ * struct vduse_vq_config - basic configuration of a virtqueue
140
+ * @index: virtqueue index
141
+ * @max_size: the max size of virtqueue
142
+ * @reserved: for future use, needs to be initialized to zero
143
+ *
144
+ * Structure used by VDUSE_VQ_SETUP ioctl to setup a virtqueue.
145
+ */
146
+struct vduse_vq_config {
147
+    __u32 index;
148
+    __u16 max_size;
149
+    __u16 reserved[13];
150
+};
151
+
152
+/*
153
+ * Setup the specified virtqueue. Make sure all virtqueues have been
154
+ * configured before the device is attached to vDPA bus.
155
+ */
156
+#define VDUSE_VQ_SETUP        _IOW(VDUSE_BASE, 0x14, struct vduse_vq_config)
157
+
158
+/**
159
+ * struct vduse_vq_state_split - split virtqueue state
160
+ * @avail_index: available index
161
+ */
162
+struct vduse_vq_state_split {
163
+    __u16 avail_index;
164
+};
165
+
166
+/**
167
+ * struct vduse_vq_state_packed - packed virtqueue state
168
+ * @last_avail_counter: last driver ring wrap counter observed by device
169
+ * @last_avail_idx: device available index
170
+ * @last_used_counter: device ring wrap counter
171
+ * @last_used_idx: used index
172
+ */
173
+struct vduse_vq_state_packed {
174
+    __u16 last_avail_counter;
175
+    __u16 last_avail_idx;
176
+    __u16 last_used_counter;
177
+    __u16 last_used_idx;
178
+};
179
+
180
+/**
181
+ * struct vduse_vq_info - information of a virtqueue
182
+ * @index: virtqueue index
183
+ * @num: the size of virtqueue
184
+ * @desc_addr: address of desc area
185
+ * @driver_addr: address of driver area
186
+ * @device_addr: address of device area
187
+ * @split: split virtqueue state
188
+ * @packed: packed virtqueue state
189
+ * @ready: ready status of virtqueue
190
+ *
191
+ * Structure used by VDUSE_VQ_GET_INFO ioctl to get virtqueue's information.
192
+ */
193
+struct vduse_vq_info {
194
+    __u32 index;
195
+    __u32 num;
196
+    __u64 desc_addr;
197
+    __u64 driver_addr;
198
+    __u64 device_addr;
199
+    union {
200
+        struct vduse_vq_state_split split;
201
+        struct vduse_vq_state_packed packed;
202
+    };
203
+    __u8 ready;
204
+};
205
+
206
+/* Get the specified virtqueue's information. Caller should set index field. */
207
+#define VDUSE_VQ_GET_INFO    _IOWR(VDUSE_BASE, 0x15, struct vduse_vq_info)
208
+
209
+/**
210
+ * struct vduse_vq_eventfd - eventfd configuration for a virtqueue
211
+ * @index: virtqueue index
212
+ * @fd: eventfd, -1 means de-assigning the eventfd
213
+ *
214
+ * Structure used by VDUSE_VQ_SETUP_KICKFD ioctl to setup kick eventfd.
215
+ */
216
+struct vduse_vq_eventfd {
217
+    __u32 index;
218
+#define VDUSE_EVENTFD_DEASSIGN -1
219
+    int fd;
220
+};
221
+
222
+/*
223
+ * Setup kick eventfd for specified virtqueue. The kick eventfd is used
224
+ * by VDUSE kernel module to notify userspace to consume the avail vring.
225
+ */
226
+#define VDUSE_VQ_SETUP_KICKFD    _IOW(VDUSE_BASE, 0x16, struct vduse_vq_eventfd)
227
+
228
+/*
229
+ * Inject an interrupt for specific virtqueue. It's used to notify virtio driver
230
+ * to consume the used vring.
231
+ */
232
+#define VDUSE_VQ_INJECT_IRQ    _IOW(VDUSE_BASE, 0x17, __u32)
233
+
234
+/* The control messages definition for read(2)/write(2) on /dev/vduse/$NAME */
235
+
236
+/**
237
+ * enum vduse_req_type - request type
238
+ * @VDUSE_GET_VQ_STATE: get the state for specified virtqueue from userspace
239
+ * @VDUSE_SET_STATUS: set the device status
240
+ * @VDUSE_UPDATE_IOTLB: Notify userspace to update the memory mapping for
241
+ * specified IOVA range via VDUSE_IOTLB_GET_FD ioctl
242
+ */
243
+enum vduse_req_type {
244
+    VDUSE_GET_VQ_STATE,
245
+    VDUSE_SET_STATUS,
246
+    VDUSE_UPDATE_IOTLB,
247
+};
248
+
249
+/**
250
+ * struct vduse_vq_state - virtqueue state
251
+ * @index: virtqueue index
252
+ * @split: split virtqueue state
253
+ * @packed: packed virtqueue state
254
+ */
255
+struct vduse_vq_state {
256
+    __u32 index;
257
+    union {
258
+        struct vduse_vq_state_split split;
259
+        struct vduse_vq_state_packed packed;
260
+    };
261
+};
262
+
263
+/**
264
+ * struct vduse_dev_status - device status
265
+ * @status: device status
266
+ */
267
+struct vduse_dev_status {
268
+    __u8 status;
269
+};
270
+
271
+/**
272
+ * struct vduse_iova_range - IOVA range [start, last]
273
+ * @start: start of the IOVA range
274
+ * @last: last of the IOVA range
275
+ */
276
+struct vduse_iova_range {
277
+    __u64 start;
278
+    __u64 last;
279
+};
280
+
281
+/**
282
+ * struct vduse_dev_request - control request
283
+ * @type: request type
284
+ * @request_id: request id
285
+ * @reserved: for future use
286
+ * @vq_state: virtqueue state, only index field is available
287
+ * @s: device status
288
+ * @iova: IOVA range for updating
289
+ * @padding: padding
290
+ *
291
+ * Structure used by read(2) on /dev/vduse/$NAME.
292
+ */
293
+struct vduse_dev_request {
294
+    __u32 type;
295
+    __u32 request_id;
296
+    __u32 reserved[4];
297
+    union {
298
+        struct vduse_vq_state vq_state;
299
+        struct vduse_dev_status s;
300
+        struct vduse_iova_range iova;
301
+        __u32 padding[32];
302
+    };
303
+};
304
+
305
+/**
306
+ * struct vduse_dev_response - response to control request
307
+ * @request_id: corresponding request id
308
+ * @result: the result of request
309
+ * @reserved: for future use, needs to be initialized to zero
310
+ * @vq_state: virtqueue state
311
+ * @padding: padding
312
+ *
313
+ * Structure used by write(2) on /dev/vduse/$NAME.
314
+ */
315
+struct vduse_dev_response {
316
+    __u32 request_id;
317
+#define VDUSE_REQ_RESULT_OK    0x00
318
+#define VDUSE_REQ_RESULT_FAILED    0x01
319
+    __u32 result;
320
+    __u32 reserved[4];
321
+    union {
322
+        struct vduse_vq_state vq_state;
323
+        __u32 padding[32];
324
+    };
325
+};
326
+
327
+#endif /* _VDUSE_H_ */
328
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
329
index XXXXXXX..XXXXXXX 100755
330
--- a/scripts/update-linux-headers.sh
331
+++ b/scripts/update-linux-headers.sh
332
@@ -XXX,XX +XXX,XX @@ done
333
rm -rf "$output/linux-headers/linux"
334
mkdir -p "$output/linux-headers/linux"
335
for header in kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \
336
- psci.h psp-sev.h userfaultfd.h mman.h; do
337
+ psci.h psp-sev.h userfaultfd.h mman.h vduse.h; do
338
cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
339
done
340
238
--
341
--
239
2.19.1
342
2.35.3
240
241
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Xie Yongji <xieyongji@bytedance.com>
2
2
3
This patch tests that you can add and remove drives from a Quorum
3
VDUSE [1] is a linux framework that makes it possible to implement
4
using the x-blockdev-change command.
4
software-emulated vDPA devices in userspace. This adds a library
5
as a subproject to help implementing VDUSE backends in QEMU.
5
6
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
[1] https://www.kernel.org/doc/html/latest/userspace-api/vduse.html
8
9
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
10
Message-Id: <20220523084611.91-6-xieyongji@bytedance.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
13
---
9
tests/qemu-iotests/081 | 86 ++++++++++++++++++++++++++++++++++++++
14
meson_options.txt | 2 +
10
tests/qemu-iotests/081.out | 54 ++++++++++++++++++++++++
15
subprojects/libvduse/include/atomic.h | 1 +
11
2 files changed, 140 insertions(+)
16
subprojects/libvduse/include/compiler.h | 1 +
17
subprojects/libvduse/libvduse.h | 235 ++++
18
subprojects/libvduse/libvduse.c | 1150 +++++++++++++++++++
19
MAINTAINERS | 5 +
20
meson.build | 15 +
21
scripts/meson-buildoptions.sh | 3 +
22
subprojects/libvduse/linux-headers/linux | 1 +
23
subprojects/libvduse/meson.build | 10 +
24
subprojects/libvduse/standard-headers/linux | 1 +
25
11 files changed, 1424 insertions(+)
26
create mode 120000 subprojects/libvduse/include/atomic.h
27
create mode 120000 subprojects/libvduse/include/compiler.h
28
create mode 100644 subprojects/libvduse/libvduse.h
29
create mode 100644 subprojects/libvduse/libvduse.c
30
create mode 120000 subprojects/libvduse/linux-headers/linux
31
create mode 100644 subprojects/libvduse/meson.build
32
create mode 120000 subprojects/libvduse/standard-headers/linux
12
33
13
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
34
diff --git a/meson_options.txt b/meson_options.txt
14
index XXXXXXX..XXXXXXX 100755
35
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/081
36
--- a/meson_options.txt
16
+++ b/tests/qemu-iotests/081
37
+++ b/meson_options.txt
17
@@ -XXX,XX +XXX,XX @@ quorum="$quorum,file.children.2.driver=raw"
38
@@ -XXX,XX +XXX,XX @@ option('virtfs', type: 'feature', value: 'auto',
18
39
description: 'virtio-9p support')
19
$QEMU_IO -c "open -o $quorum" | _filter_qemu_io
40
option('virtiofsd', type: 'feature', value: 'auto',
20
41
description: 'build virtiofs daemon (virtiofsd)')
21
+echo
42
+option('libvduse', type: 'feature', value: 'auto',
22
+echo "== dynamically adding a child to a quorum =="
43
+ description: 'build VDUSE Library')
23
+
44
24
+for verify in false true; do
45
option('capstone', type: 'feature', value: 'auto',
25
+ run_qemu <<EOF
46
description: 'Whether and how to find the capstone library')
26
+ { "execute": "qmp_capabilities" }
47
diff --git a/subprojects/libvduse/include/atomic.h b/subprojects/libvduse/include/atomic.h
27
+ { "execute": "blockdev-add",
48
new file mode 120000
28
+ "arguments": {
49
index XXXXXXX..XXXXXXX
29
+ "driver": "quorum",
50
--- /dev/null
30
+ "node-name": "drive0-quorum",
51
+++ b/subprojects/libvduse/include/atomic.h
31
+ "vote-threshold": 2,
52
@@ -0,0 +1 @@
32
+ "blkverify": ${verify},
53
+../../../include/qemu/atomic.h
33
+ "children": [
54
\ No newline at end of file
34
+ {
55
diff --git a/subprojects/libvduse/include/compiler.h b/subprojects/libvduse/include/compiler.h
35
+ "driver": "$IMGFMT",
56
new file mode 120000
36
+ "file": {
57
index XXXXXXX..XXXXXXX
37
+ "driver": "file",
58
--- /dev/null
38
+ "filename": "$TEST_DIR/1.raw"
59
+++ b/subprojects/libvduse/include/compiler.h
39
+ }
60
@@ -0,0 +1 @@
40
+ },
61
+../../../include/qemu/compiler.h
41
+ {
62
\ No newline at end of file
42
+ "driver": "$IMGFMT",
63
diff --git a/subprojects/libvduse/libvduse.h b/subprojects/libvduse/libvduse.h
43
+ "file": {
64
new file mode 100644
44
+ "driver": "file",
65
index XXXXXXX..XXXXXXX
45
+ "filename": "$TEST_DIR/2.raw"
66
--- /dev/null
46
+ }
67
+++ b/subprojects/libvduse/libvduse.h
47
+ }
68
@@ -XXX,XX +XXX,XX @@
48
+ ]
69
+/*
70
+ * VDUSE (vDPA Device in Userspace) library
71
+ *
72
+ * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved.
73
+ *
74
+ * Author:
75
+ * Xie Yongji <xieyongji@bytedance.com>
76
+ *
77
+ * This work is licensed under the terms of the GNU GPL, version 2 or
78
+ * later. See the COPYING file in the top-level directory.
79
+ */
80
+
81
+#ifndef LIBVDUSE_H
82
+#define LIBVDUSE_H
83
+
84
+#include <stdint.h>
85
+#include <sys/uio.h>
86
+
87
+#define VIRTQUEUE_MAX_SIZE 1024
88
+
89
+/* VDUSE device structure */
90
+typedef struct VduseDev VduseDev;
91
+
92
+/* Virtqueue structure */
93
+typedef struct VduseVirtq VduseVirtq;
94
+
95
+/* Some operation of VDUSE backend */
96
+typedef struct VduseOps {
97
+ /* Called when virtqueue can be processed */
98
+ void (*enable_queue)(VduseDev *dev, VduseVirtq *vq);
99
+ /* Called when virtqueue processing should be stopped */
100
+ void (*disable_queue)(VduseDev *dev, VduseVirtq *vq);
101
+} VduseOps;
102
+
103
+/* Describing elements of the I/O buffer */
104
+typedef struct VduseVirtqElement {
105
+ /* Descriptor table index */
106
+ unsigned int index;
107
+ /* Number of physically-contiguous device-readable descriptors */
108
+ unsigned int out_num;
109
+ /* Number of physically-contiguous device-writable descriptors */
110
+ unsigned int in_num;
111
+ /* Array to store physically-contiguous device-writable descriptors */
112
+ struct iovec *in_sg;
113
+ /* Array to store physically-contiguous device-readable descriptors */
114
+ struct iovec *out_sg;
115
+} VduseVirtqElement;
116
+
117
+
118
+/**
119
+ * vduse_get_virtio_features:
120
+ *
121
+ * Get supported virtio features
122
+ *
123
+ * Returns: supported feature bits
124
+ */
125
+uint64_t vduse_get_virtio_features(void);
126
+
127
+/**
128
+ * vduse_queue_get_dev:
129
+ * @vq: specified virtqueue
130
+ *
131
+ * Get corresponding VDUSE device from the virtqueue.
132
+ *
133
+ * Returns: a pointer to VDUSE device on success, NULL on failure.
134
+ */
135
+VduseDev *vduse_queue_get_dev(VduseVirtq *vq);
136
+
137
+/**
138
+ * vduse_queue_get_fd:
139
+ * @vq: specified virtqueue
140
+ *
141
+ * Get the kick fd for the virtqueue.
142
+ *
143
+ * Returns: file descriptor on success, -1 on failure.
144
+ */
145
+int vduse_queue_get_fd(VduseVirtq *vq);
146
+
147
+/**
148
+ * vduse_queue_pop:
149
+ * @vq: specified virtqueue
150
+ * @sz: the size of struct to return (must be >= VduseVirtqElement)
151
+ *
152
+ * Pop an element from virtqueue available ring.
153
+ *
154
+ * Returns: a pointer to a structure containing VduseVirtqElement on success,
155
+ * NULL on failure.
156
+ */
157
+void *vduse_queue_pop(VduseVirtq *vq, size_t sz);
158
+
159
+/**
160
+ * vduse_queue_push:
161
+ * @vq: specified virtqueue
162
+ * @elem: pointer to VduseVirtqElement returned by vduse_queue_pop()
163
+ * @len: length in bytes to write
164
+ *
165
+ * Push an element to virtqueue used ring.
166
+ */
167
+void vduse_queue_push(VduseVirtq *vq, const VduseVirtqElement *elem,
168
+ unsigned int len);
169
+/**
170
+ * vduse_queue_notify:
171
+ * @vq: specified virtqueue
172
+ *
173
+ * Request to notify the queue.
174
+ */
175
+void vduse_queue_notify(VduseVirtq *vq);
176
+
177
+/**
178
+ * vduse_dev_get_priv:
179
+ * @dev: VDUSE device
180
+ *
181
+ * Get the private pointer passed to vduse_dev_create().
182
+ *
183
+ * Returns: private pointer on success, NULL on failure.
184
+ */
185
+void *vduse_dev_get_priv(VduseDev *dev);
186
+
187
+/**
188
+ * vduse_dev_get_queue:
189
+ * @dev: VDUSE device
190
+ * @index: virtqueue index
191
+ *
192
+ * Get the specified virtqueue.
193
+ *
194
+ * Returns: a pointer to the virtqueue on success, NULL on failure.
195
+ */
196
+VduseVirtq *vduse_dev_get_queue(VduseDev *dev, int index);
197
+
198
+/**
199
+ * vduse_dev_get_fd:
200
+ * @dev: VDUSE device
201
+ *
202
+ * Get the control message fd for the VDUSE device.
203
+ *
204
+ * Returns: file descriptor on success, -1 on failure.
205
+ */
206
+int vduse_dev_get_fd(VduseDev *dev);
207
+
208
+/**
209
+ * vduse_dev_handler:
210
+ * @dev: VDUSE device
211
+ *
212
+ * Used to process the control message.
213
+ *
214
+ * Returns: file descriptor on success, -errno on failure.
215
+ */
216
+int vduse_dev_handler(VduseDev *dev);
217
+
218
+/**
219
+ * vduse_dev_update_config:
220
+ * @dev: VDUSE device
221
+ * @size: the size to write to configuration space
222
+ * @offset: the offset from the beginning of configuration space
223
+ * @buffer: the buffer used to write from
224
+ *
225
+ * Update device configuration space and inject a config interrupt.
226
+ *
227
+ * Returns: 0 on success, -errno on failure.
228
+ */
229
+int vduse_dev_update_config(VduseDev *dev, uint32_t size,
230
+ uint32_t offset, char *buffer);
231
+
232
+/**
233
+ * vduse_dev_setup_queue:
234
+ * @dev: VDUSE device
235
+ * @index: virtqueue index
236
+ * @max_size: the max size of virtqueue
237
+ *
238
+ * Setup the specified virtqueue.
239
+ *
240
+ * Returns: 0 on success, -errno on failure.
241
+ */
242
+int vduse_dev_setup_queue(VduseDev *dev, int index, int max_size);
243
+
244
+/**
245
+ * vduse_dev_create_by_fd:
246
+ * @fd: passed file descriptor
247
+ * @num_queues: the number of virtqueues
248
+ * @ops: the operation of VDUSE backend
249
+ * @priv: private pointer
250
+ *
251
+ * Create VDUSE device from a passed file descriptor.
252
+ *
253
+ * Returns: pointer to VDUSE device on success, NULL on failure.
254
+ */
255
+VduseDev *vduse_dev_create_by_fd(int fd, uint16_t num_queues,
256
+ const VduseOps *ops, void *priv);
257
+
258
+/**
259
+ * vduse_dev_create_by_name:
260
+ * @name: VDUSE device name
261
+ * @num_queues: the number of virtqueues
262
+ * @ops: the operation of VDUSE backend
263
+ * @priv: private pointer
264
+ *
265
+ * Create VDUSE device on /dev/vduse/$NAME.
266
+ *
267
+ * Returns: pointer to VDUSE device on success, NULL on failure.
268
+ */
269
+VduseDev *vduse_dev_create_by_name(const char *name, uint16_t num_queues,
270
+ const VduseOps *ops, void *priv);
271
+
272
+/**
273
+ * vduse_dev_create:
274
+ * @name: VDUSE device name
275
+ * @device_id: virtio device id
276
+ * @vendor_id: virtio vendor id
277
+ * @features: virtio features
278
+ * @num_queues: the number of virtqueues
279
+ * @config_size: the size of the configuration space
280
+ * @config: the buffer of the configuration space
281
+ * @ops: the operation of VDUSE backend
282
+ * @priv: private pointer
283
+ *
284
+ * Create VDUSE device.
285
+ *
286
+ * Returns: pointer to VDUSE device on success, NULL on failure.
287
+ */
288
+VduseDev *vduse_dev_create(const char *name, uint32_t device_id,
289
+ uint32_t vendor_id, uint64_t features,
290
+ uint16_t num_queues, uint32_t config_size,
291
+ char *config, const VduseOps *ops, void *priv);
292
+
293
+/**
294
+ * vduse_dev_destroy:
295
+ * @dev: VDUSE device
296
+ *
297
+ * Destroy the VDUSE device.
298
+ *
299
+ * Returns: 0 on success, -errno on failure.
300
+ */
301
+int vduse_dev_destroy(VduseDev *dev);
302
+
303
+#endif
304
diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c
305
new file mode 100644
306
index XXXXXXX..XXXXXXX
307
--- /dev/null
308
+++ b/subprojects/libvduse/libvduse.c
309
@@ -XXX,XX +XXX,XX @@
310
+/*
311
+ * VDUSE (vDPA Device in Userspace) library
312
+ *
313
+ * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved.
314
+ * Portions of codes and concepts borrowed from libvhost-user.c, so:
315
+ * Copyright IBM, Corp. 2007
316
+ * Copyright (c) 2016 Red Hat, Inc.
317
+ *
318
+ * Author:
319
+ * Xie Yongji <xieyongji@bytedance.com>
320
+ * Anthony Liguori <aliguori@us.ibm.com>
321
+ * Marc-André Lureau <mlureau@redhat.com>
322
+ * Victor Kaplansky <victork@redhat.com>
323
+ *
324
+ * This work is licensed under the terms of the GNU GPL, version 2 or
325
+ * later. See the COPYING file in the top-level directory.
326
+ */
327
+
328
+#include <stdlib.h>
329
+#include <stdio.h>
330
+#include <stdbool.h>
331
+#include <stddef.h>
332
+#include <errno.h>
333
+#include <string.h>
334
+#include <assert.h>
335
+#include <endian.h>
336
+#include <unistd.h>
337
+#include <limits.h>
338
+#include <fcntl.h>
339
+#include <inttypes.h>
340
+
341
+#include <sys/ioctl.h>
342
+#include <sys/eventfd.h>
343
+#include <sys/mman.h>
344
+
345
+#include "include/atomic.h"
346
+#include "linux-headers/linux/virtio_ring.h"
347
+#include "linux-headers/linux/virtio_config.h"
348
+#include "linux-headers/linux/vduse.h"
349
+#include "libvduse.h"
350
+
351
+#define VDUSE_VQ_ALIGN 4096
352
+#define MAX_IOVA_REGIONS 256
353
+
354
+/* Round number down to multiple */
355
+#define ALIGN_DOWN(n, m) ((n) / (m) * (m))
356
+
357
+/* Round number up to multiple */
358
+#define ALIGN_UP(n, m) ALIGN_DOWN((n) + (m) - 1, (m))
359
+
360
+#ifndef unlikely
361
+#define unlikely(x) __builtin_expect(!!(x), 0)
362
+#endif
363
+
364
+typedef struct VduseRing {
365
+ unsigned int num;
366
+ uint64_t desc_addr;
367
+ uint64_t avail_addr;
368
+ uint64_t used_addr;
369
+ struct vring_desc *desc;
370
+ struct vring_avail *avail;
371
+ struct vring_used *used;
372
+} VduseRing;
373
+
374
+struct VduseVirtq {
375
+ VduseRing vring;
376
+ uint16_t last_avail_idx;
377
+ uint16_t shadow_avail_idx;
378
+ uint16_t used_idx;
379
+ uint16_t signalled_used;
380
+ bool signalled_used_valid;
381
+ int index;
382
+ int inuse;
383
+ bool ready;
384
+ int fd;
385
+ VduseDev *dev;
386
+};
387
+
388
+typedef struct VduseIovaRegion {
389
+ uint64_t iova;
390
+ uint64_t size;
391
+ uint64_t mmap_offset;
392
+ uint64_t mmap_addr;
393
+} VduseIovaRegion;
394
+
395
+struct VduseDev {
396
+ VduseVirtq *vqs;
397
+ VduseIovaRegion regions[MAX_IOVA_REGIONS];
398
+ int num_regions;
399
+ char *name;
400
+ uint32_t device_id;
401
+ uint32_t vendor_id;
402
+ uint16_t num_queues;
403
+ uint16_t queue_size;
404
+ uint64_t features;
405
+ const VduseOps *ops;
406
+ int fd;
407
+ int ctrl_fd;
408
+ void *priv;
409
+};
410
+
411
+static inline bool has_feature(uint64_t features, unsigned int fbit)
412
+{
413
+ assert(fbit < 64);
414
+ return !!(features & (1ULL << fbit));
415
+}
416
+
417
+static inline bool vduse_dev_has_feature(VduseDev *dev, unsigned int fbit)
418
+{
419
+ return has_feature(dev->features, fbit);
420
+}
421
+
422
+uint64_t vduse_get_virtio_features(void)
423
+{
424
+ return (1ULL << VIRTIO_F_IOMMU_PLATFORM) |
425
+ (1ULL << VIRTIO_F_VERSION_1) |
426
+ (1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) |
427
+ (1ULL << VIRTIO_RING_F_EVENT_IDX) |
428
+ (1ULL << VIRTIO_RING_F_INDIRECT_DESC);
429
+}
430
+
431
+VduseDev *vduse_queue_get_dev(VduseVirtq *vq)
432
+{
433
+ return vq->dev;
434
+}
435
+
436
+int vduse_queue_get_fd(VduseVirtq *vq)
437
+{
438
+ return vq->fd;
439
+}
440
+
441
+void *vduse_dev_get_priv(VduseDev *dev)
442
+{
443
+ return dev->priv;
444
+}
445
+
446
+VduseVirtq *vduse_dev_get_queue(VduseDev *dev, int index)
447
+{
448
+ return &dev->vqs[index];
449
+}
450
+
451
+int vduse_dev_get_fd(VduseDev *dev)
452
+{
453
+ return dev->fd;
454
+}
455
+
456
+static int vduse_inject_irq(VduseDev *dev, int index)
457
+{
458
+ return ioctl(dev->fd, VDUSE_VQ_INJECT_IRQ, &index);
459
+}
460
+
461
+static void vduse_iova_remove_region(VduseDev *dev, uint64_t start,
462
+ uint64_t last)
463
+{
464
+ int i;
465
+
466
+ if (last == start) {
467
+ return;
468
+ }
469
+
470
+ for (i = 0; i < MAX_IOVA_REGIONS; i++) {
471
+ if (!dev->regions[i].mmap_addr) {
472
+ continue;
49
+ }
473
+ }
50
+ }
474
+
51
+ { "execute": "blockdev-add",
475
+ if (start <= dev->regions[i].iova &&
52
+ "arguments": {
476
+ last >= (dev->regions[i].iova + dev->regions[i].size - 1)) {
53
+ "node-name": "drive3",
477
+ munmap((void *)(uintptr_t)dev->regions[i].mmap_addr,
54
+ "driver": "$IMGFMT",
478
+ dev->regions[i].mmap_offset + dev->regions[i].size);
55
+ "file": {
479
+ dev->regions[i].mmap_addr = 0;
56
+ "driver": "file",
480
+ dev->num_regions--;
57
+ "filename": "$TEST_DIR/2.raw"
481
+ }
482
+ }
483
+}
484
+
485
+static int vduse_iova_add_region(VduseDev *dev, int fd,
486
+ uint64_t offset, uint64_t start,
487
+ uint64_t last, int prot)
488
+{
489
+ int i;
490
+ uint64_t size = last - start + 1;
491
+ void *mmap_addr = mmap(0, size + offset, prot, MAP_SHARED, fd, 0);
492
+
493
+ if (mmap_addr == MAP_FAILED) {
494
+ close(fd);
495
+ return -EINVAL;
496
+ }
497
+
498
+ for (i = 0; i < MAX_IOVA_REGIONS; i++) {
499
+ if (!dev->regions[i].mmap_addr) {
500
+ dev->regions[i].mmap_addr = (uint64_t)(uintptr_t)mmap_addr;
501
+ dev->regions[i].mmap_offset = offset;
502
+ dev->regions[i].iova = start;
503
+ dev->regions[i].size = size;
504
+ dev->num_regions++;
505
+ break;
506
+ }
507
+ }
508
+ assert(i < MAX_IOVA_REGIONS);
509
+ close(fd);
510
+
511
+ return 0;
512
+}
513
+
514
+static int perm_to_prot(uint8_t perm)
515
+{
516
+ int prot = 0;
517
+
518
+ switch (perm) {
519
+ case VDUSE_ACCESS_WO:
520
+ prot |= PROT_WRITE;
521
+ break;
522
+ case VDUSE_ACCESS_RO:
523
+ prot |= PROT_READ;
524
+ break;
525
+ case VDUSE_ACCESS_RW:
526
+ prot |= PROT_READ | PROT_WRITE;
527
+ break;
528
+ default:
529
+ break;
530
+ }
531
+
532
+ return prot;
533
+}
534
+
535
+static inline void *iova_to_va(VduseDev *dev, uint64_t *plen, uint64_t iova)
536
+{
537
+ int i, ret;
538
+ struct vduse_iotlb_entry entry;
539
+
540
+ for (i = 0; i < MAX_IOVA_REGIONS; i++) {
541
+ VduseIovaRegion *r = &dev->regions[i];
542
+
543
+ if (!r->mmap_addr) {
544
+ continue;
545
+ }
546
+
547
+ if ((iova >= r->iova) && (iova < (r->iova + r->size))) {
548
+ if ((iova + *plen) > (r->iova + r->size)) {
549
+ *plen = r->iova + r->size - iova;
550
+ }
551
+ return (void *)(uintptr_t)(iova - r->iova +
552
+ r->mmap_addr + r->mmap_offset);
553
+ }
554
+ }
555
+
556
+ entry.start = iova;
557
+ entry.last = iova + 1;
558
+ ret = ioctl(dev->fd, VDUSE_IOTLB_GET_FD, &entry);
559
+ if (ret < 0) {
560
+ return NULL;
561
+ }
562
+
563
+ if (!vduse_iova_add_region(dev, ret, entry.offset, entry.start,
564
+ entry.last, perm_to_prot(entry.perm))) {
565
+ return iova_to_va(dev, plen, iova);
566
+ }
567
+
568
+ return NULL;
569
+}
570
+
571
+static inline uint16_t vring_avail_flags(VduseVirtq *vq)
572
+{
573
+ return le16toh(vq->vring.avail->flags);
574
+}
575
+
576
+static inline uint16_t vring_avail_idx(VduseVirtq *vq)
577
+{
578
+ vq->shadow_avail_idx = le16toh(vq->vring.avail->idx);
579
+
580
+ return vq->shadow_avail_idx;
581
+}
582
+
583
+static inline uint16_t vring_avail_ring(VduseVirtq *vq, int i)
584
+{
585
+ return le16toh(vq->vring.avail->ring[i]);
586
+}
587
+
588
+static inline uint16_t vring_get_used_event(VduseVirtq *vq)
589
+{
590
+ return vring_avail_ring(vq, vq->vring.num);
591
+}
592
+
593
+static bool vduse_queue_get_head(VduseVirtq *vq, unsigned int idx,
594
+ unsigned int *head)
595
+{
596
+ /*
597
+ * Grab the next descriptor number they're advertising, and increment
598
+ * the index we've seen.
599
+ */
600
+ *head = vring_avail_ring(vq, idx % vq->vring.num);
601
+
602
+ /* If their number is silly, that's a fatal mistake. */
603
+ if (*head >= vq->vring.num) {
604
+ fprintf(stderr, "Guest says index %u is available\n", *head);
605
+ return false;
606
+ }
607
+
608
+ return true;
609
+}
610
+
611
+static int
612
+vduse_queue_read_indirect_desc(VduseDev *dev, struct vring_desc *desc,
613
+ uint64_t addr, size_t len)
614
+{
615
+ struct vring_desc *ori_desc;
616
+ uint64_t read_len;
617
+
618
+ if (len > (VIRTQUEUE_MAX_SIZE * sizeof(struct vring_desc))) {
619
+ return -1;
620
+ }
621
+
622
+ if (len == 0) {
623
+ return -1;
624
+ }
625
+
626
+ while (len) {
627
+ read_len = len;
628
+ ori_desc = iova_to_va(dev, &read_len, addr);
629
+ if (!ori_desc) {
630
+ return -1;
631
+ }
632
+
633
+ memcpy(desc, ori_desc, read_len);
634
+ len -= read_len;
635
+ addr += read_len;
636
+ desc += read_len;
637
+ }
638
+
639
+ return 0;
640
+}
641
+
642
+enum {
643
+ VIRTQUEUE_READ_DESC_ERROR = -1,
644
+ VIRTQUEUE_READ_DESC_DONE = 0, /* end of chain */
645
+ VIRTQUEUE_READ_DESC_MORE = 1, /* more buffers in chain */
646
+};
647
+
648
+static int vduse_queue_read_next_desc(struct vring_desc *desc, int i,
649
+ unsigned int max, unsigned int *next)
650
+{
651
+ /* If this descriptor says it doesn't chain, we're done. */
652
+ if (!(le16toh(desc[i].flags) & VRING_DESC_F_NEXT)) {
653
+ return VIRTQUEUE_READ_DESC_DONE;
654
+ }
655
+
656
+ /* Check they're not leading us off end of descriptors. */
657
+ *next = desc[i].next;
658
+ /* Make sure compiler knows to grab that: we don't want it changing! */
659
+ smp_wmb();
660
+
661
+ if (*next >= max) {
662
+ fprintf(stderr, "Desc next is %u\n", *next);
663
+ return VIRTQUEUE_READ_DESC_ERROR;
664
+ }
665
+
666
+ return VIRTQUEUE_READ_DESC_MORE;
667
+}
668
+
669
+/*
670
+ * Fetch avail_idx from VQ memory only when we really need to know if
671
+ * guest has added some buffers.
672
+ */
673
+static bool vduse_queue_empty(VduseVirtq *vq)
674
+{
675
+ if (unlikely(!vq->vring.avail)) {
676
+ return true;
677
+ }
678
+
679
+ if (vq->shadow_avail_idx != vq->last_avail_idx) {
680
+ return false;
681
+ }
682
+
683
+ return vring_avail_idx(vq) == vq->last_avail_idx;
684
+}
685
+
686
+static bool vduse_queue_should_notify(VduseVirtq *vq)
687
+{
688
+ VduseDev *dev = vq->dev;
689
+ uint16_t old, new;
690
+ bool v;
691
+
692
+ /* We need to expose used array entries before checking used event. */
693
+ smp_mb();
694
+
695
+ /* Always notify when queue is empty (when feature acknowledge) */
696
+ if (vduse_dev_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
697
+ !vq->inuse && vduse_queue_empty(vq)) {
698
+ return true;
699
+ }
700
+
701
+ if (!vduse_dev_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
702
+ return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
703
+ }
704
+
705
+ v = vq->signalled_used_valid;
706
+ vq->signalled_used_valid = true;
707
+ old = vq->signalled_used;
708
+ new = vq->signalled_used = vq->used_idx;
709
+ return !v || vring_need_event(vring_get_used_event(vq), new, old);
710
+}
711
+
712
+void vduse_queue_notify(VduseVirtq *vq)
713
+{
714
+ VduseDev *dev = vq->dev;
715
+
716
+ if (unlikely(!vq->vring.avail)) {
717
+ return;
718
+ }
719
+
720
+ if (!vduse_queue_should_notify(vq)) {
721
+ return;
722
+ }
723
+
724
+ if (vduse_inject_irq(dev, vq->index) < 0) {
725
+ fprintf(stderr, "Error inject irq for vq %d: %s\n",
726
+ vq->index, strerror(errno));
727
+ }
728
+}
729
+
730
+static inline void vring_set_avail_event(VduseVirtq *vq, uint16_t val)
731
+{
732
+ *((uint16_t *)&vq->vring.used->ring[vq->vring.num]) = htole16(val);
733
+}
734
+
735
+static bool vduse_queue_map_single_desc(VduseVirtq *vq, unsigned int *p_num_sg,
736
+ struct iovec *iov, unsigned int max_num_sg,
737
+ bool is_write, uint64_t pa, size_t sz)
738
+{
739
+ unsigned num_sg = *p_num_sg;
740
+ VduseDev *dev = vq->dev;
741
+
742
+ assert(num_sg <= max_num_sg);
743
+
744
+ if (!sz) {
745
+ fprintf(stderr, "virtio: zero sized buffers are not allowed\n");
746
+ return false;
747
+ }
748
+
749
+ while (sz) {
750
+ uint64_t len = sz;
751
+
752
+ if (num_sg == max_num_sg) {
753
+ fprintf(stderr,
754
+ "virtio: too many descriptors in indirect table\n");
755
+ return false;
756
+ }
757
+
758
+ iov[num_sg].iov_base = iova_to_va(dev, &len, pa);
759
+ if (iov[num_sg].iov_base == NULL) {
760
+ fprintf(stderr, "virtio: invalid address for buffers\n");
761
+ return false;
762
+ }
763
+ iov[num_sg++].iov_len = len;
764
+ sz -= len;
765
+ pa += len;
766
+ }
767
+
768
+ *p_num_sg = num_sg;
769
+ return true;
770
+}
771
+
772
+static void *vduse_queue_alloc_element(size_t sz, unsigned out_num,
773
+ unsigned in_num)
774
+{
775
+ VduseVirtqElement *elem;
776
+ size_t in_sg_ofs = ALIGN_UP(sz, __alignof__(elem->in_sg[0]));
777
+ size_t out_sg_ofs = in_sg_ofs + in_num * sizeof(elem->in_sg[0]);
778
+ size_t out_sg_end = out_sg_ofs + out_num * sizeof(elem->out_sg[0]);
779
+
780
+ assert(sz >= sizeof(VduseVirtqElement));
781
+ elem = malloc(out_sg_end);
782
+ if (!elem) {
783
+ return NULL;
784
+ }
785
+ elem->out_num = out_num;
786
+ elem->in_num = in_num;
787
+ elem->in_sg = (void *)elem + in_sg_ofs;
788
+ elem->out_sg = (void *)elem + out_sg_ofs;
789
+ return elem;
790
+}
791
+
792
+static void *vduse_queue_map_desc(VduseVirtq *vq, unsigned int idx, size_t sz)
793
+{
794
+ struct vring_desc *desc = vq->vring.desc;
795
+ VduseDev *dev = vq->dev;
796
+ uint64_t desc_addr, read_len;
797
+ unsigned int desc_len;
798
+ unsigned int max = vq->vring.num;
799
+ unsigned int i = idx;
800
+ VduseVirtqElement *elem;
801
+ struct iovec iov[VIRTQUEUE_MAX_SIZE];
802
+ struct vring_desc desc_buf[VIRTQUEUE_MAX_SIZE];
803
+ unsigned int out_num = 0, in_num = 0;
804
+ int rc;
805
+
806
+ if (le16toh(desc[i].flags) & VRING_DESC_F_INDIRECT) {
807
+ if (le32toh(desc[i].len) % sizeof(struct vring_desc)) {
808
+ fprintf(stderr, "Invalid size for indirect buffer table\n");
809
+ return NULL;
810
+ }
811
+
812
+ /* loop over the indirect descriptor table */
813
+ desc_addr = le64toh(desc[i].addr);
814
+ desc_len = le32toh(desc[i].len);
815
+ max = desc_len / sizeof(struct vring_desc);
816
+ read_len = desc_len;
817
+ desc = iova_to_va(dev, &read_len, desc_addr);
818
+ if (unlikely(desc && read_len != desc_len)) {
819
+ /* Failed to use zero copy */
820
+ desc = NULL;
821
+ if (!vduse_queue_read_indirect_desc(dev, desc_buf,
822
+ desc_addr,
823
+ desc_len)) {
824
+ desc = desc_buf;
58
+ }
825
+ }
59
+ }
826
+ }
60
+ }
827
+ if (!desc) {
61
+ { "execute": "x-blockdev-change",
828
+ fprintf(stderr, "Invalid indirect buffer table\n");
62
+ "arguments": { "parent": "drive0-quorum",
829
+ return NULL;
63
+ "node": "drive3" } }
830
+ }
64
+ { "execute": "quit" }
831
+ i = 0;
65
+EOF
832
+ }
66
+done
833
+
67
+
834
+ /* Collect all the descriptors */
68
+echo
835
+ do {
69
+echo "== dynamically removing a child from a quorum =="
836
+ if (le16toh(desc[i].flags) & VRING_DESC_F_WRITE) {
70
+
837
+ if (!vduse_queue_map_single_desc(vq, &in_num, iov + out_num,
71
+for verify in false true; do
838
+ VIRTQUEUE_MAX_SIZE - out_num,
72
+ for vote_threshold in 1 2; do
839
+ true, le64toh(desc[i].addr),
73
+ run_qemu <<EOF
840
+ le32toh(desc[i].len))) {
74
+ { "execute": "qmp_capabilities" }
841
+ return NULL;
75
+ { "execute": "blockdev-add",
842
+ }
76
+ "arguments": {
843
+ } else {
77
+ "driver": "quorum",
844
+ if (in_num) {
78
+ "node-name": "drive0-quorum",
845
+ fprintf(stderr, "Incorrect order for descriptors\n");
79
+ "vote-threshold": ${vote_threshold},
846
+ return NULL;
80
+ "blkverify": ${verify},
847
+ }
81
+ "children": [
848
+ if (!vduse_queue_map_single_desc(vq, &out_num, iov,
82
+ {
849
+ VIRTQUEUE_MAX_SIZE, false,
83
+ "driver": "$IMGFMT",
850
+ le64toh(desc[i].addr),
84
+ "file": {
851
+ le32toh(desc[i].len))) {
85
+ "driver": "file",
852
+ return NULL;
86
+ "filename": "$TEST_DIR/1.raw"
87
+ }
88
+ },
89
+ {
90
+ "driver": "$IMGFMT",
91
+ "file": {
92
+ "driver": "file",
93
+ "filename": "$TEST_DIR/2.raw"
94
+ }
95
+ }
96
+ ]
97
+ }
853
+ }
98
+ }
854
+ }
99
+ { "execute": "x-blockdev-change",
855
+
100
+ "arguments": { "parent": "drive0-quorum",
856
+ /* If we've got too many, that implies a descriptor loop. */
101
+ "child": "children.1" } }
857
+ if ((in_num + out_num) > max) {
102
+ { "execute": "quit" }
858
+ fprintf(stderr, "Looped descriptor\n");
103
+EOF
859
+ return NULL;
104
+ done
860
+ }
105
+done
861
+ rc = vduse_queue_read_next_desc(desc, i, max, &i);
106
+
862
+ } while (rc == VIRTQUEUE_READ_DESC_MORE);
107
# success, all done
863
+
108
echo "*** done"
864
+ if (rc == VIRTQUEUE_READ_DESC_ERROR) {
109
rm -f $seq.full
865
+ fprintf(stderr, "read descriptor error\n");
110
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
866
+ return NULL;
867
+ }
868
+
869
+ /* Now copy what we have collected and mapped */
870
+ elem = vduse_queue_alloc_element(sz, out_num, in_num);
871
+ if (!elem) {
872
+ fprintf(stderr, "read descriptor error\n");
873
+ return NULL;
874
+ }
875
+ elem->index = idx;
876
+ for (i = 0; i < out_num; i++) {
877
+ elem->out_sg[i] = iov[i];
878
+ }
879
+ for (i = 0; i < in_num; i++) {
880
+ elem->in_sg[i] = iov[out_num + i];
881
+ }
882
+
883
+ return elem;
884
+}
885
+
886
+void *vduse_queue_pop(VduseVirtq *vq, size_t sz)
887
+{
888
+ unsigned int head;
889
+ VduseVirtqElement *elem;
890
+ VduseDev *dev = vq->dev;
891
+
892
+ if (unlikely(!vq->vring.avail)) {
893
+ return NULL;
894
+ }
895
+
896
+ if (vduse_queue_empty(vq)) {
897
+ return NULL;
898
+ }
899
+ /* Needed after virtio_queue_empty() */
900
+ smp_rmb();
901
+
902
+ if (vq->inuse >= vq->vring.num) {
903
+ fprintf(stderr, "Virtqueue size exceeded: %d\n", vq->inuse);
904
+ return NULL;
905
+ }
906
+
907
+ if (!vduse_queue_get_head(vq, vq->last_avail_idx++, &head)) {
908
+ return NULL;
909
+ }
910
+
911
+ if (vduse_dev_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
912
+ vring_set_avail_event(vq, vq->last_avail_idx);
913
+ }
914
+
915
+ elem = vduse_queue_map_desc(vq, head, sz);
916
+
917
+ if (!elem) {
918
+ return NULL;
919
+ }
920
+
921
+ vq->inuse++;
922
+
923
+ return elem;
924
+}
925
+
926
+static inline void vring_used_write(VduseVirtq *vq,
927
+ struct vring_used_elem *uelem, int i)
928
+{
929
+ struct vring_used *used = vq->vring.used;
930
+
931
+ used->ring[i] = *uelem;
932
+}
933
+
934
+static void vduse_queue_fill(VduseVirtq *vq, const VduseVirtqElement *elem,
935
+ unsigned int len, unsigned int idx)
936
+{
937
+ struct vring_used_elem uelem;
938
+
939
+ if (unlikely(!vq->vring.used)) {
940
+ return;
941
+ }
942
+
943
+ idx = (idx + vq->used_idx) % vq->vring.num;
944
+
945
+ uelem.id = htole32(elem->index);
946
+ uelem.len = htole32(len);
947
+ vring_used_write(vq, &uelem, idx);
948
+}
949
+
950
+static inline void vring_used_idx_set(VduseVirtq *vq, uint16_t val)
951
+{
952
+ vq->vring.used->idx = htole16(val);
953
+ vq->used_idx = val;
954
+}
955
+
956
+static void vduse_queue_flush(VduseVirtq *vq, unsigned int count)
957
+{
958
+ uint16_t old, new;
959
+
960
+ if (unlikely(!vq->vring.used)) {
961
+ return;
962
+ }
963
+
964
+ /* Make sure buffer is written before we update index. */
965
+ smp_wmb();
966
+
967
+ old = vq->used_idx;
968
+ new = old + count;
969
+ vring_used_idx_set(vq, new);
970
+ vq->inuse -= count;
971
+ if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old))) {
972
+ vq->signalled_used_valid = false;
973
+ }
974
+}
975
+
976
+void vduse_queue_push(VduseVirtq *vq, const VduseVirtqElement *elem,
977
+ unsigned int len)
978
+{
979
+ vduse_queue_fill(vq, elem, len, 0);
980
+ vduse_queue_flush(vq, 1);
981
+}
982
+
983
+static int vduse_queue_update_vring(VduseVirtq *vq, uint64_t desc_addr,
984
+ uint64_t avail_addr, uint64_t used_addr)
985
+{
986
+ struct VduseDev *dev = vq->dev;
987
+ uint64_t len;
988
+
989
+ len = sizeof(struct vring_desc);
990
+ vq->vring.desc = iova_to_va(dev, &len, desc_addr);
991
+ if (len != sizeof(struct vring_desc)) {
992
+ return -EINVAL;
993
+ }
994
+
995
+ len = sizeof(struct vring_avail);
996
+ vq->vring.avail = iova_to_va(dev, &len, avail_addr);
997
+ if (len != sizeof(struct vring_avail)) {
998
+ return -EINVAL;
999
+ }
1000
+
1001
+ len = sizeof(struct vring_used);
1002
+ vq->vring.used = iova_to_va(dev, &len, used_addr);
1003
+ if (len != sizeof(struct vring_used)) {
1004
+ return -EINVAL;
1005
+ }
1006
+
1007
+ if (!vq->vring.desc || !vq->vring.avail || !vq->vring.used) {
1008
+ fprintf(stderr, "Failed to get vq[%d] iova mapping\n", vq->index);
1009
+ return -EINVAL;
1010
+ }
1011
+
1012
+ return 0;
1013
+}
1014
+
1015
+static void vduse_queue_enable(VduseVirtq *vq)
1016
+{
1017
+ struct VduseDev *dev = vq->dev;
1018
+ struct vduse_vq_info vq_info;
1019
+ struct vduse_vq_eventfd vq_eventfd;
1020
+ int fd;
1021
+
1022
+ vq_info.index = vq->index;
1023
+ if (ioctl(dev->fd, VDUSE_VQ_GET_INFO, &vq_info)) {
1024
+ fprintf(stderr, "Failed to get vq[%d] info: %s\n",
1025
+ vq->index, strerror(errno));
1026
+ return;
1027
+ }
1028
+
1029
+ if (!vq_info.ready) {
1030
+ return;
1031
+ }
1032
+
1033
+ vq->vring.num = vq_info.num;
1034
+ vq->vring.desc_addr = vq_info.desc_addr;
1035
+ vq->vring.avail_addr = vq_info.driver_addr;
1036
+ vq->vring.used_addr = vq_info.device_addr;
1037
+
1038
+ if (vduse_queue_update_vring(vq, vq_info.desc_addr,
1039
+ vq_info.driver_addr, vq_info.device_addr)) {
1040
+ fprintf(stderr, "Failed to update vring for vq[%d]\n", vq->index);
1041
+ return;
1042
+ }
1043
+
1044
+ fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
1045
+ if (fd < 0) {
1046
+ fprintf(stderr, "Failed to init eventfd for vq[%d]\n", vq->index);
1047
+ return;
1048
+ }
1049
+
1050
+ vq_eventfd.index = vq->index;
1051
+ vq_eventfd.fd = fd;
1052
+ if (ioctl(dev->fd, VDUSE_VQ_SETUP_KICKFD, &vq_eventfd)) {
1053
+ fprintf(stderr, "Failed to setup kick fd for vq[%d]\n", vq->index);
1054
+ close(fd);
1055
+ return;
1056
+ }
1057
+
1058
+ vq->fd = fd;
1059
+ vq->shadow_avail_idx = vq->last_avail_idx = vq_info.split.avail_index;
1060
+ vq->inuse = 0;
1061
+ vq->used_idx = 0;
1062
+ vq->signalled_used_valid = false;
1063
+ vq->ready = true;
1064
+
1065
+ dev->ops->enable_queue(dev, vq);
1066
+}
1067
+
1068
+static void vduse_queue_disable(VduseVirtq *vq)
1069
+{
1070
+ struct VduseDev *dev = vq->dev;
1071
+ struct vduse_vq_eventfd eventfd;
1072
+
1073
+ if (!vq->ready) {
1074
+ return;
1075
+ }
1076
+
1077
+ dev->ops->disable_queue(dev, vq);
1078
+
1079
+ eventfd.index = vq->index;
1080
+ eventfd.fd = VDUSE_EVENTFD_DEASSIGN;
1081
+ ioctl(dev->fd, VDUSE_VQ_SETUP_KICKFD, &eventfd);
1082
+ close(vq->fd);
1083
+
1084
+ assert(vq->inuse == 0);
1085
+
1086
+ vq->vring.num = 0;
1087
+ vq->vring.desc_addr = 0;
1088
+ vq->vring.avail_addr = 0;
1089
+ vq->vring.used_addr = 0;
1090
+ vq->vring.desc = 0;
1091
+ vq->vring.avail = 0;
1092
+ vq->vring.used = 0;
1093
+ vq->ready = false;
1094
+ vq->fd = -1;
1095
+}
1096
+
1097
+static void vduse_dev_start_dataplane(VduseDev *dev)
1098
+{
1099
+ int i;
1100
+
1101
+ if (ioctl(dev->fd, VDUSE_DEV_GET_FEATURES, &dev->features)) {
1102
+ fprintf(stderr, "Failed to get features: %s\n", strerror(errno));
1103
+ return;
1104
+ }
1105
+ assert(vduse_dev_has_feature(dev, VIRTIO_F_VERSION_1));
1106
+
1107
+ for (i = 0; i < dev->num_queues; i++) {
1108
+ vduse_queue_enable(&dev->vqs[i]);
1109
+ }
1110
+}
1111
+
1112
+static void vduse_dev_stop_dataplane(VduseDev *dev)
1113
+{
1114
+ int i;
1115
+
1116
+ for (i = 0; i < dev->num_queues; i++) {
1117
+ vduse_queue_disable(&dev->vqs[i]);
1118
+ }
1119
+ dev->features = 0;
1120
+ vduse_iova_remove_region(dev, 0, ULONG_MAX);
1121
+}
1122
+
1123
+int vduse_dev_handler(VduseDev *dev)
1124
+{
1125
+ struct vduse_dev_request req;
1126
+ struct vduse_dev_response resp = { 0 };
1127
+ VduseVirtq *vq;
1128
+ int i, ret;
1129
+
1130
+ ret = read(dev->fd, &req, sizeof(req));
1131
+ if (ret != sizeof(req)) {
1132
+ fprintf(stderr, "Read request error [%d]: %s\n",
1133
+ ret, strerror(errno));
1134
+ return -errno;
1135
+ }
1136
+ resp.request_id = req.request_id;
1137
+
1138
+ switch (req.type) {
1139
+ case VDUSE_GET_VQ_STATE:
1140
+ vq = &dev->vqs[req.vq_state.index];
1141
+ resp.vq_state.split.avail_index = vq->last_avail_idx;
1142
+ resp.result = VDUSE_REQ_RESULT_OK;
1143
+ break;
1144
+ case VDUSE_SET_STATUS:
1145
+ if (req.s.status & VIRTIO_CONFIG_S_DRIVER_OK) {
1146
+ vduse_dev_start_dataplane(dev);
1147
+ } else if (req.s.status == 0) {
1148
+ vduse_dev_stop_dataplane(dev);
1149
+ }
1150
+ resp.result = VDUSE_REQ_RESULT_OK;
1151
+ break;
1152
+ case VDUSE_UPDATE_IOTLB:
1153
+ /* The iova will be updated by iova_to_va() later, so just remove it */
1154
+ vduse_iova_remove_region(dev, req.iova.start, req.iova.last);
1155
+ for (i = 0; i < dev->num_queues; i++) {
1156
+ VduseVirtq *vq = &dev->vqs[i];
1157
+ if (vq->ready) {
1158
+ if (vduse_queue_update_vring(vq, vq->vring.desc_addr,
1159
+ vq->vring.avail_addr,
1160
+ vq->vring.used_addr)) {
1161
+ fprintf(stderr, "Failed to update vring for vq[%d]\n",
1162
+ vq->index);
1163
+ }
1164
+ }
1165
+ }
1166
+ resp.result = VDUSE_REQ_RESULT_OK;
1167
+ break;
1168
+ default:
1169
+ resp.result = VDUSE_REQ_RESULT_FAILED;
1170
+ break;
1171
+ }
1172
+
1173
+ ret = write(dev->fd, &resp, sizeof(resp));
1174
+ if (ret != sizeof(resp)) {
1175
+ fprintf(stderr, "Write request %d error [%d]: %s\n",
1176
+ req.type, ret, strerror(errno));
1177
+ return -errno;
1178
+ }
1179
+ return 0;
1180
+}
1181
+
1182
+int vduse_dev_update_config(VduseDev *dev, uint32_t size,
1183
+ uint32_t offset, char *buffer)
1184
+{
1185
+ int ret;
1186
+ struct vduse_config_data *data;
1187
+
1188
+ data = malloc(offsetof(struct vduse_config_data, buffer) + size);
1189
+ if (!data) {
1190
+ return -ENOMEM;
1191
+ }
1192
+
1193
+ data->offset = offset;
1194
+ data->length = size;
1195
+ memcpy(data->buffer, buffer, size);
1196
+
1197
+ ret = ioctl(dev->fd, VDUSE_DEV_SET_CONFIG, data);
1198
+ free(data);
1199
+
1200
+ if (ret) {
1201
+ return -errno;
1202
+ }
1203
+
1204
+ if (ioctl(dev->fd, VDUSE_DEV_INJECT_CONFIG_IRQ)) {
1205
+ return -errno;
1206
+ }
1207
+
1208
+ return 0;
1209
+}
1210
+
1211
+int vduse_dev_setup_queue(VduseDev *dev, int index, int max_size)
1212
+{
1213
+ VduseVirtq *vq = &dev->vqs[index];
1214
+ struct vduse_vq_config vq_config = { 0 };
1215
+
1216
+ if (max_size > VIRTQUEUE_MAX_SIZE) {
1217
+ return -EINVAL;
1218
+ }
1219
+
1220
+ vq_config.index = vq->index;
1221
+ vq_config.max_size = max_size;
1222
+
1223
+ if (ioctl(dev->fd, VDUSE_VQ_SETUP, &vq_config)) {
1224
+ return -errno;
1225
+ }
1226
+
1227
+ return 0;
1228
+}
1229
+
1230
+static int vduse_dev_init_vqs(VduseDev *dev, uint16_t num_queues)
1231
+{
1232
+ VduseVirtq *vqs;
1233
+ int i;
1234
+
1235
+ vqs = calloc(sizeof(VduseVirtq), num_queues);
1236
+ if (!vqs) {
1237
+ return -ENOMEM;
1238
+ }
1239
+
1240
+ for (i = 0; i < num_queues; i++) {
1241
+ vqs[i].index = i;
1242
+ vqs[i].dev = dev;
1243
+ vqs[i].fd = -1;
1244
+ }
1245
+ dev->vqs = vqs;
1246
+
1247
+ return 0;
1248
+}
1249
+
1250
+static int vduse_dev_init(VduseDev *dev, const char *name,
1251
+ uint16_t num_queues, const VduseOps *ops,
1252
+ void *priv)
1253
+{
1254
+ char *dev_path, *dev_name;
1255
+ int ret, fd;
1256
+
1257
+ dev_path = malloc(strlen(name) + strlen("/dev/vduse/") + 1);
1258
+ if (!dev_path) {
1259
+ return -ENOMEM;
1260
+ }
1261
+ sprintf(dev_path, "/dev/vduse/%s", name);
1262
+
1263
+ fd = open(dev_path, O_RDWR);
1264
+ free(dev_path);
1265
+ if (fd < 0) {
1266
+ fprintf(stderr, "Failed to open vduse dev %s: %s\n",
1267
+ name, strerror(errno));
1268
+ return -errno;
1269
+ }
1270
+
1271
+ dev_name = strdup(name);
1272
+ if (!dev_name) {
1273
+ close(fd);
1274
+ return -ENOMEM;
1275
+ }
1276
+
1277
+ ret = vduse_dev_init_vqs(dev, num_queues);
1278
+ if (ret) {
1279
+ free(dev_name);
1280
+ close(fd);
1281
+ return ret;
1282
+ }
1283
+
1284
+ dev->name = dev_name;
1285
+ dev->num_queues = num_queues;
1286
+ dev->fd = fd;
1287
+ dev->ops = ops;
1288
+ dev->priv = priv;
1289
+
1290
+ return 0;
1291
+}
1292
+
1293
+static inline bool vduse_name_is_valid(const char *name)
1294
+{
1295
+ return strlen(name) >= VDUSE_NAME_MAX || strstr(name, "..");
1296
+}
1297
+
1298
+VduseDev *vduse_dev_create_by_fd(int fd, uint16_t num_queues,
1299
+ const VduseOps *ops, void *priv)
1300
+{
1301
+ VduseDev *dev;
1302
+ int ret;
1303
+
1304
+ if (!ops || !ops->enable_queue || !ops->disable_queue) {
1305
+ fprintf(stderr, "Invalid parameter for vduse\n");
1306
+ return NULL;
1307
+ }
1308
+
1309
+ dev = calloc(sizeof(VduseDev), 1);
1310
+ if (!dev) {
1311
+ fprintf(stderr, "Failed to allocate vduse device\n");
1312
+ return NULL;
1313
+ }
1314
+
1315
+ ret = vduse_dev_init_vqs(dev, num_queues);
1316
+ if (ret) {
1317
+ fprintf(stderr, "Failed to init vqs\n");
1318
+ free(dev);
1319
+ return NULL;
1320
+ }
1321
+
1322
+ dev->num_queues = num_queues;
1323
+ dev->fd = fd;
1324
+ dev->ops = ops;
1325
+ dev->priv = priv;
1326
+
1327
+ return dev;
1328
+}
1329
+
1330
+VduseDev *vduse_dev_create_by_name(const char *name, uint16_t num_queues,
1331
+ const VduseOps *ops, void *priv)
1332
+{
1333
+ VduseDev *dev;
1334
+ int ret;
1335
+
1336
+ if (!name || vduse_name_is_valid(name) || !ops ||
1337
+ !ops->enable_queue || !ops->disable_queue) {
1338
+ fprintf(stderr, "Invalid parameter for vduse\n");
1339
+ return NULL;
1340
+ }
1341
+
1342
+ dev = calloc(sizeof(VduseDev), 1);
1343
+ if (!dev) {
1344
+ fprintf(stderr, "Failed to allocate vduse device\n");
1345
+ return NULL;
1346
+ }
1347
+
1348
+ ret = vduse_dev_init(dev, name, num_queues, ops, priv);
1349
+ if (ret < 0) {
1350
+ fprintf(stderr, "Failed to init vduse device %s: %s\n",
1351
+ name, strerror(ret));
1352
+ free(dev);
1353
+ return NULL;
1354
+ }
1355
+
1356
+ return dev;
1357
+}
1358
+
1359
+VduseDev *vduse_dev_create(const char *name, uint32_t device_id,
1360
+ uint32_t vendor_id, uint64_t features,
1361
+ uint16_t num_queues, uint32_t config_size,
1362
+ char *config, const VduseOps *ops, void *priv)
1363
+{
1364
+ VduseDev *dev;
1365
+ int ret, ctrl_fd;
1366
+ uint64_t version;
1367
+ struct vduse_dev_config *dev_config;
1368
+ size_t size = offsetof(struct vduse_dev_config, config);
1369
+
1370
+ if (!name || vduse_name_is_valid(name) ||
1371
+ !has_feature(features, VIRTIO_F_VERSION_1) || !config ||
1372
+ !config_size || !ops || !ops->enable_queue || !ops->disable_queue) {
1373
+ fprintf(stderr, "Invalid parameter for vduse\n");
1374
+ return NULL;
1375
+ }
1376
+
1377
+ dev = calloc(sizeof(VduseDev), 1);
1378
+ if (!dev) {
1379
+ fprintf(stderr, "Failed to allocate vduse device\n");
1380
+ return NULL;
1381
+ }
1382
+
1383
+ ctrl_fd = open("/dev/vduse/control", O_RDWR);
1384
+ if (ctrl_fd < 0) {
1385
+ fprintf(stderr, "Failed to open /dev/vduse/control: %s\n",
1386
+ strerror(errno));
1387
+ goto err_ctrl;
1388
+ }
1389
+
1390
+ version = VDUSE_API_VERSION;
1391
+ if (ioctl(ctrl_fd, VDUSE_SET_API_VERSION, &version)) {
1392
+ fprintf(stderr, "Failed to set api version %" PRIu64 ": %s\n",
1393
+ version, strerror(errno));
1394
+ goto err_dev;
1395
+ }
1396
+
1397
+ dev_config = calloc(size + config_size, 1);
1398
+ if (!dev_config) {
1399
+ fprintf(stderr, "Failed to allocate config space\n");
1400
+ goto err_dev;
1401
+ }
1402
+
1403
+ strcpy(dev_config->name, name);
1404
+ dev_config->device_id = device_id;
1405
+ dev_config->vendor_id = vendor_id;
1406
+ dev_config->features = features;
1407
+ dev_config->vq_num = num_queues;
1408
+ dev_config->vq_align = VDUSE_VQ_ALIGN;
1409
+ dev_config->config_size = config_size;
1410
+ memcpy(dev_config->config, config, config_size);
1411
+
1412
+ ret = ioctl(ctrl_fd, VDUSE_CREATE_DEV, dev_config);
1413
+ free(dev_config);
1414
+ if (ret < 0) {
1415
+ fprintf(stderr, "Failed to create vduse device %s: %s\n",
1416
+ name, strerror(errno));
1417
+ goto err_dev;
1418
+ }
1419
+ dev->ctrl_fd = ctrl_fd;
1420
+
1421
+ ret = vduse_dev_init(dev, name, num_queues, ops, priv);
1422
+ if (ret < 0) {
1423
+ fprintf(stderr, "Failed to init vduse device %s: %s\n",
1424
+ name, strerror(ret));
1425
+ goto err;
1426
+ }
1427
+
1428
+ return dev;
1429
+err:
1430
+ ioctl(ctrl_fd, VDUSE_DESTROY_DEV, name);
1431
+err_dev:
1432
+ close(ctrl_fd);
1433
+err_ctrl:
1434
+ free(dev);
1435
+
1436
+ return NULL;
1437
+}
1438
+
1439
+int vduse_dev_destroy(VduseDev *dev)
1440
+{
1441
+ int ret = 0;
1442
+
1443
+ free(dev->vqs);
1444
+ if (dev->fd >= 0) {
1445
+ close(dev->fd);
1446
+ dev->fd = -1;
1447
+ }
1448
+ if (dev->ctrl_fd >= 0) {
1449
+ if (ioctl(dev->ctrl_fd, VDUSE_DESTROY_DEV, dev->name)) {
1450
+ ret = -errno;
1451
+ }
1452
+ close(dev->ctrl_fd);
1453
+ dev->ctrl_fd = -1;
1454
+ }
1455
+ free(dev->name);
1456
+ free(dev);
1457
+
1458
+ return ret;
1459
+}
1460
diff --git a/MAINTAINERS b/MAINTAINERS
111
index XXXXXXX..XXXXXXX 100644
1461
index XXXXXXX..XXXXXXX 100644
112
--- a/tests/qemu-iotests/081.out
1462
--- a/MAINTAINERS
113
+++ b/tests/qemu-iotests/081.out
1463
+++ b/MAINTAINERS
114
@@ -XXX,XX +XXX,XX @@ read 10485760/10485760 bytes at offset 0
1464
@@ -XXX,XX +XXX,XX @@ L: qemu-block@nongnu.org
115
1465
S: Supported
116
== checking the blkverify mode with invalid settings ==
1466
F: block/export/fuse.c
117
can't open: blkverify=on can only be set if there are exactly two files and vote-threshold is 2
1467
118
+
1468
+VDUSE library
119
+== dynamically adding a child to a quorum ==
1469
+M: Xie Yongji <xieyongji@bytedance.com>
120
+Testing:
1470
+S: Maintained
121
+QMP_VERSION
1471
+F: subprojects/libvduse/
122
+{"return": {}}
1472
+
123
+{"return": {}}
1473
Replication
124
+{"return": {}}
1474
M: Wen Congyang <wencongyang2@huawei.com>
125
+{"return": {}}
1475
M: Xie Changlong <xiechanglong.d@gmail.com>
126
+{"return": {}}
1476
diff --git a/meson.build b/meson.build
127
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
1477
index XXXXXXX..XXXXXXX 100644
128
+
1478
--- a/meson.build
129
+Testing:
1479
+++ b/meson.build
130
+QMP_VERSION
1480
@@ -XXX,XX +XXX,XX @@ if get_option('fuse_lseek').allowed()
131
+{"return": {}}
1481
endif
132
+{"return": {}}
1482
endif
133
+{"return": {}}
1483
134
+{"error": {"class": "GenericError", "desc": "Cannot add a child to a quorum in blkverify mode"}}
1484
+have_libvduse = (targetos == 'linux')
135
+{"return": {}}
1485
+if get_option('libvduse').enabled()
136
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
1486
+ if targetos != 'linux'
137
+
1487
+ error('libvduse requires linux')
138
+
1488
+ endif
139
+== dynamically removing a child from a quorum ==
1489
+elif get_option('libvduse').disabled()
140
+Testing:
1490
+ have_libvduse = false
141
+QMP_VERSION
1491
+endif
142
+{"return": {}}
1492
+
143
+{"return": {}}
1493
# libbpf
144
+{"return": {}}
1494
libbpf = dependency('libbpf', required: get_option('bpf'), method: 'pkg-config')
145
+{"return": {}}
1495
if libbpf.found() and not cc.links('''
146
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
1496
@@ -XXX,XX +XXX,XX @@ if targetos == 'linux' and have_vhost_user
147
+
1497
vhost_user = libvhost_user.get_variable('vhost_user_dep')
148
+Testing:
1498
endif
149
+QMP_VERSION
1499
150
+{"return": {}}
1500
+libvduse = not_found
151
+{"return": {}}
1501
+if have_libvduse
152
+{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
1502
+ libvduse_proj = subproject('libvduse')
153
+{"return": {}}
1503
+ libvduse = libvduse_proj.get_variable('libvduse_dep')
154
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
1504
+endif
155
+
1505
+
156
+Testing:
1506
# NOTE: the trace/ subdirectory needs the qapi_trace_events variable
157
+QMP_VERSION
1507
# that is filled in by qapi/.
158
+{"return": {}}
1508
subdir('qapi')
159
+{"error": {"class": "GenericError", "desc": "blkverify=on can only be set if there are exactly two files and vote-threshold is 2"}}
1509
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
160
+{"error": {"class": "GenericError", "desc": "Cannot find device=drive0-quorum nor node_name=drive0-quorum"}}
1510
index XXXXXXX..XXXXXXX 100644
161
+{"return": {}}
1511
--- a/scripts/meson-buildoptions.sh
162
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
1512
+++ b/scripts/meson-buildoptions.sh
163
+
1513
@@ -XXX,XX +XXX,XX @@ meson_options_help() {
164
+Testing:
1514
printf "%s\n" ' libssh ssh block device support'
165
+QMP_VERSION
1515
printf "%s\n" ' libudev Use libudev to enumerate host devices'
166
+{"return": {}}
1516
printf "%s\n" ' libusb libusb support for USB passthrough'
167
+{"return": {}}
1517
+ printf "%s\n" ' libvduse build VDUSE Library'
168
+{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
1518
printf "%s\n" ' linux-aio Linux AIO support'
169
+{"return": {}}
1519
printf "%s\n" ' linux-io-uring Linux io_uring support'
170
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
1520
printf "%s\n" ' live-block-migration'
171
+
1521
@@ -XXX,XX +XXX,XX @@ _meson_option_parse() {
172
*** done
1522
--disable-libudev) printf "%s" -Dlibudev=disabled ;;
1523
--enable-libusb) printf "%s" -Dlibusb=enabled ;;
1524
--disable-libusb) printf "%s" -Dlibusb=disabled ;;
1525
+ --enable-libvduse) printf "%s" -Dlibvduse=enabled ;;
1526
+ --disable-libvduse) printf "%s" -Dlibvduse=disabled ;;
1527
--enable-linux-aio) printf "%s" -Dlinux_aio=enabled ;;
1528
--disable-linux-aio) printf "%s" -Dlinux_aio=disabled ;;
1529
--enable-linux-io-uring) printf "%s" -Dlinux_io_uring=enabled ;;
1530
diff --git a/subprojects/libvduse/linux-headers/linux b/subprojects/libvduse/linux-headers/linux
1531
new file mode 120000
1532
index XXXXXXX..XXXXXXX
1533
--- /dev/null
1534
+++ b/subprojects/libvduse/linux-headers/linux
1535
@@ -0,0 +1 @@
1536
+../../../linux-headers/linux/
1537
\ No newline at end of file
1538
diff --git a/subprojects/libvduse/meson.build b/subprojects/libvduse/meson.build
1539
new file mode 100644
1540
index XXXXXXX..XXXXXXX
1541
--- /dev/null
1542
+++ b/subprojects/libvduse/meson.build
1543
@@ -XXX,XX +XXX,XX @@
1544
+project('libvduse', 'c',
1545
+ license: 'GPL-2.0-or-later',
1546
+ default_options: ['c_std=gnu99'])
1547
+
1548
+libvduse = static_library('vduse',
1549
+ files('libvduse.c'),
1550
+ c_args: '-D_GNU_SOURCE')
1551
+
1552
+libvduse_dep = declare_dependency(link_with: libvduse,
1553
+ include_directories: include_directories('.'))
1554
diff --git a/subprojects/libvduse/standard-headers/linux b/subprojects/libvduse/standard-headers/linux
1555
new file mode 120000
1556
index XXXXXXX..XXXXXXX
1557
--- /dev/null
1558
+++ b/subprojects/libvduse/standard-headers/linux
1559
@@ -0,0 +1 @@
1560
+../../../include/standard-headers/linux/
1561
\ No newline at end of file
173
--
1562
--
174
2.19.1
1563
2.35.3
175
1564
176
1565
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Xie Yongji <xieyongji@bytedance.com>
2
2
3
The blkverify mode of Quorum only works when the number of children is
3
This implements a VDUSE block backends based on
4
exactly two, so any attempt to add a new one must return an error.
4
the libvduse library. We can use it to export the BDSs
5
5
for both VM and container (host) usage.
6
quorum_del_child() on the other hand doesn't need any additional check
6
7
because decreasing the number of children would make it go under the
7
The new command-line syntax is:
8
vote threshold.
8
9
9
$ qemu-storage-daemon \
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
--blockdev file,node-name=drive0,filename=test.img \
11
Reported-by: Kevin Wolf <kwolf@redhat.com>
11
--export vduse-blk,node-name=drive0,id=vduse-export0,writable=on
12
13
After the qemu-storage-daemon started, we need to use
14
the "vdpa" command to attach the device to vDPA bus:
15
16
$ vdpa dev add name vduse-export0 mgmtdev vduse
17
18
Also the device must be removed via the "vdpa" command
19
before we stop the qemu-storage-daemon.
20
21
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
22
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
23
Message-Id: <20220523084611.91-7-xieyongji@bytedance.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
25
---
14
block/quorum.c | 8 ++++++++
26
qapi/block-export.json | 28 ++-
15
1 file changed, 8 insertions(+)
27
meson_options.txt | 2 +
16
28
block/export/vduse-blk.h | 20 +++
17
diff --git a/block/quorum.c b/block/quorum.c
29
block/export/export.c | 6 +
18
index XXXXXXX..XXXXXXX 100644
30
block/export/vduse-blk.c | 329 ++++++++++++++++++++++++++++++++++
19
--- a/block/quorum.c
31
MAINTAINERS | 4 +-
20
+++ b/block/quorum.c
32
block/export/meson.build | 5 +
21
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
33
meson.build | 13 ++
22
char indexstr[32];
34
scripts/meson-buildoptions.sh | 4 +
23
int ret;
35
9 files changed, 407 insertions(+), 4 deletions(-)
24
36
create mode 100644 block/export/vduse-blk.h
25
+ if (s->is_blkverify) {
37
create mode 100644 block/export/vduse-blk.c
26
+ error_setg(errp, "Cannot add a child to a quorum in blkverify mode");
38
39
diff --git a/qapi/block-export.json b/qapi/block-export.json
40
index XXXXXXX..XXXXXXX 100644
41
--- a/qapi/block-export.json
42
+++ b/qapi/block-export.json
43
@@ -XXX,XX +XXX,XX @@
44
'*allow-other': 'FuseExportAllowOther' },
45
'if': 'CONFIG_FUSE' }
46
47
+##
48
+# @BlockExportOptionsVduseBlk:
49
+#
50
+# A vduse-blk block export.
51
+#
52
+# @num-queues: the number of virtqueues. Defaults to 1.
53
+# @queue-size: the size of virtqueue. Defaults to 256.
54
+# @logical-block-size: Logical block size in bytes. Range [512, PAGE_SIZE]
55
+# and must be power of 2. Defaults to 512 bytes.
56
+#
57
+# Since: 7.1
58
+##
59
+{ 'struct': 'BlockExportOptionsVduseBlk',
60
+ 'data': { '*num-queues': 'uint16',
61
+ '*queue-size': 'uint16',
62
+ '*logical-block-size': 'size'} }
63
+
64
##
65
# @NbdServerAddOptions:
66
#
67
@@ -XXX,XX +XXX,XX @@
68
# @nbd: NBD export
69
# @vhost-user-blk: vhost-user-blk export (since 5.2)
70
# @fuse: FUSE export (since: 6.0)
71
+# @vduse-blk: vduse-blk export (since 7.1)
72
#
73
# Since: 4.2
74
##
75
@@ -XXX,XX +XXX,XX @@
76
'data': [ 'nbd',
77
{ 'name': 'vhost-user-blk',
78
'if': 'CONFIG_VHOST_USER_BLK_SERVER' },
79
- { 'name': 'fuse', 'if': 'CONFIG_FUSE' } ] }
80
+ { 'name': 'fuse', 'if': 'CONFIG_FUSE' },
81
+ { 'name': 'vduse-blk', 'if': 'CONFIG_VDUSE_BLK_EXPORT' } ] }
82
83
##
84
# @BlockExportOptions:
85
@@ -XXX,XX +XXX,XX @@
86
# Describes a block export, i.e. how single node should be exported on an
87
# external interface.
88
#
89
-# @id: A unique identifier for the block export (across all export types)
90
+# @id: A unique identifier for the block export (across the host for vduse-blk
91
+# export type or across all export types for other types)
92
#
93
# @node-name: The node name of the block node to be exported (since: 5.2)
94
#
95
@@ -XXX,XX +XXX,XX @@
96
'vhost-user-blk': { 'type': 'BlockExportOptionsVhostUserBlk',
97
'if': 'CONFIG_VHOST_USER_BLK_SERVER' },
98
'fuse': { 'type': 'BlockExportOptionsFuse',
99
- 'if': 'CONFIG_FUSE' }
100
+ 'if': 'CONFIG_FUSE' },
101
+ 'vduse-blk': { 'type': 'BlockExportOptionsVduseBlk',
102
+ 'if': 'CONFIG_VDUSE_BLK_EXPORT' }
103
} }
104
105
##
106
diff --git a/meson_options.txt b/meson_options.txt
107
index XXXXXXX..XXXXXXX 100644
108
--- a/meson_options.txt
109
+++ b/meson_options.txt
110
@@ -XXX,XX +XXX,XX @@ option('virtiofsd', type: 'feature', value: 'auto',
111
description: 'build virtiofs daemon (virtiofsd)')
112
option('libvduse', type: 'feature', value: 'auto',
113
description: 'build VDUSE Library')
114
+option('vduse_blk_export', type: 'feature', value: 'auto',
115
+ description: 'VDUSE block export support')
116
117
option('capstone', type: 'feature', value: 'auto',
118
description: 'Whether and how to find the capstone library')
119
diff --git a/block/export/vduse-blk.h b/block/export/vduse-blk.h
120
new file mode 100644
121
index XXXXXXX..XXXXXXX
122
--- /dev/null
123
+++ b/block/export/vduse-blk.h
124
@@ -XXX,XX +XXX,XX @@
125
+/*
126
+ * Export QEMU block device via VDUSE
127
+ *
128
+ * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved.
129
+ *
130
+ * Author:
131
+ * Xie Yongji <xieyongji@bytedance.com>
132
+ *
133
+ * This work is licensed under the terms of the GNU GPL, version 2 or
134
+ * later. See the COPYING file in the top-level directory.
135
+ */
136
+
137
+#ifndef VDUSE_BLK_H
138
+#define VDUSE_BLK_H
139
+
140
+#include "block/export.h"
141
+
142
+extern const BlockExportDriver blk_exp_vduse_blk;
143
+
144
+#endif /* VDUSE_BLK_H */
145
diff --git a/block/export/export.c b/block/export/export.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/block/export/export.c
148
+++ b/block/export/export.c
149
@@ -XXX,XX +XXX,XX @@
150
#ifdef CONFIG_VHOST_USER_BLK_SERVER
151
#include "vhost-user-blk-server.h"
152
#endif
153
+#ifdef CONFIG_VDUSE_BLK_EXPORT
154
+#include "vduse-blk.h"
155
+#endif
156
157
static const BlockExportDriver *blk_exp_drivers[] = {
158
&blk_exp_nbd,
159
@@ -XXX,XX +XXX,XX @@ static const BlockExportDriver *blk_exp_drivers[] = {
160
#ifdef CONFIG_FUSE
161
&blk_exp_fuse,
162
#endif
163
+#ifdef CONFIG_VDUSE_BLK_EXPORT
164
+ &blk_exp_vduse_blk,
165
+#endif
166
};
167
168
/* Only accessed from the main thread */
169
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
170
new file mode 100644
171
index XXXXXXX..XXXXXXX
172
--- /dev/null
173
+++ b/block/export/vduse-blk.c
174
@@ -XXX,XX +XXX,XX @@
175
+/*
176
+ * Export QEMU block device via VDUSE
177
+ *
178
+ * Copyright (C) 2022 Bytedance Inc. and/or its affiliates. All rights reserved.
179
+ *
180
+ * Author:
181
+ * Xie Yongji <xieyongji@bytedance.com>
182
+ *
183
+ * This work is licensed under the terms of the GNU GPL, version 2 or
184
+ * later. See the COPYING file in the top-level directory.
185
+ */
186
+
187
+#include <sys/eventfd.h>
188
+
189
+#include "qemu/osdep.h"
190
+#include "qapi/error.h"
191
+#include "block/export.h"
192
+#include "qemu/error-report.h"
193
+#include "util/block-helpers.h"
194
+#include "subprojects/libvduse/libvduse.h"
195
+#include "virtio-blk-handler.h"
196
+
197
+#include "standard-headers/linux/virtio_blk.h"
198
+
199
+#define VDUSE_DEFAULT_NUM_QUEUE 1
200
+#define VDUSE_DEFAULT_QUEUE_SIZE 256
201
+
202
+typedef struct VduseBlkExport {
203
+ BlockExport export;
204
+ VirtioBlkHandler handler;
205
+ VduseDev *dev;
206
+ uint16_t num_queues;
207
+ unsigned int inflight;
208
+} VduseBlkExport;
209
+
210
+typedef struct VduseBlkReq {
211
+ VduseVirtqElement elem;
212
+ VduseVirtq *vq;
213
+} VduseBlkReq;
214
+
215
+static void vduse_blk_inflight_inc(VduseBlkExport *vblk_exp)
216
+{
217
+ vblk_exp->inflight++;
218
+}
219
+
220
+static void vduse_blk_inflight_dec(VduseBlkExport *vblk_exp)
221
+{
222
+ if (--vblk_exp->inflight == 0) {
223
+ aio_wait_kick();
224
+ }
225
+}
226
+
227
+static void vduse_blk_req_complete(VduseBlkReq *req, size_t in_len)
228
+{
229
+ vduse_queue_push(req->vq, &req->elem, in_len);
230
+ vduse_queue_notify(req->vq);
231
+
232
+ free(req);
233
+}
234
+
235
+static void coroutine_fn vduse_blk_virtio_process_req(void *opaque)
236
+{
237
+ VduseBlkReq *req = opaque;
238
+ VduseVirtq *vq = req->vq;
239
+ VduseDev *dev = vduse_queue_get_dev(vq);
240
+ VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev);
241
+ VirtioBlkHandler *handler = &vblk_exp->handler;
242
+ VduseVirtqElement *elem = &req->elem;
243
+ struct iovec *in_iov = elem->in_sg;
244
+ struct iovec *out_iov = elem->out_sg;
245
+ unsigned in_num = elem->in_num;
246
+ unsigned out_num = elem->out_num;
247
+ int in_len;
248
+
249
+ in_len = virtio_blk_process_req(handler, in_iov,
250
+ out_iov, in_num, out_num);
251
+ if (in_len < 0) {
252
+ free(req);
27
+ return;
253
+ return;
28
+ }
254
+ }
29
+
255
+
30
assert(s->num_children <= INT_MAX / sizeof(BdrvChild *));
256
+ vduse_blk_req_complete(req, in_len);
31
if (s->num_children == INT_MAX / sizeof(BdrvChild *) ||
257
+ vduse_blk_inflight_dec(vblk_exp);
32
s->next_child_index == UINT_MAX) {
258
+}
33
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
259
+
34
return;
260
+static void vduse_blk_vq_handler(VduseDev *dev, VduseVirtq *vq)
35
}
261
+{
36
262
+ VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev);
37
+ /* We know now that num_children > threshold, so blkverify must be false */
263
+
38
+ assert(!s->is_blkverify);
264
+ while (1) {
39
+
265
+ VduseBlkReq *req;
40
bdrv_drained_begin(bs);
266
+
41
267
+ req = vduse_queue_pop(vq, sizeof(VduseBlkReq));
42
/* We can safely remove this child now */
268
+ if (!req) {
269
+ break;
270
+ }
271
+ req->vq = vq;
272
+
273
+ Coroutine *co =
274
+ qemu_coroutine_create(vduse_blk_virtio_process_req, req);
275
+
276
+ vduse_blk_inflight_inc(vblk_exp);
277
+ qemu_coroutine_enter(co);
278
+ }
279
+}
280
+
281
+static void on_vduse_vq_kick(void *opaque)
282
+{
283
+ VduseVirtq *vq = opaque;
284
+ VduseDev *dev = vduse_queue_get_dev(vq);
285
+ int fd = vduse_queue_get_fd(vq);
286
+ eventfd_t kick_data;
287
+
288
+ if (eventfd_read(fd, &kick_data) == -1) {
289
+ error_report("failed to read data from eventfd");
290
+ return;
291
+ }
292
+
293
+ vduse_blk_vq_handler(dev, vq);
294
+}
295
+
296
+static void vduse_blk_enable_queue(VduseDev *dev, VduseVirtq *vq)
297
+{
298
+ VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev);
299
+
300
+ aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq),
301
+ true, on_vduse_vq_kick, NULL, NULL, NULL, vq);
302
+}
303
+
304
+static void vduse_blk_disable_queue(VduseDev *dev, VduseVirtq *vq)
305
+{
306
+ VduseBlkExport *vblk_exp = vduse_dev_get_priv(dev);
307
+
308
+ aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq),
309
+ true, NULL, NULL, NULL, NULL, NULL);
310
+}
311
+
312
+static const VduseOps vduse_blk_ops = {
313
+ .enable_queue = vduse_blk_enable_queue,
314
+ .disable_queue = vduse_blk_disable_queue,
315
+};
316
+
317
+static void on_vduse_dev_kick(void *opaque)
318
+{
319
+ VduseDev *dev = opaque;
320
+
321
+ vduse_dev_handler(dev);
322
+}
323
+
324
+static void vduse_blk_attach_ctx(VduseBlkExport *vblk_exp, AioContext *ctx)
325
+{
326
+ int i;
327
+
328
+ aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev),
329
+ true, on_vduse_dev_kick, NULL, NULL, NULL,
330
+ vblk_exp->dev);
331
+
332
+ for (i = 0; i < vblk_exp->num_queues; i++) {
333
+ VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
334
+ int fd = vduse_queue_get_fd(vq);
335
+
336
+ if (fd < 0) {
337
+ continue;
338
+ }
339
+ aio_set_fd_handler(vblk_exp->export.ctx, fd, true,
340
+ on_vduse_vq_kick, NULL, NULL, NULL, vq);
341
+ }
342
+}
343
+
344
+static void vduse_blk_detach_ctx(VduseBlkExport *vblk_exp)
345
+{
346
+ int i;
347
+
348
+ for (i = 0; i < vblk_exp->num_queues; i++) {
349
+ VduseVirtq *vq = vduse_dev_get_queue(vblk_exp->dev, i);
350
+ int fd = vduse_queue_get_fd(vq);
351
+
352
+ if (fd < 0) {
353
+ continue;
354
+ }
355
+ aio_set_fd_handler(vblk_exp->export.ctx, fd,
356
+ true, NULL, NULL, NULL, NULL, NULL);
357
+ }
358
+ aio_set_fd_handler(vblk_exp->export.ctx, vduse_dev_get_fd(vblk_exp->dev),
359
+ true, NULL, NULL, NULL, NULL, NULL);
360
+
361
+ AIO_WAIT_WHILE(vblk_exp->export.ctx, vblk_exp->inflight > 0);
362
+}
363
+
364
+
365
+static void blk_aio_attached(AioContext *ctx, void *opaque)
366
+{
367
+ VduseBlkExport *vblk_exp = opaque;
368
+
369
+ vblk_exp->export.ctx = ctx;
370
+ vduse_blk_attach_ctx(vblk_exp, ctx);
371
+}
372
+
373
+static void blk_aio_detach(void *opaque)
374
+{
375
+ VduseBlkExport *vblk_exp = opaque;
376
+
377
+ vduse_blk_detach_ctx(vblk_exp);
378
+ vblk_exp->export.ctx = NULL;
379
+}
380
+
381
+static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
382
+ Error **errp)
383
+{
384
+ VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
385
+ BlockExportOptionsVduseBlk *vblk_opts = &opts->u.vduse_blk;
386
+ uint64_t logical_block_size = VIRTIO_BLK_SECTOR_SIZE;
387
+ uint16_t num_queues = VDUSE_DEFAULT_NUM_QUEUE;
388
+ uint16_t queue_size = VDUSE_DEFAULT_QUEUE_SIZE;
389
+ Error *local_err = NULL;
390
+ struct virtio_blk_config config = { 0 };
391
+ uint64_t features;
392
+ int i;
393
+
394
+ if (vblk_opts->has_num_queues) {
395
+ num_queues = vblk_opts->num_queues;
396
+ if (num_queues == 0) {
397
+ error_setg(errp, "num-queues must be greater than 0");
398
+ return -EINVAL;
399
+ }
400
+ }
401
+
402
+ if (vblk_opts->has_queue_size) {
403
+ queue_size = vblk_opts->queue_size;
404
+ if (queue_size <= 2 || !is_power_of_2(queue_size) ||
405
+ queue_size > VIRTQUEUE_MAX_SIZE) {
406
+ error_setg(errp, "queue-size is invalid");
407
+ return -EINVAL;
408
+ }
409
+ }
410
+
411
+ if (vblk_opts->has_logical_block_size) {
412
+ logical_block_size = vblk_opts->logical_block_size;
413
+ check_block_size(exp->id, "logical-block-size", logical_block_size,
414
+ &local_err);
415
+ if (local_err) {
416
+ error_propagate(errp, local_err);
417
+ return -EINVAL;
418
+ }
419
+ }
420
+ vblk_exp->num_queues = num_queues;
421
+ vblk_exp->handler.blk = exp->blk;
422
+ vblk_exp->handler.serial = exp->id;
423
+ vblk_exp->handler.logical_block_size = logical_block_size;
424
+ vblk_exp->handler.writable = opts->writable;
425
+
426
+ config.capacity =
427
+ cpu_to_le64(blk_getlength(exp->blk) >> VIRTIO_BLK_SECTOR_BITS);
428
+ config.seg_max = cpu_to_le32(queue_size - 2);
429
+ config.min_io_size = cpu_to_le16(1);
430
+ config.opt_io_size = cpu_to_le32(1);
431
+ config.num_queues = cpu_to_le16(num_queues);
432
+ config.blk_size = cpu_to_le32(logical_block_size);
433
+ config.max_discard_sectors = cpu_to_le32(VIRTIO_BLK_MAX_DISCARD_SECTORS);
434
+ config.max_discard_seg = cpu_to_le32(1);
435
+ config.discard_sector_alignment =
436
+ cpu_to_le32(logical_block_size >> VIRTIO_BLK_SECTOR_BITS);
437
+ config.max_write_zeroes_sectors =
438
+ cpu_to_le32(VIRTIO_BLK_MAX_WRITE_ZEROES_SECTORS);
439
+ config.max_write_zeroes_seg = cpu_to_le32(1);
440
+
441
+ features = vduse_get_virtio_features() |
442
+ (1ULL << VIRTIO_BLK_F_SEG_MAX) |
443
+ (1ULL << VIRTIO_BLK_F_TOPOLOGY) |
444
+ (1ULL << VIRTIO_BLK_F_BLK_SIZE) |
445
+ (1ULL << VIRTIO_BLK_F_FLUSH) |
446
+ (1ULL << VIRTIO_BLK_F_DISCARD) |
447
+ (1ULL << VIRTIO_BLK_F_WRITE_ZEROES);
448
+
449
+ if (num_queues > 1) {
450
+ features |= 1ULL << VIRTIO_BLK_F_MQ;
451
+ }
452
+ if (!opts->writable) {
453
+ features |= 1ULL << VIRTIO_BLK_F_RO;
454
+ }
455
+
456
+ vblk_exp->dev = vduse_dev_create(exp->id, VIRTIO_ID_BLOCK, 0,
457
+ features, num_queues,
458
+ sizeof(struct virtio_blk_config),
459
+ (char *)&config, &vduse_blk_ops,
460
+ vblk_exp);
461
+ if (!vblk_exp->dev) {
462
+ error_setg(errp, "failed to create vduse device");
463
+ return -ENOMEM;
464
+ }
465
+
466
+ for (i = 0; i < num_queues; i++) {
467
+ vduse_dev_setup_queue(vblk_exp->dev, i, queue_size);
468
+ }
469
+
470
+ aio_set_fd_handler(exp->ctx, vduse_dev_get_fd(vblk_exp->dev), true,
471
+ on_vduse_dev_kick, NULL, NULL, NULL, vblk_exp->dev);
472
+
473
+ blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
474
+ vblk_exp);
475
+
476
+ return 0;
477
+}
478
+
479
+static void vduse_blk_exp_delete(BlockExport *exp)
480
+{
481
+ VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
482
+
483
+ blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
484
+ vblk_exp);
485
+ vduse_dev_destroy(vblk_exp->dev);
486
+}
487
+
488
+static void vduse_blk_exp_request_shutdown(BlockExport *exp)
489
+{
490
+ VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
491
+
492
+ aio_context_acquire(vblk_exp->export.ctx);
493
+ vduse_blk_detach_ctx(vblk_exp);
494
+ aio_context_acquire(vblk_exp->export.ctx);
495
+}
496
+
497
+const BlockExportDriver blk_exp_vduse_blk = {
498
+ .type = BLOCK_EXPORT_TYPE_VDUSE_BLK,
499
+ .instance_size = sizeof(VduseBlkExport),
500
+ .create = vduse_blk_exp_create,
501
+ .delete = vduse_blk_exp_delete,
502
+ .request_shutdown = vduse_blk_exp_request_shutdown,
503
+};
504
diff --git a/MAINTAINERS b/MAINTAINERS
505
index XXXXXXX..XXXXXXX 100644
506
--- a/MAINTAINERS
507
+++ b/MAINTAINERS
508
@@ -XXX,XX +XXX,XX @@ L: qemu-block@nongnu.org
509
S: Supported
510
F: block/export/fuse.c
511
512
-VDUSE library
513
+VDUSE library and block device exports
514
M: Xie Yongji <xieyongji@bytedance.com>
515
S: Maintained
516
F: subprojects/libvduse/
517
+F: block/export/vduse-blk.c
518
+F: block/export/vduse-blk.h
519
520
Replication
521
M: Wen Congyang <wencongyang2@huawei.com>
522
diff --git a/block/export/meson.build b/block/export/meson.build
523
index XXXXXXX..XXXXXXX 100644
524
--- a/block/export/meson.build
525
+++ b/block/export/meson.build
526
@@ -XXX,XX +XXX,XX @@ if have_vhost_user_blk_server
527
endif
528
529
blockdev_ss.add(when: fuse, if_true: files('fuse.c'))
530
+
531
+if have_vduse_blk_export
532
+ blockdev_ss.add(files('vduse-blk.c', 'virtio-blk-handler.c'))
533
+ blockdev_ss.add(libvduse)
534
+endif
535
diff --git a/meson.build b/meson.build
536
index XXXXXXX..XXXXXXX 100644
537
--- a/meson.build
538
+++ b/meson.build
539
@@ -XXX,XX +XXX,XX @@ elif get_option('libvduse').disabled()
540
have_libvduse = false
541
endif
542
543
+have_vduse_blk_export = (have_libvduse and targetos == 'linux')
544
+if get_option('vduse_blk_export').enabled()
545
+ if targetos != 'linux'
546
+ error('vduse_blk_export requires linux')
547
+ elif not have_libvduse
548
+ error('vduse_blk_export requires libvduse support')
549
+ endif
550
+elif get_option('vduse_blk_export').disabled()
551
+ have_vduse_blk_export = false
552
+endif
553
+
554
# libbpf
555
libbpf = dependency('libbpf', required: get_option('bpf'), method: 'pkg-config')
556
if libbpf.found() and not cc.links('''
557
@@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_VHOST_CRYPTO', have_vhost_user_crypto)
558
config_host_data.set('CONFIG_VHOST_VDPA', have_vhost_vdpa)
559
config_host_data.set('CONFIG_VMNET', vmnet.found())
560
config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', have_vhost_user_blk_server)
561
+config_host_data.set('CONFIG_VDUSE_BLK_EXPORT', have_vduse_blk_export)
562
config_host_data.set('CONFIG_PNG', png.found())
563
config_host_data.set('CONFIG_VNC', vnc.found())
564
config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
565
@@ -XXX,XX +XXX,XX @@ if have_block
566
summary_info += {'qed support': get_option('qed').allowed()}
567
summary_info += {'parallels support': get_option('parallels').allowed()}
568
summary_info += {'FUSE exports': fuse}
569
+ summary_info += {'VDUSE block exports': have_vduse_blk_export}
570
endif
571
summary(summary_info, bool_yn: true, section: 'Block layer support')
572
573
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
574
index XXXXXXX..XXXXXXX 100644
575
--- a/scripts/meson-buildoptions.sh
576
+++ b/scripts/meson-buildoptions.sh
577
@@ -XXX,XX +XXX,XX @@ meson_options_help() {
578
printf "%s\n" ' vhost-user vhost-user backend support'
579
printf "%s\n" ' vhost-user-blk-server'
580
printf "%s\n" ' build vhost-user-blk server'
581
+ printf "%s\n" ' vduse-blk-export'
582
+ printf "%s\n" ' VDUSE block export support'
583
printf "%s\n" ' vhost-vdpa vhost-vdpa kernel backend support'
584
printf "%s\n" ' virglrenderer virgl rendering support'
585
printf "%s\n" ' virtfs virtio-9p support'
586
@@ -XXX,XX +XXX,XX @@ _meson_option_parse() {
587
--disable-vhost-user) printf "%s" -Dvhost_user=disabled ;;
588
--enable-vhost-user-blk-server) printf "%s" -Dvhost_user_blk_server=enabled ;;
589
--disable-vhost-user-blk-server) printf "%s" -Dvhost_user_blk_server=disabled ;;
590
+ --enable-vduse-blk-export) printf "%s" -Dvduse_blk_export=enabled ;;
591
+ --disable-vduse-blk-export) printf "%s" -Dvduse_blk_export=disabled ;;
592
--enable-vhost-vdpa) printf "%s" -Dvhost_vdpa=enabled ;;
593
--disable-vhost-vdpa) printf "%s" -Dvhost_vdpa=disabled ;;
594
--enable-virglrenderer) printf "%s" -Dvirglrenderer=enabled ;;
43
--
595
--
44
2.19.1
596
2.35.3
45
46
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Xie Yongji <xieyongji@bytedance.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
To support block resize, this uses vduse_dev_update_config()
4
it might not be actually aligned enough for that pointer type (and
4
to update the capacity field in configuration space and inject
5
thus cause a crash on dereference on some host architectures). Newer
5
config interrupt on the block resize callback.
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
6
9
There are a few places where the in-place swap function is
7
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
10
used on something other than a packed struct field; we convert
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
those anyway, for consistency.
9
Message-Id: <20220523084611.91-8-xieyongji@bytedance.com>
12
13
This patch was produced with the following spatch script:
14
15
@@
16
expression E;
17
@@
18
-be16_to_cpus(&E);
19
+E = be16_to_cpu(E);
20
@@
21
expression E;
22
@@
23
-be32_to_cpus(&E);
24
+E = be32_to_cpu(E);
25
@@
26
expression E;
27
@@
28
-be64_to_cpus(&E);
29
+E = be64_to_cpu(E);
30
@@
31
expression E;
32
@@
33
-cpu_to_be16s(&E);
34
+E = cpu_to_be16(E);
35
@@
36
expression E;
37
@@
38
-cpu_to_be32s(&E);
39
+E = cpu_to_be32(E);
40
@@
41
expression E;
42
@@
43
-cpu_to_be64s(&E);
44
+E = cpu_to_be64(E);
45
46
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
47
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
48
Tested-by: John Snow <jsnow@redhat.com>
49
Reviewed-by: John Snow <jsnow@redhat.com>
50
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
11
---
52
block/qcow2-bitmap.c | 24 ++++++++++++------------
12
block/export/vduse-blk.c | 20 ++++++++++++++++++++
53
1 file changed, 12 insertions(+), 12 deletions(-)
13
1 file changed, 20 insertions(+)
54
14
55
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
15
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
56
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qcow2-bitmap.c
17
--- a/block/export/vduse-blk.c
58
+++ b/block/qcow2-bitmap.c
18
+++ b/block/export/vduse-blk.c
59
@@ -XXX,XX +XXX,XX @@ static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
19
@@ -XXX,XX +XXX,XX @@ static void blk_aio_detach(void *opaque)
60
size_t i;
20
vblk_exp->export.ctx = NULL;
61
62
for (i = 0; i < size; ++i) {
63
- cpu_to_be64s(&bitmap_table[i]);
64
+ bitmap_table[i] = cpu_to_be64(bitmap_table[i]);
65
}
66
}
21
}
67
22
68
@@ -XXX,XX +XXX,XX @@ static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
23
+static void vduse_blk_resize(void *opaque)
69
}
24
+{
70
25
+ BlockExport *exp = opaque;
71
for (i = 0; i < tb->size; ++i) {
26
+ VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
72
- be64_to_cpus(&table[i]);
27
+ struct virtio_blk_config config;
73
+ table[i] = be64_to_cpu(table[i]);
28
+
74
ret = check_table_entry(table[i], s->cluster_size);
29
+ config.capacity =
75
if (ret < 0) {
30
+ cpu_to_le64(blk_getlength(exp->blk) >> VIRTIO_BLK_SECTOR_BITS);
76
goto fail;
31
+ vduse_dev_update_config(vblk_exp->dev, sizeof(config.capacity),
77
@@ -XXX,XX +XXX,XX @@ fail:
32
+ offsetof(struct virtio_blk_config, capacity),
78
33
+ (char *)&config.capacity);
79
static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry)
34
+}
35
+
36
+static const BlockDevOps vduse_block_ops = {
37
+ .resize_cb = vduse_blk_resize,
38
+};
39
+
40
static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
41
Error **errp)
80
{
42
{
81
- be64_to_cpus(&entry->bitmap_table_offset);
43
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
82
- be32_to_cpus(&entry->bitmap_table_size);
44
blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
83
- be32_to_cpus(&entry->flags);
45
vblk_exp);
84
- be16_to_cpus(&entry->name_size);
46
85
- be32_to_cpus(&entry->extra_data_size);
47
+ blk_set_dev_ops(exp->blk, &vduse_block_ops, exp);
86
+ entry->bitmap_table_offset = be64_to_cpu(entry->bitmap_table_offset);
48
+
87
+ entry->bitmap_table_size = be32_to_cpu(entry->bitmap_table_size);
49
return 0;
88
+ entry->flags = be32_to_cpu(entry->flags);
89
+ entry->name_size = be16_to_cpu(entry->name_size);
90
+ entry->extra_data_size = be32_to_cpu(entry->extra_data_size);
91
}
50
}
92
51
93
static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry)
52
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_exp_delete(BlockExport *exp)
94
{
53
95
- cpu_to_be64s(&entry->bitmap_table_offset);
54
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
96
- cpu_to_be32s(&entry->bitmap_table_size);
55
vblk_exp);
97
- cpu_to_be32s(&entry->flags);
56
+ blk_set_dev_ops(exp->blk, NULL, NULL);
98
- cpu_to_be16s(&entry->name_size);
57
vduse_dev_destroy(vblk_exp->dev);
99
- cpu_to_be32s(&entry->extra_data_size);
100
+ entry->bitmap_table_offset = cpu_to_be64(entry->bitmap_table_offset);
101
+ entry->bitmap_table_size = cpu_to_be32(entry->bitmap_table_size);
102
+ entry->flags = cpu_to_be32(entry->flags);
103
+ entry->name_size = cpu_to_be16(entry->name_size);
104
+ entry->extra_data_size = cpu_to_be32(entry->extra_data_size);
105
}
58
}
106
59
107
static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size)
108
--
60
--
109
2.19.1
61
2.35.3
110
111
diff view generated by jsdifflib
1
To fully change the read-only state of a node, we must not only change
1
From: Xie Yongji <xieyongji@bytedance.com>
2
bs->read_only, but also update bs->open_flags.
3
2
3
To support reconnecting after restart or crash, VDUSE backend
4
might need to resubmit inflight I/Os. This stores the metadata
5
such as the index of inflight I/O's descriptors to a shm file so
6
that VDUSE backend can restore them during reconnecting.
7
8
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
9
Message-Id: <20220523084611.91-9-xieyongji@bytedance.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
---
12
---
8
block.c | 7 +++++++
13
subprojects/libvduse/libvduse.h | 12 ++
9
1 file changed, 7 insertions(+)
14
block/export/vduse-blk.c | 19 ++-
15
subprojects/libvduse/libvduse.c | 235 +++++++++++++++++++++++++++++++-
16
3 files changed, 260 insertions(+), 6 deletions(-)
10
17
11
diff --git a/block.c b/block.c
18
diff --git a/subprojects/libvduse/libvduse.h b/subprojects/libvduse/libvduse.h
12
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
20
--- a/subprojects/libvduse/libvduse.h
14
+++ b/block.c
21
+++ b/subprojects/libvduse/libvduse.h
15
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
22
@@ -XXX,XX +XXX,XX @@ int vduse_dev_update_config(VduseDev *dev, uint32_t size,
16
}
23
*/
17
24
int vduse_dev_setup_queue(VduseDev *dev, int index, int max_size);
18
bs->read_only = read_only;
25
19
+
26
+/**
20
+ if (read_only) {
27
+ * vduse_set_reconnect_log_file:
21
+ bs->open_flags &= ~BDRV_O_RDWR;
28
+ * @dev: VDUSE device
22
+ } else {
29
+ * @file: filename of reconnect log
23
+ bs->open_flags |= BDRV_O_RDWR;
30
+ *
31
+ * Specify the file to store log for reconnecting. It should
32
+ * be called before vduse_dev_setup_queue().
33
+ *
34
+ * Returns: 0 on success, -errno on failure.
35
+ */
36
+int vduse_set_reconnect_log_file(VduseDev *dev, const char *filename);
37
+
38
/**
39
* vduse_dev_create_by_fd:
40
* @fd: passed file descriptor
41
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block/export/vduse-blk.c
44
+++ b/block/export/vduse-blk.c
45
@@ -XXX,XX +XXX,XX @@ typedef struct VduseBlkExport {
46
VirtioBlkHandler handler;
47
VduseDev *dev;
48
uint16_t num_queues;
49
+ char *recon_file;
50
unsigned int inflight;
51
} VduseBlkExport;
52
53
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_enable_queue(VduseDev *dev, VduseVirtq *vq)
54
55
aio_set_fd_handler(vblk_exp->export.ctx, vduse_queue_get_fd(vq),
56
true, on_vduse_vq_kick, NULL, NULL, NULL, vq);
57
+ /* Make sure we don't miss any kick afer reconnecting */
58
+ eventfd_write(vduse_queue_get_fd(vq), 1);
59
}
60
61
static void vduse_blk_disable_queue(VduseDev *dev, VduseVirtq *vq)
62
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
63
return -ENOMEM;
64
}
65
66
+ vblk_exp->recon_file = g_strdup_printf("%s/vduse-blk-%s",
67
+ g_get_tmp_dir(), exp->id);
68
+ if (vduse_set_reconnect_log_file(vblk_exp->dev, vblk_exp->recon_file)) {
69
+ error_setg(errp, "failed to set reconnect log file");
70
+ vduse_dev_destroy(vblk_exp->dev);
71
+ g_free(vblk_exp->recon_file);
72
+ return -EINVAL;
73
+ }
74
+
75
for (i = 0; i < num_queues; i++) {
76
vduse_dev_setup_queue(vblk_exp->dev, i, queue_size);
77
}
78
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
79
static void vduse_blk_exp_delete(BlockExport *exp)
80
{
81
VduseBlkExport *vblk_exp = container_of(exp, VduseBlkExport, export);
82
+ int ret;
83
84
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
85
vblk_exp);
86
blk_set_dev_ops(exp->blk, NULL, NULL);
87
- vduse_dev_destroy(vblk_exp->dev);
88
+ ret = vduse_dev_destroy(vblk_exp->dev);
89
+ if (ret != -EBUSY) {
90
+ unlink(vblk_exp->recon_file);
91
+ }
92
+ g_free(vblk_exp->recon_file);
93
}
94
95
static void vduse_blk_exp_request_shutdown(BlockExport *exp)
96
diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/subprojects/libvduse/libvduse.c
99
+++ b/subprojects/libvduse/libvduse.c
100
@@ -XXX,XX +XXX,XX @@
101
#define VDUSE_VQ_ALIGN 4096
102
#define MAX_IOVA_REGIONS 256
103
104
+#define LOG_ALIGNMENT 64
105
+
106
/* Round number down to multiple */
107
#define ALIGN_DOWN(n, m) ((n) / (m) * (m))
108
109
@@ -XXX,XX +XXX,XX @@
110
#define unlikely(x) __builtin_expect(!!(x), 0)
111
#endif
112
113
+typedef struct VduseDescStateSplit {
114
+ uint8_t inflight;
115
+ uint8_t padding[5];
116
+ uint16_t next;
117
+ uint64_t counter;
118
+} VduseDescStateSplit;
119
+
120
+typedef struct VduseVirtqLogInflight {
121
+ uint64_t features;
122
+ uint16_t version;
123
+ uint16_t desc_num;
124
+ uint16_t last_batch_head;
125
+ uint16_t used_idx;
126
+ VduseDescStateSplit desc[];
127
+} VduseVirtqLogInflight;
128
+
129
+typedef struct VduseVirtqLog {
130
+ VduseVirtqLogInflight inflight;
131
+} VduseVirtqLog;
132
+
133
+typedef struct VduseVirtqInflightDesc {
134
+ uint16_t index;
135
+ uint64_t counter;
136
+} VduseVirtqInflightDesc;
137
+
138
typedef struct VduseRing {
139
unsigned int num;
140
uint64_t desc_addr;
141
@@ -XXX,XX +XXX,XX @@ struct VduseVirtq {
142
bool ready;
143
int fd;
144
VduseDev *dev;
145
+ VduseVirtqInflightDesc *resubmit_list;
146
+ uint16_t resubmit_num;
147
+ uint64_t counter;
148
+ VduseVirtqLog *log;
149
};
150
151
typedef struct VduseIovaRegion {
152
@@ -XXX,XX +XXX,XX @@ struct VduseDev {
153
int fd;
154
int ctrl_fd;
155
void *priv;
156
+ void *log;
157
};
158
159
+static inline size_t vduse_vq_log_size(uint16_t queue_size)
160
+{
161
+ return ALIGN_UP(sizeof(VduseDescStateSplit) * queue_size +
162
+ sizeof(VduseVirtqLogInflight), LOG_ALIGNMENT);
163
+}
164
+
165
+static void *vduse_log_get(const char *filename, size_t size)
166
+{
167
+ void *ptr = MAP_FAILED;
168
+ int fd;
169
+
170
+ fd = open(filename, O_RDWR | O_CREAT, 0600);
171
+ if (fd == -1) {
172
+ return MAP_FAILED;
173
+ }
174
+
175
+ if (ftruncate(fd, size) == -1) {
176
+ goto out;
177
+ }
178
+
179
+ ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
180
+
181
+out:
182
+ close(fd);
183
+ return ptr;
184
+}
185
+
186
static inline bool has_feature(uint64_t features, unsigned int fbit)
187
{
188
assert(fbit < 64);
189
@@ -XXX,XX +XXX,XX @@ static int vduse_inject_irq(VduseDev *dev, int index)
190
return ioctl(dev->fd, VDUSE_VQ_INJECT_IRQ, &index);
191
}
192
193
+static int inflight_desc_compare(const void *a, const void *b)
194
+{
195
+ VduseVirtqInflightDesc *desc0 = (VduseVirtqInflightDesc *)a,
196
+ *desc1 = (VduseVirtqInflightDesc *)b;
197
+
198
+ if (desc1->counter > desc0->counter &&
199
+ (desc1->counter - desc0->counter) < VIRTQUEUE_MAX_SIZE * 2) {
200
+ return 1;
201
+ }
202
+
203
+ return -1;
204
+}
205
+
206
+static int vduse_queue_check_inflights(VduseVirtq *vq)
207
+{
208
+ int i = 0;
209
+ VduseDev *dev = vq->dev;
210
+
211
+ vq->used_idx = le16toh(vq->vring.used->idx);
212
+ vq->resubmit_num = 0;
213
+ vq->resubmit_list = NULL;
214
+ vq->counter = 0;
215
+
216
+ if (unlikely(vq->log->inflight.used_idx != vq->used_idx)) {
217
+ if (vq->log->inflight.last_batch_head > VIRTQUEUE_MAX_SIZE) {
218
+ return -1;
219
+ }
220
+
221
+ vq->log->inflight.desc[vq->log->inflight.last_batch_head].inflight = 0;
222
+
223
+ barrier();
224
+
225
+ vq->log->inflight.used_idx = vq->used_idx;
226
+ }
227
+
228
+ for (i = 0; i < vq->log->inflight.desc_num; i++) {
229
+ if (vq->log->inflight.desc[i].inflight == 1) {
230
+ vq->inuse++;
231
+ }
232
+ }
233
+
234
+ vq->shadow_avail_idx = vq->last_avail_idx = vq->inuse + vq->used_idx;
235
+
236
+ if (vq->inuse) {
237
+ vq->resubmit_list = calloc(vq->inuse, sizeof(VduseVirtqInflightDesc));
238
+ if (!vq->resubmit_list) {
239
+ return -1;
240
+ }
241
+
242
+ for (i = 0; i < vq->log->inflight.desc_num; i++) {
243
+ if (vq->log->inflight.desc[i].inflight) {
244
+ vq->resubmit_list[vq->resubmit_num].index = i;
245
+ vq->resubmit_list[vq->resubmit_num].counter =
246
+ vq->log->inflight.desc[i].counter;
247
+ vq->resubmit_num++;
248
+ }
249
+ }
250
+
251
+ if (vq->resubmit_num > 1) {
252
+ qsort(vq->resubmit_list, vq->resubmit_num,
253
+ sizeof(VduseVirtqInflightDesc), inflight_desc_compare);
254
+ }
255
+ vq->counter = vq->resubmit_list[0].counter + 1;
256
+ }
257
+
258
+ vduse_inject_irq(dev, vq->index);
259
+
260
+ return 0;
261
+}
262
+
263
+static int vduse_queue_inflight_get(VduseVirtq *vq, int desc_idx)
264
+{
265
+ vq->log->inflight.desc[desc_idx].counter = vq->counter++;
266
+
267
+ barrier();
268
+
269
+ vq->log->inflight.desc[desc_idx].inflight = 1;
270
+
271
+ return 0;
272
+}
273
+
274
+static int vduse_queue_inflight_pre_put(VduseVirtq *vq, int desc_idx)
275
+{
276
+ vq->log->inflight.last_batch_head = desc_idx;
277
+
278
+ return 0;
279
+}
280
+
281
+static int vduse_queue_inflight_post_put(VduseVirtq *vq, int desc_idx)
282
+{
283
+ vq->log->inflight.desc[desc_idx].inflight = 0;
284
+
285
+ barrier();
286
+
287
+ vq->log->inflight.used_idx = vq->used_idx;
288
+
289
+ return 0;
290
+}
291
+
292
static void vduse_iova_remove_region(VduseDev *dev, uint64_t start,
293
uint64_t last)
294
{
295
@@ -XXX,XX +XXX,XX @@ void *vduse_queue_pop(VduseVirtq *vq, size_t sz)
296
unsigned int head;
297
VduseVirtqElement *elem;
298
VduseDev *dev = vq->dev;
299
+ int i;
300
301
if (unlikely(!vq->vring.avail)) {
302
return NULL;
303
}
304
305
+ if (unlikely(vq->resubmit_list && vq->resubmit_num > 0)) {
306
+ i = (--vq->resubmit_num);
307
+ elem = vduse_queue_map_desc(vq, vq->resubmit_list[i].index, sz);
308
+
309
+ if (!vq->resubmit_num) {
310
+ free(vq->resubmit_list);
311
+ vq->resubmit_list = NULL;
312
+ }
313
+
314
+ return elem;
315
+ }
316
+
317
if (vduse_queue_empty(vq)) {
318
return NULL;
319
}
320
@@ -XXX,XX +XXX,XX @@ void *vduse_queue_pop(VduseVirtq *vq, size_t sz)
321
322
vq->inuse++;
323
324
+ vduse_queue_inflight_get(vq, head);
325
+
326
return elem;
327
}
328
329
@@ -XXX,XX +XXX,XX @@ void vduse_queue_push(VduseVirtq *vq, const VduseVirtqElement *elem,
330
unsigned int len)
331
{
332
vduse_queue_fill(vq, elem, len, 0);
333
+ vduse_queue_inflight_pre_put(vq, elem->index);
334
vduse_queue_flush(vq, 1);
335
+ vduse_queue_inflight_post_put(vq, elem->index);
336
}
337
338
static int vduse_queue_update_vring(VduseVirtq *vq, uint64_t desc_addr,
339
@@ -XXX,XX +XXX,XX @@ static void vduse_queue_enable(VduseVirtq *vq)
340
}
341
342
vq->fd = fd;
343
- vq->shadow_avail_idx = vq->last_avail_idx = vq_info.split.avail_index;
344
- vq->inuse = 0;
345
- vq->used_idx = 0;
346
vq->signalled_used_valid = false;
347
vq->ready = true;
348
349
+ if (vduse_queue_check_inflights(vq)) {
350
+ fprintf(stderr, "Failed to check inflights for vq[%d]\n", vq->index);
351
+ close(fd);
352
+ return;
353
+ }
354
+
355
dev->ops->enable_queue(dev, vq);
356
}
357
358
@@ -XXX,XX +XXX,XX @@ static void vduse_dev_start_dataplane(VduseDev *dev)
359
360
static void vduse_dev_stop_dataplane(VduseDev *dev)
361
{
362
+ size_t log_size = dev->num_queues * vduse_vq_log_size(VIRTQUEUE_MAX_SIZE);
363
int i;
364
365
for (i = 0; i < dev->num_queues; i++) {
366
vduse_queue_disable(&dev->vqs[i]);
367
}
368
+ if (dev->log) {
369
+ memset(dev->log, 0, log_size);
370
+ }
371
dev->features = 0;
372
vduse_iova_remove_region(dev, 0, ULONG_MAX);
373
}
374
@@ -XXX,XX +XXX,XX @@ int vduse_dev_setup_queue(VduseDev *dev, int index, int max_size)
375
return -errno;
376
}
377
378
+ vduse_queue_enable(vq);
379
+
380
+ return 0;
381
+}
382
+
383
+int vduse_set_reconnect_log_file(VduseDev *dev, const char *filename)
384
+{
385
+
386
+ size_t log_size = dev->num_queues * vduse_vq_log_size(VIRTQUEUE_MAX_SIZE);
387
+ void *log;
388
+ int i;
389
+
390
+ dev->log = log = vduse_log_get(filename, log_size);
391
+ if (log == MAP_FAILED) {
392
+ fprintf(stderr, "Failed to get vduse log\n");
393
+ return -EINVAL;
394
+ }
395
+
396
+ for (i = 0; i < dev->num_queues; i++) {
397
+ dev->vqs[i].log = log;
398
+ dev->vqs[i].log->inflight.desc_num = VIRTQUEUE_MAX_SIZE;
399
+ log = (void *)((char *)log + vduse_vq_log_size(VIRTQUEUE_MAX_SIZE));
24
+ }
400
+ }
25
+
401
+
26
return 0;
402
return 0;
27
}
403
}
28
404
405
@@ -XXX,XX +XXX,XX @@ static int vduse_dev_init(VduseDev *dev, const char *name,
406
return -errno;
407
}
408
409
+ if (ioctl(fd, VDUSE_DEV_GET_FEATURES, &dev->features)) {
410
+ fprintf(stderr, "Failed to get features: %s\n", strerror(errno));
411
+ close(fd);
412
+ return -errno;
413
+ }
414
+
415
dev_name = strdup(name);
416
if (!dev_name) {
417
close(fd);
418
@@ -XXX,XX +XXX,XX @@ VduseDev *vduse_dev_create_by_fd(int fd, uint16_t num_queues,
419
return NULL;
420
}
421
422
+ if (ioctl(fd, VDUSE_DEV_GET_FEATURES, &dev->features)) {
423
+ fprintf(stderr, "Failed to get features: %s\n", strerror(errno));
424
+ free(dev);
425
+ return NULL;
426
+ }
427
+
428
ret = vduse_dev_init_vqs(dev, num_queues);
429
if (ret) {
430
fprintf(stderr, "Failed to init vqs\n");
431
@@ -XXX,XX +XXX,XX @@ VduseDev *vduse_dev_create(const char *name, uint32_t device_id,
432
433
ret = ioctl(ctrl_fd, VDUSE_CREATE_DEV, dev_config);
434
free(dev_config);
435
- if (ret < 0) {
436
+ if (ret && errno != EEXIST) {
437
fprintf(stderr, "Failed to create vduse device %s: %s\n",
438
name, strerror(errno));
439
goto err_dev;
440
@@ -XXX,XX +XXX,XX @@ err_ctrl:
441
442
int vduse_dev_destroy(VduseDev *dev)
443
{
444
- int ret = 0;
445
+ size_t log_size = dev->num_queues * vduse_vq_log_size(VIRTQUEUE_MAX_SIZE);
446
+ int i, ret = 0;
447
448
+ if (dev->log) {
449
+ munmap(dev->log, log_size);
450
+ }
451
+ for (i = 0; i < dev->num_queues; i++) {
452
+ free(dev->vqs[i].resubmit_list);
453
+ }
454
free(dev->vqs);
455
if (dev->fd >= 0) {
456
close(dev->fd);
29
--
457
--
30
2.19.1
458
2.35.3
31
32
diff view generated by jsdifflib
1
From: Leonid Bloch <lbloch@janustech.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
The lookup table for power-of-two sizes was added in commit 540b8492618eb
3
Document vduse-blk exports in qemu-storage-daemon --help and the
4
for the purpose of having convenient shortcuts for these sizes in cases
4
qemu-storage-daemon(1) man page.
5
when the literal number has to be present at compile time, and
6
expressions as '(1 * KiB)' can not be used. One such case is the
7
stringification of sizes. Beyond that, it is convenient to use these
8
shortcuts for all power-of-two sizes, even if they don't have to be
9
literal numbers.
10
5
11
Despite its convenience, this table introduced 55 lines of "dumb" code,
6
Based-on: <20220523084611.91-1-xieyongji@bytedance.com>
12
the purpose and origin of which are obscure without reading the message
7
Cc: Xie Yongji <xieyongji@bytedance.com>
13
of the commit which introduced it. This patch fixes that by adding a
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
comment to the code itself with a brief explanation for the reasoning
9
Message-Id: <20220525121947.859820-1-stefanha@redhat.com>
15
behind this table. This comment includes the short AWK script that
16
generated the table, so that anyone who's interested could make sure
17
that the values in it are correct (otherwise these values look as if
18
they were typed manually).
19
20
Signed-off-by: Leonid Bloch <lbloch@janustech.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
11
---
23
include/qemu/units.h | 18 ++++++++++++++++++
12
docs/tools/qemu-storage-daemon.rst | 21 +++++++++++++++++++++
24
1 file changed, 18 insertions(+)
13
storage-daemon/qemu-storage-daemon.c | 9 +++++++++
14
2 files changed, 30 insertions(+)
25
15
26
diff --git a/include/qemu/units.h b/include/qemu/units.h
16
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
27
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
28
--- a/include/qemu/units.h
18
--- a/docs/tools/qemu-storage-daemon.rst
29
+++ b/include/qemu/units.h
19
+++ b/docs/tools/qemu-storage-daemon.rst
30
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ Standard options:
31
#define PiB (INT64_C(1) << 50)
21
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=unix,addr.path=<socket-path>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
32
#define EiB (INT64_C(1) << 60)
22
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=fd,addr.str=<fd>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
33
23
--export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>[,growable=on|off][,writable=on|off][,allow-other=on|off|auto]
34
+/*
24
+ --export [type=]vduse-blk,id=<id>,node-name=<node-name>[,writable=on|off][,num-queues=<num-queues>][,queue-size=<queue-size>][,logical-block-size=<block-size>]
35
+ * The following lookup table is intended to be used when a literal string of
25
36
+ * the number of bytes is required (for example if it needs to be stringified).
26
is a block export definition. ``node-name`` is the block node that should be
37
+ * It can also be used for generic shortcuts of power-of-two sizes.
27
exported. ``writable`` determines whether or not the export allows write
38
+ * This table is generated using the AWK script below:
28
@@ -XXX,XX +XXX,XX @@ Standard options:
39
+ *
29
``allow-other`` to auto (the default) will try enabling this option, and on
40
+ * BEGIN {
30
error fall back to disabling it.
41
+ * suffix="KMGTPE";
31
42
+ * for(i=10; i<64; i++) {
32
+ The ``vduse-blk`` export type uses the ``id`` as the VDUSE device name.
43
+ * val=2**i;
33
+ ``num-queues`` sets the number of virtqueues (the default is 1).
44
+ * s=substr(suffix, int(i/10), 1);
34
+ ``queue-size`` sets the virtqueue descriptor table size (the default is 256).
45
+ * n=2**(i%10);
46
+ * pad=21-int(log(n)/log(10));
47
+ * printf("#define S_%d%siB %*d\n", n, s, pad, val);
48
+ * }
49
+ * }
50
+ */
51
+
35
+
52
#define S_1KiB 1024
36
+ The instantiated VDUSE device must then be added to the vDPA bus using the
53
#define S_2KiB 2048
37
+ vdpa(8) command from the iproute2 project::
54
#define S_4KiB 4096
38
+
39
+ # vdpa dev add name <id> mgmtdev vduse
40
+
41
+ The device can be removed from the vDPA bus later as follows::
42
+
43
+ # vdpa dev del <id>
44
+
45
+ For more information about attaching vDPA devices to the host with
46
+ virtio_vdpa.ko or attaching them to guests with vhost_vdpa.ko, see
47
+ https://vdpa-dev.gitlab.io/.
48
+
49
+ For more information about VDUSE, see
50
+ https://docs.kernel.org/userspace-api/vduse.html.
51
+
52
.. option:: --monitor MONITORDEF
53
54
is a QMP monitor definition. See the :manpage:`qemu(1)` manual page for
55
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/storage-daemon/qemu-storage-daemon.c
58
+++ b/storage-daemon/qemu-storage-daemon.c
59
@@ -XXX,XX +XXX,XX @@ static void help(void)
60
" vhost-user-blk device over file descriptor\n"
61
"\n"
62
#endif /* CONFIG_VHOST_USER_BLK_SERVER */
63
+#ifdef CONFIG_VDUSE_BLK_EXPORT
64
+" --export [type=]vduse-blk,id=<id>,node-name=<node-name>\n"
65
+" [,writable=on|off][,num-queues=<num-queues>]\n"
66
+" [,queue-size=<queue-size>]\n"
67
+" [,logical-block-size=<logical-block-size>]\n"
68
+" export the specified block node as a vduse-blk\n"
69
+" device using the id as the VDUSE device name\n"
70
+"\n"
71
+#endif /* CONFIG_VDUSE_BLK_EXPORT */
72
" --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n"
73
" configure a QMP monitor\n"
74
"\n"
55
--
75
--
56
2.19.1
76
2.35.3
57
58
diff view generated by jsdifflib
1
Commit e2b8247a322 introduced an error path in qemu_rbd_open() after
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
calling rbd_open(), but neglected to close the image again in this error
3
path. The error path should contain everything that the regular close
4
function qemu_rbd_close() contains.
5
2
6
This adds the missing rbd_close() call.
3
If the namespace does not exist, rbd_create() fails with -ENOENT and
4
QEMU reports a generic "error rbd create: No such file or directory":
7
5
6
$ qemu-img create rbd:rbd/namespace/image 1M
7
Formatting 'rbd:rbd/namespace/image', fmt=raw size=1048576
8
qemu-img: rbd:rbd/namespace/image: error rbd create: No such file or directory
9
10
Unfortunately rados_ioctx_set_namespace() does not fail if the namespace
11
does not exist, so let's use rbd_namespace_exists() in qemu_rbd_connect()
12
to check if the namespace exists, reporting a more understandable error:
13
14
$ qemu-img create rbd:rbd/namespace/image 1M
15
Formatting 'rbd:rbd/namespace/image', fmt=raw size=1048576
16
qemu-img: rbd:rbd/namespace/image: namespace 'namespace' does not exist
17
18
Reported-by: Tingting Mao <timao@redhat.com>
19
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
20
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
21
Message-Id: <20220517071012.6120-1-sgarzare@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
---
23
---
11
block/rbd.c | 1 +
24
block/rbd.c | 24 ++++++++++++++++++++++++
12
1 file changed, 1 insertion(+)
25
meson.build | 6 ++++++
26
2 files changed, 30 insertions(+)
13
27
14
diff --git a/block/rbd.c b/block/rbd.c
28
diff --git a/block/rbd.c b/block/rbd.c
15
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
16
--- a/block/rbd.c
30
--- a/block/rbd.c
17
+++ b/block/rbd.c
31
+++ b/block/rbd.c
18
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
32
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
19
"automatically marking the image read-only.");
33
error_setg_errno(errp, -r, "error opening pool %s", opts->pool);
20
r = bdrv_set_read_only(bs, true, &local_err);
34
goto failed_shutdown;
21
if (r < 0) {
35
}
22
+ rbd_close(s->image);
36
+
23
error_propagate(errp, local_err);
37
+#ifdef HAVE_RBD_NAMESPACE_EXISTS
24
goto failed_open;
38
+ if (opts->has_q_namespace && strlen(opts->q_namespace) > 0) {
25
}
39
+ bool exists;
40
+
41
+ r = rbd_namespace_exists(*io_ctx, opts->q_namespace, &exists);
42
+ if (r < 0) {
43
+ error_setg_errno(errp, -r, "error checking namespace");
44
+ goto failed_ioctx_destroy;
45
+ }
46
+
47
+ if (!exists) {
48
+ error_setg(errp, "namespace '%s' does not exist",
49
+ opts->q_namespace);
50
+ r = -ENOENT;
51
+ goto failed_ioctx_destroy;
52
+ }
53
+ }
54
+#endif
55
+
56
/*
57
* Set the namespace after opening the io context on the pool,
58
* if nspace == NULL or if nspace == "", it is just as we did nothing
59
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
60
r = 0;
61
goto out;
62
63
+#ifdef HAVE_RBD_NAMESPACE_EXISTS
64
+failed_ioctx_destroy:
65
+ rados_ioctx_destroy(*io_ctx);
66
+#endif
67
failed_shutdown:
68
rados_shutdown(*cluster);
69
out:
70
diff --git a/meson.build b/meson.build
71
index XXXXXXX..XXXXXXX 100644
72
--- a/meson.build
73
+++ b/meson.build
74
@@ -XXX,XX +XXX,XX @@ config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
75
config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
76
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
77
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
78
+if rbd.found()
79
+ config_host_data.set('HAVE_RBD_NAMESPACE_EXISTS',
80
+ cc.has_function('rbd_namespace_exists',
81
+ dependencies: rbd,
82
+ prefix: '#include <rbd/librbd.h>'))
83
+endif
84
if rdma.found()
85
config_host_data.set('HAVE_IBV_ADVISE_MR',
86
cc.has_function('ibv_advise_mr',
26
--
87
--
27
2.19.1
88
2.35.3
28
29
diff view generated by jsdifflib
1
If read-only=off, but auto-read-only=on is given, open the file
1
From: Fabian Ebner <f.ebner@proxmox.com>
2
read-write if we have the permissions, but instead of erroring out for
3
read-only files, just degrade to read-only.
4
2
3
On 64-bit platforms, assigning SIZE_MAX to the int64_t max_pdiscard
4
results in a negative value, and the following assertion would trigger
5
down the line (it's not the same max_pdiscard, but computed from the
6
other one):
7
qemu-system-x86_64: ../block/io.c:3166: bdrv_co_pdiscard: Assertion
8
`max_pdiscard >= bs->bl.request_alignment' failed.
9
10
On 32-bit platforms, it's fine to keep using SIZE_MAX.
11
12
The assertion in qemu_gluster_co_pdiscard() is checking that the value
13
of 'bytes' can safely be passed to glfs_discard_async(), which takes a
14
size_t for the argument in question, so it is kept as is. And since
15
max_pdiscard is still <= SIZE_MAX, relying on max_pdiscard is still
16
fine.
17
18
Fixes: 0c8022876f ("block: use int64_t instead of int in driver discard handlers")
19
Cc: qemu-stable@nongnu.org
20
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
21
Message-Id: <20220520075922.43972-1-f.ebner@proxmox.com>
22
Reviewed-by: Eric Blake <eblake@redhat.com>
23
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
24
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Niels de Vos <ndevos@redhat.com>
7
---
26
---
8
block/gluster.c | 12 ++++++++++--
27
block/gluster.c | 2 +-
9
1 file changed, 10 insertions(+), 2 deletions(-)
28
1 file changed, 1 insertion(+), 1 deletion(-)
10
29
11
diff --git a/block/gluster.c b/block/gluster.c
30
diff --git a/block/gluster.c b/block/gluster.c
12
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
13
--- a/block/gluster.c
32
--- a/block/gluster.c
14
+++ b/block/gluster.c
33
+++ b/block/gluster.c
15
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
34
@@ -XXX,XX +XXX,XX @@ out:
16
qemu_gluster_parse_flags(bdrv_flags, &open_flags);
35
static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp)
17
36
{
18
s->fd = glfs_open(s->glfs, gconf->path, open_flags);
37
bs->bl.max_transfer = GLUSTER_MAX_TRANSFER;
19
- if (!s->fd) {
38
- bs->bl.max_pdiscard = SIZE_MAX;
20
- ret = -errno;
39
+ bs->bl.max_pdiscard = MIN(SIZE_MAX, INT64_MAX);
21
+ ret = s->fd ? 0 : -errno;
40
}
22
+
41
23
+ if (ret == -EACCES || ret == -EROFS) {
42
static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
24
+ /* Try to degrade to read-only, but if it doesn't work, still use the
25
+ * normal error message. */
26
+ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
27
+ open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
28
+ s->fd = glfs_open(s->glfs, gconf->path, open_flags);
29
+ ret = s->fd ? 0 : -errno;
30
+ }
31
}
32
33
s->supports_seek_data = qemu_gluster_test_seek(s->fd);
34
--
43
--
35
2.19.1
44
2.35.3
36
37
diff view generated by jsdifflib
1
From: Stefan Weil <sw@weilnetz.de>
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
2
3
Use %zu instead of %zd for unsigned numbers.
3
It seems that aio_wait_kick always required a memory barrier
4
or atomic operation in the caller, but nobody actually
5
took care of doing it.
4
6
5
This fixes two error messages from the LSTM static code analyzer:
7
Let's put the barrier in the function instead, and pair it
8
with another one in AIO_WAIT_WHILE. Read aio_wait_kick()
9
comment for further explanation.
6
10
7
This argument should be of type 'ssize_t' but is of type 'unsigned long'
11
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
8
12
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Signed-off-by: Stefan Weil <sw@weilnetz.de>
13
Message-Id: <20220524173054.12651-1-eesposit@redhat.com>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
17
---
13
qemu-io-cmds.c | 4 ++--
18
include/block/aio-wait.h | 2 ++
14
1 file changed, 2 insertions(+), 2 deletions(-)
19
util/aio-wait.c | 16 +++++++++++++++-
20
2 files changed, 17 insertions(+), 1 deletion(-)
15
21
16
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
22
diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h
17
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-io-cmds.c
24
--- a/include/block/aio-wait.h
19
+++ b/qemu-io-cmds.c
25
+++ b/include/block/aio-wait.h
20
@@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
26
@@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait;
21
memset(cmp_buf, pattern, qiov.size);
27
AioContext *ctx_ = (ctx); \
22
if (memcmp(buf, cmp_buf, qiov.size)) {
28
/* Increment wait_->num_waiters before evaluating cond. */ \
23
printf("Pattern verification failed at offset %"
29
qatomic_inc(&wait_->num_waiters); \
24
- PRId64 ", %zd bytes\n", offset, qiov.size);
30
+ /* Paired with smp_mb in aio_wait_kick(). */ \
25
+ PRId64 ", %zu bytes\n", offset, qiov.size);
31
+ smp_mb(); \
26
ret = -EINVAL;
32
if (ctx_ && in_aio_context_home_thread(ctx_)) { \
27
}
33
while ((cond)) { \
28
g_free(cmp_buf);
34
aio_poll(ctx_, true); \
29
@@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret)
35
diff --git a/util/aio-wait.c b/util/aio-wait.c
30
memset(cmp_buf, ctx->pattern, ctx->qiov.size);
36
index XXXXXXX..XXXXXXX 100644
31
if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
37
--- a/util/aio-wait.c
32
printf("Pattern verification failed at offset %"
38
+++ b/util/aio-wait.c
33
- PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
39
@@ -XXX,XX +XXX,XX @@ static void dummy_bh_cb(void *opaque)
34
+ PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size);
40
35
}
41
void aio_wait_kick(void)
36
g_free(cmp_buf);
42
{
43
- /* The barrier (or an atomic op) is in the caller. */
44
+ /*
45
+ * Paired with smp_mb in AIO_WAIT_WHILE. Here we have:
46
+ * write(condition);
47
+ * aio_wait_kick() {
48
+ * smp_mb();
49
+ * read(num_waiters);
50
+ * }
51
+ *
52
+ * And in AIO_WAIT_WHILE:
53
+ * write(num_waiters);
54
+ * smp_mb();
55
+ * read(condition);
56
+ */
57
+ smp_mb();
58
+
59
if (qatomic_read(&global_aio_wait.num_waiters)) {
60
aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
37
}
61
}
38
--
62
--
39
2.19.1
63
2.35.3
40
41
diff view generated by jsdifflib
1
From: Leonid Bloch <lbloch@janustech.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
If an expression is used to define DEFAULT_CLUSTER_SIZE, when compiled,
3
CID 1488362 points out that the second 'rc >= 0' check is now dead
4
it will be embedded as a literal expression in the binary (as the
4
code.
5
default value) because it is stringified to mark the size of the default
6
value. Now this is fixed by using a defined number to define this value.
7
5
8
Signed-off-by: Leonid Bloch <lbloch@janustech.com>
6
Reported-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Stefan Weil <sw@weilnetz.de>
7
Fixes: 172f5f1a40(nbd: remove peppering of nbd_client_connected)
8
Signed-off-by: Eric Blake <eblake@redhat.com>
9
Message-Id: <20220516210519.76135-1-eblake@redhat.com>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
13
---
12
block/vdi.c | 4 ++--
14
block/nbd.c | 8 ++------
13
1 file changed, 2 insertions(+), 2 deletions(-)
15
1 file changed, 2 insertions(+), 6 deletions(-)
14
16
15
diff --git a/block/vdi.c b/block/vdi.c
17
diff --git a/block/nbd.c b/block/nbd.c
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/block/vdi.c
19
--- a/block/nbd.c
18
+++ b/block/vdi.c
20
+++ b/block/nbd.c
19
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nbd_co_send_request(BlockDriverState *bs,
20
#define BLOCK_OPT_STATIC "static"
22
if (qiov) {
21
23
qio_channel_set_cork(s->ioc, true);
22
#define SECTOR_SIZE 512
24
rc = nbd_send_request(s->ioc, request);
23
-#define DEFAULT_CLUSTER_SIZE (1 * MiB)
25
- if (rc >= 0) {
24
+#define DEFAULT_CLUSTER_SIZE S_1MiB
26
- if (qio_channel_writev_all(s->ioc, qiov->iov, qiov->niov,
25
27
- NULL) < 0) {
26
#if defined(CONFIG_VDI_DEBUG)
28
- rc = -EIO;
27
#define VDI_DEBUG 1
29
- }
28
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
30
- } else if (rc >= 0) {
29
goto fail;
31
+ if (rc >= 0 && qio_channel_writev_all(s->ioc, qiov->iov, qiov->niov,
30
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
32
+ NULL) < 0) {
31
error_setg(errp, "unsupported VDI image (block size %" PRIu32
33
rc = -EIO;
32
- " is not %" PRIu64 ")",
34
}
33
+ " is not %" PRIu32 ")",
35
qio_channel_set_cork(s->ioc, false);
34
header.block_size, DEFAULT_CLUSTER_SIZE);
35
ret = -ENOTSUP;
36
goto fail;
37
--
36
--
38
2.19.1
37
2.35.3
39
40
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Xie Yongji <xieyongji@bytedance.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
Add a 'serial' option to allow user to specify this value
4
it might not be actually aligned enough for that pointer type (and
4
explicitly. And the default value is changed to an empty
5
thus cause a crash on dereference on some host architectures). Newer
5
string as what we did in "hw/block/virtio-blk.c".
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
6
9
There are a few places where the in-place swap function is
7
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
10
used on something other than a packed struct field; we convert
8
Message-Id: <20220614051532.92-6-xieyongji@bytedance.com>
11
those anyway, for consistency.
12
13
Patch produced with scripts/coccinelle/inplace-byteswaps.cocci.
14
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
10
---
19
block/vhdx.h | 12 ++---
11
qapi/block-export.json | 4 +++-
20
block/vhdx-endian.c | 118 ++++++++++++++++++++++----------------------
12
docs/tools/qemu-storage-daemon.rst | 2 +-
21
block/vhdx-log.c | 4 +-
13
block/export/virtio-blk-handler.h | 2 +-
22
block/vhdx.c | 18 +++----
14
block/export/vduse-blk.c | 20 ++++++++++++++------
23
4 files changed, 76 insertions(+), 76 deletions(-)
15
block/export/vhost-user-blk-server.c | 4 +++-
16
storage-daemon/qemu-storage-daemon.c | 1 +
17
6 files changed, 23 insertions(+), 10 deletions(-)
24
18
25
diff --git a/block/vhdx.h b/block/vhdx.h
19
diff --git a/qapi/block-export.json b/qapi/block-export.json
26
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
27
--- a/block/vhdx.h
21
--- a/qapi/block-export.json
28
+++ b/block/vhdx.h
22
+++ b/qapi/block-export.json
29
@@ -XXX,XX +XXX,XX @@ int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
23
@@ -XXX,XX +XXX,XX @@
30
24
# @queue-size: the size of virtqueue. Defaults to 256.
31
static inline void leguid_to_cpus(MSGUID *guid)
25
# @logical-block-size: Logical block size in bytes. Range [512, PAGE_SIZE]
32
{
26
# and must be power of 2. Defaults to 512 bytes.
33
- le32_to_cpus(&guid->data1);
27
+# @serial: the serial number of virtio block device. Defaults to empty string.
34
- le16_to_cpus(&guid->data2);
28
#
35
- le16_to_cpus(&guid->data3);
29
# Since: 7.1
36
+ guid->data1 = le32_to_cpu(guid->data1);
30
##
37
+ guid->data2 = le16_to_cpu(guid->data2);
31
{ 'struct': 'BlockExportOptionsVduseBlk',
38
+ guid->data3 = le16_to_cpu(guid->data3);
32
'data': { '*num-queues': 'uint16',
33
'*queue-size': 'uint16',
34
- '*logical-block-size': 'size'} }
35
+ '*logical-block-size': 'size',
36
+ '*serial': 'str' } }
37
38
##
39
# @NbdServerAddOptions:
40
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
41
index XXXXXXX..XXXXXXX 100644
42
--- a/docs/tools/qemu-storage-daemon.rst
43
+++ b/docs/tools/qemu-storage-daemon.rst
44
@@ -XXX,XX +XXX,XX @@ Standard options:
45
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=unix,addr.path=<socket-path>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
46
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=fd,addr.str=<fd>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
47
--export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>[,growable=on|off][,writable=on|off][,allow-other=on|off|auto]
48
- --export [type=]vduse-blk,id=<id>,node-name=<node-name>[,writable=on|off][,num-queues=<num-queues>][,queue-size=<queue-size>][,logical-block-size=<block-size>]
49
+ --export [type=]vduse-blk,id=<id>,node-name=<node-name>[,writable=on|off][,num-queues=<num-queues>][,queue-size=<queue-size>][,logical-block-size=<block-size>][,serial=<serial-number>]
50
51
is a block export definition. ``node-name`` is the block node that should be
52
exported. ``writable`` determines whether or not the export allows write
53
diff --git a/block/export/virtio-blk-handler.h b/block/export/virtio-blk-handler.h
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/export/virtio-blk-handler.h
56
+++ b/block/export/virtio-blk-handler.h
57
@@ -XXX,XX +XXX,XX @@
58
59
typedef struct {
60
BlockBackend *blk;
61
- const char *serial;
62
+ char *serial;
63
uint32_t logical_block_size;
64
bool writable;
65
} VirtioBlkHandler;
66
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/block/export/vduse-blk.c
69
+++ b/block/export/vduse-blk.c
70
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
71
Error *local_err = NULL;
72
struct virtio_blk_config config = { 0 };
73
uint64_t features;
74
- int i;
75
+ int i, ret;
76
77
if (vblk_opts->has_num_queues) {
78
num_queues = vblk_opts->num_queues;
79
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
80
}
81
vblk_exp->num_queues = num_queues;
82
vblk_exp->handler.blk = exp->blk;
83
- vblk_exp->handler.serial = exp->id;
84
+ vblk_exp->handler.serial = g_strdup(vblk_opts->has_serial ?
85
+ vblk_opts->serial : "");
86
vblk_exp->handler.logical_block_size = logical_block_size;
87
vblk_exp->handler.writable = opts->writable;
88
89
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
90
vblk_exp);
91
if (!vblk_exp->dev) {
92
error_setg(errp, "failed to create vduse device");
93
- return -ENOMEM;
94
+ ret = -ENOMEM;
95
+ goto err_dev;
96
}
97
98
vblk_exp->recon_file = g_strdup_printf("%s/vduse-blk-%s",
99
g_get_tmp_dir(), exp->id);
100
if (vduse_set_reconnect_log_file(vblk_exp->dev, vblk_exp->recon_file)) {
101
error_setg(errp, "failed to set reconnect log file");
102
- vduse_dev_destroy(vblk_exp->dev);
103
- g_free(vblk_exp->recon_file);
104
- return -EINVAL;
105
+ ret = -EINVAL;
106
+ goto err;
107
}
108
109
for (i = 0; i < num_queues; i++) {
110
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
111
blk_set_dev_ops(exp->blk, &vduse_block_ops, exp);
112
113
return 0;
114
+err:
115
+ vduse_dev_destroy(vblk_exp->dev);
116
+ g_free(vblk_exp->recon_file);
117
+err_dev:
118
+ g_free(vblk_exp->handler.serial);
119
+ return ret;
39
}
120
}
40
121
41
static inline void cpu_to_leguids(MSGUID *guid)
122
static void vduse_blk_exp_delete(BlockExport *exp)
42
{
123
@@ -XXX,XX +XXX,XX @@ static void vduse_blk_exp_delete(BlockExport *exp)
43
- cpu_to_le32s(&guid->data1);
124
unlink(vblk_exp->recon_file);
44
- cpu_to_le16s(&guid->data2);
125
}
45
- cpu_to_le16s(&guid->data3);
126
g_free(vblk_exp->recon_file);
46
+ guid->data1 = cpu_to_le32(guid->data1);
127
+ g_free(vblk_exp->handler.serial);
47
+ guid->data2 = cpu_to_le16(guid->data2);
48
+ guid->data3 = cpu_to_le16(guid->data3);
49
}
128
}
50
129
51
void vhdx_header_le_import(VHDXHeader *h);
130
static void vduse_blk_exp_request_shutdown(BlockExport *exp)
52
diff --git a/block/vhdx-endian.c b/block/vhdx-endian.c
131
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
53
index XXXXXXX..XXXXXXX 100644
132
index XXXXXXX..XXXXXXX 100644
54
--- a/block/vhdx-endian.c
133
--- a/block/export/vhost-user-blk-server.c
55
+++ b/block/vhdx-endian.c
134
+++ b/block/export/vhost-user-blk-server.c
56
@@ -XXX,XX +XXX,XX @@ void vhdx_header_le_import(VHDXHeader *h)
135
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
57
{
136
return -EINVAL;
58
assert(h != NULL);
137
}
59
138
vexp->handler.blk = exp->blk;
60
- le32_to_cpus(&h->signature);
139
- vexp->handler.serial = "vhost_user_blk";
61
- le32_to_cpus(&h->checksum);
140
+ vexp->handler.serial = g_strdup("vhost_user_blk");
62
- le64_to_cpus(&h->sequence_number);
141
vexp->handler.logical_block_size = logical_block_size;
63
+ h->signature = le32_to_cpu(h->signature);
142
vexp->handler.writable = opts->writable;
64
+ h->checksum = le32_to_cpu(h->checksum);
143
65
+ h->sequence_number = le64_to_cpu(h->sequence_number);
144
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
66
145
num_queues, &vu_blk_iface, errp)) {
67
leguid_to_cpus(&h->file_write_guid);
146
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached,
68
leguid_to_cpus(&h->data_write_guid);
147
blk_aio_detach, vexp);
69
leguid_to_cpus(&h->log_guid);
148
+ g_free(vexp->handler.serial);
70
149
return -EADDRNOTAVAIL;
71
- le16_to_cpus(&h->log_version);
150
}
72
- le16_to_cpus(&h->version);
151
73
- le32_to_cpus(&h->log_length);
152
@@ -XXX,XX +XXX,XX @@ static void vu_blk_exp_delete(BlockExport *exp)
74
- le64_to_cpus(&h->log_offset);
153
75
+ h->log_version = le16_to_cpu(h->log_version);
154
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
76
+ h->version = le16_to_cpu(h->version);
155
vexp);
77
+ h->log_length = le32_to_cpu(h->log_length);
156
+ g_free(vexp->handler.serial);
78
+ h->log_offset = le64_to_cpu(h->log_offset);
79
}
157
}
80
158
81
void vhdx_header_le_export(VHDXHeader *orig_h, VHDXHeader *new_h)
159
const BlockExportDriver blk_exp_vhost_user_blk = {
82
@@ -XXX,XX +XXX,XX @@ void vhdx_log_desc_le_import(VHDXLogDescriptor *d)
160
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
83
{
84
assert(d != NULL);
85
86
- le32_to_cpus(&d->signature);
87
- le64_to_cpus(&d->file_offset);
88
- le64_to_cpus(&d->sequence_number);
89
+ d->signature = le32_to_cpu(d->signature);
90
+ d->file_offset = le64_to_cpu(d->file_offset);
91
+ d->sequence_number = le64_to_cpu(d->sequence_number);
92
}
93
94
void vhdx_log_desc_le_export(VHDXLogDescriptor *d)
95
{
96
assert(d != NULL);
97
98
- cpu_to_le32s(&d->signature);
99
- cpu_to_le32s(&d->trailing_bytes);
100
- cpu_to_le64s(&d->leading_bytes);
101
- cpu_to_le64s(&d->file_offset);
102
- cpu_to_le64s(&d->sequence_number);
103
+ d->signature = cpu_to_le32(d->signature);
104
+ d->trailing_bytes = cpu_to_le32(d->trailing_bytes);
105
+ d->leading_bytes = cpu_to_le64(d->leading_bytes);
106
+ d->file_offset = cpu_to_le64(d->file_offset);
107
+ d->sequence_number = cpu_to_le64(d->sequence_number);
108
}
109
110
void vhdx_log_data_le_import(VHDXLogDataSector *d)
111
{
112
assert(d != NULL);
113
114
- le32_to_cpus(&d->data_signature);
115
- le32_to_cpus(&d->sequence_high);
116
- le32_to_cpus(&d->sequence_low);
117
+ d->data_signature = le32_to_cpu(d->data_signature);
118
+ d->sequence_high = le32_to_cpu(d->sequence_high);
119
+ d->sequence_low = le32_to_cpu(d->sequence_low);
120
}
121
122
void vhdx_log_data_le_export(VHDXLogDataSector *d)
123
{
124
assert(d != NULL);
125
126
- cpu_to_le32s(&d->data_signature);
127
- cpu_to_le32s(&d->sequence_high);
128
- cpu_to_le32s(&d->sequence_low);
129
+ d->data_signature = cpu_to_le32(d->data_signature);
130
+ d->sequence_high = cpu_to_le32(d->sequence_high);
131
+ d->sequence_low = cpu_to_le32(d->sequence_low);
132
}
133
134
void vhdx_log_entry_hdr_le_import(VHDXLogEntryHeader *hdr)
135
{
136
assert(hdr != NULL);
137
138
- le32_to_cpus(&hdr->signature);
139
- le32_to_cpus(&hdr->checksum);
140
- le32_to_cpus(&hdr->entry_length);
141
- le32_to_cpus(&hdr->tail);
142
- le64_to_cpus(&hdr->sequence_number);
143
- le32_to_cpus(&hdr->descriptor_count);
144
+ hdr->signature = le32_to_cpu(hdr->signature);
145
+ hdr->checksum = le32_to_cpu(hdr->checksum);
146
+ hdr->entry_length = le32_to_cpu(hdr->entry_length);
147
+ hdr->tail = le32_to_cpu(hdr->tail);
148
+ hdr->sequence_number = le64_to_cpu(hdr->sequence_number);
149
+ hdr->descriptor_count = le32_to_cpu(hdr->descriptor_count);
150
leguid_to_cpus(&hdr->log_guid);
151
- le64_to_cpus(&hdr->flushed_file_offset);
152
- le64_to_cpus(&hdr->last_file_offset);
153
+ hdr->flushed_file_offset = le64_to_cpu(hdr->flushed_file_offset);
154
+ hdr->last_file_offset = le64_to_cpu(hdr->last_file_offset);
155
}
156
157
void vhdx_log_entry_hdr_le_export(VHDXLogEntryHeader *hdr)
158
{
159
assert(hdr != NULL);
160
161
- cpu_to_le32s(&hdr->signature);
162
- cpu_to_le32s(&hdr->checksum);
163
- cpu_to_le32s(&hdr->entry_length);
164
- cpu_to_le32s(&hdr->tail);
165
- cpu_to_le64s(&hdr->sequence_number);
166
- cpu_to_le32s(&hdr->descriptor_count);
167
+ hdr->signature = cpu_to_le32(hdr->signature);
168
+ hdr->checksum = cpu_to_le32(hdr->checksum);
169
+ hdr->entry_length = cpu_to_le32(hdr->entry_length);
170
+ hdr->tail = cpu_to_le32(hdr->tail);
171
+ hdr->sequence_number = cpu_to_le64(hdr->sequence_number);
172
+ hdr->descriptor_count = cpu_to_le32(hdr->descriptor_count);
173
cpu_to_leguids(&hdr->log_guid);
174
- cpu_to_le64s(&hdr->flushed_file_offset);
175
- cpu_to_le64s(&hdr->last_file_offset);
176
+ hdr->flushed_file_offset = cpu_to_le64(hdr->flushed_file_offset);
177
+ hdr->last_file_offset = cpu_to_le64(hdr->last_file_offset);
178
}
179
180
181
@@ -XXX,XX +XXX,XX @@ void vhdx_region_header_le_import(VHDXRegionTableHeader *hdr)
182
{
183
assert(hdr != NULL);
184
185
- le32_to_cpus(&hdr->signature);
186
- le32_to_cpus(&hdr->checksum);
187
- le32_to_cpus(&hdr->entry_count);
188
+ hdr->signature = le32_to_cpu(hdr->signature);
189
+ hdr->checksum = le32_to_cpu(hdr->checksum);
190
+ hdr->entry_count = le32_to_cpu(hdr->entry_count);
191
}
192
193
void vhdx_region_header_le_export(VHDXRegionTableHeader *hdr)
194
{
195
assert(hdr != NULL);
196
197
- cpu_to_le32s(&hdr->signature);
198
- cpu_to_le32s(&hdr->checksum);
199
- cpu_to_le32s(&hdr->entry_count);
200
+ hdr->signature = cpu_to_le32(hdr->signature);
201
+ hdr->checksum = cpu_to_le32(hdr->checksum);
202
+ hdr->entry_count = cpu_to_le32(hdr->entry_count);
203
}
204
205
void vhdx_region_entry_le_import(VHDXRegionTableEntry *e)
206
@@ -XXX,XX +XXX,XX @@ void vhdx_region_entry_le_import(VHDXRegionTableEntry *e)
207
assert(e != NULL);
208
209
leguid_to_cpus(&e->guid);
210
- le64_to_cpus(&e->file_offset);
211
- le32_to_cpus(&e->length);
212
- le32_to_cpus(&e->data_bits);
213
+ e->file_offset = le64_to_cpu(e->file_offset);
214
+ e->length = le32_to_cpu(e->length);
215
+ e->data_bits = le32_to_cpu(e->data_bits);
216
}
217
218
void vhdx_region_entry_le_export(VHDXRegionTableEntry *e)
219
@@ -XXX,XX +XXX,XX @@ void vhdx_region_entry_le_export(VHDXRegionTableEntry *e)
220
assert(e != NULL);
221
222
cpu_to_leguids(&e->guid);
223
- cpu_to_le64s(&e->file_offset);
224
- cpu_to_le32s(&e->length);
225
- cpu_to_le32s(&e->data_bits);
226
+ e->file_offset = cpu_to_le64(e->file_offset);
227
+ e->length = cpu_to_le32(e->length);
228
+ e->data_bits = cpu_to_le32(e->data_bits);
229
}
230
231
232
@@ -XXX,XX +XXX,XX @@ void vhdx_metadata_header_le_import(VHDXMetadataTableHeader *hdr)
233
{
234
assert(hdr != NULL);
235
236
- le64_to_cpus(&hdr->signature);
237
- le16_to_cpus(&hdr->entry_count);
238
+ hdr->signature = le64_to_cpu(hdr->signature);
239
+ hdr->entry_count = le16_to_cpu(hdr->entry_count);
240
}
241
242
void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr)
243
{
244
assert(hdr != NULL);
245
246
- cpu_to_le64s(&hdr->signature);
247
- cpu_to_le16s(&hdr->entry_count);
248
+ hdr->signature = cpu_to_le64(hdr->signature);
249
+ hdr->entry_count = cpu_to_le16(hdr->entry_count);
250
}
251
252
void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e)
253
@@ -XXX,XX +XXX,XX @@ void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e)
254
assert(e != NULL);
255
256
leguid_to_cpus(&e->item_id);
257
- le32_to_cpus(&e->offset);
258
- le32_to_cpus(&e->length);
259
- le32_to_cpus(&e->data_bits);
260
+ e->offset = le32_to_cpu(e->offset);
261
+ e->length = le32_to_cpu(e->length);
262
+ e->data_bits = le32_to_cpu(e->data_bits);
263
}
264
void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e)
265
{
266
assert(e != NULL);
267
268
cpu_to_leguids(&e->item_id);
269
- cpu_to_le32s(&e->offset);
270
- cpu_to_le32s(&e->length);
271
- cpu_to_le32s(&e->data_bits);
272
+ e->offset = cpu_to_le32(e->offset);
273
+ e->length = cpu_to_le32(e->length);
274
+ e->data_bits = cpu_to_le32(e->data_bits);
275
}
276
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
277
index XXXXXXX..XXXXXXX 100644
161
index XXXXXXX..XXXXXXX 100644
278
--- a/block/vhdx-log.c
162
--- a/storage-daemon/qemu-storage-daemon.c
279
+++ b/block/vhdx-log.c
163
+++ b/storage-daemon/qemu-storage-daemon.c
280
@@ -XXX,XX +XXX,XX @@ static void vhdx_log_raw_to_le_sector(VHDXLogDescriptor *desc,
164
@@ -XXX,XX +XXX,XX @@ static void help(void)
281
/* 8 + 4084 + 4 = 4096, 1 log sector */
165
" [,writable=on|off][,num-queues=<num-queues>]\n"
282
memcpy(&desc->leading_bytes, data, 8);
166
" [,queue-size=<queue-size>]\n"
283
data += 8;
167
" [,logical-block-size=<logical-block-size>]\n"
284
- cpu_to_le64s(&desc->leading_bytes);
168
+" [,serial=<serial-number>]\n"
285
+ desc->leading_bytes = cpu_to_le64(desc->leading_bytes);
169
" export the specified block node as a vduse-blk\n"
286
memcpy(sector->data, data, 4084);
170
" device using the id as the VDUSE device name\n"
287
data += 4084;
171
"\n"
288
memcpy(&desc->trailing_bytes, data, 4);
289
- cpu_to_le32s(&desc->trailing_bytes);
290
+ desc->trailing_bytes = cpu_to_le32(desc->trailing_bytes);
291
data += 4;
292
293
sector->sequence_high = (uint32_t) (seq >> 32);
294
diff --git a/block/vhdx.c b/block/vhdx.c
295
index XXXXXXX..XXXXXXX 100644
296
--- a/block/vhdx.c
297
+++ b/block/vhdx.c
298
@@ -XXX,XX +XXX,XX @@ uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset)
299
300
memset(buf + crc_offset, 0, sizeof(crc));
301
crc = crc32c(0xffffffff, buf, size);
302
- cpu_to_le32s(&crc);
303
+ crc = cpu_to_le32(crc);
304
memcpy(buf + crc_offset, &crc, sizeof(crc));
305
306
return crc;
307
@@ -XXX,XX +XXX,XX @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
308
goto exit;
309
}
310
311
- le32_to_cpus(&s->params.block_size);
312
- le32_to_cpus(&s->params.data_bits);
313
+ s->params.block_size = le32_to_cpu(s->params.block_size);
314
+ s->params.data_bits = le32_to_cpu(s->params.data_bits);
315
316
317
/* We now have the file parameters, so we can tell if this is a
318
@@ -XXX,XX +XXX,XX @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
319
goto exit;
320
}
321
322
- le64_to_cpus(&s->virtual_disk_size);
323
- le32_to_cpus(&s->logical_sector_size);
324
- le32_to_cpus(&s->physical_sector_size);
325
+ s->virtual_disk_size = le64_to_cpu(s->virtual_disk_size);
326
+ s->logical_sector_size = le32_to_cpu(s->logical_sector_size);
327
+ s->physical_sector_size = le32_to_cpu(s->physical_sector_size);
328
329
if (s->params.block_size < VHDX_BLOCK_SIZE_MIN ||
330
s->params.block_size > VHDX_BLOCK_SIZE_MAX) {
331
@@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
332
/* endian convert, and verify populated BAT field file offsets against
333
* region table and log entries */
334
for (i = 0; i < s->bat_entries; i++) {
335
- le64_to_cpus(&s->bat[i]);
336
+ s->bat[i] = le64_to_cpu(s->bat[i]);
337
if (payblocks--) {
338
/* payload bat entries */
339
if ((s->bat[i] & VHDX_BAT_STATE_BIT_MASK) ==
340
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_new_metadata(BlockBackend *blk,
341
mt_file_params->block_size = cpu_to_le32(block_size);
342
if (type == VHDX_TYPE_FIXED) {
343
mt_file_params->data_bits |= VHDX_PARAMS_LEAVE_BLOCKS_ALLOCED;
344
- cpu_to_le32s(&mt_file_params->data_bits);
345
+ mt_file_params->data_bits = cpu_to_le32(mt_file_params->data_bits);
346
}
347
348
vhdx_guid_generate(&mt_page83->page_83_data);
349
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
350
sinfo.file_offset = ROUND_UP(sinfo.file_offset, MiB);
351
vhdx_update_bat_table_entry(blk_bs(blk), s, &sinfo, &unused, &unused,
352
block_state);
353
- cpu_to_le64s(&s->bat[sinfo.bat_idx]);
354
+ s->bat[sinfo.bat_idx] = cpu_to_le64(s->bat[sinfo.bat_idx]);
355
sector_num += s->sectors_per_block;
356
}
357
ret = blk_pwrite(blk, file_offset, s->bat, length, 0);
358
--
172
--
359
2.19.1
173
2.35.3
360
361
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Xie Yongji <xieyongji@bytedance.com>
2
2
3
Taking the address of a field in a packed struct is a bad idea, because
3
Currently we use 'id' option as the name of VDUSE device.
4
it might not be actually aligned enough for that pointer type (and
4
It's a bit confusing since we use one value for two different
5
thus cause a crash on dereference on some host architectures). Newer
5
purposes: the ID to identfy the export within QEMU (must be
6
versions of clang warn about this. Avoid the bug by not using the
6
distinct from any other exports in the same QEMU process, but
7
"modify in place" byte swapping functions.
7
can overlap with names used by other processes), and the VDUSE
8
name to uniquely identify it on the host (must be distinct from
9
other VDUSE devices on the same host, but can overlap with other
10
export types like NBD in the same process). To make it clear,
11
this patch adds a separate 'name' option to specify the VDUSE
12
name for the vduse-blk export instead.
8
13
9
There are a few places where the in-place swap function is
14
Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
10
used on something other than a packed struct field; we convert
15
Message-Id: <20220614051532.92-7-xieyongji@bytedance.com>
11
those anyway, for consistency.
12
13
This patch was produced with the following spatch script:
14
15
@@
16
expression E;
17
@@
18
-be16_to_cpus(&E);
19
+E = be16_to_cpu(E);
20
@@
21
expression E;
22
@@
23
-be32_to_cpus(&E);
24
+E = be32_to_cpu(E);
25
@@
26
expression E;
27
@@
28
-be64_to_cpus(&E);
29
+E = be64_to_cpu(E);
30
@@
31
expression E;
32
@@
33
-cpu_to_be16s(&E);
34
+E = cpu_to_be16(E);
35
@@
36
expression E;
37
@@
38
-cpu_to_be32s(&E);
39
+E = cpu_to_be32(E);
40
@@
41
expression E;
42
@@
43
-cpu_to_be64s(&E);
44
+E = cpu_to_be64(E);
45
46
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
47
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
48
Tested-by: John Snow <jsnow@redhat.com>
49
Reviewed-by: John Snow <jsnow@redhat.com>
50
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
17
---
52
block/qcow.c | 18 +++++++++---------
18
qapi/block-export.json | 7 ++++---
53
1 file changed, 9 insertions(+), 9 deletions(-)
19
docs/tools/qemu-storage-daemon.rst | 5 +++--
20
block/export/vduse-blk.c | 4 ++--
21
storage-daemon/qemu-storage-daemon.c | 8 ++++----
22
4 files changed, 13 insertions(+), 11 deletions(-)
54
23
55
diff --git a/block/qcow.c b/block/qcow.c
24
diff --git a/qapi/block-export.json b/qapi/block-export.json
56
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qcow.c
26
--- a/qapi/block-export.json
58
+++ b/block/qcow.c
27
+++ b/qapi/block-export.json
59
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
28
@@ -XXX,XX +XXX,XX @@
60
if (ret < 0) {
29
#
61
goto fail;
30
# A vduse-blk block export.
31
#
32
+# @name: the name of VDUSE device (must be unique across the host).
33
# @num-queues: the number of virtqueues. Defaults to 1.
34
# @queue-size: the size of virtqueue. Defaults to 256.
35
# @logical-block-size: Logical block size in bytes. Range [512, PAGE_SIZE]
36
@@ -XXX,XX +XXX,XX @@
37
# Since: 7.1
38
##
39
{ 'struct': 'BlockExportOptionsVduseBlk',
40
- 'data': { '*num-queues': 'uint16',
41
+ 'data': { 'name': 'str',
42
+ '*num-queues': 'uint16',
43
'*queue-size': 'uint16',
44
'*logical-block-size': 'size',
45
'*serial': 'str' } }
46
@@ -XXX,XX +XXX,XX @@
47
# Describes a block export, i.e. how single node should be exported on an
48
# external interface.
49
#
50
-# @id: A unique identifier for the block export (across the host for vduse-blk
51
-# export type or across all export types for other types)
52
+# @id: A unique identifier for the block export (across all export types)
53
#
54
# @node-name: The node name of the block node to be exported (since: 5.2)
55
#
56
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
57
index XXXXXXX..XXXXXXX 100644
58
--- a/docs/tools/qemu-storage-daemon.rst
59
+++ b/docs/tools/qemu-storage-daemon.rst
60
@@ -XXX,XX +XXX,XX @@ Standard options:
61
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=unix,addr.path=<socket-path>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
62
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=fd,addr.str=<fd>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
63
--export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>[,growable=on|off][,writable=on|off][,allow-other=on|off|auto]
64
- --export [type=]vduse-blk,id=<id>,node-name=<node-name>[,writable=on|off][,num-queues=<num-queues>][,queue-size=<queue-size>][,logical-block-size=<block-size>][,serial=<serial-number>]
65
+ --export [type=]vduse-blk,id=<id>,node-name=<node-name>,name=<vduse-name>[,writable=on|off][,num-queues=<num-queues>][,queue-size=<queue-size>][,logical-block-size=<block-size>][,serial=<serial-number>]
66
67
is a block export definition. ``node-name`` is the block node that should be
68
exported. ``writable`` determines whether or not the export allows write
69
@@ -XXX,XX +XXX,XX @@ Standard options:
70
``allow-other`` to auto (the default) will try enabling this option, and on
71
error fall back to disabling it.
72
73
- The ``vduse-blk`` export type uses the ``id`` as the VDUSE device name.
74
+ The ``vduse-blk`` export type takes a ``name`` (must be unique across the host)
75
+ to create the VDUSE device.
76
``num-queues`` sets the number of virtqueues (the default is 1).
77
``queue-size`` sets the virtqueue descriptor table size (the default is 256).
78
79
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
80
index XXXXXXX..XXXXXXX 100644
81
--- a/block/export/vduse-blk.c
82
+++ b/block/export/vduse-blk.c
83
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
84
features |= 1ULL << VIRTIO_BLK_F_RO;
62
}
85
}
63
- be32_to_cpus(&header.magic);
86
64
- be32_to_cpus(&header.version);
87
- vblk_exp->dev = vduse_dev_create(exp->id, VIRTIO_ID_BLOCK, 0,
65
- be64_to_cpus(&header.backing_file_offset);
88
+ vblk_exp->dev = vduse_dev_create(vblk_opts->name, VIRTIO_ID_BLOCK, 0,
66
- be32_to_cpus(&header.backing_file_size);
89
features, num_queues,
67
- be32_to_cpus(&header.mtime);
90
sizeof(struct virtio_blk_config),
68
- be64_to_cpus(&header.size);
91
(char *)&config, &vduse_blk_ops,
69
- be32_to_cpus(&header.crypt_method);
92
@@ -XXX,XX +XXX,XX @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
70
- be64_to_cpus(&header.l1_table_offset);
71
+ header.magic = be32_to_cpu(header.magic);
72
+ header.version = be32_to_cpu(header.version);
73
+ header.backing_file_offset = be64_to_cpu(header.backing_file_offset);
74
+ header.backing_file_size = be32_to_cpu(header.backing_file_size);
75
+ header.mtime = be32_to_cpu(header.mtime);
76
+ header.size = be64_to_cpu(header.size);
77
+ header.crypt_method = be32_to_cpu(header.crypt_method);
78
+ header.l1_table_offset = be64_to_cpu(header.l1_table_offset);
79
80
if (header.magic != QCOW_MAGIC) {
81
error_setg(errp, "Image not in qcow format");
82
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
83
}
93
}
84
94
85
for(i = 0;i < s->l1_size; i++) {
95
vblk_exp->recon_file = g_strdup_printf("%s/vduse-blk-%s",
86
- be64_to_cpus(&s->l1_table[i]);
96
- g_get_tmp_dir(), exp->id);
87
+ s->l1_table[i] = be64_to_cpu(s->l1_table[i]);
97
+ g_get_tmp_dir(), vblk_opts->name);
88
}
98
if (vduse_set_reconnect_log_file(vblk_exp->dev, vblk_exp->recon_file)) {
89
99
error_setg(errp, "failed to set reconnect log file");
90
/* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
100
ret = -EINVAL;
101
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/storage-daemon/qemu-storage-daemon.c
104
+++ b/storage-daemon/qemu-storage-daemon.c
105
@@ -XXX,XX +XXX,XX @@ static void help(void)
106
#endif /* CONFIG_VHOST_USER_BLK_SERVER */
107
#ifdef CONFIG_VDUSE_BLK_EXPORT
108
" --export [type=]vduse-blk,id=<id>,node-name=<node-name>\n"
109
-" [,writable=on|off][,num-queues=<num-queues>]\n"
110
-" [,queue-size=<queue-size>]\n"
111
+" ,name=<vduse-name>[,writable=on|off]\n"
112
+" [,num-queues=<num-queues>][,queue-size=<queue-size>]\n"
113
" [,logical-block-size=<logical-block-size>]\n"
114
" [,serial=<serial-number>]\n"
115
-" export the specified block node as a vduse-blk\n"
116
-" device using the id as the VDUSE device name\n"
117
+" export the specified block node as a\n"
118
+" vduse-blk device\n"
119
"\n"
120
#endif /* CONFIG_VDUSE_BLK_EXPORT */
121
" --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n"
91
--
122
--
92
2.19.1
123
2.35.3
93
94
diff view generated by jsdifflib
Deleted patch
1
From: Daniel P. Berrangé <berrange@redhat.com>
2
1
3
The qcow2 block driver expects to see a valid sector size even when it
4
has opened the crypto layer with QCRYPTO_BLOCK_OPEN_NO_IO.
5
6
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
crypto/block-qcow.c | 2 ++
11
1 file changed, 2 insertions(+)
12
13
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/crypto/block-qcow.c
16
+++ b/crypto/block-qcow.c
17
@@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_open(QCryptoBlock *block,
18
Error **errp)
19
{
20
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
21
+ block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
22
+ block->payload_offset = 0;
23
return 0;
24
} else {
25
if (!options->u.qcow.key_secret) {
26
--
27
2.19.1
28
29
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
This doesn't have any practical effect at the moment because the
4
values of BDRV_SECTOR_SIZE, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE and
5
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE are all the same (512 bytes), but
6
future encryption methods could have different requirements.
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block/qcow2.c | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
14
15
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2.c
18
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
20
21
if (bs->encrypted) {
22
/* Encryption works on a sector granularity */
23
- bs->bl.request_alignment = BDRV_SECTOR_SIZE;
24
+ bs->bl.request_alignment = qcrypto_block_get_sector_size(s->crypto);
25
}
26
bs->bl.pwrite_zeroes_alignment = s->cluster_size;
27
bs->bl.pdiscard_alignment = s->cluster_size;
28
--
29
2.19.1
30
31
diff view generated by jsdifflib
Deleted patch
1
From: Cleber Rosa <crosa@redhat.com>
2
1
3
While testing the Python 3 changes which touch the 083 test, I noticed
4
that it would fail with qcow2. Expanding the testing, I noticed it
5
had nothing to do with the Python 3 changes, and in fact, it would not
6
pass on anything but raw:
7
8
raw: pass
9
bochs: not generic
10
cloop: not generic
11
parallels: fail
12
qcow: fail
13
qcow2: fail
14
qed: fail
15
vdi: fail
16
vhdx: fail
17
vmdk: fail
18
vpc: fail
19
luks: fail
20
21
The errors are a mixture I/O and "image not in xxx format", such as:
22
23
=== Check disconnect before data ===
24
25
Unexpected end-of-file before all bytes were read
26
-read failed: Input/output error
27
+can't open device nbd+tcp://127.0.0.1:PORT/foo: Could not open 'nbd://127.0.0.1:PORT/foo': Input/output error
28
29
=== Check disconnect after data ===
30
31
-read 512/512 bytes at offset 0
32
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
33
+can't open device nbd+tcp://127.0.0.1:PORT/foo: Image not in qcow format
34
35
I'm not aware if there's a quick fix, so, for the time being, it looks
36
like the honest approach is to make the test known to work on raw
37
only.
38
39
Signed-off-by: Cleber Rosa <crosa@redhat.com>
40
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
41
---
42
tests/qemu-iotests/083 | 2 +-
43
1 file changed, 1 insertion(+), 1 deletion(-)
44
45
diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083
46
index XXXXXXX..XXXXXXX 100755
47
--- a/tests/qemu-iotests/083
48
+++ b/tests/qemu-iotests/083
49
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
50
. ./common.rc
51
. ./common.filter
52
53
-_supported_fmt generic
54
+_supported_fmt raw
55
_supported_proto nbd
56
_supported_os Linux
57
58
--
59
2.19.1
60
61
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Alberto Garcia <berto@igalia.com>
3
---
4
block/vpc.c | 2 ++
5
1 file changed, 2 insertions(+)
6
1
7
diff --git a/block/vpc.c b/block/vpc.c
8
index XXXXXXX..XXXXXXX 100644
9
--- a/block/vpc.c
10
+++ b/block/vpc.c
11
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
12
}
13
14
qemu_co_mutex_init(&s->lock);
15
+ qemu_opts_del(opts);
16
17
return 0;
18
19
fail:
20
+ qemu_opts_del(opts);
21
qemu_vfree(s->pagetable);
22
#ifdef CACHE
23
g_free(s->pageentry_u8);
24
--
25
2.19.1
26
27
diff view generated by jsdifflib
Deleted patch
1
From: Peter Maydell <peter.maydell@linaro.org>
2
1
3
Taking the address of a field in a packed struct is a bad idea, because
4
it might not be actually aligned enough for that pointer type (and
5
thus cause a crash on dereference on some host architectures). Newer
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
9
There are a few places where the in-place swap function is
10
used on something other than a packed struct field; we convert
11
those anyway, for consistency.
12
13
Patch produced with scripts/coccinelle/inplace-byteswaps.cocci.
14
15
There are other places where we take the address of a packed member
16
in this file for other purposes than passing it to a byteswap
17
function (all the calls to qemu_uuid_*()); we leave those for now.
18
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
23
block/vdi.c | 64 ++++++++++++++++++++++++++---------------------------
24
1 file changed, 32 insertions(+), 32 deletions(-)
25
26
diff --git a/block/vdi.c b/block/vdi.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/vdi.c
29
+++ b/block/vdi.c
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
31
32
static void vdi_header_to_cpu(VdiHeader *header)
33
{
34
- le32_to_cpus(&header->signature);
35
- le32_to_cpus(&header->version);
36
- le32_to_cpus(&header->header_size);
37
- le32_to_cpus(&header->image_type);
38
- le32_to_cpus(&header->image_flags);
39
- le32_to_cpus(&header->offset_bmap);
40
- le32_to_cpus(&header->offset_data);
41
- le32_to_cpus(&header->cylinders);
42
- le32_to_cpus(&header->heads);
43
- le32_to_cpus(&header->sectors);
44
- le32_to_cpus(&header->sector_size);
45
- le64_to_cpus(&header->disk_size);
46
- le32_to_cpus(&header->block_size);
47
- le32_to_cpus(&header->block_extra);
48
- le32_to_cpus(&header->blocks_in_image);
49
- le32_to_cpus(&header->blocks_allocated);
50
+ header->signature = le32_to_cpu(header->signature);
51
+ header->version = le32_to_cpu(header->version);
52
+ header->header_size = le32_to_cpu(header->header_size);
53
+ header->image_type = le32_to_cpu(header->image_type);
54
+ header->image_flags = le32_to_cpu(header->image_flags);
55
+ header->offset_bmap = le32_to_cpu(header->offset_bmap);
56
+ header->offset_data = le32_to_cpu(header->offset_data);
57
+ header->cylinders = le32_to_cpu(header->cylinders);
58
+ header->heads = le32_to_cpu(header->heads);
59
+ header->sectors = le32_to_cpu(header->sectors);
60
+ header->sector_size = le32_to_cpu(header->sector_size);
61
+ header->disk_size = le64_to_cpu(header->disk_size);
62
+ header->block_size = le32_to_cpu(header->block_size);
63
+ header->block_extra = le32_to_cpu(header->block_extra);
64
+ header->blocks_in_image = le32_to_cpu(header->blocks_in_image);
65
+ header->blocks_allocated = le32_to_cpu(header->blocks_allocated);
66
qemu_uuid_bswap(&header->uuid_image);
67
qemu_uuid_bswap(&header->uuid_last_snap);
68
qemu_uuid_bswap(&header->uuid_link);
69
@@ -XXX,XX +XXX,XX @@ static void vdi_header_to_cpu(VdiHeader *header)
70
71
static void vdi_header_to_le(VdiHeader *header)
72
{
73
- cpu_to_le32s(&header->signature);
74
- cpu_to_le32s(&header->version);
75
- cpu_to_le32s(&header->header_size);
76
- cpu_to_le32s(&header->image_type);
77
- cpu_to_le32s(&header->image_flags);
78
- cpu_to_le32s(&header->offset_bmap);
79
- cpu_to_le32s(&header->offset_data);
80
- cpu_to_le32s(&header->cylinders);
81
- cpu_to_le32s(&header->heads);
82
- cpu_to_le32s(&header->sectors);
83
- cpu_to_le32s(&header->sector_size);
84
- cpu_to_le64s(&header->disk_size);
85
- cpu_to_le32s(&header->block_size);
86
- cpu_to_le32s(&header->block_extra);
87
- cpu_to_le32s(&header->blocks_in_image);
88
- cpu_to_le32s(&header->blocks_allocated);
89
+ header->signature = cpu_to_le32(header->signature);
90
+ header->version = cpu_to_le32(header->version);
91
+ header->header_size = cpu_to_le32(header->header_size);
92
+ header->image_type = cpu_to_le32(header->image_type);
93
+ header->image_flags = cpu_to_le32(header->image_flags);
94
+ header->offset_bmap = cpu_to_le32(header->offset_bmap);
95
+ header->offset_data = cpu_to_le32(header->offset_data);
96
+ header->cylinders = cpu_to_le32(header->cylinders);
97
+ header->heads = cpu_to_le32(header->heads);
98
+ header->sectors = cpu_to_le32(header->sectors);
99
+ header->sector_size = cpu_to_le32(header->sector_size);
100
+ header->disk_size = cpu_to_le64(header->disk_size);
101
+ header->block_size = cpu_to_le32(header->block_size);
102
+ header->block_extra = cpu_to_le32(header->block_extra);
103
+ header->blocks_in_image = cpu_to_le32(header->blocks_in_image);
104
+ header->blocks_allocated = cpu_to_le32(header->blocks_allocated);
105
qemu_uuid_bswap(&header->uuid_image);
106
qemu_uuid_bswap(&header->uuid_last_snap);
107
qemu_uuid_bswap(&header->uuid_link);
108
--
109
2.19.1
110
111
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
The blkverify mode of Quorum can only be enabled if the number of
4
children is exactly two and the value of vote-threshold is also two.
5
6
If the user tries to enable it but the other settings are incorrect
7
then QEMU simply prints an error message to stderr and carries on
8
disabling the blkverify setting.
9
10
This patch makes quorum_open() fail and return an error in this case.
11
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
Reported-by: Markus Armbruster <armbru@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
block/quorum.c | 13 ++++++-------
17
1 file changed, 6 insertions(+), 7 deletions(-)
18
19
diff --git a/block/quorum.c b/block/quorum.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/quorum.c
22
+++ b/block/quorum.c
23
@@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
24
s->read_pattern = ret;
25
26
if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
27
- /* is the driver in blkverify mode */
28
- if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false) &&
29
- s->num_children == 2 && s->threshold == 2) {
30
- s->is_blkverify = true;
31
- } else if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false)) {
32
- fprintf(stderr, "blkverify mode is set by setting blkverify=on "
33
- "and using two files with vote_threshold=2\n");
34
+ s->is_blkverify = qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false);
35
+ if (s->is_blkverify && (s->num_children != 2 || s->threshold != 2)) {
36
+ error_setg(&local_err, "blkverify=on can only be set if there are "
37
+ "exactly two files and vote-threshold is 2");
38
+ ret = -EINVAL;
39
+ goto exit;
40
}
41
42
s->rewrite_corrupted = qemu_opt_get_bool(opts, QUORUM_OPT_REWRITE,
43
--
44
2.19.1
45
46
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
tests/qemu-iotests/081 | 30 ++++++++++++++++++++++++++++++
7
tests/qemu-iotests/081.out | 16 ++++++++++++++++
8
2 files changed, 46 insertions(+)
9
10
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
11
index XXXXXXX..XXXXXXX 100755
12
--- a/tests/qemu-iotests/081
13
+++ b/tests/qemu-iotests/081
14
@@ -XXX,XX +XXX,XX @@ echo "== checking that quorum is broken =="
15
16
$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
17
18
+echo
19
+echo "== checking the blkverify mode with broken content =="
20
+
21
+quorum="driver=raw,file.driver=quorum,file.vote-threshold=2,file.blkverify=on"
22
+quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
23
+quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
24
+quorum="$quorum,file.children.0.driver=raw"
25
+quorum="$quorum,file.children.1.driver=raw"
26
+
27
+$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
28
+
29
+echo
30
+echo "== writing the same data to both files =="
31
+
32
+$QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/1.raw" | _filter_qemu_io
33
+$QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
34
+
35
+echo
36
+echo "== checking the blkverify mode with valid content =="
37
+
38
+$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
39
+
40
+echo
41
+echo "== checking the blkverify mode with invalid settings =="
42
+
43
+quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw"
44
+quorum="$quorum,file.children.2.driver=raw"
45
+
46
+$QEMU_IO -c "open -o $quorum" | _filter_qemu_io
47
+
48
# success, all done
49
echo "*** done"
50
rm -f $seq.full
51
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
52
index XXXXXXX..XXXXXXX 100644
53
--- a/tests/qemu-iotests/081.out
54
+++ b/tests/qemu-iotests/081.out
55
@@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 0
56
57
== checking that quorum is broken ==
58
read failed: Input/output error
59
+
60
+== checking the blkverify mode with broken content ==
61
+quorum: offset=0 bytes=10485760 contents mismatch at offset 0
62
+
63
+== writing the same data to both files ==
64
+wrote 10485760/10485760 bytes at offset 0
65
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
66
+wrote 10485760/10485760 bytes at offset 0
67
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
68
+
69
+== checking the blkverify mode with valid content ==
70
+read 10485760/10485760 bytes at offset 0
71
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
72
+
73
+== checking the blkverify mode with invalid settings ==
74
+can't open: blkverify=on can only be set if there are exactly two files and vote-threshold is 2
75
*** done
76
--
77
2.19.1
78
79
diff view generated by jsdifflib
Deleted patch
1
If read-only=off, but auto-read-only=on is given, open a read-write NBD
2
connection if the server provides a read-write export, but instead of
3
erroring out for read-only exports, just degrade to read-only.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
block/nbd-client.c | 10 +++++-----
9
1 file changed, 5 insertions(+), 5 deletions(-)
10
11
diff --git a/block/nbd-client.c b/block/nbd-client.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/nbd-client.c
14
+++ b/block/nbd-client.c
15
@@ -XXX,XX +XXX,XX @@ int nbd_client_init(BlockDriverState *bs,
16
logout("Failed to negotiate with the NBD server\n");
17
return ret;
18
}
19
- if (client->info.flags & NBD_FLAG_READ_ONLY &&
20
- !bdrv_is_read_only(bs)) {
21
- error_setg(errp,
22
- "request for write access conflicts with read-only export");
23
- return -EACCES;
24
+ if (client->info.flags & NBD_FLAG_READ_ONLY) {
25
+ ret = bdrv_apply_auto_read_only(bs, "NBD export is read-only", errp);
26
+ if (ret < 0) {
27
+ return ret;
28
+ }
29
}
30
if (client->info.flags & NBD_FLAG_SEND_FUA) {
31
bs->supported_write_flags = BDRV_REQ_FUA;
32
--
33
2.19.1
34
35
diff view generated by jsdifflib
Deleted patch
1
If read-only=off, but auto-read-only=on is given, open the file
2
read-write if we have the permissions, but instead of erroring out for
3
read-only files, just degrade to read-only.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
block/file-posix.c | 19 ++++++++++++++++---
9
1 file changed, 16 insertions(+), 3 deletions(-)
10
11
diff --git a/block/file-posix.c b/block/file-posix.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/file-posix.c
14
+++ b/block/file-posix.c
15
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
16
17
s->fd = -1;
18
fd = qemu_open(filename, s->open_flags, 0644);
19
- if (fd < 0) {
20
- ret = -errno;
21
- error_setg_errno(errp, errno, "Could not open '%s'", filename);
22
+ ret = fd < 0 ? -errno : 0;
23
+
24
+ if (ret == -EACCES || ret == -EROFS) {
25
+ /* Try to degrade to read-only, but if it doesn't work, still use the
26
+ * normal error message. */
27
+ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
28
+ bdrv_flags &= ~BDRV_O_RDWR;
29
+ raw_parse_flags(bdrv_flags, &s->open_flags);
30
+ assert(!(s->open_flags & O_CREAT));
31
+ fd = qemu_open(filename, s->open_flags);
32
+ ret = fd < 0 ? -errno : 0;
33
+ }
34
+ }
35
+
36
+ if (ret < 0) {
37
+ error_setg_errno(errp, -ret, "Could not open '%s'", filename);
38
if (ret == -EROFS) {
39
ret = -EACCES;
40
}
41
--
42
2.19.1
43
44
diff view generated by jsdifflib
Deleted patch
1
If read-only=off, but auto-read-only=on is given, just degrade to
2
read-only.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
---
7
block/curl.c | 8 ++++----
8
1 file changed, 4 insertions(+), 4 deletions(-)
9
10
diff --git a/block/curl.c b/block/curl.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/curl.c
13
+++ b/block/curl.c
14
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
15
const char *protocol_delimiter;
16
int ret;
17
18
-
19
- if (flags & BDRV_O_RDWR) {
20
- error_setg(errp, "curl block device does not support writes");
21
- return -EROFS;
22
+ ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
23
+ errp);
24
+ if (ret < 0) {
25
+ return ret;
26
}
27
28
if (!libcurl_initialized) {
29
--
30
2.19.1
31
32
diff view generated by jsdifflib
Deleted patch
1
If read-only=off, but auto-read-only=on is given, open the volume
2
read-write if we have the permissions, but instead of erroring out for
3
read-only volumes, just degrade to read-only.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
block/iscsi.c | 8 +++++---
9
1 file changed, 5 insertions(+), 3 deletions(-)
10
11
diff --git a/block/iscsi.c b/block/iscsi.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/iscsi.c
14
+++ b/block/iscsi.c
15
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
16
/* Check the write protect flag of the LUN if we want to write */
17
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
18
iscsilun->write_protected) {
19
- error_setg(errp, "Cannot open a write protected LUN as read-write");
20
- ret = -EACCES;
21
- goto out;
22
+ ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp);
23
+ if (ret < 0) {
24
+ goto out;
25
+ }
26
+ flags &= ~BDRV_O_RDWR;
27
}
28
29
iscsi_readcapacity_sync(iscsilun, &local_err);
30
--
31
2.19.1
32
33
diff view generated by jsdifflib
Deleted patch
1
While we want machine interfaces like -blockdev and QMP blockdev-add to
2
add as little auto-detection as possible so that management tools are
3
explicit about their needs, -drive is a convenience option for human
4
users. Enabling auto-read-only=on by default there enables users to use
5
read-only images for read-only guest devices without having to specify
6
read-only=on explicitly. If they try to attach the image to a read-write
7
device, they will still get an error message.
8
1
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
---
12
blockdev.c | 1 +
13
1 file changed, 1 insertion(+)
14
15
diff --git a/blockdev.c b/blockdev.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/blockdev.c
18
+++ b/blockdev.c
19
@@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
20
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
21
qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY,
22
read_only ? "on" : "off");
23
+ qdict_set_default_str(bs_opts, BDRV_OPT_AUTO_READ_ONLY, "on");
24
assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
25
26
if (runstate_check(RUN_STATE_INMIGRATE)) {
27
--
28
2.19.1
29
30
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Following the example of qemu_opts_print_help(), indent all entries in
4
the list of character devices.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
chardev/char.c | 2 +-
11
1 file changed, 1 insertion(+), 1 deletion(-)
12
13
diff --git a/chardev/char.c b/chardev/char.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/chardev/char.c
16
+++ b/chardev/char.c
17
@@ -XXX,XX +XXX,XX @@ help_string_append(const char *name, void *opaque)
18
{
19
GString *str = opaque;
20
21
- g_string_append_printf(str, "\n%s", name);
22
+ g_string_append_printf(str, "\n %s", name);
23
}
24
25
static const char *chardev_alias_translate(const char *name)
26
--
27
2.19.1
28
29
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Just like in qemu_opts_print_help(), print the object name as a caption
4
instead of on every single line, indent all options, add angle brackets
5
around types, and align the descriptions after 24 characters.
6
7
Also, indent every object name in the list of available objects.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
vl.c | 13 ++++++++++---
14
1 file changed, 10 insertions(+), 3 deletions(-)
15
16
diff --git a/vl.c b/vl.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/vl.c
19
+++ b/vl.c
20
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
21
list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
22
for (l = list; l != NULL; l = l->next) {
23
ObjectClass *oc = OBJECT_CLASS(l->data);
24
- printf("%s\n", object_class_get_name(oc));
25
+ printf(" %s\n", object_class_get_name(oc));
26
}
27
g_slist_free(list);
28
exit(0);
29
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
30
}
31
32
str = g_string_new(NULL);
33
- g_string_append_printf(str, "%s.%s=%s", type,
34
- prop->name, prop->type);
35
+ g_string_append_printf(str, " %s=<%s>", prop->name, prop->type);
36
if (prop->description) {
37
+ if (str->len < 24) {
38
+ g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
39
+ }
40
g_string_append_printf(str, " - %s", prop->description);
41
}
42
g_ptr_array_add(array, g_string_free(str, false));
43
}
44
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
45
+ if (array->len > 0) {
46
+ printf("%s options:\n", type);
47
+ } else {
48
+ printf("There are no options for %s.\n", type);
49
+ }
50
for (i = 0; i < array->len; i++) {
51
printf("%s\n", (char *)array->pdata[i]);
52
}
53
--
54
2.19.1
55
56
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
There is no good reason why there should be a newline in this
4
description, so remove it.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
vl.c | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
14
diff --git a/vl.c b/vl.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/vl.c
17
+++ b/vl.c
18
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qemu_fw_cfg_opts = {
19
}, {
20
.name = "file",
21
.type = QEMU_OPT_STRING,
22
- .help = "Sets the name of the file from which\n"
23
+ .help = "Sets the name of the file from which "
24
"the fw_cfg blob will be loaded",
25
}, {
26
.name = "string",
27
--
28
2.19.1
29
30
diff view generated by jsdifflib