1
The following changes since commit 5704c36d25ee84e7129722cb0db53df9faefe943:
1
The following changes since commit 42f6c9179be4401974dd3a75ee72defd16b5092d:
2
2
3
Merge remote-tracking branch 'remotes/kraxel/tags/fixes-31-20181112-pull-request' into staging (2018-11-12 15:55:40 +0000)
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://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 1a42e5d8298d1b0f90d2254e7d559391dd3a45ca:
9
for you to fetch changes up to 7461272c5f6032436ef9032c091c0118539483e4:
10
10
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-11-12' into queue-block (2018-11-12 17:57:32 +0100)
11
softmmu/qdev-monitor: fix use-after-free in qdev_set_id() (2021-11-15 15:49:46 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- file-posix: Don't waste a file descriptor for locking, don't lock the
16
- Fixes to image streaming job and block layer reconfiguration to make
17
same bit multiple times
17
iotest 030 pass again
18
- nvme: Fix double free and memory leak
18
- docs: Deprecate incorrectly typed device_add arguments
19
- Misc error handling fixes
19
- file-posix: Fix alignment after reopen changing O_DIRECT
20
- Added NULL checks found by static analysis
21
- Allow more block drivers to not be included in the qemu build
22
20
23
----------------------------------------------------------------
21
----------------------------------------------------------------
24
Fam Zheng (4):
22
Hanna Reitz (10):
25
file-posix: Use error API properly
23
stream: Traverse graph after modification
26
file-posix: Skip effectiveless OFD lock operations
24
block: Manipulate children list in .attach/.detach
27
file-posix: Drop s->lock_fd
25
block: Unite remove_empty_child and child_free
28
tests: Add unit tests for image locking
26
block: Drop detached child from ignore list
27
block: Pass BdrvChild ** to replace_child_noperm
28
block: Restructure remove_file_or_backing_child()
29
transactions: Invoke clean() after everything else
30
block: Let replace_child_tran keep indirect pointer
31
block: Let replace_child_noperm free children
32
iotests/030: Unthrottle parallel jobs in reverse
29
33
30
Jeff Cody (1):
34
Kevin Wolf (2):
31
block: Make more block drivers compile-time configurable
35
docs: Deprecate incorrectly typed device_add arguments
36
file-posix: Fix alignment after reopen changing O_DIRECT
32
37
33
Kevin Wolf (1):
38
Stefan Hajnoczi (1):
34
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-11-12' into queue-block
39
softmmu/qdev-monitor: fix use-after-free in qdev_set_id()
35
40
36
Li Qiang (2):
41
docs/about/deprecated.rst | 14 +++
37
nvme: don't unref ctrl_mem when device unrealized
42
include/qemu/transactions.h | 3 +
38
nvme: free cmbuf in nvme_exit
43
block.c | 233 +++++++++++++++++++++++++++++++++-----------
44
block/file-posix.c | 20 +++-
45
block/stream.c | 7 +-
46
softmmu/qdev-monitor.c | 2 +-
47
util/transactions.c | 8 +-
48
tests/qemu-iotests/030 | 11 ++-
49
tests/qemu-iotests/142 | 22 +++++
50
tests/qemu-iotests/142.out | 15 +++
51
10 files changed, 269 insertions(+), 66 deletions(-)
39
52
40
Liam Merwick (5):
41
job: Fix off-by-one assert checks for JobSTT and JobVerbTable
42
block: Null pointer dereference in blk_root_get_parent_desc()
43
qemu-img: assert block_job_get() does not return NULL in img_commit()
44
block: Fix potential Null pointer dereferences in vvfat.c
45
qcow2: Read outside array bounds in qcow2_pre_write_overlap_check()
46
53
47
Peter Maydell (1):
48
blockdev: Consistently use snapshot_node_name in external_snapshot_prepare()
49
50
zhenwei pi (1):
51
blockdev: handle error on block latency histogram set error
52
53
configure | 91 ++++++++++++++++++++++++++
54
block/block-backend.c | 3 +-
55
block/file-posix.c | 122 ++++++++++++++++++++---------------
56
block/qcow2-refcount.c | 18 +++---
57
block/vvfat.c | 46 ++++++++-----
58
blockdev.c | 21 ++++--
59
hw/block/nvme.c | 6 +-
60
job.c | 4 +-
61
qemu-img.c | 1 +
62
tests/test-image-locking.c | 157 +++++++++++++++++++++++++++++++++++++++++++++
63
block/Makefile.objs | 22 +++++--
64
tests/Makefile.include | 2 +
65
12 files changed, 400 insertions(+), 93 deletions(-)
66
create mode 100644 tests/test-image-locking.c
67
diff view generated by jsdifflib
1
From: Liam Merwick <Liam.Merwick@oracle.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
Although the function block_job_get() can return NULL, it would be a
3
bdrv_cor_filter_drop() modifies the block graph. That means that other
4
serious bug if it did so (because the job yields before executing anything
4
parties can also modify the block graph before it returns. Therefore,
5
(if it started successfully); but otherwise, commit_active_start() would
5
we cannot assume that the result of a graph traversal we did before
6
have returned an error). However, as a precaution, before dereferencing
6
remains valid afterwards.
7
the 'job' pointer in img_commit() assert it is not NULL.
8
7
9
Signed-off-by: Liam Merwick <Liam.Merwick@oracle.com>
8
We should thus fetch `base` and `unfiltered_base` afterwards instead of
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
before.
11
Message-id: 1541453919-25973-4-git-send-email-Liam.Merwick@oracle.com
10
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Message-Id: <20211111120829.81329-2-hreitz@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
16
---
14
qemu-img.c | 1 +
17
block/stream.c | 7 +++++--
15
1 file changed, 1 insertion(+)
18
1 file changed, 5 insertions(+), 2 deletions(-)
16
19
17
diff --git a/qemu-img.c b/qemu-img.c
20
diff --git a/block/stream.c b/block/stream.c
18
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
19
--- a/qemu-img.c
22
--- a/block/stream.c
20
+++ b/qemu-img.c
23
+++ b/block/stream.c
21
@@ -XXX,XX +XXX,XX @@ static int img_commit(int argc, char **argv)
24
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
22
}
25
{
23
26
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
24
job = block_job_get("commit");
27
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
25
+ assert(job);
28
- BlockDriverState *base = bdrv_filter_or_cow_bs(s->above_base);
26
run_block_job(job, &local_err);
29
- BlockDriverState *unfiltered_base = bdrv_skip_filters(base);
27
if (local_err) {
30
+ BlockDriverState *base;
28
goto unref_backing;
31
+ BlockDriverState *unfiltered_base;
32
Error *local_err = NULL;
33
int ret = 0;
34
35
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
36
bdrv_cor_filter_drop(s->cor_filter_bs);
37
s->cor_filter_bs = NULL;
38
39
+ base = bdrv_filter_or_cow_bs(s->above_base);
40
+ unfiltered_base = bdrv_skip_filters(base);
41
+
42
if (bdrv_cow_child(unfiltered_bs)) {
43
const char *base_id = NULL, *base_fmt = NULL;
44
if (unfiltered_base) {
29
--
45
--
30
2.19.1
46
2.31.1
31
47
32
48
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
The lock_fd field is not strictly necessary because transferring locked
3
The children list is specific to BDS parents. We should not modify it
4
bytes from old fd to the new one shouldn't fail anyway. This spares the
4
in the general children modification code, but let BDS parents deal with
5
user one fd per image.
5
it in their .attach() and .detach() methods.
6
6
7
Signed-off-by: Fam Zheng <famz@redhat.com>
7
This also has the advantage that a BdrvChild is removed from the
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
children list before its .bs pointer can become NULL. BDS parents
9
generally assume that their children's .bs pointer is never NULL, so
10
this is actually a bug fix.
11
12
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Message-Id: <20211111120829.81329-3-hreitz@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
16
---
11
block/file-posix.c | 37 +++++++++++++------------------------
17
block.c | 14 +++++---------
12
1 file changed, 13 insertions(+), 24 deletions(-)
18
1 file changed, 5 insertions(+), 9 deletions(-)
13
19
14
diff --git a/block/file-posix.c b/block/file-posix.c
20
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
16
--- a/block/file-posix.c
22
--- a/block.c
17
+++ b/block/file-posix.c
23
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ do { \
24
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child)
19
25
{
20
typedef struct BDRVRawState {
26
BlockDriverState *bs = child->opaque;
21
int fd;
27
22
- int lock_fd;
28
+ QLIST_INSERT_HEAD(&bs->children, child, next);
23
bool use_lock;
29
+
24
int type;
30
if (child->role & BDRV_CHILD_COW) {
25
int open_flags;
31
bdrv_backing_attach(child);
26
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState {
27
uint64_t shared_perm;
28
29
/* The perms bits whose corresponding bytes are already locked in
30
- * s->lock_fd. */
31
+ * s->fd. */
32
uint64_t locked_perm;
33
uint64_t locked_shared_perm;
34
35
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
36
}
32
}
37
s->fd = fd;
33
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_detach(BdrvChild *child)
38
39
- s->lock_fd = -1;
40
- if (s->use_lock) {
41
- fd = qemu_open(filename, s->open_flags);
42
- if (fd < 0) {
43
- ret = -errno;
44
- error_setg_errno(errp, errno, "Could not open '%s' for locking",
45
- filename);
46
- qemu_close(s->fd);
47
- goto fail;
48
- }
49
- s->lock_fd = fd;
50
- }
51
s->perm = 0;
52
s->shared_perm = BLK_PERM_ALL;
53
54
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
55
return 0;
56
}
34
}
57
35
58
- assert(s->lock_fd > 0);
36
bdrv_unapply_subtree_drain(child, bs);
37
+
38
+ QLIST_REMOVE(child, next);
39
}
40
41
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
42
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_free(void *opaque)
43
static void bdrv_remove_empty_child(BdrvChild *child)
44
{
45
assert(!child->bs);
46
- QLIST_SAFE_REMOVE(child, next);
47
+ assert(!child->next.le_prev); /* not in children list */
48
bdrv_child_free(child);
49
}
50
51
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
52
return ret;
53
}
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
- */
59
-
60
-
60
switch (op) {
61
return 0;
61
case RAW_PL_PREPARE:
62
- ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm,
63
+ ret = raw_apply_lock_bytes(s, s->fd, s->perm | new_perm,
64
~s->shared_perm | ~new_shared,
65
false, errp);
66
if (!ret) {
67
- ret = raw_check_lock_bytes(s->lock_fd, new_perm, new_shared, errp);
68
+ ret = raw_check_lock_bytes(s->fd, new_perm, new_shared, errp);
69
if (!ret) {
70
return 0;
71
}
72
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
73
op = RAW_PL_ABORT;
74
/* fall through to unlock bytes. */
75
case RAW_PL_ABORT:
76
- raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm,
77
+ raw_apply_lock_bytes(s, s->fd, s->perm, ~s->shared_perm,
78
true, &local_err);
79
if (local_err) {
80
/* Theoretically the above call only unlocks bytes and it cannot
81
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
82
}
83
break;
84
case RAW_PL_COMMIT:
85
- raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared,
86
+ raw_apply_lock_bytes(s, s->fd, new_perm, ~new_shared,
87
true, &local_err);
88
if (local_err) {
89
/* Theoretically the above call only unlocks bytes and it cannot
90
@@ -XXX,XX +XXX,XX @@ static void raw_reopen_commit(BDRVReopenState *state)
91
{
92
BDRVRawReopenState *rs = state->opaque;
93
BDRVRawState *s = state->bs->opaque;
94
+ Error *local_err = NULL;
95
96
s->check_cache_dropped = rs->check_cache_dropped;
97
s->open_flags = rs->open_flags;
98
99
+ /* Copy locks to the new fd before closing the old one. */
100
+ raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
101
+ ~s->locked_shared_perm, false, &local_err);
102
+ if (local_err) {
103
+ /* shouldn't fail in a sane host, but report it just in case. */
104
+ error_report_err(local_err);
105
+ }
106
qemu_close(s->fd);
107
s->fd = rs->fd;
108
109
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
110
qemu_close(s->fd);
111
s->fd = -1;
112
}
113
- if (s->lock_fd >= 0) {
114
- qemu_close(s->lock_fd);
115
- s->lock_fd = -1;
116
- }
117
}
62
}
118
63
119
/**
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 {
120
--
80
--
121
2.19.1
81
2.31.1
122
82
123
83
diff view generated by jsdifflib
1
From: Liam Merwick <Liam.Merwick@oracle.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
The calls to find_mapping_for_cluster() may return NULL but it
3
Now that bdrv_remove_empty_child() no longer removes the child from the
4
isn't always checked for before dereferencing the value returned.
4
parent's children list but only checks that it is not in such a list, it
5
Additionally, add some asserts to cover cases where NULL can't
5
is only a wrapper around bdrv_child_free() that checks that the child is
6
be returned but which might not be obvious at first glance.
6
empty and unused. That should apply to all children that we free, so
7
put those checks into bdrv_child_free() and drop
8
bdrv_remove_empty_child().
7
9
8
Signed-off-by: Liam Merwick <Liam.Merwick@oracle.com>
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
Message-id: 1541453919-25973-5-git-send-email-Liam.Merwick@oracle.com
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
[mreitz: Dropped superfluous check of "mapping" following an assertion
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
that it is not NULL, and fixed some indentation]
13
Message-Id: <20211111120829.81329-4-hreitz@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
15
---
14
block/vvfat.c | 46 ++++++++++++++++++++++++++++++----------------
16
block.c | 26 +++++++++++++-------------
15
1 file changed, 30 insertions(+), 16 deletions(-)
17
1 file changed, 13 insertions(+), 13 deletions(-)
16
18
17
diff --git a/block/vvfat.c b/block/vvfat.c
19
diff --git a/block.c b/block.c
18
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
19
--- a/block/vvfat.c
21
--- a/block.c
20
+++ b/block/vvfat.c
22
+++ b/block.c
21
@@ -XXX,XX +XXX,XX @@ static inline void array_free(array_t* array)
23
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
22
/* does not automatically grow */
24
}
23
static inline void* array_get(array_t* array,unsigned int index) {
24
assert(index < array->next);
25
+ assert(array->pointer);
26
return array->pointer + index * array->item_size;
27
}
25
}
28
26
29
-static inline int array_ensure_allocated(array_t* array, int index)
27
-static void bdrv_child_free(void *opaque)
30
+static inline void array_ensure_allocated(array_t *array, int index)
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)
31
{
43
{
32
if((index + 1) * array->item_size > array->size) {
44
assert(!child->bs);
33
int new_size = (index + 32) * array->item_size;
45
assert(!child->next.le_prev); /* not in children list */
34
array->pointer = g_realloc(array->pointer, new_size);
46
- bdrv_child_free(child);
35
- if (!array->pointer)
47
+
36
- return -1;
48
+ g_free(child->name);
37
+ assert(array->pointer);
49
+ g_free(child);
38
memset(array->pointer + array->size, 0, new_size - array->size);
50
}
39
array->size = new_size;
51
40
array->next = index + 1;
52
typedef struct BdrvAttachChildCommonState {
53
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
41
}
54
}
42
-
55
43
- return 0;
56
bdrv_unref(bs);
57
- bdrv_remove_empty_child(child);
58
+ bdrv_child_free(child);
59
*s->child = NULL;
44
}
60
}
45
61
46
static inline void* array_get_next(array_t* array) {
62
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
47
unsigned int next = array->next;
63
48
64
if (ret < 0) {
49
- if (array_ensure_allocated(array, next) < 0)
65
error_propagate(errp, local_err);
50
- return NULL;
66
- bdrv_remove_empty_child(new_child);
51
-
67
+ bdrv_child_free(new_child);
52
+ array_ensure_allocated(array, next);
68
return ret;
53
array->next = next + 1;
69
}
54
return array_get(array, next);
70
}
55
}
71
@@ -XXX,XX +XXX,XX @@ static void bdrv_detach_child(BdrvChild *child)
56
@@ -XXX,XX +XXX,XX @@ static int commit_direntries(BDRVVVFATState* s,
72
BlockDriverState *old_bs = child->bs;
57
direntry_t* direntry = array_get(&(s->directory), dir_index);
73
58
uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
74
bdrv_replace_child_noperm(child, NULL);
59
mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
75
- bdrv_remove_empty_child(child);
60
-
76
+ bdrv_child_free(child);
61
int factor = 0x10 * s->sectors_per_cluster;
77
62
int old_cluster_count, new_cluster_count;
78
if (old_bs) {
63
- int current_dir_index = mapping->info.dir.first_dir_index;
79
/*
64
- int first_dir_index = current_dir_index;
65
+ int current_dir_index;
66
+ int first_dir_index;
67
int ret, i;
68
uint32_t c;
69
70
-DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
71
-
72
assert(direntry);
73
assert(mapping);
74
assert(mapping->begin == first_cluster);
75
@@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapp
76
assert(mapping->mode & MODE_DIRECTORY);
77
assert(dir_index == 0 || is_directory(direntry));
78
79
+ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n",
80
+ mapping->path, parent_mapping_index));
81
+
82
+ current_dir_index = mapping->info.dir.first_dir_index;
83
+ first_dir_index = current_dir_index;
84
mapping->info.dir.parent_mapping_index = parent_mapping_index;
85
86
if (first_cluster == 0) {
87
@@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapp
88
direntry = array_get(&(s->directory), first_dir_index + i);
89
if (is_directory(direntry) && !is_dot(direntry)) {
90
mapping = find_mapping_for_cluster(s, first_cluster);
91
+ if (mapping == NULL) {
92
+ return -1;
93
+ }
94
assert(mapping->mode & MODE_DIRECTORY);
95
ret = commit_direntries(s, first_dir_index + i,
96
array_index(&(s->mapping), mapping));
97
@@ -XXX,XX +XXX,XX @@ static int commit_one_file(BDRVVVFATState* s,
98
assert(offset < size);
99
assert((offset % s->cluster_size) == 0);
100
101
+ if (mapping == NULL) {
102
+ return -1;
103
+ }
104
+
105
for (i = s->cluster_size; i < offset; i += s->cluster_size)
106
c = modified_fat_get(s, c);
107
108
@@ -XXX,XX +XXX,XX @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
109
if (commit->action == ACTION_RENAME) {
110
mapping_t* mapping = find_mapping_for_cluster(s,
111
commit->param.rename.cluster);
112
- char* old_path = mapping->path;
113
+ char *old_path;
114
115
+ if (mapping == NULL) {
116
+ return -1;
117
+ }
118
+ old_path = mapping->path;
119
assert(commit->path);
120
mapping->path = commit->path;
121
if (rename(old_path, mapping->path))
122
@@ -XXX,XX +XXX,XX @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
123
direntry_t* d = direntry + i;
124
125
if (is_file(d) || (is_directory(d) && !is_dot(d))) {
126
+ int l;
127
+ char *new_path;
128
mapping_t* m = find_mapping_for_cluster(s,
129
begin_of_direntry(d));
130
- int l = strlen(m->path);
131
- char* new_path = g_malloc(l + diff + 1);
132
+ if (m == NULL) {
133
+ return -1;
134
+ }
135
+ l = strlen(m->path);
136
+ new_path = g_malloc(l + diff + 1);
137
138
assert(!strncmp(m->path, mapping->path, l2));
139
140
--
80
--
141
2.19.1
81
2.31.1
142
82
143
83
diff view generated by jsdifflib
1
From: zhenwei pi <pizhenwei@bytedance.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
Function block_latency_histogram_set may return error, but qapi ignore this.
3
bdrv_attach_child_common_abort() restores the parent's AioContext. To
4
This can be reproduced easily by qmp command:
4
do so, the child (which was supposed to be attached, but is now detached
5
virsh qemu-monitor-command INSTANCE '{"execute":"x-block-latency-histogram-set",
5
again by this abort handler) is added to the ignore list for the
6
"arguments":{"device":"drive-virtio-disk1","boundaries":[10,200,40]}}'
6
AioContext changing functions.
7
In fact this command does not work, but we still get success result.
8
7
9
qmp_x_block_latency_histogram_set is a batch setting API, report error ASAP.
8
However, since we modify a BDS's children list in the BdrvChildClass's
9
.attach and .detach handlers, the child is already effectively detached
10
from the parent by this point. We do not need to put it into the ignore
11
list.
10
12
11
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
13
Use this opportunity to clean up the empty line structure: Keep setting
14
the ignore list, invoking the AioContext function, and freeing the
15
ignore list in blocks separated by empty lines.
16
17
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
18
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
19
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
20
Message-Id: <20211111120829.81329-5-hreitz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
22
---
14
blockdev.c | 19 ++++++++++++++++---
23
block.c | 8 +++++---
15
1 file changed, 16 insertions(+), 3 deletions(-)
24
1 file changed, 5 insertions(+), 3 deletions(-)
16
25
17
diff --git a/blockdev.c b/blockdev.c
26
diff --git a/block.c b/block.c
18
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
19
--- a/blockdev.c
28
--- a/block.c
20
+++ b/blockdev.c
29
+++ b/block.c
21
@@ -XXX,XX +XXX,XX @@ void qmp_x_block_latency_histogram_set(
30
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
22
{
23
BlockBackend *blk = blk_by_name(device);
24
BlockAcctStats *stats;
25
+ int ret;
26
27
if (!blk) {
28
error_setg(errp, "Device '%s' not found", device);
29
@@ -XXX,XX +XXX,XX @@ void qmp_x_block_latency_histogram_set(
30
}
31
}
31
32
32
if (has_boundaries || has_boundaries_read) {
33
if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) {
33
- block_latency_histogram_set(
34
- GSList *ignore = g_slist_prepend(NULL, child);
34
+ ret = block_latency_histogram_set(
35
+ GSList *ignore;
35
stats, BLOCK_ACCT_READ,
36
36
has_boundaries_read ? boundaries_read : boundaries);
37
+ /* No need to ignore `child`, because it has been detached already */
37
+ if (ret) {
38
+ ignore = NULL;
38
+ error_setg(errp, "Device '%s' set read boundaries fail", device);
39
child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore,
39
+ return;
40
&error_abort);
40
+ }
41
g_slist_free(ignore);
42
- ignore = g_slist_prepend(NULL, child);
43
- child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
44
45
+ ignore = NULL;
46
+ child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
47
g_slist_free(ignore);
41
}
48
}
42
49
43
if (has_boundaries || has_boundaries_write) {
44
- block_latency_histogram_set(
45
+ ret = block_latency_histogram_set(
46
stats, BLOCK_ACCT_WRITE,
47
has_boundaries_write ? boundaries_write : boundaries);
48
+ if (ret) {
49
+ error_setg(errp, "Device '%s' set write boundaries fail", device);
50
+ return;
51
+ }
52
}
53
54
if (has_boundaries || has_boundaries_flush) {
55
- block_latency_histogram_set(
56
+ ret = block_latency_histogram_set(
57
stats, BLOCK_ACCT_FLUSH,
58
has_boundaries_flush ? boundaries_flush : boundaries);
59
+ if (ret) {
60
+ error_setg(errp, "Device '%s' set flush boundaries fail", device);
61
+ return;
62
+ }
63
}
64
}
65
66
--
50
--
67
2.19.1
51
2.31.1
68
52
69
53
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
Use error_report for situations that affect user operation (i.e. we're
3
bdrv_replace_child_noperm() modifies BdrvChild.bs, and can potentially
4
actually returning error), and warn_report/warn_report_err when some
4
set it to NULL. That is dangerous, because BDS parents generally assume
5
less critical error happened but the user operation can still carry on.
5
that their children's .bs pointer is never NULL. We therefore want to
6
let bdrv_replace_child_noperm() set the corresponding BdrvChild pointer
7
to NULL, too.
6
8
7
For raw_normalize_devicepath, add Error parameter to propagate to
9
This patch lays the foundation for it by passing a BdrvChild ** pointer
8
its callers.
10
to bdrv_replace_child_noperm() so that it can later use it to NULL the
11
BdrvChild pointer immediately after setting BdrvChild.bs to NULL.
9
12
10
Suggested-by: Markus Armbruster <armbru@redhat.com>
13
(We will still need to undertake some intermediate steps, though.)
11
Signed-off-by: Fam Zheng <famz@redhat.com>
14
15
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
16
Message-Id: <20211111120829.81329-6-hreitz@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
19
---
14
block/file-posix.c | 39 ++++++++++++++++-----------------------
20
block.c | 23 ++++++++++++-----------
15
1 file changed, 16 insertions(+), 23 deletions(-)
21
1 file changed, 12 insertions(+), 11 deletions(-)
16
22
17
diff --git a/block/file-posix.c b/block/file-posix.c
23
diff --git a/block.c b/block.c
18
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
19
--- a/block/file-posix.c
25
--- a/block.c
20
+++ b/block/file-posix.c
26
+++ b/block.c
21
@@ -XXX,XX +XXX,XX @@ static int cdrom_reopen(BlockDriverState *bs);
27
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
22
#endif
28
static bool bdrv_recurse_has_child(BlockDriverState *bs,
23
29
BlockDriverState *child);
24
#if defined(__NetBSD__)
30
25
-static int raw_normalize_devicepath(const char **filename)
31
-static void bdrv_replace_child_noperm(BdrvChild *child,
26
+static int raw_normalize_devicepath(const char **filename, Error **errp)
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);
43
}
44
45
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
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)
27
{
61
{
28
static char namebuf[PATH_MAX];
62
+ BdrvChild *child = *childp;
29
const char *dp, *fname;
63
BlockDriverState *old_bs = child->bs;
30
@@ -XXX,XX +XXX,XX @@ static int raw_normalize_devicepath(const char **filename)
64
int new_bs_quiesce_counter;
31
fname = *filename;
65
int drain_saldo;
32
dp = strrchr(fname, '/');
66
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
33
if (lstat(fname, &sb) < 0) {
67
BdrvChild *child = *s->child;
34
- fprintf(stderr, "%s: stat failed: %s\n",
68
BlockDriverState *bs = child->bs;
35
- fname, strerror(errno));
69
36
+ error_setg_errno(errp, errno, "%s: stat failed", fname);
70
- bdrv_replace_child_noperm(child, NULL);
37
return -errno;
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,
38
}
76
}
39
77
40
@@ -XXX,XX +XXX,XX @@ static int raw_normalize_devicepath(const char **filename)
78
bdrv_ref(child_bs);
41
snprintf(namebuf, PATH_MAX, "%.*s/r%s",
79
- bdrv_replace_child_noperm(new_child, child_bs);
42
(int)(dp - fname), fname, dp + 1);
80
+ bdrv_replace_child_noperm(&new_child, child_bs);
43
}
81
44
- fprintf(stderr, "%s is a block device", fname);
82
*child = new_child;
45
*filename = namebuf;
83
46
- fprintf(stderr, ", using %s\n", *filename);
84
@@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
47
+ warn_report("%s is a block device, using %s", fname, *filename);
48
49
return 0;
85
return 0;
50
}
86
}
51
#else
87
52
-static int raw_normalize_devicepath(const char **filename)
88
-static void bdrv_detach_child(BdrvChild *child)
53
+static int raw_normalize_devicepath(const char **filename, Error **errp)
89
+static void bdrv_detach_child(BdrvChild **childp)
54
{
90
{
55
return 0;
91
- BlockDriverState *old_bs = child->bs;
92
+ BlockDriverState *old_bs = (*childp)->bs;
93
94
- bdrv_replace_child_noperm(child, NULL);
95
- bdrv_child_free(child);
96
+ bdrv_replace_child_noperm(childp, NULL);
97
+ bdrv_child_free(*childp);
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);
56
}
108
}
57
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
58
59
filename = qemu_opt_get(opts, "filename");
60
61
- ret = raw_normalize_devicepath(&filename);
62
+ ret = raw_normalize_devicepath(&filename, errp);
63
if (ret != 0) {
64
- error_setg_errno(errp, -ret, "Could not normalize device path");
65
goto fail;
66
}
67
68
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
69
case ON_OFF_AUTO_ON:
70
s->use_lock = true;
71
if (!qemu_has_ofd_lock()) {
72
- fprintf(stderr,
73
- "File lock requested but OFD locking syscall is "
74
- "unavailable, falling back to POSIX file locks.\n"
75
- "Due to the implementation, locks can be lost "
76
- "unexpectedly.\n");
77
+ warn_report("File lock requested but OFD locking syscall is "
78
+ "unavailable, falling back to POSIX file locks");
79
+ error_printf("Due to the implementation, locks can be lost "
80
+ "unexpectedly.\n");
81
}
82
break;
83
case ON_OFF_AUTO_OFF:
84
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
85
/* Theoretically the above call only unlocks bytes and it cannot
86
* fail. Something weird happened, report it.
87
*/
88
- error_report_err(local_err);
89
+ warn_report_err(local_err);
90
}
91
break;
92
case RAW_PL_COMMIT:
93
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
94
/* Theoretically the above call only unlocks bytes and it cannot
95
* fail. Something weird happened, report it.
96
*/
97
- error_report_err(local_err);
98
+ warn_report_err(local_err);
99
}
100
break;
101
}
102
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
103
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
104
if (rs->fd == -1) {
105
const char *normalized_filename = state->bs->filename;
106
- ret = raw_normalize_devicepath(&normalized_filename);
107
- if (ret < 0) {
108
- error_setg_errno(errp, -ret, "Could not normalize device path");
109
- } else {
110
+ ret = raw_normalize_devicepath(&normalized_filename, errp);
111
+ if (ret >= 0) {
112
assert(!(rs->open_flags & O_CREAT));
113
rs->fd = qemu_open(normalized_filename, rs->open_flags);
114
if (rs->fd == -1) {
115
@@ -XXX,XX +XXX,XX @@ static int aio_worker(void *arg)
116
ret = handle_aiocb_truncate(aiocb);
117
break;
118
default:
119
- fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
120
+ error_report("invalid aio request (0x%x)", aiocb->aio_type);
121
ret = -EINVAL;
122
break;
123
}
124
@@ -XXX,XX +XXX,XX @@ out_unlock:
125
* not mean the whole creation operation has failed. So
126
* report it the user for their convenience, but do not report
127
* it to the caller. */
128
- error_report_err(local_err);
129
+ warn_report_err(local_err);
130
}
131
132
out_close:
133
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts
134
135
(void)has_prefix;
136
137
- ret = raw_normalize_devicepath(&filename);
138
+ ret = raw_normalize_devicepath(&filename, errp);
139
if (ret < 0) {
140
- error_setg_errno(errp, -ret, "Could not normalize device path");
141
return ret;
142
}
143
109
144
--
110
--
145
2.19.1
111
2.31.1
146
112
147
113
diff view generated by jsdifflib
1
From: Liam Merwick <Liam.Merwick@oracle.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
The dev_id returned by the call to blk_get_attached_dev_id() in
3
As of a future patch, bdrv_replace_child_tran() will take a BdrvChild **
4
blk_root_get_parent_desc() can be NULL (an internal call to
4
pointer. Prepare for that by getting such a pointer and using it where
5
object_get_canonical_path may have returned NULL).
5
applicable, and (dereferenced) as a parameter for
6
bdrv_replace_child_tran().
6
7
7
Instead of just checking this case before before dereferencing,
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
8
adjust blk_get_attached_dev_id() to return the empty string if no
9
Message-Id: <20211111120829.81329-7-hreitz@redhat.com>
9
object path can be found (similar to the case when blk->dev is NULL
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
and an empty string is returned).
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block.c | 21 ++++++++++++---------
14
1 file changed, 12 insertions(+), 9 deletions(-)
11
15
12
Signed-off-by: Liam Merwick <Liam.Merwick@oracle.com>
16
diff --git a/block.c b/block.c
13
Message-id: 1541453919-25973-3-git-send-email-Liam.Merwick@oracle.com
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
block/block-backend.c | 3 ++-
18
1 file changed, 2 insertions(+), 1 deletion(-)
19
20
diff --git a/block/block-backend.c b/block/block-backend.c
21
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
22
--- a/block/block-backend.c
18
--- a/block.c
23
+++ b/block/block-backend.c
19
+++ b/block.c
24
@@ -XXX,XX +XXX,XX @@ char *blk_get_attached_dev_id(BlockBackend *blk)
20
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
25
} else if (dev->id) {
21
BdrvChild *child,
26
return g_strdup(dev->id);
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;
27
}
31
}
28
- return object_get_canonical_path(OBJECT(dev));
32
33
+ if (child == bs->backing) {
34
+ childp = &bs->backing;
35
+ } else if (child == bs->file) {
36
+ childp = &bs->file;
37
+ } else {
38
+ g_assert_not_reached();
39
+ }
29
+
40
+
30
+ return object_get_canonical_path(OBJECT(dev)) ?: g_strdup("");
41
if (child->bs) {
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
}
32
61
33
/*
62
/*
34
--
63
--
35
2.19.1
64
2.31.1
36
65
37
66
diff view generated by jsdifflib
1
From: Liam Merwick <Liam.Merwick@oracle.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
In the assert checking the array dereference of JobVerbTable[verb]
3
Invoke the transaction drivers' .clean() methods only after all
4
in job_apply_verb() the check of the index, verb, allows an overrun
4
.commit() or .abort() handlers are done.
5
because an index equal to the array size is permitted.
6
5
7
Similarly, in the assert check of JobSTT[s0][s1] with index s1
6
This makes it easier to have nested transactions where the top-level
8
in job_state_transition(), an off-by-one overrun is not flagged
7
transactions pass objects to lower transactions that the latter can
9
either.
8
still use throughout their commit/abort phases, while the top-level
9
transaction keeps a reference that is released in its .clean() method.
10
10
11
This is not a run-time issue as there are no callers actually
11
(Before this commit, that is also possible, but the top-level
12
passing in the max value.
12
transaction would need to take care to invoke tran_add() before the
13
lower-level transaction does. This commit makes the ordering
14
irrelevant, which is just a bit nicer.)
13
15
14
Signed-off-by: Liam Merwick <Liam.Merwick@oracle.com>
16
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
15
Reviewed-by: Darren Kenny <Darren.Kenny@oracle.com>
17
Message-Id: <20211111120829.81329-8-hreitz@redhat.com>
16
Reviewed-by: Mark Kanda <Mark.Kanda@oracle.com>
18
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: John Snow <jsnow@redhat.com>
19
Message-id: 1541453919-25973-2-git-send-email-Liam.Merwick@oracle.com
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
---
20
---
22
job.c | 4 ++--
21
include/qemu/transactions.h | 3 +++
23
1 file changed, 2 insertions(+), 2 deletions(-)
22
util/transactions.c | 8 ++++++--
23
2 files changed, 9 insertions(+), 2 deletions(-)
24
24
25
diff --git a/job.c b/job.c
25
diff --git a/include/qemu/transactions.h b/include/qemu/transactions.h
26
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
27
--- a/job.c
27
--- a/include/qemu/transactions.h
28
+++ b/job.c
28
+++ b/include/qemu/transactions.h
29
@@ -XXX,XX +XXX,XX @@ bool job_is_internal(Job *job)
29
@@ -XXX,XX +XXX,XX @@
30
static void job_state_transition(Job *job, JobStatus s1)
30
* tran_create(), call your "prepare" functions on it, and finally call
31
* tran_abort() or tran_commit() to finalize the transaction by corresponding
32
* finalization actions in reverse order.
33
+ *
34
+ * The clean() functions registered by the drivers in a transaction are called
35
+ * last, after all abort() or commit() functions have been called.
36
*/
37
38
#ifndef QEMU_TRANSACTIONS_H
39
diff --git a/util/transactions.c b/util/transactions.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/util/transactions.c
42
+++ b/util/transactions.c
43
@@ -XXX,XX +XXX,XX @@ void tran_abort(Transaction *tran)
31
{
44
{
32
JobStatus s0 = job->status;
45
TransactionAction *act, *next;
33
- assert(s1 >= 0 && s1 <= JOB_STATUS__MAX);
46
34
+ assert(s1 >= 0 && s1 < JOB_STATUS__MAX);
47
- QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
35
trace_job_state_transition(job, job->ret,
48
+ QSLIST_FOREACH(act, &tran->actions, entry) {
36
JobSTT[s0][s1] ? "allowed" : "disallowed",
49
if (act->drv->abort) {
37
JobStatus_str(s0), JobStatus_str(s1));
50
act->drv->abort(act->opaque);
38
@@ -XXX,XX +XXX,XX @@ static void job_state_transition(Job *job, JobStatus s1)
51
}
39
int job_apply_verb(Job *job, JobVerb verb, Error **errp)
52
+ }
53
54
+ QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
55
if (act->drv->clean) {
56
act->drv->clean(act->opaque);
57
}
58
@@ -XXX,XX +XXX,XX @@ void tran_commit(Transaction *tran)
40
{
59
{
41
JobStatus s0 = job->status;
60
TransactionAction *act, *next;
42
- assert(verb >= 0 && verb <= JOB_VERB__MAX);
61
43
+ assert(verb >= 0 && verb < JOB_VERB__MAX);
62
- QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
44
trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb),
63
+ QSLIST_FOREACH(act, &tran->actions, entry) {
45
JobVerbTable[verb][s0] ? "allowed" : "prohibited");
64
if (act->drv->commit) {
46
if (JobVerbTable[verb][s0]) {
65
act->drv->commit(act->opaque);
66
}
67
+ }
68
69
+ QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
70
if (act->drv->clean) {
71
act->drv->clean(act->opaque);
72
}
47
--
73
--
48
2.19.1
74
2.31.1
49
75
50
76
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
Signed-off-by: Fam Zheng <famz@redhat.com>
3
As of a future commit, bdrv_replace_child_noperm() will clear the
4
indirect BdrvChild pointer passed to it if the new child BDS is NULL.
5
bdrv_replace_child_tran() will want to let it do that, but revert this
6
change in its abort handler. For that, we need to have it receive a
7
BdrvChild ** pointer, too, and keep it stored in the
8
BdrvReplaceChildState object that we attach to the transaction.
9
10
Note that we do not need to store it in the BdrvReplaceChildState when
11
new_bs is not NULL, because then there is nothing to revert. This is
12
important so that bdrv_replace_node_noperm() can pass a pointer to a
13
loop-local variable to bdrv_replace_child_tran() without worrying that
14
this pointer will outlive one loop iteration.
15
16
(Of course, for that to work, bdrv_replace_node_noperm() and in turn
17
bdrv_replace_node() and its relatives may not be called with a NULL @to
18
node. Luckily, they already are not, but now we should assert this.)
19
20
bdrv_remove_file_or_backing_child() on the other hand needs to ensure
21
that the indirect pointer it passes will stay valid for the duration of
22
the transaction. Ensure this by keeping a strong reference to the BDS
23
whose &bs->backing or &bs->file it passes to bdrv_replace_child_tran(),
24
and giving up that reference only in the transaction .clean() handler.
25
26
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
27
Message-Id: <20211111120829.81329-9-hreitz@redhat.com>
28
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
30
---
6
tests/test-image-locking.c | 157 +++++++++++++++++++++++++++++++++++++
31
block.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
7
tests/Makefile.include | 2 +
32
1 file changed, 73 insertions(+), 10 deletions(-)
8
2 files changed, 159 insertions(+)
33
9
create mode 100644 tests/test-image-locking.c
34
diff --git a/block.c b/block.c
10
35
index XXXXXXX..XXXXXXX 100644
11
diff --git a/tests/test-image-locking.c b/tests/test-image-locking.c
36
--- a/block.c
12
new file mode 100644
37
+++ b/block.c
13
index XXXXXXX..XXXXXXX
38
@@ -XXX,XX +XXX,XX @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
14
--- /dev/null
39
15
+++ b/tests/test-image-locking.c
40
typedef struct BdrvReplaceChildState {
16
@@ -XXX,XX +XXX,XX @@
41
BdrvChild *child;
17
+/*
42
+ BdrvChild **childp;
18
+ * Image locking tests
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.
19
+ *
81
+ *
20
+ * Copyright (c) 2018 Red Hat Inc.
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.
21
+ *
86
+ *
22
+ * Author: Fam Zheng <famz@redhat.com>
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)
128
+{
129
+ BdrvRemoveFilterOrCowChild *s = opaque;
130
+
131
+ /* Drop the bs reference after the transaction is done */
132
+ bdrv_unref(s->bs);
133
+ g_free(s);
134
+}
135
+
136
static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
137
.abort = bdrv_remove_filter_or_cow_child_abort,
138
.commit = bdrv_remove_filter_or_cow_child_commit,
139
- .clean = g_free,
140
+ .clean = bdrv_remove_filter_or_cow_child_clean,
141
};
142
143
/*
144
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
145
return;
146
}
147
148
+ /*
149
+ * Keep a reference to @bs so @childp will stay valid throughout the
150
+ * transaction (required by bdrv_replace_child_tran())
151
+ */
152
+ bdrv_ref(bs);
153
if (child == bs->backing) {
154
childp = &bs->backing;
155
} else if (child == bs->file) {
156
@@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
157
}
158
159
if (child->bs) {
160
- bdrv_replace_child_tran(*childp, NULL, tran);
161
+ bdrv_replace_child_tran(childp, NULL, tran);
162
}
163
164
s = g_new(BdrvRemoveFilterOrCowChild, 1);
165
*s = (BdrvRemoveFilterOrCowChild) {
166
.child = child,
167
+ .bs = bs,
168
.is_backing = (childp == &bs->backing),
169
};
170
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
171
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
172
{
173
BdrvChild *c, *next;
174
175
+ assert(to != NULL);
176
+
177
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
178
assert(c->bs == from);
179
if (!should_update_child(c, to)) {
180
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
181
c->name, from->node_name);
182
return -EPERM;
183
}
184
- bdrv_replace_child_tran(c, to, tran);
185
+
186
+ /*
187
+ * Passing a pointer to the local variable @c is fine here, because
188
+ * @to is not NULL, and so &c will not be attached to the transaction.
189
+ */
190
+ bdrv_replace_child_tran(&c, to, tran);
191
}
192
193
return 0;
194
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
195
*
196
* With @detach_subchain=true @to must be in a backing chain of @from. In this
197
* case backing link of the cow-parent of @to is removed.
23
+ *
198
+ *
24
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
199
+ * @to must not be NULL.
25
+ * of this software and associated documentation files (the "Software"), to deal
200
*/
26
+ * in the Software without restriction, including without limitation the rights
201
static int bdrv_replace_node_common(BlockDriverState *from,
27
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
202
BlockDriverState *to,
28
+ * copies of the Software, and to permit persons to whom the Software is
203
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
29
+ * furnished to do so, subject to the following conditions:
204
BlockDriverState *to_cow_parent = NULL;
30
+ *
205
int ret;
31
+ * The above copyright notice and this permission notice shall be included in
206
32
+ * all copies or substantial portions of the Software.
207
+ assert(to != NULL);
33
+ *
208
+
34
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
209
if (detach_subchain) {
35
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
210
assert(bdrv_chain_contains(from, to));
36
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
211
assert(from != to);
37
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
212
@@ -XXX,XX +XXX,XX @@ out:
38
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
213
return ret;
39
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
214
}
40
+ * THE SOFTWARE.
215
216
+/**
217
+ * Replace node @from by @to (where neither may be NULL).
41
+ */
218
+ */
42
+
219
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
43
+#include "qemu/osdep.h"
220
Error **errp)
44
+#include "block/block.h"
221
{
45
+#include "sysemu/block-backend.h"
222
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
46
+#include "qapi/error.h"
223
bdrv_drained_begin(old_bs);
47
+#include "qapi/qmp/qdict.h"
224
bdrv_drained_begin(new_bs);
48
+
225
49
+static BlockBackend *open_image(const char *path,
226
- bdrv_replace_child_tran(child, new_bs, tran);
50
+ uint64_t perm, uint64_t shared_perm,
227
+ bdrv_replace_child_tran(&child, new_bs, tran);
51
+ Error **errp)
228
52
+{
229
found = g_hash_table_new(NULL, NULL);
53
+ Error *local_err = NULL;
230
refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs);
54
+ BlockBackend *blk;
55
+ QDict *options = qdict_new();
56
+
57
+ qdict_put_str(options, "driver", "raw");
58
+ blk = blk_new_open(path, NULL, options, BDRV_O_RDWR, &local_err);
59
+ if (blk) {
60
+ g_assert_null(local_err);
61
+ if (blk_set_perm(blk, perm, shared_perm, errp)) {
62
+ blk_unref(blk);
63
+ blk = NULL;
64
+ }
65
+ } else {
66
+ error_propagate(errp, local_err);
67
+ }
68
+ return blk;
69
+}
70
+
71
+static void check_locked_bytes(int fd, uint64_t perm_locks,
72
+ uint64_t shared_perm_locks)
73
+{
74
+ int i;
75
+
76
+ if (!perm_locks && !shared_perm_locks) {
77
+ g_assert(!qemu_lock_fd_test(fd, 0, 0, true));
78
+ return;
79
+ }
80
+ for (i = 0; (1ULL << i) <= BLK_PERM_ALL; i++) {
81
+ uint64_t bit = (1ULL << i);
82
+ bool perm_expected = !!(bit & perm_locks);
83
+ bool shared_perm_expected = !!(bit & shared_perm_locks);
84
+ g_assert_cmpint(perm_expected, ==,
85
+ !!qemu_lock_fd_test(fd, 100 + i, 1, true));
86
+ g_assert_cmpint(shared_perm_expected, ==,
87
+ !!qemu_lock_fd_test(fd, 200 + i, 1, true));
88
+ }
89
+}
90
+
91
+static void test_image_locking_basic(void)
92
+{
93
+ BlockBackend *blk1, *blk2, *blk3;
94
+ char img_path[] = "/tmp/qtest.XXXXXX";
95
+ uint64_t perm, shared_perm;
96
+
97
+ int fd = mkstemp(img_path);
98
+ assert(fd >= 0);
99
+
100
+ perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ;
101
+ shared_perm = BLK_PERM_ALL;
102
+ blk1 = open_image(img_path, perm, shared_perm, &error_abort);
103
+ g_assert(blk1);
104
+
105
+ check_locked_bytes(fd, perm, ~shared_perm);
106
+
107
+ /* compatible perm between blk1 and blk2 */
108
+ blk2 = open_image(img_path, perm | BLK_PERM_RESIZE, shared_perm, NULL);
109
+ g_assert(blk2);
110
+ check_locked_bytes(fd, perm | BLK_PERM_RESIZE, ~shared_perm);
111
+
112
+ /* incompatible perm with already open blk1 and blk2 */
113
+ blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, NULL);
114
+ g_assert_null(blk3);
115
+
116
+ blk_unref(blk2);
117
+
118
+ /* Check that extra bytes in blk2 are correctly unlocked */
119
+ check_locked_bytes(fd, perm, ~shared_perm);
120
+
121
+ blk_unref(blk1);
122
+
123
+ /* Image is unused, no lock there */
124
+ check_locked_bytes(fd, 0, 0);
125
+ blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, &error_abort);
126
+ g_assert(blk3);
127
+ blk_unref(blk3);
128
+ close(fd);
129
+ unlink(img_path);
130
+}
131
+
132
+static void test_set_perm_abort(void)
133
+{
134
+ BlockBackend *blk1, *blk2;
135
+ char img_path[] = "/tmp/qtest.XXXXXX";
136
+ uint64_t perm, shared_perm;
137
+ int r;
138
+ int fd = mkstemp(img_path);
139
+ assert(fd >= 0);
140
+
141
+ perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ;
142
+ shared_perm = BLK_PERM_ALL;
143
+ blk1 = open_image(img_path, perm, shared_perm, &error_abort);
144
+ g_assert(blk1);
145
+
146
+ blk2 = open_image(img_path, perm, shared_perm, &error_abort);
147
+ g_assert(blk2);
148
+
149
+ check_locked_bytes(fd, perm, ~shared_perm);
150
+
151
+ /* A failed blk_set_perm mustn't change perm status (locked bytes) */
152
+ r = blk_set_perm(blk2, perm | BLK_PERM_RESIZE, BLK_PERM_WRITE_UNCHANGED,
153
+ NULL);
154
+ g_assert_cmpint(r, !=, 0);
155
+ check_locked_bytes(fd, perm, ~shared_perm);
156
+ blk_unref(blk1);
157
+ blk_unref(blk2);
158
+}
159
+
160
+int main(int argc, char **argv)
161
+{
162
+ bdrv_init();
163
+ qemu_init_main_loop(&error_abort);
164
+
165
+ g_test_init(&argc, &argv, NULL);
166
+
167
+ if (qemu_has_ofd_lock()) {
168
+ g_test_add_func("/image-locking/basic", test_image_locking_basic);
169
+ g_test_add_func("/image-locking/set-perm-abort", test_set_perm_abort);
170
+ }
171
+
172
+ return g_test_run();
173
+}
174
diff --git a/tests/Makefile.include b/tests/Makefile.include
175
index XXXXXXX..XXXXXXX 100644
176
--- a/tests/Makefile.include
177
+++ b/tests/Makefile.include
178
@@ -XXX,XX +XXX,XX @@ check-unit-y += tests/test-bdrv-drain$(EXESUF)
179
check-unit-y += tests/test-blockjob$(EXESUF)
180
check-unit-y += tests/test-blockjob-txn$(EXESUF)
181
check-unit-y += tests/test-block-backend$(EXESUF)
182
+check-unit-y += tests/test-image-locking$(EXESUF)
183
check-unit-y += tests/test-x86-cpuid$(EXESUF)
184
# all code tested by test-x86-cpuid is inside topology.h
185
ifeq ($(CONFIG_SOFTMMU),y)
186
@@ -XXX,XX +XXX,XX @@ tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(te
187
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
188
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
189
tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y)
190
+tests/test-image-locking$(EXESUF): tests/test-image-locking.o $(test-block-obj-y) $(test-util-obj-y)
191
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
192
tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
193
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
194
--
231
--
195
2.19.1
232
2.31.1
196
233
197
234
diff view generated by jsdifflib
1
From: Liam Merwick <Liam.Merwick@oracle.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
The commit for 0e4e4318eaa5 increments QCOW2_OL_MAX_BITNR but does not
3
In most of the block layer, especially when traversing down from other
4
add an array entry for QCOW2_OL_BITMAP_DIRECTORY_BITNR to metadata_ol_names[].
4
BlockDriverStates, we assume that BdrvChild.bs can never be NULL. When
5
As a result, an array dereference of metadata_ol_names[8] in
5
it becomes NULL, it is expected that the corresponding BdrvChild pointer
6
qcow2_pre_write_overlap_check() could result in a read outside of the array bounds.
6
also becomes NULL and the BdrvChild object is freed.
7
7
8
Fixes: 0e4e4318eaa5 ('qcow2: add overlap check for bitmap directory')
8
Therefore, once bdrv_replace_child_noperm() sets the BdrvChild.bs
9
9
pointer to NULL, it should also immediately set the corresponding
10
Cc: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
BdrvChild pointer (like bs->file or bs->backing) to NULL.
11
Signed-off-by: Liam Merwick <Liam.Merwick@oracle.com>
11
12
Reviewed-by: Eric Blake <eblake@redhat.com>
12
In that context, it also makes sense for this function to free the
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
child. Sometimes we cannot do so, though, because it is called in a
14
Message-id: 1541453919-25973-6-git-send-email-Liam.Merwick@oracle.com
14
transactional context where the caller might still want to reinstate the
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
child in the abort branch (and free it only on commit), so this behavior
16
has to remain optional.
17
18
In bdrv_replace_child_tran()'s abort handler, we now rely on the fact
19
that the BdrvChild passed to bdrv_replace_child_tran() must have had a
20
non-NULL .bs pointer initially. Make a note of that and assert it.
21
22
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
23
Message-Id: <20211111120829.81329-10-hreitz@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
25
---
17
block/qcow2-refcount.c | 18 ++++++++++--------
26
block.c | 102 +++++++++++++++++++++++++++++++++++++++++++-------------
18
1 file changed, 10 insertions(+), 8 deletions(-)
27
1 file changed, 79 insertions(+), 23 deletions(-)
19
28
20
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
29
diff --git a/block.c b/block.c
21
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
22
--- a/block/qcow2-refcount.c
31
--- a/block.c
23
+++ b/block/qcow2-refcount.c
32
+++ b/block.c
24
@@ -XXX,XX +XXX,XX @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
33
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
25
}
34
static bool bdrv_recurse_has_child(BlockDriverState *bs,
26
35
BlockDriverState *child);
27
static const char *metadata_ol_names[] = {
36
28
- [QCOW2_OL_MAIN_HEADER_BITNR] = "qcow2_header",
37
+static void bdrv_child_free(BdrvChild *child);
29
- [QCOW2_OL_ACTIVE_L1_BITNR] = "active L1 table",
38
static void bdrv_replace_child_noperm(BdrvChild **child,
30
- [QCOW2_OL_ACTIVE_L2_BITNR] = "active L2 table",
39
- BlockDriverState *new_bs);
31
- [QCOW2_OL_REFCOUNT_TABLE_BITNR] = "refcount table",
40
+ BlockDriverState *new_bs,
32
- [QCOW2_OL_REFCOUNT_BLOCK_BITNR] = "refcount block",
41
+ bool free_empty_child);
33
- [QCOW2_OL_SNAPSHOT_TABLE_BITNR] = "snapshot table",
42
static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
34
- [QCOW2_OL_INACTIVE_L1_BITNR] = "inactive L1 table",
43
BdrvChild *child,
35
- [QCOW2_OL_INACTIVE_L2_BITNR] = "inactive L2 table",
44
Transaction *tran);
36
+ [QCOW2_OL_MAIN_HEADER_BITNR] = "qcow2_header",
45
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvReplaceChildState {
37
+ [QCOW2_OL_ACTIVE_L1_BITNR] = "active L1 table",
46
BdrvChild *child;
38
+ [QCOW2_OL_ACTIVE_L2_BITNR] = "active L2 table",
47
BdrvChild **childp;
39
+ [QCOW2_OL_REFCOUNT_TABLE_BITNR] = "refcount table",
48
BlockDriverState *old_bs;
40
+ [QCOW2_OL_REFCOUNT_BLOCK_BITNR] = "refcount block",
49
+ bool free_empty_child;
41
+ [QCOW2_OL_SNAPSHOT_TABLE_BITNR] = "snapshot table",
50
} BdrvReplaceChildState;
42
+ [QCOW2_OL_INACTIVE_L1_BITNR] = "inactive L1 table",
51
43
+ [QCOW2_OL_INACTIVE_L2_BITNR] = "inactive L2 table",
52
static void bdrv_replace_child_commit(void *opaque)
44
+ [QCOW2_OL_BITMAP_DIRECTORY_BITNR] = "bitmap directory",
53
{
45
};
54
BdrvReplaceChildState *s = opaque;
46
+QEMU_BUILD_BUG_ON(QCOW2_OL_MAX_BITNR != ARRAY_SIZE(metadata_ol_names));
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
}
47
255
48
/*
256
/*
49
* First performs a check for metadata overlaps (through
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);
50
--
277
--
51
2.19.1
278
2.31.1
52
279
53
280
diff view generated by jsdifflib
1
From: Li Qiang <liq3ea@gmail.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
Currently, when hotplug/unhotplug nvme device, it will cause an
3
See the comment for why this is necessary.
4
assert in object.c. Following is the backtrack:
5
4
6
ERROR:qom/object.c:981:object_unref: assertion failed: (obj->ref > 0)
5
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
6
Message-Id: <20211111120829.81329-11-hreitz@redhat.com>
8
Thread 2 "qemu-system-x86" received signal SIGABRT, Aborted.
9
[Switching to Thread 0x7fffcbd32700 (LWP 18844)]
10
0x00007fffdb9e4fff in raise () from /lib/x86_64-linux-gnu/libc.so.6
11
(gdb) bt
12
/lib/x86_64-linux-gnu/libglib-2.0.so.0
13
/lib/x86_64-linux-gnu/libglib-2.0.so.0
14
qom/object.c:981
15
/home/liqiang02/qemu-upstream/qemu/memory.c:1732
16
/home/liqiang02/qemu-upstream/qemu/memory.c:285
17
util/qemu-thread-posix.c:504
18
/lib/x86_64-linux-gnu/libpthread.so.0
19
20
This is caused by memory_region_unref in nvme_exit.
21
22
Remove it to make the PCIdevice refcount correct.
23
24
Signed-off-by: Li Qiang <liq3ea@gmail.com>
25
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
---
8
---
28
hw/block/nvme.c | 3 ---
9
tests/qemu-iotests/030 | 11 ++++++++++-
29
1 file changed, 3 deletions(-)
10
1 file changed, 10 insertions(+), 1 deletion(-)
30
11
31
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
12
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
32
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100755
33
--- a/hw/block/nvme.c
14
--- a/tests/qemu-iotests/030
34
+++ b/hw/block/nvme.c
15
+++ b/tests/qemu-iotests/030
35
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
16
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
36
g_free(n->namespaces);
17
speed=1024)
37
g_free(n->cq);
18
self.assert_qmp(result, 'return', {})
38
g_free(n->sq);
19
39
- if (n->cmbsz) {
20
- for job in pending_jobs:
40
- memory_region_unref(&n->ctrl_mem);
21
+ # Do this in reverse: After unthrottling them, some jobs may finish
41
- }
22
+ # before we have unthrottled all of them. This will drain their
42
23
+ # subgraph, and this will make jobs above them advance (despite those
43
msix_uninit_exclusive_bar(pci_dev);
24
+ # jobs on top being throttled). In the worst case, all jobs below the
44
}
25
+ # top one are finished before we can unthrottle it, and this makes it
26
+ # advance so far that it completes before we can unthrottle it - which
27
+ # results in an error.
28
+ # Starting from the top (i.e. in reverse) does not have this problem:
29
+ # When a job finishes, the ones below it are not advanced.
30
+ for job in reversed(pending_jobs):
31
result = self.vm.qmp('block-job-set-speed', device=job, speed=0)
32
self.assert_qmp(result, 'return', {})
33
45
--
34
--
46
2.19.1
35
2.31.1
47
36
48
37
diff view generated by jsdifflib
1
From: Li Qiang <liq3ea@gmail.com>
1
While introducing a non-QemuOpts code path for device creation for JSON
2
-device, we noticed that QMP device_add doesn't check its input
3
correctly (accepting arguments that should have been rejected), and that
4
users may be relying on this behaviour (libvirt did until it was fixed
5
recently).
2
6
3
This avoid a memory leak in unhotplug nvme device.
7
Let's use a deprecation period before we fix this bug in QEMU to avoid
8
nasty surprises for users.
4
9
5
Signed-off-by: Li Qiang <liq3ea@gmail.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
11
Message-Id: <20211111143530.18985-1-kwolf@redhat.com>
12
Reviewed-by: Markus Armbruster <armbru@redhat.com>
13
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
15
---
9
hw/block/nvme.c | 3 +++
16
docs/about/deprecated.rst | 14 ++++++++++++++
10
1 file changed, 3 insertions(+)
17
1 file changed, 14 insertions(+)
11
18
12
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
19
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
13
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/block/nvme.c
21
--- a/docs/about/deprecated.rst
15
+++ b/hw/block/nvme.c
22
+++ b/docs/about/deprecated.rst
16
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
23
@@ -XXX,XX +XXX,XX @@ options are removed in favor of using explicit ``blockdev-create`` and
17
g_free(n->cq);
24
``blockdev-add`` calls. See :doc:`/interop/live-block-operations` for
18
g_free(n->sq);
25
details.
19
26
20
+ if (n->cmb_size_mb) {
27
+Incorrectly typed ``device_add`` arguments (since 6.2)
21
+ g_free(n->cmbuf);
28
+''''''''''''''''''''''''''''''''''''''''''''''''''''''
22
+ }
29
+
23
msix_uninit_exclusive_bar(pci_dev);
30
+Due to shortcomings in the internal implementation of ``device_add``, QEMU
24
}
31
+incorrectly accepts certain invalid arguments: Any object or list arguments are
32
+silently ignored. Other argument types are not checked, but an implicit
33
+conversion happens, so that e.g. string values can be assigned to integer
34
+device properties or vice versa.
35
+
36
+This is a bug in QEMU that will be fixed in the future so that previously
37
+accepted incorrect commands will return an error. Users should make sure that
38
+all arguments passed to ``device_add`` are consistent with the documented
39
+property types.
40
+
41
System accelerators
42
-------------------
25
43
26
--
44
--
27
2.19.1
45
2.31.1
28
46
29
47
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
At the end of a reopen, we already call bdrv_refresh_limits(), which
2
should update bs->request_alignment according to the new file
3
descriptor. However, raw_probe_alignment() relies on s->needs_alignment
4
and just uses 1 if it isn't set. We neglected to update this field, so
5
starting with cache=writeback and then reopening with cache=none means
6
that we get an incorrect bs->request_alignment == 1 and unaligned
7
requests fail instead of being automatically aligned.
2
8
3
If we know we've already locked the bytes, don't do it again; similarly
9
Fix this by recalculating s->needs_alignment in raw_refresh_limits()
4
don't unlock a byte if we haven't locked it. This doesn't change the
10
before calling raw_probe_alignment().
5
behavior, but fixes a corner case explained below.
6
11
7
Libvirt had an error handling bug that an image can get its (ownership,
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
file mode, SELinux) permissions changed (RHBZ 1584982) by mistake behind
13
Message-Id: <20211104113109.56336-1-kwolf@redhat.com>
9
QEMU. Specifically, an image in use by Libvirt VM has:
14
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
10
15
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
11
$ ls -lhZ b.img
12
-rw-r--r--. qemu qemu system_u:object_r:svirt_image_t:s0:c600,c690 b.img
13
14
Trying to attach it a second time won't work because of image locking.
15
And after the error, it becomes:
16
17
$ ls -lhZ b.img
18
-rw-r--r--. root root system_u:object_r:virt_image_t:s0 b.img
19
20
Then, we won't be able to do OFD lock operations with the existing fd.
21
In other words, the code such as in blk_detach_dev:
22
23
blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort);
24
25
can abort() QEMU, out of environmental changes.
26
27
This patch is an easy fix to this and the change is regardlessly
28
reasonable, so do it.
29
30
Signed-off-by: Fam Zheng <famz@redhat.com>
31
Reviewed-by: Max Reitz <mreitz@redhat.com>
32
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
33
---
17
---
34
block/file-posix.c | 54 +++++++++++++++++++++++++++++++++++++---------
18
block/file-posix.c | 20 ++++++++++++++++----
35
1 file changed, 44 insertions(+), 10 deletions(-)
19
tests/qemu-iotests/142 | 22 ++++++++++++++++++++++
20
tests/qemu-iotests/142.out | 15 +++++++++++++++
21
3 files changed, 53 insertions(+), 4 deletions(-)
36
22
37
diff --git a/block/file-posix.c b/block/file-posix.c
23
diff --git a/block/file-posix.c b/block/file-posix.c
38
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
39
--- a/block/file-posix.c
25
--- a/block/file-posix.c
40
+++ b/block/file-posix.c
26
+++ b/block/file-posix.c
41
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState {
27
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState {
42
uint64_t perm;
28
int page_cache_inconsistent; /* errno from fdatasync failure */
43
uint64_t shared_perm;
29
bool has_fallocate;
44
30
bool needs_alignment;
45
+ /* The perms bits whose corresponding bytes are already locked in
31
+ bool force_alignment;
46
+ * s->lock_fd. */
32
bool drop_cache;
47
+ uint64_t locked_perm;
33
bool check_cache_dropped;
48
+ uint64_t locked_shared_perm;
34
struct {
35
@@ -XXX,XX +XXX,XX @@ static bool dio_byte_aligned(int fd)
36
return false;
37
}
38
39
+static bool raw_needs_alignment(BlockDriverState *bs)
40
+{
41
+ BDRVRawState *s = bs->opaque;
49
+
42
+
43
+ if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
44
+ return true;
45
+ }
46
+
47
+ return s->force_alignment;
48
+}
49
+
50
/* Check if read is allowed with given memory buffer and length.
51
*
52
* This function is used to check O_DIRECT memory buffer and request alignment.
53
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
54
55
s->has_discard = true;
56
s->has_write_zeroes = true;
57
- if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
58
- s->needs_alignment = true;
59
- }
60
61
if (fstat(s->fd, &st) < 0) {
62
ret = -errno;
63
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
64
* so QEMU makes sure all IO operations on the device are aligned
65
* to sector size, or else FreeBSD will reject them with EINVAL.
66
*/
67
- s->needs_alignment = true;
68
+ s->force_alignment = true;
69
}
70
#endif
71
+ s->needs_alignment = raw_needs_alignment(bs);
72
50
#ifdef CONFIG_XFS
73
#ifdef CONFIG_XFS
51
bool is_xfs:1;
74
if (platform_test_xfs_fd(s->fd)) {
52
#endif
75
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
53
@@ -XXX,XX +XXX,XX @@ typedef enum {
76
BDRVRawState *s = bs->opaque;
54
* file; if @unlock == true, also unlock the unneeded bytes.
77
struct stat st;
55
* @shared_perm_lock_bits is the mask of all permissions that are NOT shared.
78
56
*/
79
+ s->needs_alignment = raw_needs_alignment(bs);
57
-static int raw_apply_lock_bytes(int fd,
80
raw_probe_alignment(bs, s->fd, errp);
58
+static int raw_apply_lock_bytes(BDRVRawState *s, int fd,
59
uint64_t perm_lock_bits,
60
uint64_t shared_perm_lock_bits,
61
bool unlock, Error **errp)
62
{
63
int ret;
64
int i;
65
+ uint64_t locked_perm, locked_shared_perm;
66
+
81
+
67
+ if (s) {
82
bs->bl.min_mem_alignment = s->buf_align;
68
+ locked_perm = s->locked_perm;
83
bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size);
69
+ locked_shared_perm = s->locked_shared_perm;
84
70
+ } else {
85
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
71
+ /*
86
index XXXXXXX..XXXXXXX 100755
72
+ * We don't have the previous bits, just lock/unlock for each of the
87
--- a/tests/qemu-iotests/142
73
+ * requested bits.
88
+++ b/tests/qemu-iotests/142
74
+ */
89
@@ -XXX,XX +XXX,XX @@ info block backing-file"
75
+ if (unlock) {
90
76
+ locked_perm = BLK_PERM_ALL;
91
echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache"
77
+ locked_shared_perm = BLK_PERM_ALL;
92
78
+ } else {
93
+echo
79
+ locked_perm = 0;
94
+echo "--- Alignment after changing O_DIRECT ---"
80
+ locked_shared_perm = 0;
95
+echo
81
+ }
96
+
82
+ }
97
+# Directly test the protocol level: Can unaligned requests succeed even if
83
98
+# O_DIRECT was only enabled through a reopen and vice versa?
84
PERM_FOREACH(i) {
99
+
85
int off = RAW_LOCK_PERM_BASE + i;
100
+$QEMU_IO --cache=writeback -f file $TEST_IMG <<EOF | _filter_qemu_io
86
- if (perm_lock_bits & (1ULL << i)) {
101
+read 42 42
87
+ uint64_t bit = (1ULL << i);
102
+reopen -o cache.direct=on
88
+ if ((perm_lock_bits & bit) && !(locked_perm & bit)) {
103
+read 42 42
89
ret = qemu_lock_fd(fd, off, 1, false);
104
+reopen -o cache.direct=off
90
if (ret) {
105
+read 42 42
91
error_setg(errp, "Failed to lock byte %d", off);
106
+EOF
92
return ret;
107
+$QEMU_IO --cache=none -f file $TEST_IMG <<EOF | _filter_qemu_io
93
+ } else if (s) {
108
+read 42 42
94
+ s->locked_perm |= bit;
109
+reopen -o cache.direct=off
95
}
110
+read 42 42
96
- } else if (unlock) {
111
+reopen -o cache.direct=on
97
+ } else if (unlock && (locked_perm & bit) && !(perm_lock_bits & bit)) {
112
+read 42 42
98
ret = qemu_unlock_fd(fd, off, 1);
113
+EOF
99
if (ret) {
114
+
100
error_setg(errp, "Failed to unlock byte %d", off);
115
# success, all done
101
return ret;
116
echo "*** done"
102
+ } else if (s) {
117
rm -f $seq.full
103
+ s->locked_perm &= ~bit;
118
diff --git a/tests/qemu-iotests/142.out b/tests/qemu-iotests/142.out
104
}
119
index XXXXXXX..XXXXXXX 100644
105
}
120
--- a/tests/qemu-iotests/142.out
106
}
121
+++ b/tests/qemu-iotests/142.out
107
PERM_FOREACH(i) {
122
@@ -XXX,XX +XXX,XX @@ cache.no-flush=on on backing-file
108
int off = RAW_LOCK_SHARED_BASE + i;
123
Cache mode: writeback
109
- if (shared_perm_lock_bits & (1ULL << i)) {
124
Cache mode: writeback, direct
110
+ uint64_t bit = (1ULL << i);
125
Cache mode: writeback, ignore flushes
111
+ if ((shared_perm_lock_bits & bit) && !(locked_shared_perm & bit)) {
126
+
112
ret = qemu_lock_fd(fd, off, 1, false);
127
+--- Alignment after changing O_DIRECT ---
113
if (ret) {
128
+
114
error_setg(errp, "Failed to lock byte %d", off);
129
+read 42/42 bytes at offset 42
115
return ret;
130
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
116
+ } else if (s) {
131
+read 42/42 bytes at offset 42
117
+ s->locked_shared_perm |= bit;
132
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
118
}
133
+read 42/42 bytes at offset 42
119
- } else if (unlock) {
134
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
120
+ } else if (unlock && (locked_shared_perm & bit) &&
135
+read 42/42 bytes at offset 42
121
+ !(shared_perm_lock_bits & bit)) {
136
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
122
ret = qemu_unlock_fd(fd, off, 1);
137
+read 42/42 bytes at offset 42
123
if (ret) {
138
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
124
error_setg(errp, "Failed to unlock byte %d", off);
139
+read 42/42 bytes at offset 42
125
return ret;
140
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
126
+ } else if (s) {
141
*** done
127
+ s->locked_shared_perm &= ~bit;
128
}
129
}
130
}
131
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
132
133
switch (op) {
134
case RAW_PL_PREPARE:
135
- ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm,
136
+ ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm,
137
~s->shared_perm | ~new_shared,
138
false, errp);
139
if (!ret) {
140
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
141
op = RAW_PL_ABORT;
142
/* fall through to unlock bytes. */
143
case RAW_PL_ABORT:
144
- raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm,
145
+ raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm,
146
true, &local_err);
147
if (local_err) {
148
/* Theoretically the above call only unlocks bytes and it cannot
149
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
150
}
151
break;
152
case RAW_PL_COMMIT:
153
- raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared,
154
+ raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared,
155
true, &local_err);
156
if (local_err) {
157
/* Theoretically the above call only unlocks bytes and it cannot
158
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
159
shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
160
161
/* Step one: Take locks */
162
- result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp);
163
+ result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp);
164
if (result < 0) {
165
goto out_close;
166
}
167
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
168
}
169
170
out_unlock:
171
- raw_apply_lock_bytes(fd, 0, 0, true, &local_err);
172
+ raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err);
173
if (local_err) {
174
/* The above call should not fail, and if it does, that does
175
* not mean the whole creation operation has failed. So
176
--
142
--
177
2.19.1
143
2.31.1
178
144
179
145
diff view generated by jsdifflib
1
From: Peter Maydell <peter.maydell@linaro.org>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
In the function external_snapshot_prepare() we have a
3
Reported by Coverity (CID 1465222).
4
BlockdevSnapshotSync struct, which has the usual combination
5
of has_snapshot_node_name and snapshot_node_name fields for an
6
optional field. We set up a local variable
7
const char *snapshot_node_name =
8
s->has_snapshot_node_name ? s->snapshot_node_name : NULL;
9
4
10
and then mostly use "if (!snapshot_node_name)" for checking
5
Fixes: 4a1d937796de0fecd8b22d7dbebf87f38e8282fd ("softmmu/qdev-monitor: add error handling in qdev_set_id")
11
whether we have a snapshot node name. The exception is that in
6
Cc: Damien Hedde <damien.hedde@greensocs.com>
12
one place we check s->has_snapshot_node_name instead. This
7
Cc: Kevin Wolf <kwolf@redhat.com>
13
confuses Coverity (CID 1396473), which thinks it might be
8
Cc: Michael S. Tsirkin <mst@redhat.com>
14
possible to get here with s->has_snapshot_node_name true but
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
snapshot_node_name NULL, and warns that the call to
10
Message-Id: <20211102163342.31162-1-stefanha@redhat.com>
16
qdict_put_str() will segfault in that case.
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17
12
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
18
Make the code consistent and unconfuse Coverity by using
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
19
the same check for this conditional that we do in the rest
14
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
20
of the surrounding code.
15
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
21
16
Reviewed-by: Markus Armbruster <armbru@redhat.com>
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Alberto Garcia <berto@igalia.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
18
---
26
blockdev.c | 2 +-
19
softmmu/qdev-monitor.c | 2 +-
27
1 file changed, 1 insertion(+), 1 deletion(-)
20
1 file changed, 1 insertion(+), 1 deletion(-)
28
21
29
diff --git a/blockdev.c b/blockdev.c
22
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
30
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
31
--- a/blockdev.c
24
--- a/softmmu/qdev-monitor.c
32
+++ b/blockdev.c
25
+++ b/softmmu/qdev-monitor.c
33
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
26
@@ -XXX,XX +XXX,XX @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
27
if (prop) {
28
dev->id = id;
29
} else {
30
- g_free(id);
31
error_setg(errp, "Duplicate device ID '%s'", id);
32
+ g_free(id);
33
return NULL;
34
}
34
}
35
35
} else {
36
options = qdict_new();
37
- if (s->has_snapshot_node_name) {
38
+ if (snapshot_node_name) {
39
qdict_put_str(options, "node-name", snapshot_node_name);
40
}
41
qdict_put_str(options, "driver", format);
42
--
36
--
43
2.19.1
37
2.31.1
44
38
45
39
diff view generated by jsdifflib
Deleted patch
1
From: Jeff Cody <jcody@redhat.com>
2
1
3
This adds configure options to control the following block drivers:
4
5
* Bochs
6
* Cloop
7
* Dmg
8
* Qcow (V1)
9
* Vdi
10
* Vvfat
11
* qed
12
* parallels
13
* sheepdog
14
15
Each of these defaults to being enabled.
16
17
Signed-off-by: Jeff Cody <jcody@redhat.com>
18
Signed-off-by: Markus Armbruster <armbru@redhat.com>
19
Message-id: 20181107063644.2254-1-armbru@redhat.com
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
---
22
configure | 91 +++++++++++++++++++++++++++++++++++++++++++++
23
block/Makefile.objs | 22 ++++++++---
24
2 files changed, 107 insertions(+), 6 deletions(-)
25
26
diff --git a/configure b/configure
27
index XXXXXXX..XXXXXXX 100755
28
--- a/configure
29
+++ b/configure
30
@@ -XXX,XX +XXX,XX @@ tcmalloc="no"
31
jemalloc="no"
32
replication="yes"
33
vxhs=""
34
+bochs="yes"
35
+cloop="yes"
36
+dmg="yes"
37
+qcow1="yes"
38
+vdi="yes"
39
+vvfat="yes"
40
+qed="yes"
41
+parallels="yes"
42
+sheepdog="yes"
43
libxml2=""
44
docker="no"
45
debug_mutex="no"
46
@@ -XXX,XX +XXX,XX @@ for opt do
47
;;
48
--enable-vxhs) vxhs="yes"
49
;;
50
+ --disable-bochs) bochs="no"
51
+ ;;
52
+ --enable-bochs) bochs="yes"
53
+ ;;
54
+ --disable-cloop) cloop="no"
55
+ ;;
56
+ --enable-cloop) cloop="yes"
57
+ ;;
58
+ --disable-dmg) dmg="no"
59
+ ;;
60
+ --enable-dmg) dmg="yes"
61
+ ;;
62
+ --disable-qcow1) qcow1="no"
63
+ ;;
64
+ --enable-qcow1) qcow1="yes"
65
+ ;;
66
+ --disable-vdi) vdi="no"
67
+ ;;
68
+ --enable-vdi) vdi="yes"
69
+ ;;
70
+ --disable-vvfat) vvfat="no"
71
+ ;;
72
+ --enable-vvfat) vvfat="yes"
73
+ ;;
74
+ --disable-qed) qed="no"
75
+ ;;
76
+ --enable-qed) qed="yes"
77
+ ;;
78
+ --disable-parallels) parallels="no"
79
+ ;;
80
+ --enable-parallels) parallels="yes"
81
+ ;;
82
+ --disable-sheepdog) sheepdog="no"
83
+ ;;
84
+ --enable-sheepdog) sheepdog="yes"
85
+ ;;
86
--disable-vhost-user) vhost_user="no"
87
;;
88
--enable-vhost-user)
89
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available:
90
qom-cast-debug cast debugging support
91
tools build qemu-io, qemu-nbd and qemu-image tools
92
vxhs Veritas HyperScale vDisk backend support
93
+ bochs bochs image format support
94
+ cloop cloop image format support
95
+ dmg dmg image format support
96
+ qcow1 qcow v1 image format support
97
+ vdi vdi image format support
98
+ vvfat vvfat image format support
99
+ qed qed image format support
100
+ parallels parallels image format support
101
+ sheepdog sheepdog block driver support
102
crypto-afalg Linux AF_ALG crypto backend driver
103
vhost-user vhost-user support
104
capstone capstone disassembler support
105
@@ -XXX,XX +XXX,XX @@ echo "jemalloc support $jemalloc"
106
echo "avx2 optimization $avx2_opt"
107
echo "replication support $replication"
108
echo "VxHS block device $vxhs"
109
+echo "bochs support $bochs"
110
+echo "cloop support $cloop"
111
+echo "dmg support $dmg"
112
+echo "qcow v1 support $qcow1"
113
+echo "vdi support $vdi"
114
+echo "vvfat support $vvfat"
115
+echo "qed support $qed"
116
+echo "parallels support $parallels"
117
+echo "sheepdog support $sheepdog"
118
echo "capstone $capstone"
119
echo "docker $docker"
120
echo "libpmem support $libpmem"
121
@@ -XXX,XX +XXX,XX @@ if test "$libpmem" = "yes" ; then
122
echo "CONFIG_LIBPMEM=y" >> $config_host_mak
123
fi
124
125
+if test "$bochs" = "yes" ; then
126
+ echo "CONFIG_BOCHS=y" >> $config_host_mak
127
+fi
128
+if test "$cloop" = "yes" ; then
129
+ echo "CONFIG_CLOOP=y" >> $config_host_mak
130
+fi
131
+if test "$dmg" = "yes" ; then
132
+ echo "CONFIG_DMG=y" >> $config_host_mak
133
+fi
134
+if test "$qcow1" = "yes" ; then
135
+ echo "CONFIG_QCOW1=y" >> $config_host_mak
136
+fi
137
+if test "$vdi" = "yes" ; then
138
+ echo "CONFIG_VDI=y" >> $config_host_mak
139
+fi
140
+if test "$vvfat" = "yes" ; then
141
+ echo "CONFIG_VVFAT=y" >> $config_host_mak
142
+fi
143
+if test "$qed" = "yes" ; then
144
+ echo "CONFIG_QED=y" >> $config_host_mak
145
+fi
146
+if test "$parallels" = "yes" ; then
147
+ echo "CONFIG_PARALLELS=y" >> $config_host_mak
148
+fi
149
+if test "$sheepdog" = "yes" ; then
150
+ echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
151
+fi
152
+
153
if test "$tcg_interpreter" = "yes"; then
154
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
155
elif test "$ARCH" = "sparc64" ; then
156
diff --git a/block/Makefile.objs b/block/Makefile.objs
157
index XXXXXXX..XXXXXXX 100644
158
--- a/block/Makefile.objs
159
+++ b/block/Makefile.objs
160
@@ -XXX,XX +XXX,XX @@
161
-block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
162
+block-obj-y += raw-format.o vmdk.o vpc.o
163
+block-obj-$(CONFIG_QCOW1) += qcow.o
164
+block-obj-$(CONFIG_VDI) += vdi.o
165
+block-obj-$(CONFIG_CLOOP) += cloop.o
166
+block-obj-$(CONFIG_BOCHS) += bochs.o
167
+block-obj-$(CONFIG_VVFAT) += vvfat.o
168
+block-obj-$(CONFIG_DMG) += dmg.o
169
+
170
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
171
-block-obj-y += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
172
-block-obj-y += qed-check.o
173
+block-obj-$(CONFIG_QED) += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
174
+block-obj-$(CONFIG_QED) += qed-check.o
175
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
176
block-obj-y += quorum.o
177
-block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
178
+block-obj-y += blkdebug.o blkverify.o blkreplay.o
179
+block-obj-$(CONFIG_PARALLELS) += parallels.o
180
block-obj-y += blklogwrites.o
181
block-obj-y += block-backend.o snapshot.o qapi.o
182
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
183
@@ -XXX,XX +XXX,XX @@ block-obj-y += null.o mirror.o commit.o io.o create.o
184
block-obj-y += throttle-groups.o
185
block-obj-$(CONFIG_LINUX) += nvme.o
186
187
-block-obj-y += nbd.o nbd-client.o sheepdog.o
188
+block-obj-y += nbd.o nbd-client.o
189
+block-obj-$(CONFIG_SHEEPDOG) += sheepdog.o
190
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
191
block-obj-$(if $(CONFIG_LIBISCSI),y,n) += iscsi-opts.o
192
block-obj-$(CONFIG_LIBNFS) += nfs.o
193
@@ -XXX,XX +XXX,XX @@ gluster.o-libs := $(GLUSTERFS_LIBS)
194
vxhs.o-libs := $(VXHS_LIBS)
195
ssh.o-cflags := $(LIBSSH2_CFLAGS)
196
ssh.o-libs := $(LIBSSH2_LIBS)
197
-block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
198
+block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
199
+block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y)
200
dmg-bz2.o-libs := $(BZIP2_LIBS)
201
qcow.o-libs := -lz
202
linux-aio.o-libs := -laio
203
--
204
2.19.1
205
206
diff view generated by jsdifflib