1
The following changes since commit bfec359afba088aaacc7d316f43302f28c6e642a:
1
The following changes since commit 42f6c9179be4401974dd3a75ee72defd16b5092d:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-qdev-2017-04-21' into staging (2017-04-21 11:42:03 +0100)
3
Merge tag 'pull-ppc-20211112' of https://github.com/legoater/qemu into staging (2021-11-12 12:28:25 +0100)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/codyprime/qemu-kvm-jtc.git tags/block-pull-request
7
https://gitlab.com/hreitz/qemu.git tags/pull-block-2021-11-16
8
8
9
for you to fetch changes up to 1507631e438930bc07f776f303af127a9cdb4d41:
9
for you to fetch changes up to 5dbd0ce115c7720268e653fe928bb6a0c1314a80:
10
10
11
qemu-iotests: _cleanup_qemu must be called on exit (2017-04-21 08:32:44 -0400)
11
file-posix: Fix alignment after reopen changing O_DIRECT (2021-11-16 11:30:29 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
Block patches for 6.2.0-rc1:
15
Block patches for 2.10
15
- Fixes to image streaming job and block layer reconfiguration to make
16
iotest 030 pass again
17
- docs: Deprecate incorrectly typed device_add arguments
18
- file-posix: Fix alignment after reopen changing O_DIRECT
16
19
17
----------------------------------------------------------------
20
----------------------------------------------------------------
21
v2:
22
- Fixed iotest 142 (modified by "file-posix: Fix alignment after reopen
23
changing O_DIRECT") -- at least I hope so: for me, it now passes on a
24
4k block device, and the gitlab pipeline passed, too
18
25
19
Ashish Mittal (2):
26
- Note that because I had to modify Kevin's pull request, I did not want
20
block/vxhs.c: Add support for a new block device type called "vxhs"
27
to merge it partially (with a merge commit), but instead decided to
21
block/vxhs.c: Add qemu-iotests for new block device type "vxhs"
28
apply all patches from the pull request mails (including their message
29
IDs)
22
30
23
Jeff Cody (10):
31
----------------------------------------------------------------
24
qemu-iotests: exclude vxhs from image creation via protocol
32
Hanna Reitz (10):
25
block: add bdrv_set_read_only() helper function
33
stream: Traverse graph after modification
26
block: do not set BDS read_only if copy_on_read enabled
34
block: Manipulate children list in .attach/.detach
27
block: honor BDRV_O_ALLOW_RDWR when clearing bs->read_only
35
block: Unite remove_empty_child and child_free
28
block: code movement
36
block: Drop detached child from ignore list
29
block: introduce bdrv_can_set_read_only()
37
block: Pass BdrvChild ** to replace_child_noperm
30
block: use bdrv_can_set_read_only() during reopen
38
block: Restructure remove_file_or_backing_child()
31
block/rbd - update variable names to more apt names
39
transactions: Invoke clean() after everything else
32
block/rbd: Add support for reopen()
40
block: Let replace_child_tran keep indirect pointer
33
qemu-iotests: _cleanup_qemu must be called on exit
41
block: Let replace_child_noperm free children
42
iotests/030: Unthrottle parallel jobs in reverse
34
43
35
block.c | 56 +++-
44
Kevin Wolf (2):
36
block/Makefile.objs | 2 +
45
docs: Deprecate incorrectly typed device_add arguments
37
block/bochs.c | 5 +-
46
file-posix: Fix alignment after reopen changing O_DIRECT
38
block/cloop.c | 5 +-
47
39
block/dmg.c | 6 +-
48
Stefan Hajnoczi (1):
40
block/rbd.c | 65 +++--
49
softmmu/qdev-monitor: fix use-after-free in qdev_set_id()
41
block/trace-events | 17 ++
50
42
block/vvfat.c | 19 +-
51
docs/about/deprecated.rst | 14 +++
43
block/vxhs.c | 575 +++++++++++++++++++++++++++++++++++++++
52
include/qemu/transactions.h | 3 +
44
configure | 39 +++
53
block.c | 233 +++++++++++++++++++++++++++---------
45
include/block/block.h | 2 +
54
block/file-posix.c | 20 +++-
46
qapi/block-core.json | 23 +-
55
block/stream.c | 7 +-
47
tests/qemu-iotests/017 | 1 +
56
softmmu/qdev-monitor.c | 2 +-
48
tests/qemu-iotests/020 | 1 +
57
util/transactions.c | 8 +-
49
tests/qemu-iotests/028 | 1 +
58
tests/qemu-iotests/030 | 11 +-
50
tests/qemu-iotests/029 | 1 +
59
tests/qemu-iotests/142 | 29 +++++
51
tests/qemu-iotests/073 | 1 +
60
tests/qemu-iotests/142.out | 18 +++
52
tests/qemu-iotests/094 | 11 +-
61
10 files changed, 279 insertions(+), 66 deletions(-)
53
tests/qemu-iotests/102 | 5 +-
54
tests/qemu-iotests/109 | 1 +
55
tests/qemu-iotests/114 | 1 +
56
tests/qemu-iotests/117 | 1 +
57
tests/qemu-iotests/130 | 2 +
58
tests/qemu-iotests/134 | 1 +
59
tests/qemu-iotests/140 | 1 +
60
tests/qemu-iotests/141 | 1 +
61
tests/qemu-iotests/143 | 1 +
62
tests/qemu-iotests/156 | 2 +
63
tests/qemu-iotests/158 | 1 +
64
tests/qemu-iotests/common | 6 +
65
tests/qemu-iotests/common.config | 13 +
66
tests/qemu-iotests/common.filter | 1 +
67
tests/qemu-iotests/common.rc | 19 ++
68
33 files changed, 844 insertions(+), 42 deletions(-)
69
create mode 100644 block/vxhs.c
70
62
71
--
63
--
72
2.9.3
64
2.33.1
73
65
74
66
diff view generated by jsdifflib
1
For the tests that use the common.qemu functions for running a QEMU
1
bdrv_cor_filter_drop() modifies the block graph. That means that other
2
process, _cleanup_qemu must be called in the exit function.
2
parties can also modify the block graph before it returns. Therefore,
3
we cannot assume that the result of a graph traversal we did before
4
remains valid afterwards.
3
5
4
If it is not, if the qemu process aborts, then not all of the droppings
6
We should thus fetch `base` and `unfiltered_base` afterwards instead of
5
are cleaned up (e.g. pidfile, fifos).
7
before.
6
8
7
This updates those tests that did not have a cleanup in qemu-iotests.
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Message-Id: <20211111120829.81329-2-hreitz@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Message-Id: <20211115145409.176785-2-kwolf@redhat.com>
15
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
16
---
17
block/stream.c | 7 +++++--
18
1 file changed, 5 insertions(+), 2 deletions(-)
8
19
9
(I swapped spaces for tabs in test 102 as well)
20
diff --git a/block/stream.c b/block/stream.c
10
21
index XXXXXXX..XXXXXXX 100644
11
Reported-by: Eric Blake <eblake@redhat.com>
22
--- a/block/stream.c
12
Reviewed-by: Eric Blake <eblake@redhat.com>
23
+++ b/block/stream.c
13
Signed-off-by: Jeff Cody <jcody@redhat.com>
24
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
14
Message-id: d59c2f6ad6c1da8b9b3c7f357c94a7122ccfc55a.1492544096.git.jcody@redhat.com
15
---
16
tests/qemu-iotests/028 | 1 +
17
tests/qemu-iotests/094 | 11 ++++++++---
18
tests/qemu-iotests/102 | 5 +++--
19
tests/qemu-iotests/109 | 1 +
20
tests/qemu-iotests/117 | 1 +
21
tests/qemu-iotests/130 | 1 +
22
tests/qemu-iotests/140 | 1 +
23
tests/qemu-iotests/141 | 1 +
24
tests/qemu-iotests/143 | 1 +
25
tests/qemu-iotests/156 | 1 +
26
10 files changed, 19 insertions(+), 5 deletions(-)
27
28
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
29
index XXXXXXX..XXXXXXX 100755
30
--- a/tests/qemu-iotests/028
31
+++ b/tests/qemu-iotests/028
32
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
33
34
_cleanup()
35
{
25
{
36
+ _cleanup_qemu
26
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
37
rm -f "${TEST_IMG}.copy"
27
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
38
_cleanup_test_img
28
- BlockDriverState *base = bdrv_filter_or_cow_bs(s->above_base);
39
}
29
- BlockDriverState *unfiltered_base = bdrv_skip_filters(base);
40
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
30
+ BlockDriverState *base;
41
index XXXXXXX..XXXXXXX 100755
31
+ BlockDriverState *unfiltered_base;
42
--- a/tests/qemu-iotests/094
32
Error *local_err = NULL;
43
+++ b/tests/qemu-iotests/094
33
int ret = 0;
44
@@ -XXX,XX +XXX,XX @@ echo "QA output created by $seq"
34
45
here="$PWD"
35
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
46
status=1    # failure is the default!
36
bdrv_cor_filter_drop(s->cor_filter_bs);
47
37
s->cor_filter_bs = NULL;
48
-trap "exit \$status" 0 1 2 3 15
38
49
+_cleanup()
39
+ base = bdrv_filter_or_cow_bs(s->above_base);
50
+{
40
+ unfiltered_base = bdrv_skip_filters(base);
51
+ _cleanup_qemu
52
+ _cleanup_test_img
53
+ rm -f "$TEST_DIR/source.$IMGFMT"
54
+}
55
+
41
+
56
+trap "_cleanup; exit \$status" 0 1 2 3 15
42
if (bdrv_cow_child(unfiltered_bs)) {
57
43
const char *base_id = NULL, *base_fmt = NULL;
58
# get standard environment, filters and checks
44
if (unfiltered_base) {
59
. ./common.rc
60
@@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \
61
62
wait=1 _cleanup_qemu
63
64
-_cleanup_test_img
65
-rm -f "$TEST_DIR/source.$IMGFMT"
66
67
# success, all done
68
echo '*** done'
69
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
70
index XXXXXXX..XXXXXXX 100755
71
--- a/tests/qemu-iotests/102
72
+++ b/tests/qemu-iotests/102
73
@@ -XXX,XX +XXX,XX @@ seq=$(basename $0)
74
echo "QA output created by $seq"
75
76
here=$PWD
77
-status=1    # failure is the default!
78
+status=1 # failure is the default!
79
80
_cleanup()
81
{
82
-    _cleanup_test_img
83
+ _cleanup_qemu
84
+ _cleanup_test_img
85
}
86
trap "_cleanup; exit \$status" 0 1 2 3 15
87
88
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
89
index XXXXXXX..XXXXXXX 100755
90
--- a/tests/qemu-iotests/109
91
+++ b/tests/qemu-iotests/109
92
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
93
94
_cleanup()
95
{
96
+ _cleanup_qemu
97
rm -f $TEST_IMG.src
98
    _cleanup_test_img
99
}
100
diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117
101
index XXXXXXX..XXXXXXX 100755
102
--- a/tests/qemu-iotests/117
103
+++ b/tests/qemu-iotests/117
104
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
105
106
_cleanup()
107
{
108
+ _cleanup_qemu
109
    _cleanup_test_img
110
}
111
trap "_cleanup; exit \$status" 0 1 2 3 15
112
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
113
index XXXXXXX..XXXXXXX 100755
114
--- a/tests/qemu-iotests/130
115
+++ b/tests/qemu-iotests/130
116
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
117
118
_cleanup()
119
{
120
+ _cleanup_qemu
121
_cleanup_test_img
122
}
123
trap "_cleanup; exit \$status" 0 1 2 3 15
124
diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140
125
index XXXXXXX..XXXXXXX 100755
126
--- a/tests/qemu-iotests/140
127
+++ b/tests/qemu-iotests/140
128
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
129
130
_cleanup()
131
{
132
+ _cleanup_qemu
133
_cleanup_test_img
134
rm -f "$TEST_DIR/nbd"
135
}
136
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
137
index XXXXXXX..XXXXXXX 100755
138
--- a/tests/qemu-iotests/141
139
+++ b/tests/qemu-iotests/141
140
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
141
142
_cleanup()
143
{
144
+ _cleanup_qemu
145
_cleanup_test_img
146
rm -f "$TEST_DIR/{b,m,o}.$IMGFMT"
147
}
148
diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143
149
index XXXXXXX..XXXXXXX 100755
150
--- a/tests/qemu-iotests/143
151
+++ b/tests/qemu-iotests/143
152
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
153
154
_cleanup()
155
{
156
+ _cleanup_qemu
157
rm -f "$TEST_DIR/nbd"
158
}
159
trap "_cleanup; exit \$status" 0 1 2 3 15
160
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
161
index XXXXXXX..XXXXXXX 100755
162
--- a/tests/qemu-iotests/156
163
+++ b/tests/qemu-iotests/156
164
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
165
166
_cleanup()
167
{
168
+ _cleanup_qemu
169
rm -f "$TEST_IMG{,.target}{,.backing,.overlay}"
170
}
171
trap "_cleanup; exit \$status" 0 1 2 3 15
172
--
45
--
173
2.9.3
46
2.33.1
174
47
175
48
diff view generated by jsdifflib
1
Move bdrv_is_read_only() up with its friends.
1
The children list is specific to BDS parents. We should not modify it
2
in the general children modification code, but let BDS parents deal with
3
it in their .attach() and .detach() methods.
2
4
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
This also has the advantage that a BdrvChild is removed from the
4
Reviewed-by: John Snow <jsnow@redhat.com>
6
children list before its .bs pointer can become NULL. BDS parents
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
7
generally assume that their children's .bs pointer is never NULL, so
6
Message-id: 73b2399459760c32506f9407efb9dddb3a2789de.1491597120.git.jcody@redhat.com
8
this is actually a bug fix.
9
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Message-Id: <20211111120829.81329-3-hreitz@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Message-Id: <20211115145409.176785-3-kwolf@redhat.com>
15
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
---
16
---
8
block.c | 10 +++++-----
17
block.c | 14 +++++---------
9
1 file changed, 5 insertions(+), 5 deletions(-)
18
1 file changed, 5 insertions(+), 9 deletions(-)
10
19
11
diff --git a/block.c b/block.c
20
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
22
--- a/block.c
14
+++ b/block.c
23
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
24
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child)
25
{
26
BlockDriverState *bs = child->opaque;
27
28
+ QLIST_INSERT_HEAD(&bs->children, child, next);
29
+
30
if (child->role & BDRV_CHILD_COW) {
31
bdrv_backing_attach(child);
16
}
32
}
33
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_detach(BdrvChild *child)
34
}
35
36
bdrv_unapply_subtree_drain(child, bs);
37
+
38
+ QLIST_REMOVE(child, next);
17
}
39
}
18
40
19
+bool bdrv_is_read_only(BlockDriverState *bs)
41
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
20
+{
42
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_free(void *opaque)
21
+ return bs->read_only;
43
static void bdrv_remove_empty_child(BdrvChild *child)
22
+}
23
+
24
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
25
{
44
{
26
/* Do not set read_only if copy_on_read is enabled */
45
assert(!child->bs);
27
@@ -XXX,XX +XXX,XX @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
46
- QLIST_SAFE_REMOVE(child, next);
28
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
47
+ assert(!child->next.le_prev); /* not in children list */
48
bdrv_child_free(child);
29
}
49
}
30
50
31
-bool bdrv_is_read_only(BlockDriverState *bs)
51
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
32
-{
52
return ret;
33
- return bs->read_only;
53
}
34
-}
54
55
- QLIST_INSERT_HEAD(&parent_bs->children, *child, next);
56
- /*
57
- * child is removed in bdrv_attach_child_common_abort(), so don't care to
58
- * abort this change separately.
59
- */
35
-
60
-
36
bool bdrv_is_sg(BlockDriverState *bs)
61
return 0;
37
{
62
}
38
return bs->sg;
63
64
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_filter_or_cow_child_abort(void *opaque)
65
BdrvRemoveFilterOrCowChild *s = opaque;
66
BlockDriverState *parent_bs = s->child->opaque;
67
68
- QLIST_INSERT_HEAD(&parent_bs->children, s->child, next);
69
if (s->is_backing) {
70
parent_bs->backing = s->child;
71
} else {
72
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
73
};
74
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
75
76
- QLIST_SAFE_REMOVE(child, next);
77
if (s->is_backing) {
78
bs->backing = NULL;
79
} else {
39
--
80
--
40
2.9.3
81
2.33.1
41
82
42
83
diff view generated by jsdifflib
1
A few block drivers will set the BDS read_only flag from their
1
Now that bdrv_remove_empty_child() no longer removes the child from the
2
.bdrv_open() function. This means the bs->read_only flag could
2
parent's children list but only checks that it is not in such a list, it
3
be set after we enable copy_on_read, as the BDRV_O_COPY_ON_READ
3
is only a wrapper around bdrv_child_free() that checks that the child is
4
flag check occurs prior to the call to bdrv->bdrv_open().
4
empty and unused. That should apply to all children that we free, so
5
put those checks into bdrv_child_free() and drop
6
bdrv_remove_empty_child().
5
7
6
This adds an error return to bdrv_set_read_only(), and an error will be
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
return if we try to set the BDS to read_only while copy_on_read is
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
enabled.
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
11
Message-Id: <20211111120829.81329-4-hreitz@redhat.com>
10
This patch also changes the behavior of vvfat. Before, vvfat could
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
override the drive 'readonly' flag with its own, internal 'rw' flag.
13
Message-Id: <20211115145409.176785-4-kwolf@redhat.com>
12
14
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
13
For instance, this -drive parameter would result in a writable image:
14
15
"-drive format=vvfat,dir=/tmp/vvfat,rw,if=virtio,readonly=on"
16
17
This is not correct. Now, attempting to use the above -drive parameter
18
will result in an error (i.e., 'rw' is incompatible with 'readonly=on').
19
20
Signed-off-by: Jeff Cody <jcody@redhat.com>
21
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Reviewed-by: John Snow <jsnow@redhat.com>
23
Message-id: 0c5b4c1cc2c651471b131f21376dfd5ea24d2196.1491597120.git.jcody@redhat.com
24
---
15
---
25
block.c | 10 +++++++++-
16
block.c | 26 +++++++++++++-------------
26
block/bochs.c | 5 ++++-
17
1 file changed, 13 insertions(+), 13 deletions(-)
27
block/cloop.c | 5 ++++-
28
block/dmg.c | 6 +++++-
29
block/rbd.c | 11 ++++++++++-
30
block/vvfat.c | 19 +++++++++++++++----
31
include/block/block.h | 2 +-
32
7 files changed, 48 insertions(+), 10 deletions(-)
33
18
34
diff --git a/block.c b/block.c
19
diff --git a/block.c b/block.c
35
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
36
--- a/block.c
21
--- a/block.c
37
+++ b/block.c
22
+++ b/block.c
38
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
23
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
39
}
24
}
40
}
25
}
41
26
42
-void bdrv_set_read_only(BlockDriverState *bs, bool read_only)
27
-static void bdrv_child_free(void *opaque)
43
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
28
-{
29
- BdrvChild *c = opaque;
30
-
31
- g_free(c->name);
32
- g_free(c);
33
-}
34
-
35
-static void bdrv_remove_empty_child(BdrvChild *child)
36
+/**
37
+ * Free the given @child.
38
+ *
39
+ * The child must be empty (i.e. `child->bs == NULL`) and it must be
40
+ * unused (i.e. not in a children list).
41
+ */
42
+static void bdrv_child_free(BdrvChild *child)
44
{
43
{
45
+ /* Do not set read_only if copy_on_read is enabled */
44
assert(!child->bs);
46
+ if (bs->copy_on_read && read_only) {
45
assert(!child->next.le_prev); /* not in children list */
47
+ error_setg(errp, "Can't set node '%s' to r/o with copy-on-read enabled",
46
- bdrv_child_free(child);
48
+ bdrv_get_device_or_node_name(bs));
49
+ return -EINVAL;
50
+ }
51
+
47
+
52
bs->read_only = read_only;
48
+ g_free(child->name);
53
+ return 0;
49
+ g_free(child);
54
}
50
}
55
51
56
void bdrv_get_full_backing_filename_from_filename(const char *backed,
52
typedef struct BdrvAttachChildCommonState {
57
diff --git a/block/bochs.c b/block/bochs.c
53
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/bochs.c
60
+++ b/block/bochs.c
61
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
62
return -EINVAL;
63
}
54
}
64
55
65
- bdrv_set_read_only(bs, true); /* no write support yet */
56
bdrv_unref(bs);
66
+ ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
57
- bdrv_remove_empty_child(child);
67
+ if (ret < 0) {
58
+ bdrv_child_free(child);
68
+ return ret;
59
*s->child = NULL;
69
+ }
60
}
70
61
71
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
62
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
72
if (ret < 0) {
63
73
diff --git a/block/cloop.c b/block/cloop.c
64
if (ret < 0) {
74
index XXXXXXX..XXXXXXX 100644
65
error_propagate(errp, local_err);
75
--- a/block/cloop.c
66
- bdrv_remove_empty_child(new_child);
76
+++ b/block/cloop.c
67
+ bdrv_child_free(new_child);
77
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
68
return ret;
78
return -EINVAL;
69
}
79
}
70
}
80
71
@@ -XXX,XX +XXX,XX @@ static void bdrv_detach_child(BdrvChild *child)
81
- bdrv_set_read_only(bs, true);
72
BlockDriverState *old_bs = child->bs;
82
+ ret = bdrv_set_read_only(bs, true, errp);
73
83
+ if (ret < 0) {
74
bdrv_replace_child_noperm(child, NULL);
84
+ return ret;
75
- bdrv_remove_empty_child(child);
85
+ }
76
+ bdrv_child_free(child);
86
77
87
/* read header */
78
if (old_bs) {
88
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
79
/*
89
diff --git a/block/dmg.c b/block/dmg.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/block/dmg.c
92
+++ b/block/dmg.c
93
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
94
return -EINVAL;
95
}
96
97
+ ret = bdrv_set_read_only(bs, true, errp);
98
+ if (ret < 0) {
99
+ return ret;
100
+ }
101
+
102
block_module_load_one("dmg-bz2");
103
- bdrv_set_read_only(bs, true);
104
105
s->n_chunks = 0;
106
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
107
diff --git a/block/rbd.c b/block/rbd.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/block/rbd.c
110
+++ b/block/rbd.c
111
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
112
goto failed_shutdown;
113
}
114
115
+ /* rbd_open is always r/w */
116
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
117
if (r < 0) {
118
error_setg_errno(errp, -r, "error reading header from %s", s->name);
119
goto failed_open;
120
}
121
122
- bdrv_set_read_only(bs, (s->snap != NULL));
123
+ /* If we are using an rbd snapshot, we must be r/o, otherwise
124
+ * leave as-is */
125
+ if (s->snap != NULL) {
126
+ r = bdrv_set_read_only(bs, true, &local_err);
127
+ if (r < 0) {
128
+ error_propagate(errp, local_err);
129
+ goto failed_open;
130
+ }
131
+ }
132
133
qemu_opts_del(opts);
134
return 0;
135
diff --git a/block/vvfat.c b/block/vvfat.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/block/vvfat.c
138
+++ b/block/vvfat.c
139
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
140
141
s->current_cluster=0xffffffff;
142
143
- /* read only is the default for safety */
144
- bdrv_set_read_only(bs, true);
145
s->qcow = NULL;
146
s->qcow_filename = NULL;
147
s->fat2 = NULL;
148
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
149
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
150
151
if (qemu_opt_get_bool(opts, "rw", false)) {
152
- ret = enable_write_target(bs, errp);
153
+ if (!bdrv_is_read_only(bs)) {
154
+ ret = enable_write_target(bs, errp);
155
+ if (ret < 0) {
156
+ goto fail;
157
+ }
158
+ } else {
159
+ ret = -EPERM;
160
+ error_setg(errp,
161
+ "Unable to set VVFAT to 'rw' when drive is read-only");
162
+ goto fail;
163
+ }
164
+ } else {
165
+ /* read only is the default for safety */
166
+ ret = bdrv_set_read_only(bs, true, &local_err);
167
if (ret < 0) {
168
+ error_propagate(errp, local_err);
169
goto fail;
170
}
171
- bdrv_set_read_only(bs, false);
172
}
173
174
bs->total_sectors = cyls * heads * secs;
175
diff --git a/include/block/block.h b/include/block/block.h
176
index XXXXXXX..XXXXXXX 100644
177
--- a/include/block/block.h
178
+++ b/include/block/block.h
179
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
180
int64_t sector_num, int nb_sectors, int *pnum);
181
182
bool bdrv_is_read_only(BlockDriverState *bs);
183
-void bdrv_set_read_only(BlockDriverState *bs, bool read_only);
184
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
185
bool bdrv_is_sg(BlockDriverState *bs);
186
bool bdrv_is_inserted(BlockDriverState *bs);
187
int bdrv_media_changed(BlockDriverState *bs);
188
--
80
--
189
2.9.3
81
2.33.1
190
82
191
83
diff view generated by jsdifflib
1
Signed-off-by: Jeff Cody <jcody@redhat.com>
1
bdrv_attach_child_common_abort() restores the parent's AioContext. To
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
2
do so, the child (which was supposed to be attached, but is now detached
3
Reviewed-by: John Snow <jsnow@redhat.com>
3
again by this abort handler) is added to the ignore list for the
4
Message-id: 00aed7ffdd7be4b9ed9ce1007d50028a72b34ebe.1491597120.git.jcody@redhat.com
4
AioContext changing functions.
5
6
However, since we modify a BDS's children list in the BdrvChildClass's
7
.attach and .detach handlers, the child is already effectively detached
8
from the parent by this point. We do not need to put it into the ignore
9
list.
10
11
Use this opportunity to clean up the empty line structure: Keep setting
12
the ignore list, invoking the AioContext function, and freeing the
13
ignore list in blocks separated by empty lines.
14
15
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Message-Id: <20211111120829.81329-5-hreitz@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Message-Id: <20211115145409.176785-5-kwolf@redhat.com>
21
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
5
---
22
---
6
block.c | 14 ++++++++------
23
block.c | 8 +++++---
7
1 file changed, 8 insertions(+), 6 deletions(-)
24
1 file changed, 5 insertions(+), 3 deletions(-)
8
25
9
diff --git a/block.c b/block.c
26
diff --git a/block.c b/block.c
10
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
11
--- a/block.c
28
--- a/block.c
12
+++ b/block.c
29
+++ b/block.c
13
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
30
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
14
BlockDriver *drv;
15
QemuOpts *opts;
16
const char *value;
17
+ bool read_only;
18
19
assert(reopen_state != NULL);
20
assert(reopen_state->bs->drv != NULL);
21
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
22
qdict_put(reopen_state->options, "driver", qstring_from_str(value));
23
}
31
}
24
32
25
- /* if we are to stay read-only, do not allow permission change
33
if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) {
26
- * to r/w */
34
- GSList *ignore = g_slist_prepend(NULL, child);
27
- if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) &&
35
+ GSList *ignore;
28
- reopen_state->flags & BDRV_O_RDWR) {
36
29
- error_setg(errp, "Node '%s' is read only",
37
+ /* No need to ignore `child`, because it has been detached already */
30
- bdrv_get_device_or_node_name(reopen_state->bs));
38
+ ignore = NULL;
31
+ /* If we are to stay read-only, do not allow permission change
39
child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore,
32
+ * to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is
40
&error_abort);
33
+ * not set, or if the BDS still has copy_on_read enabled */
41
g_slist_free(ignore);
34
+ read_only = !(reopen_state->flags & BDRV_O_RDWR);
42
- ignore = g_slist_prepend(NULL, child);
35
+ ret = bdrv_can_set_read_only(reopen_state->bs, read_only, &local_err);
43
- child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
36
+ if (local_err) {
44
37
+ error_propagate(errp, local_err);
45
+ ignore = NULL;
38
goto error;
46
+ child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
47
g_slist_free(ignore);
39
}
48
}
40
49
41
--
50
--
42
2.9.3
51
2.33.1
43
52
44
53
diff view generated by jsdifflib
1
Introduce check function for setting read_only flags. Will return < 0 on
1
bdrv_replace_child_noperm() modifies BdrvChild.bs, and can potentially
2
error, with appropriate Error value set. Does not alter any flags.
2
set it to NULL. That is dangerous, because BDS parents generally assume
3
that their children's .bs pointer is never NULL. We therefore want to
4
let bdrv_replace_child_noperm() set the corresponding BdrvChild pointer
5
to NULL, too.
3
6
4
Signed-off-by: Jeff Cody <jcody@redhat.com>
7
This patch lays the foundation for it by passing a BdrvChild ** pointer
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
to bdrv_replace_child_noperm() so that it can later use it to NULL the
6
Reviewed-by: John Snow <jsnow@redhat.com>
9
BdrvChild pointer immediately after setting BdrvChild.bs to NULL.
7
Message-id: e2bba34ac3bc76a0c42adc390413f358ae0566e8.1491597120.git.jcody@redhat.com
10
11
(We will still need to undertake some intermediate steps, though.)
12
13
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
14
Message-Id: <20211111120829.81329-6-hreitz@redhat.com>
15
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Message-Id: <20211115145409.176785-6-kwolf@redhat.com>
18
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
8
---
19
---
9
block.c | 14 +++++++++++++-
20
block.c | 23 ++++++++++++-----------
10
include/block/block.h | 1 +
21
1 file changed, 12 insertions(+), 11 deletions(-)
11
2 files changed, 14 insertions(+), 1 deletion(-)
12
22
13
diff --git a/block.c b/block.c
23
diff --git a/block.c b/block.c
14
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
25
--- a/block.c
16
+++ b/block.c
26
+++ b/block.c
17
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs)
27
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
18
return bs->read_only;
28
static bool bdrv_recurse_has_child(BlockDriverState *bs,
29
BlockDriverState *child);
30
31
-static void bdrv_replace_child_noperm(BdrvChild *child,
32
+static void bdrv_replace_child_noperm(BdrvChild **child,
33
BlockDriverState *new_bs);
34
static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
35
BdrvChild *child,
36
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque)
37
BlockDriverState *new_bs = s->child->bs;
38
39
/* old_bs reference is transparently moved from @s to @s->child */
40
- bdrv_replace_child_noperm(s->child, s->old_bs);
41
+ bdrv_replace_child_noperm(&s->child, s->old_bs);
42
bdrv_unref(new_bs);
19
}
43
}
20
44
21
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
45
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
22
+int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
46
if (new_bs) {
47
bdrv_ref(new_bs);
48
}
49
- bdrv_replace_child_noperm(child, new_bs);
50
+ bdrv_replace_child_noperm(&child, new_bs);
51
/* old_bs reference is transparently moved from @child to @s */
52
}
53
54
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
55
return permissions[qapi_perm];
56
}
57
58
-static void bdrv_replace_child_noperm(BdrvChild *child,
59
+static void bdrv_replace_child_noperm(BdrvChild **childp,
60
BlockDriverState *new_bs)
23
{
61
{
24
/* Do not set read_only if copy_on_read is enabled */
62
+ BdrvChild *child = *childp;
25
if (bs->copy_on_read && read_only) {
63
BlockDriverState *old_bs = child->bs;
26
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
64
int new_bs_quiesce_counter;
27
return -EPERM;
65
int drain_saldo;
66
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
67
BdrvChild *child = *s->child;
68
BlockDriverState *bs = child->bs;
69
70
- bdrv_replace_child_noperm(child, NULL);
71
+ bdrv_replace_child_noperm(s->child, NULL);
72
73
if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
74
bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
75
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
28
}
76
}
29
77
30
+ return 0;
78
bdrv_ref(child_bs);
31
+}
79
- bdrv_replace_child_noperm(new_child, child_bs);
32
+
80
+ bdrv_replace_child_noperm(&new_child, child_bs);
33
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
81
34
+{
82
*child = new_child;
35
+ int ret = 0;
83
36
+
84
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
37
+ ret = bdrv_can_set_read_only(bs, read_only, errp);
38
+ if (ret < 0) {
39
+ return ret;
40
+ }
41
+
42
bs->read_only = read_only;
43
return 0;
85
return 0;
44
}
86
}
45
diff --git a/include/block/block.h b/include/block/block.h
87
46
index XXXXXXX..XXXXXXX 100644
88
-static void bdrv_detach_child(BdrvChild *child)
47
--- a/include/block/block.h
89
+static void bdrv_detach_child(BdrvChild **childp)
48
+++ b/include/block/block.h
90
{
49
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
91
- BlockDriverState *old_bs = child->bs;
50
int64_t sector_num, int nb_sectors, int *pnum);
92
+ BlockDriverState *old_bs = (*childp)->bs;
51
93
52
bool bdrv_is_read_only(BlockDriverState *bs);
94
- bdrv_replace_child_noperm(child, NULL);
53
+int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
95
- bdrv_child_free(child);
54
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
96
+ bdrv_replace_child_noperm(childp, NULL);
55
bool bdrv_is_sg(BlockDriverState *bs);
97
+ bdrv_child_free(*childp);
56
bool bdrv_is_inserted(BlockDriverState *bs);
98
99
if (old_bs) {
100
/*
101
@@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child)
102
BlockDriverState *child_bs;
103
104
child_bs = child->bs;
105
- bdrv_detach_child(child);
106
+ bdrv_detach_child(&child);
107
bdrv_unref(child_bs);
108
}
109
57
--
110
--
58
2.9.3
111
2.33.1
59
112
60
113
diff view generated by jsdifflib
1
The BDRV_O_ALLOW_RDWR flag allows / prohibits the changing of
1
As of a future patch, bdrv_replace_child_tran() will take a BdrvChild **
2
the BDS 'read_only' state, but there are a few places where it
2
pointer. Prepare for that by getting such a pointer and using it where
3
is ignored. In the bdrv_set_read_only() helper, make sure to
3
applicable, and (dereferenced) as a parameter for
4
honor the flag.
4
bdrv_replace_child_tran().
5
5
6
Signed-off-by: Jeff Cody <jcody@redhat.com>
6
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Message-Id: <20211111120829.81329-7-hreitz@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Message-id: be2e5fb2d285cbece2b6d06bed54a6f56520d251.1491597120.git.jcody@redhat.com
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20211115145409.176785-7-kwolf@redhat.com>
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
---
12
---
11
block.c | 7 +++++++
13
block.c | 21 ++++++++++++---------
12
1 file changed, 7 insertions(+)
14
1 file changed, 12 insertions(+), 9 deletions(-)
13
15
14
diff --git a/block.c b/block.c
16
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
18
--- a/block.c
17
+++ b/block.c
19
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
20
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
19
return -EINVAL;
21
BdrvChild *child,
22
Transaction *tran)
23
{
24
+ BdrvChild **childp;
25
BdrvRemoveFilterOrCowChild *s;
26
27
- assert(child == bs->backing || child == bs->file);
28
-
29
if (!child) {
30
return;
20
}
31
}
21
32
22
+ /* Do not clear read_only if it is prohibited */
33
+ if (child == bs->backing) {
23
+ if (!read_only && !(bs->open_flags & BDRV_O_ALLOW_RDWR)) {
34
+ childp = &bs->backing;
24
+ error_setg(errp, "Node '%s' is read only",
35
+ } else if (child == bs->file) {
25
+ bdrv_get_device_or_node_name(bs));
36
+ childp = &bs->file;
26
+ return -EPERM;
37
+ } else {
38
+ g_assert_not_reached();
27
+ }
39
+ }
28
+
40
+
29
bs->read_only = read_only;
41
if (child->bs) {
30
return 0;
42
- bdrv_replace_child_tran(child, NULL, tran);
43
+ bdrv_replace_child_tran(*childp, NULL, tran);
44
}
45
46
s = g_new(BdrvRemoveFilterOrCowChild, 1);
47
*s = (BdrvRemoveFilterOrCowChild) {
48
.child = child,
49
- .is_backing = (child == bs->backing),
50
+ .is_backing = (childp == &bs->backing),
51
};
52
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
53
54
- if (s->is_backing) {
55
- bs->backing = NULL;
56
- } else {
57
- bs->file = NULL;
58
- }
59
+ *childp = NULL;
31
}
60
}
61
62
/*
32
--
63
--
33
2.9.3
64
2.33.1
34
65
35
66
diff view generated by jsdifflib
1
From: Ashish Mittal <ashmit602@gmail.com>
1
Invoke the transaction drivers' .clean() methods only after all
2
.commit() or .abort() handlers are done.
2
3
3
These changes use a vxhs test server that is a part of the following
4
This makes it easier to have nested transactions where the top-level
4
repository:
5
transactions pass objects to lower transactions that the latter can
5
https://github.com/VeritasHyperScale/libqnio.git
6
still use throughout their commit/abort phases, while the top-level
7
transaction keeps a reference that is released in its .clean() method.
6
8
7
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
9
(Before this commit, that is also possible, but the top-level
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
transaction would need to take care to invoke tran_add() before the
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
11
lower-level transaction does. This commit makes the ordering
10
Signed-off-by: Jeff Cody <jcody@redhat.com>
12
irrelevant, which is just a bit nicer.)
11
Message-id: 1491277689-24949-3-git-send-email-Ashish.Mittal@veritas.com
13
14
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
15
Message-Id: <20211111120829.81329-8-hreitz@redhat.com>
16
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Message-Id: <20211115145409.176785-8-kwolf@redhat.com>
19
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
12
---
20
---
13
tests/qemu-iotests/common | 6 ++++++
21
include/qemu/transactions.h | 3 +++
14
tests/qemu-iotests/common.config | 13 +++++++++++++
22
util/transactions.c | 8 ++++++--
15
tests/qemu-iotests/common.filter | 1 +
23
2 files changed, 9 insertions(+), 2 deletions(-)
16
tests/qemu-iotests/common.rc | 19 +++++++++++++++++++
17
4 files changed, 39 insertions(+)
18
24
19
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
25
diff --git a/include/qemu/transactions.h b/include/qemu/transactions.h
20
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/qemu-iotests/common
27
--- a/include/qemu/transactions.h
22
+++ b/tests/qemu-iotests/common
28
+++ b/include/qemu/transactions.h
23
@@ -XXX,XX +XXX,XX @@ check options
29
@@ -XXX,XX +XXX,XX @@
24
-ssh test ssh
30
* tran_create(), call your "prepare" functions on it, and finally call
25
-nfs test nfs
31
* tran_abort() or tran_commit() to finalize the transaction by corresponding
26
-luks test luks
32
* finalization actions in reverse order.
27
+ -vxhs test vxhs
33
+ *
28
-xdiff graphical mode diff
34
+ * The clean() functions registered by the drivers in a transaction are called
29
-nocache use O_DIRECT on backing file
35
+ * last, after all abort() or commit() functions have been called.
30
-misalign misalign memory allocations
36
*/
31
@@ -XXX,XX +XXX,XX @@ testlist options
37
32
xpand=false
38
#ifndef QEMU_TRANSACTIONS_H
33
;;
39
diff --git a/util/transactions.c b/util/transactions.c
34
35
+ -vxhs)
36
+ IMGPROTO=vxhs
37
+ xpand=false
38
+ ;;
39
+
40
-ssh)
41
IMGPROTO=ssh
42
xpand=false
43
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
44
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
45
--- a/tests/qemu-iotests/common.config
41
--- a/util/transactions.c
46
+++ b/tests/qemu-iotests/common.config
42
+++ b/util/transactions.c
47
@@ -XXX,XX +XXX,XX @@ if [ -z "$QEMU_NBD_PROG" ]; then
43
@@ -XXX,XX +XXX,XX @@ void tran_abort(Transaction *tran)
48
export QEMU_NBD_PROG="`set_prog_path qemu-nbd`"
49
fi
50
51
+if [ -z "$QEMU_VXHS_PROG" ]; then
52
+ export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
53
+fi
54
+
55
_qemu_wrapper()
56
{
44
{
57
(
45
TransactionAction *act, *next;
58
@@ -XXX,XX +XXX,XX @@ _qemu_nbd_wrapper()
46
59
)
47
- QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
60
}
48
+ QSLIST_FOREACH(act, &tran->actions, entry) {
61
49
if (act->drv->abort) {
62
+_qemu_vxhs_wrapper()
50
act->drv->abort(act->opaque);
63
+{
51
}
64
+ (
52
+ }
65
+ echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
53
66
+ exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
54
+ QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
67
+ )
55
if (act->drv->clean) {
68
+}
56
act->drv->clean(act->opaque);
69
+
57
}
70
export QEMU=_qemu_wrapper
58
@@ -XXX,XX +XXX,XX @@ void tran_commit(Transaction *tran)
71
export QEMU_IMG=_qemu_img_wrapper
59
{
72
export QEMU_IO=_qemu_io_wrapper
60
TransactionAction *act, *next;
73
export QEMU_NBD=_qemu_nbd_wrapper
61
74
+export QEMU_VXHS=_qemu_vxhs_wrapper
62
- QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
75
63
+ QSLIST_FOREACH(act, &tran->actions, entry) {
76
QEMU_IMG_EXTRA_ARGS=
64
if (act->drv->commit) {
77
if [ "$IMGOPTSSYNTAX" = "true" ]; then
65
act->drv->commit(act->opaque);
78
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
66
}
79
index XXXXXXX..XXXXXXX 100644
67
+ }
80
--- a/tests/qemu-iotests/common.filter
68
81
+++ b/tests/qemu-iotests/common.filter
69
+ QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
82
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
70
if (act->drv->clean) {
83
-e "s#$TEST_DIR#TEST_DIR#g" \
71
act->drv->clean(act->opaque);
84
-e "s#$IMGFMT#IMGFMT#g" \
72
}
85
-e 's#nbd://127.0.0.1:10810$#TEST_DIR/t.IMGFMT#g' \
86
+ -e 's#json.*vdisk-id.*vxhs"}}#TEST_DIR/t.IMGFMT#' \
87
-e "/encrypted: yes/d" \
88
-e "/cluster_size: [0-9]\\+/d" \
89
-e "/table_size: [0-9]\\+/d" \
90
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
91
index XXXXXXX..XXXXXXX 100644
92
--- a/tests/qemu-iotests/common.rc
93
+++ b/tests/qemu-iotests/common.rc
94
@@ -XXX,XX +XXX,XX @@ else
95
elif [ "$IMGPROTO" = "nfs" ]; then
96
TEST_DIR="nfs://127.0.0.1/$TEST_DIR"
97
TEST_IMG=$TEST_DIR/t.$IMGFMT
98
+ elif [ "$IMGPROTO" = "vxhs" ]; then
99
+ TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
100
+ TEST_IMG="vxhs://127.0.0.1:9999/t.$IMGFMT"
101
else
102
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
103
fi
104
@@ -XXX,XX +XXX,XX @@ _make_test_img()
105
eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE >/dev/null &"
106
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
107
fi
108
+
109
+ # Start QNIO server on image directory for vxhs protocol
110
+ if [ $IMGPROTO = "vxhs" ]; then
111
+ eval "$QEMU_VXHS -d $TEST_DIR > /dev/null &"
112
+ sleep 1 # Wait for server to come up.
113
+ fi
114
}
115
116
_rm_test_img()
117
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img()
118
fi
119
rm -f "$TEST_IMG_FILE"
120
;;
121
+ vxhs)
122
+ if [ -f "${TEST_DIR}/qemu-vxhs.pid" ]; then
123
+ local QEMU_VXHS_PID
124
+ read QEMU_VXHS_PID < "${TEST_DIR}/qemu-vxhs.pid"
125
+ kill ${QEMU_VXHS_PID} >/dev/null 2>&1
126
+ rm -f "${TEST_DIR}/qemu-vxhs.pid"
127
+ fi
128
+ rm -f "$TEST_IMG_FILE"
129
+ ;;
130
+
131
file)
132
_rm_test_img "$TEST_DIR/t.$IMGFMT"
133
_rm_test_img "$TEST_DIR/t.$IMGFMT.orig"
134
--
73
--
135
2.9.3
74
2.33.1
136
75
137
76
diff view generated by jsdifflib
1
We have a helper wrapper for checking for the BDS read_only flag,
1
As of a future commit, bdrv_replace_child_noperm() will clear the
2
add a helper wrapper to set the read_only flag as well.
2
indirect BdrvChild pointer passed to it if the new child BDS is NULL.
3
3
bdrv_replace_child_tran() will want to let it do that, but revert this
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
change in its abort handler. For that, we need to have it receive a
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
5
BdrvChild ** pointer, too, and keep it stored in the
6
Reviewed-by: John Snow <jsnow@redhat.com>
6
BdrvReplaceChildState object that we attach to the transaction.
7
Message-id: 9b18972d05f5fa2ac16c014f0af98d680553048d.1491597120.git.jcody@redhat.com
7
8
Note that we do not need to store it in the BdrvReplaceChildState when
9
new_bs is not NULL, because then there is nothing to revert. This is
10
important so that bdrv_replace_node_noperm() can pass a pointer to a
11
loop-local variable to bdrv_replace_child_tran() without worrying that
12
this pointer will outlive one loop iteration.
13
14
(Of course, for that to work, bdrv_replace_node_noperm() and in turn
15
bdrv_replace_node() and its relatives may not be called with a NULL @to
16
node. Luckily, they already are not, but now we should assert this.)
17
18
bdrv_remove_file_or_backing_child() on the other hand needs to ensure
19
that the indirect pointer it passes will stay valid for the duration of
20
the transaction. Ensure this by keeping a strong reference to the BDS
21
whose &bs->backing or &bs->file it passes to bdrv_replace_child_tran(),
22
and giving up that reference only in the transaction .clean() handler.
23
24
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
25
Message-Id: <20211111120829.81329-9-hreitz@redhat.com>
26
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
Message-Id: <20211115145409.176785-9-kwolf@redhat.com>
29
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
8
---
30
---
9
block.c | 5 +++++
31
block.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
10
block/bochs.c | 2 +-
32
1 file changed, 73 insertions(+), 10 deletions(-)
11
block/cloop.c | 2 +-
12
block/dmg.c | 2 +-
13
block/rbd.c | 2 +-
14
block/vvfat.c | 4 ++--
15
include/block/block.h | 1 +
16
7 files changed, 12 insertions(+), 6 deletions(-)
17
33
18
diff --git a/block.c b/block.c
34
diff --git a/block.c b/block.c
19
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
20
--- a/block.c
36
--- a/block.c
21
+++ b/block.c
37
+++ b/block.c
22
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
38
@@ -XXX,XX +XXX,XX @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
23
}
39
24
}
40
typedef struct BdrvReplaceChildState {
25
41
BdrvChild *child;
26
+void bdrv_set_read_only(BlockDriverState *bs, bool read_only)
42
+ BdrvChild **childp;
43
BlockDriverState *old_bs;
44
} BdrvReplaceChildState;
45
46
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque)
47
BdrvReplaceChildState *s = opaque;
48
BlockDriverState *new_bs = s->child->bs;
49
50
- /* old_bs reference is transparently moved from @s to @s->child */
51
+ /*
52
+ * old_bs reference is transparently moved from @s to s->child.
53
+ *
54
+ * Pass &s->child here instead of s->childp, because:
55
+ * (1) s->old_bs must be non-NULL, so bdrv_replace_child_noperm() will not
56
+ * modify the BdrvChild * pointer we indirectly pass to it, i.e. it
57
+ * will not modify s->child. From that perspective, it does not matter
58
+ * whether we pass s->childp or &s->child.
59
+ * (TODO: Right now, bdrv_replace_child_noperm() never modifies that
60
+ * pointer anyway (though it will in the future), so at this point it
61
+ * absolutely does not matter whether we pass s->childp or &s->child.)
62
+ * (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use
63
+ * it here.
64
+ * (3) If new_bs is NULL, *s->childp will have been NULLed by
65
+ * bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we
66
+ * must not pass a NULL *s->childp here.
67
+ * (TODO: In its current state, bdrv_replace_child_noperm() will not
68
+ * have NULLed *s->childp, so this does not apply yet. It will in the
69
+ * future.)
70
+ *
71
+ * So whether new_bs was NULL or not, we cannot pass s->childp here; and in
72
+ * any case, there is no reason to pass it anyway.
73
+ */
74
bdrv_replace_child_noperm(&s->child, s->old_bs);
75
bdrv_unref(new_bs);
76
}
77
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = {
78
* Note: real unref of old_bs is done only on commit.
79
*
80
* The function doesn't update permissions, caller is responsible for this.
81
+ *
82
+ * Note that if new_bs == NULL, @childp is stored in a state object attached
83
+ * to @tran, so that the old child can be reinstated in the abort handler.
84
+ * Therefore, if @new_bs can be NULL, @childp must stay valid until the
85
+ * transaction is committed or aborted.
86
+ *
87
+ * (TODO: The reinstating does not happen yet, but it will once
88
+ * bdrv_replace_child_noperm() NULLs *childp when new_bs is NULL.)
89
*/
90
-static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
91
+static void bdrv_replace_child_tran(BdrvChild **childp,
92
+ BlockDriverState *new_bs,
93
Transaction *tran)
94
{
95
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
96
*s = (BdrvReplaceChildState) {
97
- .child = child,
98
- .old_bs = child->bs,
99
+ .child = *childp,
100
+ .childp = new_bs == NULL ? childp : NULL,
101
+ .old_bs = (*childp)->bs,
102
};
103
tran_add(tran, &bdrv_replace_child_drv, s);
104
105
if (new_bs) {
106
bdrv_ref(new_bs);
107
}
108
- bdrv_replace_child_noperm(&child, new_bs);
109
- /* old_bs reference is transparently moved from @child to @s */
110
+ bdrv_replace_child_noperm(childp, new_bs);
111
+ /* old_bs reference is transparently moved from *childp to @s */
112
}
113
114
/*
115
@@ -XXX,XX +XXX,XX @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
116
117
typedef struct BdrvRemoveFilterOrCowChild {
118
BdrvChild *child;
119
+ BlockDriverState *bs;
120
bool is_backing;
121
} BdrvRemoveFilterOrCowChild;
122
123
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_filter_or_cow_child_commit(void *opaque)
124
bdrv_child_free(s->child);
125
}
126
127
+static void bdrv_remove_filter_or_cow_child_clean(void *opaque)
27
+{
128
+{
28
+ bs->read_only = read_only;
129
+ BdrvRemoveFilterOrCowChild *s = opaque;
130
+
131
+ /* Drop the bs reference after the transaction is done */
132
+ bdrv_unref(s->bs);
133
+ g_free(s);
29
+}
134
+}
30
+
135
+
31
void bdrv_get_full_backing_filename_from_filename(const char *backed,
136
static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
32
const char *backing,
137
.abort = bdrv_remove_filter_or_cow_child_abort,
33
char *dest, size_t sz,
138
.commit = bdrv_remove_filter_or_cow_child_commit,
34
diff --git a/block/bochs.c b/block/bochs.c
139
- .clean = g_free,
35
index XXXXXXX..XXXXXXX 100644
140
+ .clean = bdrv_remove_filter_or_cow_child_clean,
36
--- a/block/bochs.c
141
};
37
+++ b/block/bochs.c
142
38
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
143
/*
39
return -EINVAL;
144
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
40
}
145
return;
41
146
}
42
- bs->read_only = true; /* no write support yet */
147
43
+ bdrv_set_read_only(bs, true); /* no write support yet */
148
+ /*
44
149
+ * Keep a reference to @bs so @childp will stay valid throughout the
45
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
150
+ * transaction (required by bdrv_replace_child_tran())
46
if (ret < 0) {
151
+ */
47
diff --git a/block/cloop.c b/block/cloop.c
152
+ bdrv_ref(bs);
48
index XXXXXXX..XXXXXXX 100644
153
if (child == bs->backing) {
49
--- a/block/cloop.c
154
childp = &bs->backing;
50
+++ b/block/cloop.c
155
} else if (child == bs->file) {
51
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
156
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
52
return -EINVAL;
157
}
53
}
158
54
159
if (child->bs) {
55
- bs->read_only = true;
160
- bdrv_replace_child_tran(*childp, NULL, tran);
56
+ bdrv_set_read_only(bs, true);
161
+ bdrv_replace_child_tran(childp, NULL, tran);
57
162
}
58
/* read header */
163
59
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
164
s = g_new(BdrvRemoveFilterOrCowChild, 1);
60
diff --git a/block/dmg.c b/block/dmg.c
165
*s = (BdrvRemoveFilterOrCowChild) {
61
index XXXXXXX..XXXXXXX 100644
166
.child = child,
62
--- a/block/dmg.c
167
+ .bs = bs,
63
+++ b/block/dmg.c
168
.is_backing = (childp == &bs->backing),
64
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
169
};
65
}
170
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
66
171
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
67
block_module_load_one("dmg-bz2");
172
{
68
- bs->read_only = true;
173
BdrvChild *c, *next;
69
+ bdrv_set_read_only(bs, true);
174
70
175
+ assert(to != NULL);
71
s->n_chunks = 0;
176
+
72
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
177
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
73
diff --git a/block/rbd.c b/block/rbd.c
178
assert(c->bs == from);
74
index XXXXXXX..XXXXXXX 100644
179
if (!should_update_child(c, to)) {
75
--- a/block/rbd.c
180
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
76
+++ b/block/rbd.c
181
c->name, from->node_name);
77
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
182
return -EPERM;
78
goto failed_open;
183
}
79
}
184
- bdrv_replace_child_tran(c, to, tran);
80
185
+
81
- bs->read_only = (s->snap != NULL);
186
+ /*
82
+ bdrv_set_read_only(bs, (s->snap != NULL));
187
+ * Passing a pointer to the local variable @c is fine here, because
83
188
+ * @to is not NULL, and so &c will not be attached to the transaction.
84
qemu_opts_del(opts);
189
+ */
190
+ bdrv_replace_child_tran(&c, to, tran);
191
}
192
85
return 0;
193
return 0;
86
diff --git a/block/vvfat.c b/block/vvfat.c
194
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
87
index XXXXXXX..XXXXXXX 100644
195
*
88
--- a/block/vvfat.c
196
* With @detach_subchain=true @to must be in a backing chain of @from. In this
89
+++ b/block/vvfat.c
197
* case backing link of the cow-parent of @to is removed.
90
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
198
+ *
91
s->current_cluster=0xffffffff;
199
+ * @to must not be NULL.
92
200
*/
93
/* read only is the default for safety */
201
static int bdrv_replace_node_common(BlockDriverState *from,
94
- bs->read_only = true;
202
BlockDriverState *to,
95
+ bdrv_set_read_only(bs, true);
203
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
96
s->qcow = NULL;
204
BlockDriverState *to_cow_parent = NULL;
97
s->qcow_filename = NULL;
205
int ret;
98
s->fat2 = NULL;
206
99
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
207
+ assert(to != NULL);
100
if (ret < 0) {
208
+
101
goto fail;
209
if (detach_subchain) {
102
}
210
assert(bdrv_chain_contains(from, to));
103
- bs->read_only = false;
211
assert(from != to);
104
+ bdrv_set_read_only(bs, false);
212
@@ -XXX,XX +XXX,XX @@ out:
105
}
213
return ret;
106
214
}
107
bs->total_sectors = cyls * heads * secs;
215
108
diff --git a/include/block/block.h b/include/block/block.h
216
+/**
109
index XXXXXXX..XXXXXXX 100644
217
+ * Replace node @from by @to (where neither may be NULL).
110
--- a/include/block/block.h
218
+ */
111
+++ b/include/block/block.h
219
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
112
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
220
Error **errp)
113
int64_t sector_num, int nb_sectors, int *pnum);
221
{
114
222
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
115
bool bdrv_is_read_only(BlockDriverState *bs);
223
bdrv_drained_begin(old_bs);
116
+void bdrv_set_read_only(BlockDriverState *bs, bool read_only);
224
bdrv_drained_begin(new_bs);
117
bool bdrv_is_sg(BlockDriverState *bs);
225
118
bool bdrv_is_inserted(BlockDriverState *bs);
226
- bdrv_replace_child_tran(child, new_bs, tran);
119
int bdrv_media_changed(BlockDriverState *bs);
227
+ bdrv_replace_child_tran(&child, new_bs, tran);
228
229
found = g_hash_table_new(NULL, NULL);
230
refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs);
120
--
231
--
121
2.9.3
232
2.33.1
122
233
123
234
diff view generated by jsdifflib
New patch
1
1
In most of the block layer, especially when traversing down from other
2
BlockDriverStates, we assume that BdrvChild.bs can never be NULL. When
3
it becomes NULL, it is expected that the corresponding BdrvChild pointer
4
also becomes NULL and the BdrvChild object is freed.
5
6
Therefore, once bdrv_replace_child_noperm() sets the BdrvChild.bs
7
pointer to NULL, it should also immediately set the corresponding
8
BdrvChild pointer (like bs->file or bs->backing) to NULL.
9
10
In that context, it also makes sense for this function to free the
11
child. Sometimes we cannot do so, though, because it is called in a
12
transactional context where the caller might still want to reinstate the
13
child in the abort branch (and free it only on commit), so this behavior
14
has to remain optional.
15
16
In bdrv_replace_child_tran()'s abort handler, we now rely on the fact
17
that the BdrvChild passed to bdrv_replace_child_tran() must have had a
18
non-NULL .bs pointer initially. Make a note of that and assert it.
19
20
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
21
Message-Id: <20211111120829.81329-10-hreitz@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Message-Id: <20211115145409.176785-10-kwolf@redhat.com>
24
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
25
---
26
block.c | 102 +++++++++++++++++++++++++++++++++++++++++++-------------
27
1 file changed, 79 insertions(+), 23 deletions(-)
28
29
diff --git a/block.c b/block.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
32
+++ b/block.c
33
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
34
static bool bdrv_recurse_has_child(BlockDriverState *bs,
35
BlockDriverState *child);
36
37
+static void bdrv_child_free(BdrvChild *child);
38
static void bdrv_replace_child_noperm(BdrvChild **child,
39
- BlockDriverState *new_bs);
40
+ BlockDriverState *new_bs,
41
+ bool free_empty_child);
42
static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
43
BdrvChild *child,
44
Transaction *tran);
45
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvReplaceChildState {
46
BdrvChild *child;
47
BdrvChild **childp;
48
BlockDriverState *old_bs;
49
+ bool free_empty_child;
50
} BdrvReplaceChildState;
51
52
static void bdrv_replace_child_commit(void *opaque)
53
{
54
BdrvReplaceChildState *s = opaque;
55
56
+ if (s->free_empty_child && !s->child->bs) {
57
+ bdrv_child_free(s->child);
58
+ }
59
bdrv_unref(s->old_bs);
60
}
61
62
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque)
63
* modify the BdrvChild * pointer we indirectly pass to it, i.e. it
64
* will not modify s->child. From that perspective, it does not matter
65
* whether we pass s->childp or &s->child.
66
- * (TODO: Right now, bdrv_replace_child_noperm() never modifies that
67
- * pointer anyway (though it will in the future), so at this point it
68
- * absolutely does not matter whether we pass s->childp or &s->child.)
69
* (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use
70
* it here.
71
* (3) If new_bs is NULL, *s->childp will have been NULLed by
72
* bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we
73
* must not pass a NULL *s->childp here.
74
- * (TODO: In its current state, bdrv_replace_child_noperm() will not
75
- * have NULLed *s->childp, so this does not apply yet. It will in the
76
- * future.)
77
*
78
* So whether new_bs was NULL or not, we cannot pass s->childp here; and in
79
* any case, there is no reason to pass it anyway.
80
*/
81
- bdrv_replace_child_noperm(&s->child, s->old_bs);
82
+ bdrv_replace_child_noperm(&s->child, s->old_bs, true);
83
+ /*
84
+ * The child was pre-existing, so s->old_bs must be non-NULL, and
85
+ * s->child thus must not have been freed
86
+ */
87
+ assert(s->child != NULL);
88
+ if (!new_bs) {
89
+ /* As described above, *s->childp was cleared, so restore it */
90
+ assert(s->childp != NULL);
91
+ *s->childp = s->child;
92
+ }
93
bdrv_unref(new_bs);
94
}
95
96
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = {
97
*
98
* The function doesn't update permissions, caller is responsible for this.
99
*
100
+ * (*childp)->bs must not be NULL.
101
+ *
102
* Note that if new_bs == NULL, @childp is stored in a state object attached
103
* to @tran, so that the old child can be reinstated in the abort handler.
104
* Therefore, if @new_bs can be NULL, @childp must stay valid until the
105
* transaction is committed or aborted.
106
*
107
- * (TODO: The reinstating does not happen yet, but it will once
108
- * bdrv_replace_child_noperm() NULLs *childp when new_bs is NULL.)
109
+ * If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
110
+ * freed (on commit). @free_empty_child should only be false if the
111
+ * caller will free the BDrvChild themselves (which may be important
112
+ * if this is in turn called in another transactional context).
113
*/
114
static void bdrv_replace_child_tran(BdrvChild **childp,
115
BlockDriverState *new_bs,
116
- Transaction *tran)
117
+ Transaction *tran,
118
+ bool free_empty_child)
119
{
120
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
121
*s = (BdrvReplaceChildState) {
122
.child = *childp,
123
.childp = new_bs == NULL ? childp : NULL,
124
.old_bs = (*childp)->bs,
125
+ .free_empty_child = free_empty_child,
126
};
127
tran_add(tran, &bdrv_replace_child_drv, s);
128
129
+ /* The abort handler relies on this */
130
+ assert(s->old_bs != NULL);
131
+
132
if (new_bs) {
133
bdrv_ref(new_bs);
134
}
135
- bdrv_replace_child_noperm(childp, new_bs);
136
+ /*
137
+ * Pass free_empty_child=false, we will free the child (if
138
+ * necessary) in bdrv_replace_child_commit() (if our
139
+ * @free_empty_child parameter was true).
140
+ */
141
+ bdrv_replace_child_noperm(childp, new_bs, false);
142
/* old_bs reference is transparently moved from *childp to @s */
143
}
144
145
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
146
return permissions[qapi_perm];
147
}
148
149
+/**
150
+ * Replace (*childp)->bs by @new_bs.
151
+ *
152
+ * If @new_bs is NULL, *childp will be set to NULL, too: BDS parents
153
+ * generally cannot handle a BdrvChild with .bs == NULL, so clearing
154
+ * BdrvChild.bs should generally immediately be followed by the
155
+ * BdrvChild pointer being cleared as well.
156
+ *
157
+ * If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
158
+ * freed. @free_empty_child should only be false if the caller will
159
+ * free the BdrvChild themselves (this may be important in a
160
+ * transactional context, where it may only be freed on commit).
161
+ */
162
static void bdrv_replace_child_noperm(BdrvChild **childp,
163
- BlockDriverState *new_bs)
164
+ BlockDriverState *new_bs,
165
+ bool free_empty_child)
166
{
167
BdrvChild *child = *childp;
168
BlockDriverState *old_bs = child->bs;
169
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp,
170
}
171
172
child->bs = new_bs;
173
+ if (!new_bs) {
174
+ *childp = NULL;
175
+ }
176
177
if (new_bs) {
178
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
179
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp,
180
bdrv_parent_drained_end_single(child);
181
drain_saldo++;
182
}
183
+
184
+ if (free_empty_child && !child->bs) {
185
+ bdrv_child_free(child);
186
+ }
187
}
188
189
/**
190
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
191
BdrvChild *child = *s->child;
192
BlockDriverState *bs = child->bs;
193
194
- bdrv_replace_child_noperm(s->child, NULL);
195
+ /*
196
+ * Pass free_empty_child=false, because we still need the child
197
+ * for the AioContext operations on the parent below; those
198
+ * BdrvChildClass methods all work on a BdrvChild object, so we
199
+ * need to keep it as an empty shell (after this function, it will
200
+ * not be attached to any parent, and it will not have a .bs).
201
+ */
202
+ bdrv_replace_child_noperm(s->child, NULL, false);
203
204
if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
205
bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
206
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
207
208
bdrv_unref(bs);
209
bdrv_child_free(child);
210
- *s->child = NULL;
211
}
212
213
static TransactionActionDrv bdrv_attach_child_common_drv = {
214
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
215
}
216
217
bdrv_ref(child_bs);
218
- bdrv_replace_child_noperm(&new_child, child_bs);
219
+ bdrv_replace_child_noperm(&new_child, child_bs, true);
220
+ /* child_bs was non-NULL, so new_child must not have been freed */
221
+ assert(new_child != NULL);
222
223
*child = new_child;
224
225
@@ -XXX,XX +XXX,XX @@ static void bdrv_detach_child(BdrvChild **childp)
226
{
227
BlockDriverState *old_bs = (*childp)->bs;
228
229
- bdrv_replace_child_noperm(childp, NULL);
230
- bdrv_child_free(*childp);
231
+ bdrv_replace_child_noperm(childp, NULL, true);
232
233
if (old_bs) {
234
/*
235
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
236
}
237
238
if (child->bs) {
239
- bdrv_replace_child_tran(childp, NULL, tran);
240
+ /*
241
+ * Pass free_empty_child=false, we will free the child in
242
+ * bdrv_remove_filter_or_cow_child_commit()
243
+ */
244
+ bdrv_replace_child_tran(childp, NULL, tran, false);
245
}
246
247
s = g_new(BdrvRemoveFilterOrCowChild, 1);
248
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
249
.is_backing = (childp == &bs->backing),
250
};
251
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
252
-
253
- *childp = NULL;
254
}
255
256
/*
257
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
258
* Passing a pointer to the local variable @c is fine here, because
259
* @to is not NULL, and so &c will not be attached to the transaction.
260
*/
261
- bdrv_replace_child_tran(&c, to, tran);
262
+ bdrv_replace_child_tran(&c, to, tran, true);
263
}
264
265
return 0;
266
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
267
bdrv_drained_begin(old_bs);
268
bdrv_drained_begin(new_bs);
269
270
- bdrv_replace_child_tran(&child, new_bs, tran);
271
+ bdrv_replace_child_tran(&child, new_bs, tran, true);
272
+ /* @new_bs must have been non-NULL, so @child must not have been freed */
273
+ assert(child != NULL);
274
275
found = g_hash_table_new(NULL, NULL);
276
refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs);
277
--
278
2.33.1
279
280
diff view generated by jsdifflib
1
Update 'clientname' to be 'user', which tracks better with both
1
See the comment for why this is necessary.
2
the QAPI and rados variable naming.
3
2
4
Update 'name' to be 'image_name', as it indicates the rbd image.
3
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
5
Naming it 'image' would have been ideal, but we are using that for
4
Message-Id: <20211111120829.81329-11-hreitz@redhat.com>
6
the rados_image_t value returned by rbd_open().
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Message-Id: <20211115145409.176785-11-kwolf@redhat.com>
7
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
8
---
9
tests/qemu-iotests/030 | 11 ++++++++++-
10
1 file changed, 10 insertions(+), 1 deletion(-)
7
11
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
9
Signed-off-by: Jeff Cody <jcody@redhat.com>
13
index XXXXXXX..XXXXXXX 100755
10
Reviewed-by: John Snow <jsnow@redhat.com>
14
--- a/tests/qemu-iotests/030
11
Message-id: b7ec1fb2e1cf36f9b6911631447a5b0422590b7d.1491597120.git.jcody@redhat.com
15
+++ b/tests/qemu-iotests/030
12
---
16
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
13
block/rbd.c | 33 +++++++++++++++++----------------
17
speed=1024)
14
1 file changed, 17 insertions(+), 16 deletions(-)
18
self.assert_qmp(result, 'return', {})
15
19
16
diff --git a/block/rbd.c b/block/rbd.c
20
- for job in pending_jobs:
17
index XXXXXXX..XXXXXXX 100644
21
+ # Do this in reverse: After unthrottling them, some jobs may finish
18
--- a/block/rbd.c
22
+ # before we have unthrottled all of them. This will drain their
19
+++ b/block/rbd.c
23
+ # subgraph, and this will make jobs above them advance (despite those
20
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRBDState {
24
+ # jobs on top being throttled). In the worst case, all jobs below the
21
rados_t cluster;
25
+ # top one are finished before we can unthrottle it, and this makes it
22
rados_ioctx_t io_ctx;
26
+ # advance so far that it completes before we can unthrottle it - which
23
rbd_image_t image;
27
+ # results in an error.
24
- char *name;
28
+ # Starting from the top (i.e. in reverse) does not have this problem:
25
+ char *image_name;
29
+ # When a job finishes, the ones below it are not advanced.
26
char *snap;
30
+ for job in reversed(pending_jobs):
27
} BDRVRBDState;
31
result = self.vm.qmp('block-job-set-speed', device=job, speed=0)
28
32
self.assert_qmp(result, 'return', {})
29
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
30
int64_t bytes = 0;
31
int64_t objsize;
32
int obj_order = 0;
33
- const char *pool, *name, *conf, *clientname, *keypairs;
34
+ const char *pool, *image_name, *conf, *user, *keypairs;
35
const char *secretid;
36
rados_t cluster;
37
rados_ioctx_t io_ctx;
38
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
39
*/
40
pool = qdict_get_try_str(options, "pool");
41
conf = qdict_get_try_str(options, "conf");
42
- clientname = qdict_get_try_str(options, "user");
43
- name = qdict_get_try_str(options, "image");
44
+ user = qdict_get_try_str(options, "user");
45
+ image_name = qdict_get_try_str(options, "image");
46
keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
47
48
- ret = rados_create(&cluster, clientname);
49
+ ret = rados_create(&cluster, user);
50
if (ret < 0) {
51
error_setg_errno(errp, -ret, "error initializing");
52
goto exit;
53
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
54
goto shutdown;
55
}
56
57
- ret = rbd_create(io_ctx, name, bytes, &obj_order);
58
+ ret = rbd_create(io_ctx, image_name, bytes, &obj_order);
59
if (ret < 0) {
60
error_setg_errno(errp, -ret, "error rbd create");
61
}
62
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
63
Error **errp)
64
{
65
BDRVRBDState *s = bs->opaque;
66
- const char *pool, *snap, *conf, *clientname, *name, *keypairs;
67
+ const char *pool, *snap, *conf, *user, *image_name, *keypairs;
68
const char *secretid;
69
QemuOpts *opts;
70
Error *local_err = NULL;
71
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
72
pool = qemu_opt_get(opts, "pool");
73
conf = qemu_opt_get(opts, "conf");
74
snap = qemu_opt_get(opts, "snapshot");
75
- clientname = qemu_opt_get(opts, "user");
76
- name = qemu_opt_get(opts, "image");
77
+ user = qemu_opt_get(opts, "user");
78
+ image_name = qemu_opt_get(opts, "image");
79
keypairs = qemu_opt_get(opts, "=keyvalue-pairs");
80
81
- if (!pool || !name) {
82
+ if (!pool || !image_name) {
83
error_setg(errp, "Parameters 'pool' and 'image' are required");
84
r = -EINVAL;
85
goto failed_opts;
86
}
87
88
- r = rados_create(&s->cluster, clientname);
89
+ r = rados_create(&s->cluster, user);
90
if (r < 0) {
91
error_setg_errno(errp, -r, "error initializing");
92
goto failed_opts;
93
}
94
95
s->snap = g_strdup(snap);
96
- s->name = g_strdup(name);
97
+ s->image_name = g_strdup(image_name);
98
99
/* try default location when conf=NULL, but ignore failure */
100
r = rados_conf_read_file(s->cluster, conf);
101
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
102
}
103
104
/* rbd_open is always r/w */
105
- r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
106
+ r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
107
if (r < 0) {
108
- error_setg_errno(errp, -r, "error reading header from %s", s->name);
109
+ error_setg_errno(errp, -r, "error reading header from %s",
110
+ s->image_name);
111
goto failed_open;
112
}
113
114
@@ -XXX,XX +XXX,XX @@ failed_open:
115
failed_shutdown:
116
rados_shutdown(s->cluster);
117
g_free(s->snap);
118
- g_free(s->name);
119
+ g_free(s->image_name);
120
failed_opts:
121
qemu_opts_del(opts);
122
g_free(mon_host);
123
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_close(BlockDriverState *bs)
124
rbd_close(s->image);
125
rados_ioctx_destroy(s->io_ctx);
126
g_free(s->snap);
127
- g_free(s->name);
128
+ g_free(s->image_name);
129
rados_shutdown(s->cluster);
130
}
131
33
132
--
34
--
133
2.9.3
35
2.33.1
134
36
135
37
diff view generated by jsdifflib
1
The protocol VXHS does not support image creation. Some tests expect
1
From: Kevin Wolf <kwolf@redhat.com>
2
to be able to create images through the protocol. Exclude VXHS from
3
these tests.
4
2
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
While introducing a non-QemuOpts code path for device creation for JSON
4
-device, we noticed that QMP device_add doesn't check its input
5
correctly (accepting arguments that should have been rejected), and that
6
users may be relying on this behaviour (libvirt did until it was fixed
7
recently).
8
9
Let's use a deprecation period before we fix this bug in QEMU to avoid
10
nasty surprises for users.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Message-Id: <20211111143530.18985-1-kwolf@redhat.com>
14
Reviewed-by: Markus Armbruster <armbru@redhat.com>
15
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Message-Id: <20211115145409.176785-12-kwolf@redhat.com>
18
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
6
---
19
---
7
tests/qemu-iotests/017 | 1 +
20
docs/about/deprecated.rst | 14 ++++++++++++++
8
tests/qemu-iotests/020 | 1 +
21
1 file changed, 14 insertions(+)
9
tests/qemu-iotests/029 | 1 +
10
tests/qemu-iotests/073 | 1 +
11
tests/qemu-iotests/114 | 1 +
12
tests/qemu-iotests/130 | 1 +
13
tests/qemu-iotests/134 | 1 +
14
tests/qemu-iotests/156 | 1 +
15
tests/qemu-iotests/158 | 1 +
16
9 files changed, 9 insertions(+)
17
22
18
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
23
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
19
index XXXXXXX..XXXXXXX 100755
24
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/017
25
--- a/docs/about/deprecated.rst
21
+++ b/tests/qemu-iotests/017
26
+++ b/docs/about/deprecated.rst
22
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
27
@@ -XXX,XX +XXX,XX @@ options are removed in favor of using explicit ``blockdev-create`` and
23
# Any format supporting backing files
28
``blockdev-add`` calls. See :doc:`/interop/live-block-operations` for
24
_supported_fmt qcow qcow2 vmdk qed
29
details.
25
_supported_proto generic
30
26
+_unsupported_proto vxhs
31
+Incorrectly typed ``device_add`` arguments (since 6.2)
27
_supported_os Linux
32
+''''''''''''''''''''''''''''''''''''''''''''''''''''''
28
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
33
+
29
34
+Due to shortcomings in the internal implementation of ``device_add``, QEMU
30
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
35
+incorrectly accepts certain invalid arguments: Any object or list arguments are
31
index XXXXXXX..XXXXXXX 100755
36
+silently ignored. Other argument types are not checked, but an implicit
32
--- a/tests/qemu-iotests/020
37
+conversion happens, so that e.g. string values can be assigned to integer
33
+++ b/tests/qemu-iotests/020
38
+device properties or vice versa.
34
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
39
+
35
# Any format supporting backing files
40
+This is a bug in QEMU that will be fixed in the future so that previously
36
_supported_fmt qcow qcow2 vmdk qed
41
+accepted incorrect commands will return an error. Users should make sure that
37
_supported_proto generic
42
+all arguments passed to ``device_add`` are consistent with the documented
38
+_unsupported_proto vxhs
43
+property types.
39
_supported_os Linux
44
+
40
_unsupported_imgopts "subformat=monolithicFlat" \
45
System accelerators
41
"subformat=twoGbMaxExtentFlat" \
46
-------------------
42
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
43
index XXXXXXX..XXXXXXX 100755
44
--- a/tests/qemu-iotests/029
45
+++ b/tests/qemu-iotests/029
46
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
47
# Any format supporting intenal snapshots
48
_supported_fmt qcow2
49
_supported_proto generic
50
+_unsupported_proto vxhs
51
_supported_os Linux
52
# Internal snapshots are (currently) impossible with refcount_bits=1
53
_unsupported_imgopts 'refcount_bits=1[^0-9]'
54
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
55
index XXXXXXX..XXXXXXX 100755
56
--- a/tests/qemu-iotests/073
57
+++ b/tests/qemu-iotests/073
58
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
59
60
_supported_fmt qcow2
61
_supported_proto generic
62
+_unsupported_proto vxhs
63
_supported_os Linux
64
65
CLUSTER_SIZE=64k
66
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
67
index XXXXXXX..XXXXXXX 100755
68
--- a/tests/qemu-iotests/114
69
+++ b/tests/qemu-iotests/114
70
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
71
72
_supported_fmt qcow2
73
_supported_proto generic
74
+_unsupported_proto vxhs
75
_supported_os Linux
76
77
78
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
79
index XXXXXXX..XXXXXXX 100755
80
--- a/tests/qemu-iotests/130
81
+++ b/tests/qemu-iotests/130
82
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
83
84
_supported_fmt qcow2
85
_supported_proto generic
86
+_unsupported_proto vxhs
87
_supported_os Linux
88
89
qemu_comm_method="monitor"
90
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
91
index XXXXXXX..XXXXXXX 100755
92
--- a/tests/qemu-iotests/134
93
+++ b/tests/qemu-iotests/134
94
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
95
96
_supported_fmt qcow2
97
_supported_proto generic
98
+_unsupported_proto vxhs
99
_supported_os Linux
100
101
102
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
103
index XXXXXXX..XXXXXXX 100755
104
--- a/tests/qemu-iotests/156
105
+++ b/tests/qemu-iotests/156
106
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
107
108
_supported_fmt qcow2 qed
109
_supported_proto generic
110
+_unsupported_proto vxhs
111
_supported_os Linux
112
113
# Create source disk
114
diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158
115
index XXXXXXX..XXXXXXX 100755
116
--- a/tests/qemu-iotests/158
117
+++ b/tests/qemu-iotests/158
118
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
119
120
_supported_fmt qcow2
121
_supported_proto generic
122
+_unsupported_proto vxhs
123
_supported_os Linux
124
125
47
126
--
48
--
127
2.9.3
49
2.33.1
128
50
129
51
diff view generated by jsdifflib
1
From: Ashish Mittal <ashmit602@gmail.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Source code for the qnio library that this code loads can be downloaded from:
3
Reported by Coverity (CID 1465222).
4
https://github.com/VeritasHyperScale/libqnio.git
5
4
6
Sample command line using JSON syntax:
5
Fixes: 4a1d937796de0fecd8b22d7dbebf87f38e8282fd ("softmmu/qdev-monitor: add error handling in qdev_set_id")
7
./x86_64-softmmu/qemu-system-x86_64 -name instance-00000008 -S -vnc 0.0.0.0:0
6
Cc: Damien Hedde <damien.hedde@greensocs.com>
8
-k en-us -vga cirrus -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
7
Cc: Kevin Wolf <kwolf@redhat.com>
9
-msg timestamp=on
8
Cc: Michael S. Tsirkin <mst@redhat.com>
10
'json:{"driver":"vxhs","vdisk-id":"c3e9095a-a5ee-4dce-afeb-2a59fb387410",
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
"server":{"host":"172.172.17.4","port":"9999"}}'
10
Message-Id: <20211102163342.31162-1-stefanha@redhat.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
15
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
16
Reviewed-by: Markus Armbruster <armbru@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Message-Id: <20211115145409.176785-14-kwolf@redhat.com>
19
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
20
---
21
softmmu/qdev-monitor.c | 2 +-
22
1 file changed, 1 insertion(+), 1 deletion(-)
12
23
13
Sample command line using URI syntax:
24
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
14
qemu-img convert -f raw -O raw -n
15
/var/lib/nova/instances/_base/0c5eacd5ebea5ed914b6a3e7b18f1ce734c386ad
16
vxhs://192.168.0.1:9999/c6718f6b-0401-441d-a8c3-1f0064d75ee0
17
18
Sample command line using TLS credentials (run in secure mode):
19
./qemu-io --object
20
tls-creds-x509,id=tls0,dir=/etc/pki/qemu/vxhs,endpoint=client -c 'read
21
-v 66000 2.5k' 'json:{"server.host": "127.0.0.1", "server.port": "9999",
22
"vdisk-id": "/test.raw", "driver": "vxhs", "tls-creds":"tls0"}'
23
24
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
25
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
26
Reviewed-by: Jeff Cody <jcody@redhat.com>
27
Signed-off-by: Jeff Cody <jcody@redhat.com>
28
Message-id: 1491277689-24949-2-git-send-email-Ashish.Mittal@veritas.com
29
---
30
block/Makefile.objs | 2 +
31
block/trace-events | 17 ++
32
block/vxhs.c | 575 +++++++++++++++++++++++++++++++++++++++++++++++++++
33
configure | 39 ++++
34
qapi/block-core.json | 23 ++-
35
5 files changed, 654 insertions(+), 2 deletions(-)
36
create mode 100644 block/vxhs.c
37
38
diff --git a/block/Makefile.objs b/block/Makefile.objs
39
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
40
--- a/block/Makefile.objs
26
--- a/softmmu/qdev-monitor.c
41
+++ b/block/Makefile.objs
27
+++ b/softmmu/qdev-monitor.c
42
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_LIBNFS) += nfs.o
28
@@ -XXX,XX +XXX,XX @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
43
block-obj-$(CONFIG_CURL) += curl.o
29
if (prop) {
44
block-obj-$(CONFIG_RBD) += rbd.o
30
dev->id = id;
45
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
31
} else {
46
+block-obj-$(CONFIG_VXHS) += vxhs.o
32
- g_free(id);
47
block-obj-$(CONFIG_LIBSSH2) += ssh.o
33
error_setg(errp, "Duplicate device ID '%s'", id);
48
block-obj-y += accounting.o dirty-bitmap.o
34
+ g_free(id);
49
block-obj-y += write-threshold.o
35
return NULL;
50
@@ -XXX,XX +XXX,XX @@ rbd.o-cflags := $(RBD_CFLAGS)
36
}
51
rbd.o-libs := $(RBD_LIBS)
37
} else {
52
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
53
gluster.o-libs := $(GLUSTERFS_LIBS)
54
+vxhs.o-libs := $(VXHS_LIBS)
55
ssh.o-cflags := $(LIBSSH2_CFLAGS)
56
ssh.o-libs := $(LIBSSH2_LIBS)
57
block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
58
diff --git a/block/trace-events b/block/trace-events
59
index XXXXXXX..XXXXXXX 100644
60
--- a/block/trace-events
61
+++ b/block/trace-events
62
@@ -XXX,XX +XXX,XX @@ qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s
63
qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
64
qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
65
qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
66
+
67
+# block/vxhs.c
68
+vxhs_iio_callback(int error) "ctx is NULL: error %d"
69
+vxhs_iio_callback_chnfail(int err, int error) "QNIO channel failed, no i/o %d, %d"
70
+vxhs_iio_callback_unknwn(int opcode, int err) "unexpected opcode %d, errno %d"
71
+vxhs_aio_rw_invalid(int req) "Invalid I/O request iodir %d"
72
+vxhs_aio_rw_ioerr(char *guid, int iodir, uint64_t size, uint64_t off, void *acb, int ret, int err) "IO ERROR (vDisk %s) FOR : Read/Write = %d size = %lu offset = %lu ACB = %p. Error = %d, errno = %d"
73
+vxhs_get_vdisk_stat_err(char *guid, int ret, int err) "vDisk (%s) stat ioctl failed, ret = %d, errno = %d"
74
+vxhs_get_vdisk_stat(char *vdisk_guid, uint64_t vdisk_size) "vDisk %s stat ioctl returned size %lu"
75
+vxhs_complete_aio(void *acb, uint64_t ret) "aio failed acb %p ret %ld"
76
+vxhs_parse_uri_filename(const char *filename) "URI passed via bdrv_parse_filename %s"
77
+vxhs_open_vdiskid(const char *vdisk_id) "Opening vdisk-id %s"
78
+vxhs_open_hostinfo(char *of_vsa_addr, int port) "Adding host %s:%d to BDRVVXHSState"
79
+vxhs_open_iio_open(const char *host) "Failed to connect to storage agent on host %s"
80
+vxhs_parse_uri_hostinfo(char *host, int port) "Host: IP %s, Port %d"
81
+vxhs_close(char *vdisk_guid) "Closing vdisk %s"
82
+vxhs_get_creds(const char *cacert, const char *client_key, const char *client_cert) "cacert %s, client_key %s, client_cert %s"
83
diff --git a/block/vxhs.c b/block/vxhs.c
84
new file mode 100644
85
index XXXXXXX..XXXXXXX
86
--- /dev/null
87
+++ b/block/vxhs.c
88
@@ -XXX,XX +XXX,XX @@
89
+/*
90
+ * QEMU Block driver for Veritas HyperScale (VxHS)
91
+ *
92
+ * Copyright (c) 2017 Veritas Technologies LLC.
93
+ *
94
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
95
+ * See the COPYING file in the top-level directory.
96
+ *
97
+ */
98
+
99
+#include "qemu/osdep.h"
100
+#include <qnio/qnio_api.h>
101
+#include <sys/param.h>
102
+#include "block/block_int.h"
103
+#include "qapi/qmp/qerror.h"
104
+#include "qapi/qmp/qdict.h"
105
+#include "qapi/qmp/qstring.h"
106
+#include "trace.h"
107
+#include "qemu/uri.h"
108
+#include "qapi/error.h"
109
+#include "qemu/uuid.h"
110
+#include "crypto/tlscredsx509.h"
111
+
112
+#define VXHS_OPT_FILENAME "filename"
113
+#define VXHS_OPT_VDISK_ID "vdisk-id"
114
+#define VXHS_OPT_SERVER "server"
115
+#define VXHS_OPT_HOST "host"
116
+#define VXHS_OPT_PORT "port"
117
+
118
+/* Only accessed under QEMU global mutex */
119
+static uint32_t vxhs_ref;
120
+
121
+typedef enum {
122
+ VDISK_AIO_READ,
123
+ VDISK_AIO_WRITE,
124
+} VDISKAIOCmd;
125
+
126
+/*
127
+ * HyperScale AIO callbacks structure
128
+ */
129
+typedef struct VXHSAIOCB {
130
+ BlockAIOCB common;
131
+ int err;
132
+} VXHSAIOCB;
133
+
134
+typedef struct VXHSvDiskHostsInfo {
135
+ void *dev_handle; /* Device handle */
136
+ char *host; /* Host name or IP */
137
+ int port; /* Host's port number */
138
+} VXHSvDiskHostsInfo;
139
+
140
+/*
141
+ * Structure per vDisk maintained for state
142
+ */
143
+typedef struct BDRVVXHSState {
144
+ VXHSvDiskHostsInfo vdisk_hostinfo; /* Per host info */
145
+ char *vdisk_guid;
146
+ char *tlscredsid; /* tlscredsid */
147
+} BDRVVXHSState;
148
+
149
+static void vxhs_complete_aio_bh(void *opaque)
150
+{
151
+ VXHSAIOCB *acb = opaque;
152
+ BlockCompletionFunc *cb = acb->common.cb;
153
+ void *cb_opaque = acb->common.opaque;
154
+ int ret = 0;
155
+
156
+ if (acb->err != 0) {
157
+ trace_vxhs_complete_aio(acb, acb->err);
158
+ ret = (-EIO);
159
+ }
160
+
161
+ qemu_aio_unref(acb);
162
+ cb(cb_opaque, ret);
163
+}
164
+
165
+/*
166
+ * Called from a libqnio thread
167
+ */
168
+static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error)
169
+{
170
+ VXHSAIOCB *acb = NULL;
171
+
172
+ switch (opcode) {
173
+ case IRP_READ_REQUEST:
174
+ case IRP_WRITE_REQUEST:
175
+
176
+ /*
177
+ * ctx is VXHSAIOCB*
178
+ * ctx is NULL if error is QNIOERROR_CHANNEL_HUP
179
+ */
180
+ if (ctx) {
181
+ acb = ctx;
182
+ } else {
183
+ trace_vxhs_iio_callback(error);
184
+ goto out;
185
+ }
186
+
187
+ if (error) {
188
+ if (!acb->err) {
189
+ acb->err = error;
190
+ }
191
+ trace_vxhs_iio_callback(error);
192
+ }
193
+
194
+ aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
195
+ vxhs_complete_aio_bh, acb);
196
+ break;
197
+
198
+ default:
199
+ if (error == QNIOERROR_HUP) {
200
+ /*
201
+ * Channel failed, spontaneous notification,
202
+ * not in response to I/O
203
+ */
204
+ trace_vxhs_iio_callback_chnfail(error, errno);
205
+ } else {
206
+ trace_vxhs_iio_callback_unknwn(opcode, error);
207
+ }
208
+ break;
209
+ }
210
+out:
211
+ return;
212
+}
213
+
214
+static QemuOptsList runtime_opts = {
215
+ .name = "vxhs",
216
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
217
+ .desc = {
218
+ {
219
+ .name = VXHS_OPT_FILENAME,
220
+ .type = QEMU_OPT_STRING,
221
+ .help = "URI to the Veritas HyperScale image",
222
+ },
223
+ {
224
+ .name = VXHS_OPT_VDISK_ID,
225
+ .type = QEMU_OPT_STRING,
226
+ .help = "UUID of the VxHS vdisk",
227
+ },
228
+ {
229
+ .name = "tls-creds",
230
+ .type = QEMU_OPT_STRING,
231
+ .help = "ID of the TLS/SSL credentials to use",
232
+ },
233
+ { /* end of list */ }
234
+ },
235
+};
236
+
237
+static QemuOptsList runtime_tcp_opts = {
238
+ .name = "vxhs_tcp",
239
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head),
240
+ .desc = {
241
+ {
242
+ .name = VXHS_OPT_HOST,
243
+ .type = QEMU_OPT_STRING,
244
+ .help = "host address (ipv4 addresses)",
245
+ },
246
+ {
247
+ .name = VXHS_OPT_PORT,
248
+ .type = QEMU_OPT_NUMBER,
249
+ .help = "port number on which VxHSD is listening (default 9999)",
250
+ .def_value_str = "9999"
251
+ },
252
+ { /* end of list */ }
253
+ },
254
+};
255
+
256
+/*
257
+ * Parse incoming URI and populate *options with the host
258
+ * and device information
259
+ */
260
+static int vxhs_parse_uri(const char *filename, QDict *options)
261
+{
262
+ URI *uri = NULL;
263
+ char *port;
264
+ int ret = 0;
265
+
266
+ trace_vxhs_parse_uri_filename(filename);
267
+ uri = uri_parse(filename);
268
+ if (!uri || !uri->server || !uri->path) {
269
+ uri_free(uri);
270
+ return -EINVAL;
271
+ }
272
+
273
+ qdict_put(options, VXHS_OPT_SERVER".host", qstring_from_str(uri->server));
274
+
275
+ if (uri->port) {
276
+ port = g_strdup_printf("%d", uri->port);
277
+ qdict_put(options, VXHS_OPT_SERVER".port", qstring_from_str(port));
278
+ g_free(port);
279
+ }
280
+
281
+ qdict_put(options, "vdisk-id", qstring_from_str(uri->path));
282
+
283
+ trace_vxhs_parse_uri_hostinfo(uri->server, uri->port);
284
+ uri_free(uri);
285
+
286
+ return ret;
287
+}
288
+
289
+static void vxhs_parse_filename(const char *filename, QDict *options,
290
+ Error **errp)
291
+{
292
+ if (qdict_haskey(options, "vdisk-id") || qdict_haskey(options, "server")) {
293
+ error_setg(errp, "vdisk-id/server and a file name may not be specified "
294
+ "at the same time");
295
+ return;
296
+ }
297
+
298
+ if (strstr(filename, "://")) {
299
+ int ret = vxhs_parse_uri(filename, options);
300
+ if (ret < 0) {
301
+ error_setg(errp, "Invalid URI. URI should be of the form "
302
+ " vxhs://<host_ip>:<port>/<vdisk-id>");
303
+ }
304
+ }
305
+}
306
+
307
+static int vxhs_init_and_ref(void)
308
+{
309
+ if (vxhs_ref++ == 0) {
310
+ if (iio_init(QNIO_VERSION, vxhs_iio_callback)) {
311
+ return -ENODEV;
312
+ }
313
+ }
314
+ return 0;
315
+}
316
+
317
+static void vxhs_unref(void)
318
+{
319
+ if (--vxhs_ref == 0) {
320
+ iio_fini();
321
+ }
322
+}
323
+
324
+static void vxhs_get_tls_creds(const char *id, char **cacert,
325
+ char **key, char **cert, Error **errp)
326
+{
327
+ Object *obj;
328
+ QCryptoTLSCreds *creds;
329
+ QCryptoTLSCredsX509 *creds_x509;
330
+
331
+ obj = object_resolve_path_component(
332
+ object_get_objects_root(), id);
333
+
334
+ if (!obj) {
335
+ error_setg(errp, "No TLS credentials with id '%s'",
336
+ id);
337
+ return;
338
+ }
339
+
340
+ creds_x509 = (QCryptoTLSCredsX509 *)
341
+ object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS_X509);
342
+
343
+ if (!creds_x509) {
344
+ error_setg(errp, "Object with id '%s' is not TLS credentials",
345
+ id);
346
+ return;
347
+ }
348
+
349
+ creds = &creds_x509->parent_obj;
350
+
351
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
352
+ error_setg(errp,
353
+ "Expecting TLS credentials with a client endpoint");
354
+ return;
355
+ }
356
+
357
+ /*
358
+ * Get the cacert, client_cert and client_key file names.
359
+ */
360
+ if (!creds->dir) {
361
+ error_setg(errp, "TLS object missing 'dir' property value");
362
+ return;
363
+ }
364
+
365
+ *cacert = g_strdup_printf("%s/%s", creds->dir,
366
+ QCRYPTO_TLS_CREDS_X509_CA_CERT);
367
+ *cert = g_strdup_printf("%s/%s", creds->dir,
368
+ QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
369
+ *key = g_strdup_printf("%s/%s", creds->dir,
370
+ QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
371
+}
372
+
373
+static int vxhs_open(BlockDriverState *bs, QDict *options,
374
+ int bdrv_flags, Error **errp)
375
+{
376
+ BDRVVXHSState *s = bs->opaque;
377
+ void *dev_handlep;
378
+ QDict *backing_options = NULL;
379
+ QemuOpts *opts = NULL;
380
+ QemuOpts *tcp_opts = NULL;
381
+ char *of_vsa_addr = NULL;
382
+ Error *local_err = NULL;
383
+ const char *vdisk_id_opt;
384
+ const char *server_host_opt;
385
+ int ret = 0;
386
+ char *cacert = NULL;
387
+ char *client_key = NULL;
388
+ char *client_cert = NULL;
389
+
390
+ ret = vxhs_init_and_ref();
391
+ if (ret < 0) {
392
+ ret = -EINVAL;
393
+ goto out;
394
+ }
395
+
396
+ /* Create opts info from runtime_opts and runtime_tcp_opts list */
397
+ opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
398
+ tcp_opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort);
399
+
400
+ qemu_opts_absorb_qdict(opts, options, &local_err);
401
+ if (local_err) {
402
+ ret = -EINVAL;
403
+ goto out;
404
+ }
405
+
406
+ /* vdisk-id is the disk UUID */
407
+ vdisk_id_opt = qemu_opt_get(opts, VXHS_OPT_VDISK_ID);
408
+ if (!vdisk_id_opt) {
409
+ error_setg(&local_err, QERR_MISSING_PARAMETER, VXHS_OPT_VDISK_ID);
410
+ ret = -EINVAL;
411
+ goto out;
412
+ }
413
+
414
+ /* vdisk-id may contain a leading '/' */
415
+ if (strlen(vdisk_id_opt) > UUID_FMT_LEN + 1) {
416
+ error_setg(&local_err, "vdisk-id cannot be more than %d characters",
417
+ UUID_FMT_LEN);
418
+ ret = -EINVAL;
419
+ goto out;
420
+ }
421
+
422
+ s->vdisk_guid = g_strdup(vdisk_id_opt);
423
+ trace_vxhs_open_vdiskid(vdisk_id_opt);
424
+
425
+ /* get the 'server.' arguments */
426
+ qdict_extract_subqdict(options, &backing_options, VXHS_OPT_SERVER".");
427
+
428
+ qemu_opts_absorb_qdict(tcp_opts, backing_options, &local_err);
429
+ if (local_err != NULL) {
430
+ ret = -EINVAL;
431
+ goto out;
432
+ }
433
+
434
+ server_host_opt = qemu_opt_get(tcp_opts, VXHS_OPT_HOST);
435
+ if (!server_host_opt) {
436
+ error_setg(&local_err, QERR_MISSING_PARAMETER,
437
+ VXHS_OPT_SERVER"."VXHS_OPT_HOST);
438
+ ret = -EINVAL;
439
+ goto out;
440
+ }
441
+
442
+ if (strlen(server_host_opt) > MAXHOSTNAMELEN) {
443
+ error_setg(&local_err, "server.host cannot be more than %d characters",
444
+ MAXHOSTNAMELEN);
445
+ ret = -EINVAL;
446
+ goto out;
447
+ }
448
+
449
+ /* check if we got tls-creds via the --object argument */
450
+ s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds"));
451
+ if (s->tlscredsid) {
452
+ vxhs_get_tls_creds(s->tlscredsid, &cacert, &client_key,
453
+ &client_cert, &local_err);
454
+ if (local_err != NULL) {
455
+ ret = -EINVAL;
456
+ goto out;
457
+ }
458
+ trace_vxhs_get_creds(cacert, client_key, client_cert);
459
+ }
460
+
461
+ s->vdisk_hostinfo.host = g_strdup(server_host_opt);
462
+ s->vdisk_hostinfo.port = g_ascii_strtoll(qemu_opt_get(tcp_opts,
463
+ VXHS_OPT_PORT),
464
+ NULL, 0);
465
+
466
+ trace_vxhs_open_hostinfo(s->vdisk_hostinfo.host,
467
+ s->vdisk_hostinfo.port);
468
+
469
+ of_vsa_addr = g_strdup_printf("of://%s:%d",
470
+ s->vdisk_hostinfo.host,
471
+ s->vdisk_hostinfo.port);
472
+
473
+ /*
474
+ * Open qnio channel to storage agent if not opened before
475
+ */
476
+ dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0,
477
+ cacert, client_key, client_cert);
478
+ if (dev_handlep == NULL) {
479
+ trace_vxhs_open_iio_open(of_vsa_addr);
480
+ ret = -ENODEV;
481
+ goto out;
482
+ }
483
+ s->vdisk_hostinfo.dev_handle = dev_handlep;
484
+
485
+out:
486
+ g_free(of_vsa_addr);
487
+ QDECREF(backing_options);
488
+ qemu_opts_del(tcp_opts);
489
+ qemu_opts_del(opts);
490
+ g_free(cacert);
491
+ g_free(client_key);
492
+ g_free(client_cert);
493
+
494
+ if (ret < 0) {
495
+ vxhs_unref();
496
+ error_propagate(errp, local_err);
497
+ g_free(s->vdisk_hostinfo.host);
498
+ g_free(s->vdisk_guid);
499
+ g_free(s->tlscredsid);
500
+ s->vdisk_guid = NULL;
501
+ }
502
+
503
+ return ret;
504
+}
505
+
506
+static const AIOCBInfo vxhs_aiocb_info = {
507
+ .aiocb_size = sizeof(VXHSAIOCB)
508
+};
509
+
510
+/*
511
+ * This allocates QEMU-VXHS callback for each IO
512
+ * and is passed to QNIO. When QNIO completes the work,
513
+ * it will be passed back through the callback.
514
+ */
515
+static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num,
516
+ QEMUIOVector *qiov, int nb_sectors,
517
+ BlockCompletionFunc *cb, void *opaque,
518
+ VDISKAIOCmd iodir)
519
+{
520
+ VXHSAIOCB *acb = NULL;
521
+ BDRVVXHSState *s = bs->opaque;
522
+ size_t size;
523
+ uint64_t offset;
524
+ int iio_flags = 0;
525
+ int ret = 0;
526
+ void *dev_handle = s->vdisk_hostinfo.dev_handle;
527
+
528
+ offset = sector_num * BDRV_SECTOR_SIZE;
529
+ size = nb_sectors * BDRV_SECTOR_SIZE;
530
+ acb = qemu_aio_get(&vxhs_aiocb_info, bs, cb, opaque);
531
+
532
+ /*
533
+ * Initialize VXHSAIOCB.
534
+ */
535
+ acb->err = 0;
536
+
537
+ iio_flags = IIO_FLAG_ASYNC;
538
+
539
+ switch (iodir) {
540
+ case VDISK_AIO_WRITE:
541
+ ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov,
542
+ offset, (uint64_t)size, iio_flags);
543
+ break;
544
+ case VDISK_AIO_READ:
545
+ ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov,
546
+ offset, (uint64_t)size, iio_flags);
547
+ break;
548
+ default:
549
+ trace_vxhs_aio_rw_invalid(iodir);
550
+ goto errout;
551
+ }
552
+
553
+ if (ret != 0) {
554
+ trace_vxhs_aio_rw_ioerr(s->vdisk_guid, iodir, size, offset,
555
+ acb, ret, errno);
556
+ goto errout;
557
+ }
558
+ return &acb->common;
559
+
560
+errout:
561
+ qemu_aio_unref(acb);
562
+ return NULL;
563
+}
564
+
565
+static BlockAIOCB *vxhs_aio_readv(BlockDriverState *bs,
566
+ int64_t sector_num, QEMUIOVector *qiov,
567
+ int nb_sectors,
568
+ BlockCompletionFunc *cb, void *opaque)
569
+{
570
+ return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
571
+ opaque, VDISK_AIO_READ);
572
+}
573
+
574
+static BlockAIOCB *vxhs_aio_writev(BlockDriverState *bs,
575
+ int64_t sector_num, QEMUIOVector *qiov,
576
+ int nb_sectors,
577
+ BlockCompletionFunc *cb, void *opaque)
578
+{
579
+ return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors,
580
+ cb, opaque, VDISK_AIO_WRITE);
581
+}
582
+
583
+static void vxhs_close(BlockDriverState *bs)
584
+{
585
+ BDRVVXHSState *s = bs->opaque;
586
+
587
+ trace_vxhs_close(s->vdisk_guid);
588
+
589
+ g_free(s->vdisk_guid);
590
+ s->vdisk_guid = NULL;
591
+
592
+ /*
593
+ * Close vDisk device
594
+ */
595
+ if (s->vdisk_hostinfo.dev_handle) {
596
+ iio_close(s->vdisk_hostinfo.dev_handle);
597
+ s->vdisk_hostinfo.dev_handle = NULL;
598
+ }
599
+
600
+ vxhs_unref();
601
+
602
+ /*
603
+ * Free the dynamically allocated host string etc
604
+ */
605
+ g_free(s->vdisk_hostinfo.host);
606
+ g_free(s->tlscredsid);
607
+ s->tlscredsid = NULL;
608
+ s->vdisk_hostinfo.host = NULL;
609
+ s->vdisk_hostinfo.port = 0;
610
+}
611
+
612
+static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s)
613
+{
614
+ int64_t vdisk_size = -1;
615
+ int ret = 0;
616
+ void *dev_handle = s->vdisk_hostinfo.dev_handle;
617
+
618
+ ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0);
619
+ if (ret < 0) {
620
+ trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno);
621
+ return -EIO;
622
+ }
623
+
624
+ trace_vxhs_get_vdisk_stat(s->vdisk_guid, vdisk_size);
625
+ return vdisk_size;
626
+}
627
+
628
+/*
629
+ * Returns the size of vDisk in bytes. This is required
630
+ * by QEMU block upper block layer so that it is visible
631
+ * to guest.
632
+ */
633
+static int64_t vxhs_getlength(BlockDriverState *bs)
634
+{
635
+ BDRVVXHSState *s = bs->opaque;
636
+ int64_t vdisk_size;
637
+
638
+ vdisk_size = vxhs_get_vdisk_stat(s);
639
+ if (vdisk_size < 0) {
640
+ return -EIO;
641
+ }
642
+
643
+ return vdisk_size;
644
+}
645
+
646
+static BlockDriver bdrv_vxhs = {
647
+ .format_name = "vxhs",
648
+ .protocol_name = "vxhs",
649
+ .instance_size = sizeof(BDRVVXHSState),
650
+ .bdrv_file_open = vxhs_open,
651
+ .bdrv_parse_filename = vxhs_parse_filename,
652
+ .bdrv_close = vxhs_close,
653
+ .bdrv_getlength = vxhs_getlength,
654
+ .bdrv_aio_readv = vxhs_aio_readv,
655
+ .bdrv_aio_writev = vxhs_aio_writev,
656
+};
657
+
658
+static void bdrv_vxhs_init(void)
659
+{
660
+ bdrv_register(&bdrv_vxhs);
661
+}
662
+
663
+block_init(bdrv_vxhs_init);
664
diff --git a/configure b/configure
665
index XXXXXXX..XXXXXXX 100755
666
--- a/configure
667
+++ b/configure
668
@@ -XXX,XX +XXX,XX @@ numa=""
669
tcmalloc="no"
670
jemalloc="no"
671
replication="yes"
672
+vxhs=""
673
674
supported_cpu="no"
675
supported_os="no"
676
@@ -XXX,XX +XXX,XX @@ for opt do
677
;;
678
--enable-replication) replication="yes"
679
;;
680
+ --disable-vxhs) vxhs="no"
681
+ ;;
682
+ --enable-vxhs) vxhs="yes"
683
+ ;;
684
*)
685
echo "ERROR: unknown option $opt"
686
echo "Try '$0 --help' for more information"
687
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available:
688
xfsctl xfsctl support
689
qom-cast-debug cast debugging support
690
tools build qemu-io, qemu-nbd and qemu-image tools
691
+ vxhs Veritas HyperScale vDisk backend support
692
693
NOTE: The object files are built at the place where configure is launched
694
EOF
695
@@ -XXX,XX +XXX,XX @@ if compile_prog "" "" ; then
696
fi
697
698
##########################################
699
+# Veritas HyperScale block driver VxHS
700
+# Check if libvxhs is installed
701
+
702
+if test "$vxhs" != "no" ; then
703
+ cat > $TMPC <<EOF
704
+#include <stdint.h>
705
+#include <qnio/qnio_api.h>
706
+
707
+void *vxhs_callback;
708
+
709
+int main(void) {
710
+ iio_init(QNIO_VERSION, vxhs_callback);
711
+ return 0;
712
+}
713
+EOF
714
+ vxhs_libs="-lvxhs -lssl"
715
+ if compile_prog "" "$vxhs_libs" ; then
716
+ vxhs=yes
717
+ else
718
+ if test "$vxhs" = "yes" ; then
719
+ feature_not_found "vxhs block device" "Install libvxhs See github"
720
+ fi
721
+ vxhs=no
722
+ fi
723
+fi
724
+
725
+##########################################
726
# End of CC checks
727
# After here, no more $cc or $ld runs
728
729
@@ -XXX,XX +XXX,XX @@ echo "tcmalloc support $tcmalloc"
730
echo "jemalloc support $jemalloc"
731
echo "avx2 optimization $avx2_opt"
732
echo "replication support $replication"
733
+echo "VxHS block device $vxhs"
734
735
if test "$sdl_too_old" = "yes"; then
736
echo "-> Your SDL version is too old - please upgrade to have SDL support"
737
@@ -XXX,XX +XXX,XX @@ if test "$pthread_setname_np" = "yes" ; then
738
echo "CONFIG_PTHREAD_SETNAME_NP=y" >> $config_host_mak
739
fi
740
741
+if test "$vxhs" = "yes" ; then
742
+ echo "CONFIG_VXHS=y" >> $config_host_mak
743
+ echo "VXHS_LIBS=$vxhs_libs" >> $config_host_mak
744
+fi
745
+
746
if test "$tcg_interpreter" = "yes"; then
747
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
748
elif test "$ARCH" = "sparc64" ; then
749
diff --git a/qapi/block-core.json b/qapi/block-core.json
750
index XXXXXXX..XXXXXXX 100644
751
--- a/qapi/block-core.json
752
+++ b/qapi/block-core.json
753
@@ -XXX,XX +XXX,XX @@
754
#
755
# Drivers that are supported in block device operations.
756
#
757
+# @vxhs: Since 2.10
758
+#
759
# Since: 2.9
760
##
761
{ 'enum': 'BlockdevDriver',
762
@@ -XXX,XX +XXX,XX @@
763
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
764
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
765
'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
766
- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
767
+ 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
768
769
##
770
# @BlockdevOptionsFile:
771
@@ -XXX,XX +XXX,XX @@
772
'data': { '*offset': 'int', '*size': 'int' } }
773
774
##
775
+# @BlockdevOptionsVxHS:
776
+#
777
+# Driver specific block device options for VxHS
778
+#
779
+# @vdisk-id: UUID of VxHS volume
780
+# @server: vxhs server IP, port
781
+# @tls-creds: TLS credentials ID
782
+#
783
+# Since: 2.10
784
+##
785
+{ 'struct': 'BlockdevOptionsVxHS',
786
+ 'data': { 'vdisk-id': 'str',
787
+ 'server': 'InetSocketAddressBase',
788
+ '*tls-creds': 'str' } }
789
+
790
+##
791
# @BlockdevOptions:
792
#
793
# Options for creating a block device. Many options are available for all
794
@@ -XXX,XX +XXX,XX @@
795
'vhdx': 'BlockdevOptionsGenericFormat',
796
'vmdk': 'BlockdevOptionsGenericCOWFormat',
797
'vpc': 'BlockdevOptionsGenericFormat',
798
- 'vvfat': 'BlockdevOptionsVVFAT'
799
+ 'vvfat': 'BlockdevOptionsVVFAT',
800
+ 'vxhs': 'BlockdevOptionsVxHS'
801
} }
802
803
##
804
--
38
--
805
2.9.3
39
2.33.1
806
40
807
41
diff view generated by jsdifflib
1
This adds support for reopen in rbd, for changing between r/w and r/o.
1
From: Kevin Wolf <kwolf@redhat.com>
2
2
3
Note, that this is only a flag change, but we will block a change from
3
At the end of a reopen, we already call bdrv_refresh_limits(), which
4
r/o to r/w if we are using an RBD internal snapshot.
4
should update bs->request_alignment according to the new file
5
descriptor. However, raw_probe_alignment() relies on s->needs_alignment
6
and just uses 1 if it isn't set. We neglected to update this field, so
7
starting with cache=writeback and then reopening with cache=none means
8
that we get an incorrect bs->request_alignment == 1 and unaligned
9
requests fail instead of being automatically aligned.
5
10
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Fix this by recalculating s->needs_alignment in raw_refresh_limits()
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
12
before calling raw_probe_alignment().
8
Reviewed-by: John Snow <jsnow@redhat.com>
13
9
Message-id: d4e87539167ec6527d44c97b164eabcccf96e4f3.1491597120.git.jcody@redhat.com
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Message-Id: <20211104113109.56336-1-kwolf@redhat.com>
16
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
17
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Message-Id: <20211115145409.176785-13-kwolf@redhat.com>
20
[hreitz: Fix iotest 142 for block sizes greater than 512 by operating on
21
a file with a size of 1 MB]
22
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
23
Message-Id: <20211116101431.105252-1-hreitz@redhat.com>
10
---
24
---
11
block/rbd.c | 21 +++++++++++++++++++++
25
block/file-posix.c | 20 ++++++++++++++++----
12
1 file changed, 21 insertions(+)
26
tests/qemu-iotests/142 | 29 +++++++++++++++++++++++++++++
27
tests/qemu-iotests/142.out | 18 ++++++++++++++++++
28
3 files changed, 63 insertions(+), 4 deletions(-)
13
29
14
diff --git a/block/rbd.c b/block/rbd.c
30
diff --git a/block/file-posix.c b/block/file-posix.c
15
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
16
--- a/block/rbd.c
32
--- a/block/file-posix.c
17
+++ b/block/rbd.c
33
+++ b/block/file-posix.c
18
@@ -XXX,XX +XXX,XX @@ failed_opts:
34
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState {
19
return r;
35
int page_cache_inconsistent; /* errno from fdatasync failure */
36
bool has_fallocate;
37
bool needs_alignment;
38
+ bool force_alignment;
39
bool drop_cache;
40
bool check_cache_dropped;
41
struct {
42
@@ -XXX,XX +XXX,XX @@ static bool dio_byte_aligned(int fd)
43
return false;
20
}
44
}
21
45
46
+static bool raw_needs_alignment(BlockDriverState *bs)
47
+{
48
+ BDRVRawState *s = bs->opaque;
22
+
49
+
23
+/* Since RBD is currently always opened R/W via the API,
50
+ if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
24
+ * we just need to check if we are using a snapshot or not, in
51
+ return true;
25
+ * order to determine if we will allow it to be R/W */
26
+static int qemu_rbd_reopen_prepare(BDRVReopenState *state,
27
+ BlockReopenQueue *queue, Error **errp)
28
+{
29
+ BDRVRBDState *s = state->bs->opaque;
30
+ int ret = 0;
31
+
32
+ if (s->snap && state->flags & BDRV_O_RDWR) {
33
+ error_setg(errp,
34
+ "Cannot change node '%s' to r/w when using RBD snapshot",
35
+ bdrv_get_device_or_node_name(state->bs));
36
+ ret = -EINVAL;
37
+ }
52
+ }
38
+
53
+
39
+ return ret;
54
+ return s->force_alignment;
40
+}
55
+}
41
+
56
+
42
static void qemu_rbd_close(BlockDriverState *bs)
57
/* Check if read is allowed with given memory buffer and length.
43
{
58
*
44
BDRVRBDState *s = bs->opaque;
59
* This function is used to check O_DIRECT memory buffer and request alignment.
45
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
60
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
46
.bdrv_parse_filename = qemu_rbd_parse_filename,
61
47
.bdrv_file_open = qemu_rbd_open,
62
s->has_discard = true;
48
.bdrv_close = qemu_rbd_close,
63
s->has_write_zeroes = true;
49
+ .bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
64
- if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
50
.bdrv_create = qemu_rbd_create,
65
- s->needs_alignment = true;
51
.bdrv_has_zero_init = bdrv_has_zero_init_1,
66
- }
52
.bdrv_get_info = qemu_rbd_getinfo,
67
68
if (fstat(s->fd, &st) < 0) {
69
ret = -errno;
70
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
71
* so QEMU makes sure all IO operations on the device are aligned
72
* to sector size, or else FreeBSD will reject them with EINVAL.
73
*/
74
- s->needs_alignment = true;
75
+ s->force_alignment = true;
76
}
77
#endif
78
+ s->needs_alignment = raw_needs_alignment(bs);
79
80
#ifdef CONFIG_XFS
81
if (platform_test_xfs_fd(s->fd)) {
82
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
83
BDRVRawState *s = bs->opaque;
84
struct stat st;
85
86
+ s->needs_alignment = raw_needs_alignment(bs);
87
raw_probe_alignment(bs, s->fd, errp);
88
+
89
bs->bl.min_mem_alignment = s->buf_align;
90
bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size);
91
92
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
93
index XXXXXXX..XXXXXXX 100755
94
--- a/tests/qemu-iotests/142
95
+++ b/tests/qemu-iotests/142
96
@@ -XXX,XX +XXX,XX @@ info block backing-file"
97
98
echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache"
99
100
+echo
101
+echo "--- Alignment after changing O_DIRECT ---"
102
+echo
103
+
104
+# Directly test the protocol level: Can unaligned requests succeed even if
105
+# O_DIRECT was only enabled through a reopen and vice versa?
106
+
107
+# Ensure image size is a multiple of the sector size (required for O_DIRECT)
108
+$QEMU_IMG create -f file "$TEST_IMG" 1M | _filter_img_create
109
+
110
+# And write some data (not strictly necessary, but it feels better to actually
111
+# have something to be read)
112
+$QEMU_IO -f file -c 'write 0 4096' "$TEST_IMG" | _filter_qemu_io
113
+
114
+$QEMU_IO --cache=writeback -f file $TEST_IMG <<EOF | _filter_qemu_io
115
+read 42 42
116
+reopen -o cache.direct=on
117
+read 42 42
118
+reopen -o cache.direct=off
119
+read 42 42
120
+EOF
121
+$QEMU_IO --cache=none -f file $TEST_IMG <<EOF | _filter_qemu_io
122
+read 42 42
123
+reopen -o cache.direct=off
124
+read 42 42
125
+reopen -o cache.direct=on
126
+read 42 42
127
+EOF
128
+
129
# success, all done
130
echo "*** done"
131
rm -f $seq.full
132
diff --git a/tests/qemu-iotests/142.out b/tests/qemu-iotests/142.out
133
index XXXXXXX..XXXXXXX 100644
134
--- a/tests/qemu-iotests/142.out
135
+++ b/tests/qemu-iotests/142.out
136
@@ -XXX,XX +XXX,XX @@ cache.no-flush=on on backing-file
137
Cache mode: writeback
138
Cache mode: writeback, direct
139
Cache mode: writeback, ignore flushes
140
+
141
+--- Alignment after changing O_DIRECT ---
142
+
143
+Formatting 'TEST_DIR/t.IMGFMT', fmt=file size=1048576
144
+wrote 4096/4096 bytes at offset 0
145
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
146
+read 42/42 bytes at offset 42
147
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
148
+read 42/42 bytes at offset 42
149
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
150
+read 42/42 bytes at offset 42
151
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
152
+read 42/42 bytes at offset 42
153
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
154
+read 42/42 bytes at offset 42
155
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
156
+read 42/42 bytes at offset 42
157
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
158
*** done
53
--
159
--
54
2.9.3
160
2.33.1
55
161
56
162
diff view generated by jsdifflib