1
The following changes since commit 19b599f7664b2ebfd0f405fb79c14dd241557452:
1
The following changes since commit 2d2c73d0e3d504a61f868e46e6abd5643f38091b:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-error-2018-08-27-v2' into staging (2018-08-27 16:44:20 +0100)
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20200914-1' into staging (2020-09-14 16:03:08 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://git.xanclic.moe/XanClic/qemu.git tags/pull-block-2018-08-31
7
https://github.com/XanClic/qemu.git tags/pull-block-2020-09-15
8
8
9
for you to fetch changes up to 40954cc7831c4f95f9ce6402ae3d6761f44f31ff:
9
for you to fetch changes up to 7bae7c805d82675eb3a02c744093703d84ada2d6:
10
10
11
jobs: remove job_defer_to_main_loop (2018-08-31 16:11:27 +0200)
11
block/rbd: add 'namespace' to qemu_rbd_strong_runtime_opts[] (2020-09-15 11:31:10 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Block patches:
15
- (Block) job exit refactoring, part 1
15
- Several qcow2 fixes and refactorings
16
(removing job_defer_to_main_loop())
16
- Let qemu-img convert try to stay at cluster boundaries
17
- Locking fix for the file-posix block driver
17
- Stable child names for quorum (with x-blockdev-change)
18
- test-bdrv-drain leak fix
18
- Explicitly drop vhdx 4k sector support, as it was never actually
19
working
20
- rbd: Mark @namespace a strong runtime option
21
- iotests.py improvements
22
- Drop unused runtime_opts objects
23
- Skip a test case in 030 when run through make check-block
19
24
20
----------------------------------------------------------------
25
----------------------------------------------------------------
21
Fam Zheng (1):
26
Alberto Garcia (9):
22
file-posix: Skip effectiveless OFD lock operations
27
qcow2: Use macros for the L1, refcount and bitmap table entry sizes
28
qcow2: Fix removal of list members from BDRVQcow2State.cluster_allocs
29
qcow2: Don't check nb_clusters when removing l2meta from the list
30
qcow2: Rewrite the documentation of qcow2_alloc_cluster_offset()
31
qcow2: Handle QCowL2Meta on error in preallocate_co()
32
qcow2: Make qcow2_free_any_clusters() free only one cluster
33
qcow2: Return the original error code in qcow2_co_pwrite_zeroes()
34
qcow2: Make preallocate_co() resize the image to the correct size
35
qcow2: Convert qcow2_alloc_cluster_offset() into
36
qcow2_alloc_host_offset()
23
37
24
John Snow (9):
38
John Snow (2):
25
jobs: change start callback to run callback
39
block/rbd: remove runtime_opts
26
jobs: canonize Error object
40
block/qcow: remove runtime opts
27
jobs: add exit shim
28
block/commit: utilize job_exit shim
29
block/mirror: utilize job_exit shim
30
jobs: utilize job_exit shim
31
block/backup: make function variables consistently named
32
jobs: remove ret argument to job_completed; privatize it
33
jobs: remove job_defer_to_main_loop
34
41
35
Marc-André Lureau (1):
42
Lukas Straub (1):
36
tests: fix bdrv-drain leak
43
block/quorum.c: stable children names
37
44
38
include/qemu/job.h | 70 ++++++++++++++++-----------------
45
Nir Soffer (5):
39
block/backup.c | 81 ++++++++++++++++-----------------------
46
qemu-iotests: Fix FilePaths cleanup
40
block/commit.c | 29 +++++---------
47
qemu-iotests: Fix FilePaths docstring
41
block/create.c | 19 +++------
48
qemu-iotests: Support varargs syntax in FilePaths
42
block/file-posix.c | 41 +++++++++++++++-----
49
qemu-iotests: Merge FilePaths and FilePath
43
block/mirror.c | 39 ++++++++-----------
50
qemu-iotests: Simplify FilePath __init__
44
block/stream.c | 29 ++++++--------
51
45
job-qmp.c | 5 ++-
52
Peter Lieven (1):
46
job.c | 73 ++++++++++++-----------------------
53
qemu-img: avoid unaligned read requests during convert
47
tests/test-bdrv-drain.c | 14 +++----
54
48
tests/test-blockjob-txn.c | 25 +++++-------
55
Stefano Garzarella (1):
49
tests/test-blockjob.c | 17 ++++----
56
block/rbd: add 'namespace' to qemu_rbd_strong_runtime_opts[]
50
trace-events | 2 +-
57
51
13 files changed, 192 insertions(+), 252 deletions(-)
58
Swapnil Ingle (1):
59
block/vhdx: Support vhdx image only with 512 bytes logical sector size
60
61
Thomas Huth (1):
62
iotests: Skip test_stream_parallel in test 030 when doing "make check"
63
64
Yi Li (1):
65
qemu-img: Explicit number replaced by a constant
66
67
block/qcow2.h | 16 +++--
68
block/qcow.c | 9 ---
69
block/qcow2-bitmap.c | 11 ++--
70
block/qcow2-cluster.c | 69 ++++++++++++----------
71
block/qcow2-refcount.c | 97 +++++++++++++++---------------
72
block/qcow2-snapshot.c | 20 +++----
73
block/qcow2.c | 108 ++++++++++++++--------------------
74
block/quorum.c | 20 +++++--
75
block/rbd.c | 43 +-------------
76
block/vhdx.c | 6 +-
77
qemu-img.c | 32 ++++++++--
78
tests/check-block.sh | 3 +
79
tests/qemu-iotests/030 | 2 +
80
tests/qemu-iotests/125 | 44 ++++++++------
81
tests/qemu-iotests/125.out | 28 ++++++++-
82
tests/qemu-iotests/194 | 4 +-
83
tests/qemu-iotests/208 | 2 +-
84
tests/qemu-iotests/222 | 2 +-
85
tests/qemu-iotests/251 | 7 ++-
86
tests/qemu-iotests/257 | 10 ++--
87
tests/qemu-iotests/305 | 74 +++++++++++++++++++++++
88
tests/qemu-iotests/305.out | 16 +++++
89
tests/qemu-iotests/group | 1 +
90
tests/qemu-iotests/iotests.py | 53 +++++++++--------
91
24 files changed, 395 insertions(+), 282 deletions(-)
92
create mode 100755 tests/qemu-iotests/305
93
create mode 100644 tests/qemu-iotests/305.out
52
94
53
--
95
--
54
2.17.1
96
2.26.2
55
97
56
98
diff view generated by jsdifflib
New patch
1
From: Nir Soffer <nirsof@gmail.com>
1
2
3
If os.remove() fails to remove one of the paths, for example if the file
4
was removed by the test, the cleanup loop would exit silently, without
5
removing the rest of the files.
6
7
Fixes: de263986b5dc
8
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-Id: <20200828232152.205833-2-nsoffer@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
tests/qemu-iotests/iotests.py | 8 ++++----
14
1 file changed, 4 insertions(+), 4 deletions(-)
15
16
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
17
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/iotests.py
19
+++ b/tests/qemu-iotests/iotests.py
20
@@ -XXX,XX +XXX,XX @@ class FilePaths:
21
return self.paths
22
23
def __exit__(self, exc_type, exc_val, exc_tb):
24
- try:
25
- for path in self.paths:
26
+ for path in self.paths:
27
+ try:
28
os.remove(path)
29
- except OSError:
30
- pass
31
+ except OSError:
32
+ pass
33
return False
34
35
class FilePath(FilePaths):
36
--
37
2.26.2
38
39
diff view generated by jsdifflib
New patch
1
From: Nir Soffer <nirsof@gmail.com>
1
2
3
When this class was extracted from FilePath, the docstring was not
4
updated for generating multiple files, and the example usage was
5
referencing unrelated file.
6
7
While fixing the docstring, add example for creating sockets, which
8
should use iotests.sock_dir instead of the default base_dir.
9
10
Fixes: de263986b5dc
11
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
12
Message-Id: <20200828232152.205833-3-nsoffer@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
tests/qemu-iotests/iotests.py | 19 +++++++++++++------
16
1 file changed, 13 insertions(+), 6 deletions(-)
17
18
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
19
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/iotests.py
21
+++ b/tests/qemu-iotests/iotests.py
22
@@ -XXX,XX +XXX,XX @@ def file_pattern(name):
23
24
class FilePaths:
25
"""
26
- FilePaths is an auto-generated filename that cleans itself up.
27
+ Context manager generating multiple file names. The generated files are
28
+ removed when exiting the context.
29
30
- Use this context manager to generate filenames and ensure that the file
31
- gets deleted::
32
+ Example usage:
33
+
34
+ with FilePaths(['a.img', 'b.img']) as (img_a, img_b):
35
+ # Use img_a and img_b here...
36
+
37
+ # a.img and b.img are automatically removed here.
38
+
39
+ By default images are created in iotests.test_dir. To create sockets use
40
+ iotests.sock_dir:
41
+
42
+ with FilePaths(['a.sock'], base_dir=iotests.sock_dir) as (sock,):
43
44
- with FilePaths(['test.img']) as img_path:
45
- qemu_img('create', img_path, '1G')
46
- # migration_sock_path is automatically deleted
47
"""
48
def __init__(self, names, base_dir=test_dir):
49
self.paths = []
50
--
51
2.26.2
52
53
diff view generated by jsdifflib
New patch
1
From: Nir Soffer <nirsof@gmail.com>
1
2
3
Accept variable number of names instead of a sequence:
4
5
with FilePaths("a", "b", "c") as (a, b, c):
6
7
The disadvantage is that base_dir must be used as kwarg:
8
9
with FilePaths("a", "b", base_dir=soc_dir) as (sock1, sock2):
10
11
But this is more clear and calling optional argument as positional
12
arguments is bad idea anyway.
13
14
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Message-Id: <20200828232152.205833-4-nsoffer@redhat.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
tests/qemu-iotests/194 | 4 ++--
20
tests/qemu-iotests/257 | 10 ++++------
21
tests/qemu-iotests/iotests.py | 8 ++++----
22
3 files changed, 10 insertions(+), 12 deletions(-)
23
24
diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194
25
index XXXXXXX..XXXXXXX 100755
26
--- a/tests/qemu-iotests/194
27
+++ b/tests/qemu-iotests/194
28
@@ -XXX,XX +XXX,XX @@ iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'],
29
30
with iotests.FilePath('source.img') as source_img_path, \
31
iotests.FilePath('dest.img') as dest_img_path, \
32
- iotests.FilePaths(['migration.sock', 'nbd.sock'], iotests.sock_dir) as \
33
- [migration_sock_path, nbd_sock_path], \
34
+ iotests.FilePaths('migration.sock', 'nbd.sock', base_dir=iotests.sock_dir) \
35
+ as (migration_sock_path, nbd_sock_path), \
36
iotests.VM('source') as source_vm, \
37
iotests.VM('dest') as dest_vm:
38
39
diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
40
index XXXXXXX..XXXXXXX 100755
41
--- a/tests/qemu-iotests/257
42
+++ b/tests/qemu-iotests/257
43
@@ -XXX,XX +XXX,XX @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
44
an incomplete backup. Testing limitations prevent
45
testing competing writes.
46
"""
47
- with iotests.FilePaths(['img', 'bsync1', 'bsync2',
48
- 'fbackup0', 'fbackup1', 'fbackup2']) as \
49
- (img_path, bsync1, bsync2,
50
- fbackup0, fbackup1, fbackup2), \
51
+ with iotests.FilePaths(
52
+ 'img', 'bsync1', 'bsync2', 'fbackup0', 'fbackup1', 'fbackup2') as \
53
+ (img_path, bsync1, bsync2, fbackup0, fbackup1, fbackup2), \
54
iotests.VM() as vm:
55
56
mode = "Mode {:s}; Bitmap Sync {:s}".format(msync_mode, bsync_mode)
57
@@ -XXX,XX +XXX,XX @@ def test_backup_api():
58
"""
59
Test malformed and prohibited invocations of the backup API.
60
"""
61
- with iotests.FilePaths(['img', 'bsync1']) as \
62
- (img_path, backup_path), \
63
+ with iotests.FilePaths('img', 'bsync1') as (img_path, backup_path), \
64
iotests.VM() as vm:
65
66
log("\n=== API failure tests ===\n")
67
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
68
index XXXXXXX..XXXXXXX 100644
69
--- a/tests/qemu-iotests/iotests.py
70
+++ b/tests/qemu-iotests/iotests.py
71
@@ -XXX,XX +XXX,XX @@ class FilePaths:
72
73
Example usage:
74
75
- with FilePaths(['a.img', 'b.img']) as (img_a, img_b):
76
+ with FilePaths('a.img', 'b.img') as (img_a, img_b):
77
# Use img_a and img_b here...
78
79
# a.img and b.img are automatically removed here.
80
@@ -XXX,XX +XXX,XX @@ class FilePaths:
81
By default images are created in iotests.test_dir. To create sockets use
82
iotests.sock_dir:
83
84
- with FilePaths(['a.sock'], base_dir=iotests.sock_dir) as (sock,):
85
+ with FilePaths('a.sock', base_dir=iotests.sock_dir) as (sock,):
86
87
"""
88
- def __init__(self, names, base_dir=test_dir):
89
+ def __init__(self, *names, base_dir=test_dir):
90
self.paths = []
91
for name in names:
92
self.paths.append(os.path.join(base_dir, file_pattern(name)))
93
@@ -XXX,XX +XXX,XX @@ class FilePath(FilePaths):
94
FilePath is a specialization of FilePaths that takes a single filename.
95
"""
96
def __init__(self, name, base_dir=test_dir):
97
- super(FilePath, self).__init__([name], base_dir)
98
+ super(FilePath, self).__init__(name, base_dir=base_dir)
99
100
def __enter__(self):
101
return self.paths[0]
102
--
103
2.26.2
104
105
diff view generated by jsdifflib
New patch
1
From: Nir Soffer <nirsof@gmail.com>
1
2
3
FilePath creates now one temporary file:
4
5
with FilePath("a") as a:
6
7
Or more:
8
9
with FilePath("a", "b", "c") as (a, b, c):
10
11
This is also the behavior of the file_path() helper, used by some of the
12
tests. Now we have only 2 helpers for creating temporary files instead
13
of 3.
14
15
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
16
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
Message-Id: <20200828232152.205833-5-nsoffer@redhat.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
tests/qemu-iotests/194 | 2 +-
21
tests/qemu-iotests/208 | 2 +-
22
tests/qemu-iotests/222 | 2 +-
23
tests/qemu-iotests/257 | 4 ++--
24
tests/qemu-iotests/iotests.py | 23 ++++++++++-------------
25
5 files changed, 15 insertions(+), 18 deletions(-)
26
27
diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194
28
index XXXXXXX..XXXXXXX 100755
29
--- a/tests/qemu-iotests/194
30
+++ b/tests/qemu-iotests/194
31
@@ -XXX,XX +XXX,XX @@ iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'],
32
33
with iotests.FilePath('source.img') as source_img_path, \
34
iotests.FilePath('dest.img') as dest_img_path, \
35
- iotests.FilePaths('migration.sock', 'nbd.sock', base_dir=iotests.sock_dir) \
36
+ iotests.FilePath('migration.sock', 'nbd.sock', base_dir=iotests.sock_dir) \
37
as (migration_sock_path, nbd_sock_path), \
38
iotests.VM('source') as source_vm, \
39
iotests.VM('dest') as dest_vm:
40
diff --git a/tests/qemu-iotests/208 b/tests/qemu-iotests/208
41
index XXXXXXX..XXXXXXX 100755
42
--- a/tests/qemu-iotests/208
43
+++ b/tests/qemu-iotests/208
44
@@ -XXX,XX +XXX,XX @@ iotests.script_initialize(supported_fmts=['generic'])
45
46
with iotests.FilePath('disk.img') as disk_img_path, \
47
iotests.FilePath('disk-snapshot.img') as disk_snapshot_img_path, \
48
- iotests.FilePath('nbd.sock', iotests.sock_dir) as nbd_sock_path, \
49
+ iotests.FilePath('nbd.sock', base_dir=iotests.sock_dir) as nbd_sock_path, \
50
iotests.VM() as vm:
51
52
img_size = '10M'
53
diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/222
54
index XXXXXXX..XXXXXXX 100755
55
--- a/tests/qemu-iotests/222
56
+++ b/tests/qemu-iotests/222
57
@@ -XXX,XX +XXX,XX @@ remainder = [("0xd5", "0x108000", "32k"), # Right-end of partial-left [1]
58
59
with iotests.FilePath('base.img') as base_img_path, \
60
iotests.FilePath('fleece.img') as fleece_img_path, \
61
- iotests.FilePath('nbd.sock', iotests.sock_dir) as nbd_sock_path, \
62
+ iotests.FilePath('nbd.sock', base_dir=iotests.sock_dir) as nbd_sock_path, \
63
iotests.VM() as vm:
64
65
log('--- Setting up images ---')
66
diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
67
index XXXXXXX..XXXXXXX 100755
68
--- a/tests/qemu-iotests/257
69
+++ b/tests/qemu-iotests/257
70
@@ -XXX,XX +XXX,XX @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
71
an incomplete backup. Testing limitations prevent
72
testing competing writes.
73
"""
74
- with iotests.FilePaths(
75
+ with iotests.FilePath(
76
'img', 'bsync1', 'bsync2', 'fbackup0', 'fbackup1', 'fbackup2') as \
77
(img_path, bsync1, bsync2, fbackup0, fbackup1, fbackup2), \
78
iotests.VM() as vm:
79
@@ -XXX,XX +XXX,XX @@ def test_backup_api():
80
"""
81
Test malformed and prohibited invocations of the backup API.
82
"""
83
- with iotests.FilePaths('img', 'bsync1') as (img_path, backup_path), \
84
+ with iotests.FilePath('img', 'bsync1') as (img_path, backup_path), \
85
iotests.VM() as vm:
86
87
log("\n=== API failure tests ===\n")
88
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
89
index XXXXXXX..XXXXXXX 100644
90
--- a/tests/qemu-iotests/iotests.py
91
+++ b/tests/qemu-iotests/iotests.py
92
@@ -XXX,XX +XXX,XX @@ class Timeout:
93
def file_pattern(name):
94
return "{0}-{1}".format(os.getpid(), name)
95
96
-class FilePaths:
97
+class FilePath:
98
"""
99
Context manager generating multiple file names. The generated files are
100
removed when exiting the context.
101
102
Example usage:
103
104
- with FilePaths('a.img', 'b.img') as (img_a, img_b):
105
+ with FilePath('a.img', 'b.img') as (img_a, img_b):
106
# Use img_a and img_b here...
107
108
# a.img and b.img are automatically removed here.
109
@@ -XXX,XX +XXX,XX @@ class FilePaths:
110
By default images are created in iotests.test_dir. To create sockets use
111
iotests.sock_dir:
112
113
- with FilePaths('a.sock', base_dir=iotests.sock_dir) as (sock,):
114
+ with FilePath('a.sock', base_dir=iotests.sock_dir) as sock:
115
+
116
+ For convenience, calling with one argument yields a single file instead of
117
+ a tuple with one item.
118
119
"""
120
def __init__(self, *names, base_dir=test_dir):
121
@@ -XXX,XX +XXX,XX @@ class FilePaths:
122
self.paths.append(os.path.join(base_dir, file_pattern(name)))
123
124
def __enter__(self):
125
- return self.paths
126
+ if len(self.paths) == 1:
127
+ return self.paths[0]
128
+ else:
129
+ return self.paths
130
131
def __exit__(self, exc_type, exc_val, exc_tb):
132
for path in self.paths:
133
@@ -XXX,XX +XXX,XX @@ class FilePaths:
134
pass
135
return False
136
137
-class FilePath(FilePaths):
138
- """
139
- FilePath is a specialization of FilePaths that takes a single filename.
140
- """
141
- def __init__(self, name, base_dir=test_dir):
142
- super(FilePath, self).__init__(name, base_dir=base_dir)
143
-
144
- def __enter__(self):
145
- return self.paths[0]
146
147
def file_path_remover():
148
for path in reversed(file_path_remover.paths):
149
--
150
2.26.2
151
152
diff view generated by jsdifflib
New patch
1
From: Nir Soffer <nirsof@gmail.com>
1
2
3
Use list comprehension instead of append loop.
4
5
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-Id: <20200828232152.205833-6-nsoffer@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/iotests.py | 5 ++---
11
1 file changed, 2 insertions(+), 3 deletions(-)
12
13
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/iotests.py
16
+++ b/tests/qemu-iotests/iotests.py
17
@@ -XXX,XX +XXX,XX @@ class FilePath:
18
19
"""
20
def __init__(self, *names, base_dir=test_dir):
21
- self.paths = []
22
- for name in names:
23
- self.paths.append(os.path.join(base_dir, file_pattern(name)))
24
+ self.paths = [os.path.join(base_dir, file_pattern(name))
25
+ for name in names]
26
27
def __enter__(self):
28
if len(self.paths) == 1:
29
--
30
2.26.2
31
32
diff view generated by jsdifflib
New patch
1
From: Lukas Straub <lukasstraub2@web.de>
1
2
3
If we remove the child with the highest index from the quorum,
4
decrement s->next_child_index. This way we get stable children
5
names as long as we only remove the last child.
6
7
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
8
Fixes: https://bugs.launchpad.net/bugs/1881231
9
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Message-Id: <5d5f930424c1c770754041aa8ad6421dc4e2b58e.1596536719.git.lukasstraub2@web.de>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/quorum.c | 20 ++++++++++++++------
15
1 file changed, 14 insertions(+), 6 deletions(-)
16
17
diff --git a/block/quorum.c b/block/quorum.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/quorum.c
20
+++ b/block/quorum.c
21
@@ -XXX,XX +XXX,XX @@
22
23
#define HASH_LENGTH 32
24
25
+#define INDEXSTR_LEN 32
26
+
27
#define QUORUM_OPT_VOTE_THRESHOLD "vote-threshold"
28
#define QUORUM_OPT_BLKVERIFY "blkverify"
29
#define QUORUM_OPT_REWRITE "rewrite-corrupted"
30
@@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
31
opened = g_new0(bool, s->num_children);
32
33
for (i = 0; i < s->num_children; i++) {
34
- char indexstr[32];
35
- ret = snprintf(indexstr, 32, "children.%d", i);
36
- assert(ret < 32);
37
+ char indexstr[INDEXSTR_LEN];
38
+ ret = snprintf(indexstr, INDEXSTR_LEN, "children.%d", i);
39
+ assert(ret < INDEXSTR_LEN);
40
41
s->children[i] = bdrv_open_child(NULL, options, indexstr, bs,
42
&child_of_bds, BDRV_CHILD_DATA, false,
43
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
44
{
45
BDRVQuorumState *s = bs->opaque;
46
BdrvChild *child;
47
- char indexstr[32];
48
+ char indexstr[INDEXSTR_LEN];
49
int ret;
50
51
if (s->is_blkverify) {
52
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
53
return;
54
}
55
56
- ret = snprintf(indexstr, 32, "children.%u", s->next_child_index);
57
- if (ret < 0 || ret >= 32) {
58
+ ret = snprintf(indexstr, INDEXSTR_LEN, "children.%u", s->next_child_index);
59
+ if (ret < 0 || ret >= INDEXSTR_LEN) {
60
error_setg(errp, "cannot generate child name");
61
return;
62
}
63
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
64
Error **errp)
65
{
66
BDRVQuorumState *s = bs->opaque;
67
+ char indexstr[INDEXSTR_LEN];
68
int i;
69
70
for (i = 0; i < s->num_children; i++) {
71
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
72
/* We know now that num_children > threshold, so blkverify must be false */
73
assert(!s->is_blkverify);
74
75
+ snprintf(indexstr, INDEXSTR_LEN, "children.%u", s->next_child_index - 1);
76
+ if (!strncmp(child->name, indexstr, INDEXSTR_LEN)) {
77
+ s->next_child_index--;
78
+ }
79
+
80
bdrv_drained_begin(bs);
81
82
/* We can safely remove this child now */
83
--
84
2.26.2
85
86
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Peter Lieven <pl@kamp.de>
2
2
3
All jobs do the same thing when they leave their running loop:
3
in case of large continous areas that share the same allocation status
4
- Store the return code in a structure
4
it happens that the value of s->sector_next_status is unaligned to the
5
- wait to receive this structure in the main thread
5
cluster size or even request alignment of the source. Avoid this by
6
- signal job completion via job_completed
6
stripping down the s->sector_next_status position to cluster boundaries.
7
7
8
Few jobs do anything beyond exactly this. Consolidate this exit
8
Signed-off-by: Peter Lieven <pl@kamp.de>
9
logic for a net reduction in SLOC.
9
Message-Id: <20200901125129.6398-1-pl@kamp.de>
10
10
[mreitz: Disable vhdx for 251]
11
More seriously, when we utilize job_defer_to_main_loop_bh to call
12
a function that calls job_completed, job_finalize_single will run
13
in a context where it has recursively taken the aio_context lock,
14
which can cause hangs if it puts down a reference that causes a flush.
15
16
You can observe this in practice by looking at mirror_exit's careful
17
placement of job_completed and bdrv_unref calls.
18
19
If we centralize job exiting, we can signal job completion from outside
20
of the aio_context, which should allow for job cleanup code to run with
21
only one lock, which makes cleanup callbacks less tricky to write.
22
23
Signed-off-by: John Snow <jsnow@redhat.com>
24
Reviewed-by: Max Reitz <mreitz@redhat.com>
25
Message-id: 20180830015734.19765-4-jsnow@redhat.com
26
Reviewed-by: Jeff Cody <jcody@redhat.com>
27
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
28
---
12
---
29
include/qemu/job.h | 11 +++++++++++
13
qemu-img.c | 22 ++++++++++++++++++++++
30
job.c | 18 ++++++++++++++++++
14
tests/qemu-iotests/251 | 7 +++++--
31
2 files changed, 29 insertions(+)
15
2 files changed, 27 insertions(+), 2 deletions(-)
32
16
33
diff --git a/include/qemu/job.h b/include/qemu/job.h
17
diff --git a/qemu-img.c b/qemu-img.c
34
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
35
--- a/include/qemu/job.h
19
--- a/qemu-img.c
36
+++ b/include/qemu/job.h
20
+++ b/qemu-img.c
37
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
21
@@ -XXX,XX +XXX,XX @@ enum ImgConvertBlockStatus {
38
*/
22
typedef struct ImgConvertState {
39
void (*drain)(Job *job);
23
BlockBackend **src;
40
24
int64_t *src_sectors;
41
+ /**
25
+ int *src_alignment;
42
+ * If the callback is not NULL, exit will be invoked from the main thread
26
int src_num;
43
+ * when the job's coroutine has finished, but before transactional
27
int64_t total_sectors;
44
+ * convergence; before @prepare or @abort.
28
int64_t allocated_sectors;
45
+ *
29
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
46
+ * FIXME TODO: This callback is only temporary to transition remaining jobs
30
if (s->sector_next_status <= sector_num) {
47
+ * to prepare/commit/abort/clean callbacks and will be removed before 3.1.
31
uint64_t offset = (sector_num - src_cur_offset) * BDRV_SECTOR_SIZE;
48
+ * is released.
32
int64_t count;
49
+ */
33
+ int tail;
50
+ void (*exit)(Job *job);
34
BlockDriverState *src_bs = blk_bs(s->src[src_cur]);
35
BlockDriverState *base;
36
37
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
38
39
n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE);
40
41
+ /*
42
+ * Avoid that s->sector_next_status becomes unaligned to the source
43
+ * request alignment and/or cluster size to avoid unnecessary read
44
+ * cycles.
45
+ */
46
+ tail = (sector_num - src_cur_offset + n) % s->src_alignment[src_cur];
47
+ if (n > tail) {
48
+ n -= tail;
49
+ }
51
+
50
+
52
/**
51
if (ret & BDRV_BLOCK_ZERO) {
53
* If the callback is not NULL, prepare will be invoked when all the jobs
52
s->status = post_backing_zero ? BLK_BACKING_FILE : BLK_ZERO;
54
* belonging to the same transaction complete; or upon this job's completion
53
} else if (ret & BDRV_BLOCK_DATA) {
55
diff --git a/job.c b/job.c
54
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
56
index XXXXXXX..XXXXXXX 100644
55
57
--- a/job.c
56
s.src = g_new0(BlockBackend *, s.src_num);
58
+++ b/job.c
57
s.src_sectors = g_new(int64_t, s.src_num);
59
@@ -XXX,XX +XXX,XX @@ void job_drain(Job *job)
58
+ s.src_alignment = g_new(int, s.src_num);
59
60
for (bs_i = 0; bs_i < s.src_num; bs_i++) {
61
+ BlockDriverState *src_bs;
62
s.src[bs_i] = img_open(image_opts, argv[optind + bs_i],
63
fmt, src_flags, src_writethrough, s.quiet,
64
force_share);
65
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
66
ret = -1;
67
goto out;
68
}
69
+ src_bs = blk_bs(s.src[bs_i]);
70
+ s.src_alignment[bs_i] = DIV_ROUND_UP(src_bs->bl.request_alignment,
71
+ BDRV_SECTOR_SIZE);
72
+ if (!bdrv_get_info(src_bs, &bdi)) {
73
+ s.src_alignment[bs_i] = MAX(s.src_alignment[bs_i],
74
+ bdi.cluster_size / BDRV_SECTOR_SIZE);
75
+ }
76
s.total_sectors += s.src_sectors[bs_i];
60
}
77
}
61
}
78
62
79
@@ -XXX,XX +XXX,XX @@ out:
63
+static void job_exit(void *opaque)
80
g_free(s.src);
64
+{
81
}
65
+ Job *job = (Job *)opaque;
82
g_free(s.src_sectors);
66
+ AioContext *aio_context = job->aio_context;
83
+ g_free(s.src_alignment);
67
+
84
fail_getopt:
68
+ if (job->driver->exit) {
85
g_free(options);
69
+ aio_context_acquire(aio_context);
86
70
+ job->driver->exit(job);
87
diff --git a/tests/qemu-iotests/251 b/tests/qemu-iotests/251
71
+ aio_context_release(aio_context);
88
index XXXXXXX..XXXXXXX 100755
72
+ }
89
--- a/tests/qemu-iotests/251
73
+ job_completed(job, job->ret);
90
+++ b/tests/qemu-iotests/251
74
+}
91
@@ -XXX,XX +XXX,XX @@ if [ "$IMGOPTSSYNTAX" = "true" ]; then
75
92
# We use json:{} filenames here, so we cannot work with additional options.
76
/**
93
_unsupported_fmt $IMGFMT
77
* All jobs must allow a pause point before entering their job proper. This
94
else
78
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
95
- # With VDI, the output is ordered differently. Just disable it.
79
assert(job && job->driver && job->driver->run);
96
- _unsupported_fmt vdi
80
job_pause_point(job);
97
+ # - With VDI, the output is ordered differently. Just disable it.
81
job->ret = job->driver->run(job, &job->err);
98
+ # - VHDX has large clusters; because qemu-img convert tries to
82
+ if (!job->deferred_to_main_loop) {
99
+ # align the requests to the cluster size, the output is ordered
83
+ job->deferred_to_main_loop = true;
100
+ # differently, so disable it, too.
84
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
101
+ _unsupported_fmt vdi vhdx
85
+ job_exit,
102
fi
86
+ job);
87
+ }
88
}
89
103
90
104
91
--
105
--
92
2.17.1
106
2.26.2
93
107
94
108
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Now that the job infrastructure is handling the job_completed call for
3
This patch replaces instances of sizeof(uint64_t) in the qcow2 driver
4
all implemented jobs, we can remove the interface that allowed jobs to
4
with macros that indicate what those sizes are actually referring to.
5
schedule their own completion.
6
5
7
Signed-off-by: John Snow <jsnow@redhat.com>
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-Id: <20200828110828.13833-1-berto@igalia.com>
9
Message-id: 20180830015734.19765-10-jsnow@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
9
---
12
include/qemu/job.h | 17 -----------------
10
block/qcow2.h | 6 +++
13
job.c | 40 ++--------------------------------------
11
block/qcow2-bitmap.c | 11 ++++--
14
2 files changed, 2 insertions(+), 55 deletions(-)
12
block/qcow2-cluster.c | 24 ++++++------
13
block/qcow2-refcount.c | 89 ++++++++++++++++++++++--------------------
14
block/qcow2-snapshot.c | 20 +++++-----
15
block/qcow2.c | 27 ++++++-------
16
6 files changed, 94 insertions(+), 83 deletions(-)
15
17
16
diff --git a/include/qemu/job.h b/include/qemu/job.h
18
diff --git a/block/qcow2.h b/block/qcow2.h
17
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
18
--- a/include/qemu/job.h
20
--- a/block/qcow2.h
19
+++ b/include/qemu/job.h
21
+++ b/block/qcow2.h
20
@@ -XXX,XX +XXX,XX @@ void job_finalize(Job *job, Error **errp);
22
@@ -XXX,XX +XXX,XX @@
21
*/
23
#define L2E_SIZE_NORMAL (sizeof(uint64_t))
22
void job_dismiss(Job **job, Error **errp);
24
#define L2E_SIZE_EXTENDED (sizeof(uint64_t) * 2)
23
25
24
-typedef void JobDeferToMainLoopFn(Job *job, void *opaque);
26
+/* Size of L1 table entries */
25
-
27
+#define L1E_SIZE (sizeof(uint64_t))
26
-/**
28
+
27
- * @job: The job
29
+/* Size of reftable entries */
28
- * @fn: The function to run in the main loop
30
+#define REFTABLE_ENTRY_SIZE (sizeof(uint64_t))
29
- * @opaque: The opaque value that is passed to @fn
31
+
30
- *
32
#define MIN_CLUSTER_BITS 9
31
- * This function must be called by the main job coroutine just before it
33
#define MAX_CLUSTER_BITS 21
32
- * returns. @fn is executed in the main loop with the job AioContext acquired.
34
33
- *
35
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
34
- * Block jobs must call bdrv_unref(), bdrv_close(), and anything that uses
35
- * bdrv_drain_all() in the main loop.
36
- *
37
- * The @job AioContext is held while @fn executes.
38
- */
39
-void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque);
40
-
41
/**
42
* Synchronously finishes the given @job. If @finish is given, it is called to
43
* trigger completion or cancellation of the job.
44
diff --git a/job.c b/job.c
45
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
46
--- a/job.c
37
--- a/block/qcow2-bitmap.c
47
+++ b/job.c
38
+++ b/block/qcow2-bitmap.c
48
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
39
@@ -XXX,XX +XXX,XX @@
49
assert(job && job->driver && job->driver->run);
40
#define BME_MIN_GRANULARITY_BITS 9
50
job_pause_point(job);
41
#define BME_MAX_NAME_SIZE 1023
51
job->ret = job->driver->run(job, &job->err);
42
52
- if (!job->deferred_to_main_loop) {
43
+/* Size of bitmap table entries */
53
- job->deferred_to_main_loop = true;
44
+#define BME_TABLE_ENTRY_SIZE (sizeof(uint64_t))
54
- aio_bh_schedule_oneshot(qemu_get_aio_context(),
45
+
55
- job_exit,
46
QEMU_BUILD_BUG_ON(BME_MAX_NAME_SIZE != BDRV_BITMAP_MAX_NAME_SIZE);
56
- job);
47
57
- }
48
#if BME_MAX_TABLE_SIZE * 8ULL > INT_MAX
58
+ job->deferred_to_main_loop = true;
49
@@ -XXX,XX +XXX,XX @@ static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
59
+ aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job);
50
51
assert(tb->size <= BME_MAX_TABLE_SIZE);
52
ret = bdrv_pread(bs->file, tb->offset,
53
- table, tb->size * sizeof(uint64_t));
54
+ table, tb->size * BME_TABLE_ENTRY_SIZE);
55
if (ret < 0) {
56
goto fail;
57
}
58
@@ -XXX,XX +XXX,XX @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
59
}
60
61
clear_bitmap_table(bs, bitmap_table, tb->size);
62
- qcow2_free_clusters(bs, tb->offset, tb->size * sizeof(uint64_t),
63
+ qcow2_free_clusters(bs, tb->offset, tb->size * BME_TABLE_ENTRY_SIZE,
64
QCOW2_DISCARD_OTHER);
65
g_free(bitmap_table);
66
67
@@ -XXX,XX +XXX,XX @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
68
ret = qcow2_inc_refcounts_imrt(bs, res,
69
refcount_table, refcount_table_size,
70
bm->table.offset,
71
- bm->table.size * sizeof(uint64_t));
72
+ bm->table.size * BME_TABLE_ENTRY_SIZE);
73
if (ret < 0) {
74
goto out;
75
}
76
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *in_bs,
77
/* Assume the entire bitmap is allocated */
78
bitmaps_size += bmclusters * cluster_size;
79
/* Also reserve space for the bitmap table entries */
80
- bitmaps_size += ROUND_UP(bmclusters * sizeof(uint64_t),
81
+ bitmaps_size += ROUND_UP(bmclusters * BME_TABLE_ENTRY_SIZE,
82
cluster_size);
83
/* And space for contribution to bitmap directory size */
84
bitmap_dir_size += calc_dir_entry_size(strlen(name), 0);
85
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/block/qcow2-cluster.c
88
+++ b/block/qcow2-cluster.c
89
@@ -XXX,XX +XXX,XX @@ int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size)
90
91
BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE);
92
ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset +
93
- new_l1_size * sizeof(uint64_t),
94
- (s->l1_size - new_l1_size) * sizeof(uint64_t), 0);
95
+ new_l1_size * L1E_SIZE,
96
+ (s->l1_size - new_l1_size) * L1E_SIZE, 0);
97
if (ret < 0) {
98
goto fail;
99
}
100
@@ -XXX,XX +XXX,XX @@ fail:
101
* l1_table in memory to avoid possible image corruption.
102
*/
103
memset(s->l1_table + new_l1_size, 0,
104
- (s->l1_size - new_l1_size) * sizeof(uint64_t));
105
+ (s->l1_size - new_l1_size) * L1E_SIZE);
106
return ret;
60
}
107
}
61
108
62
109
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
63
@@ -XXX,XX +XXX,XX @@ void job_complete(Job *job, Error **errp)
110
/* Do a sanity check on min_size before trying to calculate new_l1_size
64
job->driver->complete(job, errp);
111
* (this prevents overflows during the while loop for the calculation of
65
}
112
* new_l1_size) */
66
113
- if (min_size > INT_MAX / sizeof(uint64_t)) {
67
-
114
+ if (min_size > INT_MAX / L1E_SIZE) {
68
-typedef struct {
115
return -EFBIG;
69
- Job *job;
116
}
70
- JobDeferToMainLoopFn *fn;
117
71
- void *opaque;
118
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
72
-} JobDeferToMainLoopData;
119
}
73
-
120
74
-static void job_defer_to_main_loop_bh(void *opaque)
121
QEMU_BUILD_BUG_ON(QCOW_MAX_L1_SIZE > INT_MAX);
75
-{
122
- if (new_l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
76
- JobDeferToMainLoopData *data = opaque;
123
+ if (new_l1_size > QCOW_MAX_L1_SIZE / L1E_SIZE) {
77
- Job *job = data->job;
124
return -EFBIG;
78
- AioContext *aio_context = job->aio_context;
125
}
79
-
126
80
- aio_context_acquire(aio_context);
127
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
81
- data->fn(data->job, data->opaque);
128
s->l1_size, new_l1_size);
82
- aio_context_release(aio_context);
129
#endif
83
-
130
84
- g_free(data);
131
- new_l1_size2 = sizeof(uint64_t) * new_l1_size;
85
-}
132
+ new_l1_size2 = L1E_SIZE * new_l1_size;
86
-
133
new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_size2);
87
-void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque)
134
if (new_l1_table == NULL) {
88
-{
135
return -ENOMEM;
89
- JobDeferToMainLoopData *data = g_malloc(sizeof(*data));
136
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
90
- data->job = job;
137
memset(new_l1_table, 0, new_l1_size2);
91
- data->fn = fn;
138
92
- data->opaque = opaque;
139
if (s->l1_size) {
93
- job->deferred_to_main_loop = true;
140
- memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
94
-
141
+ memcpy(new_l1_table, s->l1_table, s->l1_size * L1E_SIZE);
95
- aio_bh_schedule_oneshot(qemu_get_aio_context(),
142
}
96
- job_defer_to_main_loop_bh, data);
143
97
-}
144
/* write new table (align to cluster) */
98
-
145
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
99
int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
146
s->l1_table = new_l1_table;
147
old_l1_size = s->l1_size;
148
s->l1_size = new_l1_size;
149
- qcow2_free_clusters(bs, old_l1_table_offset, old_l1_size * sizeof(uint64_t),
150
+ qcow2_free_clusters(bs, old_l1_table_offset, old_l1_size * L1E_SIZE,
151
QCOW2_DISCARD_OTHER);
152
return 0;
153
fail:
154
@@ -XXX,XX +XXX,XX @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
155
BDRVQcow2State *s = bs->opaque;
156
int l1_start_index;
157
int i, ret;
158
- int bufsize = MAX(sizeof(uint64_t),
159
+ int bufsize = MAX(L1E_SIZE,
160
MIN(bs->file->bs->bl.request_alignment, s->cluster_size));
161
- int nentries = bufsize / sizeof(uint64_t);
162
+ int nentries = bufsize / L1E_SIZE;
163
g_autofree uint64_t *buf = g_try_new0(uint64_t, nentries);
164
165
if (buf == NULL) {
166
@@ -XXX,XX +XXX,XX @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
167
Error *local_err = NULL;
168
169
ret = qcow2_validate_table(bs, s->snapshots[i].l1_table_offset,
170
- s->snapshots[i].l1_size, sizeof(uint64_t),
171
+ s->snapshots[i].l1_size, L1E_SIZE,
172
QCOW_MAX_L1_SIZE, "Snapshot L1 table",
173
&local_err);
174
if (ret < 0) {
175
@@ -XXX,XX +XXX,XX @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
176
goto fail;
177
}
178
179
- l1_size2 = s->snapshots[i].l1_size * sizeof(uint64_t);
180
+ l1_size2 = s->snapshots[i].l1_size * L1E_SIZE;
181
new_l1_table = g_try_realloc(l1_table, l1_size2);
182
183
if (!new_l1_table) {
184
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
185
index XXXXXXX..XXXXXXX 100644
186
--- a/block/qcow2-refcount.c
187
+++ b/block/qcow2-refcount.c
188
@@ -XXX,XX +XXX,XX @@ int qcow2_refcount_init(BlockDriverState *bs)
189
s->get_refcount = get_refcount_funcs[s->refcount_order];
190
s->set_refcount = set_refcount_funcs[s->refcount_order];
191
192
- assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
193
- refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
194
+ assert(s->refcount_table_size <= INT_MAX / REFTABLE_ENTRY_SIZE);
195
+ refcount_table_size2 = s->refcount_table_size * REFTABLE_ENTRY_SIZE;
196
s->refcount_table = g_try_malloc(refcount_table_size2);
197
198
if (s->refcount_table_size > 0) {
199
@@ -XXX,XX +XXX,XX @@ static int alloc_refcount_block(BlockDriverState *bs,
200
if (refcount_table_index < s->refcount_table_size) {
201
uint64_t data64 = cpu_to_be64(new_block);
202
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
203
- ret = bdrv_pwrite_sync(bs->file,
204
- s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
205
+ ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset +
206
+ refcount_table_index * REFTABLE_ENTRY_SIZE,
207
&data64, sizeof(data64));
208
if (ret < 0) {
209
goto fail;
210
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
211
DIV_ROUND_UP(total_refblock_count, 2);
212
}
213
/* The qcow2 file can only store the reftable size in number of clusters */
214
- table_size = ROUND_UP(table_size, s->cluster_size / sizeof(uint64_t));
215
- table_clusters = (table_size * sizeof(uint64_t)) / s->cluster_size;
216
+ table_size = ROUND_UP(table_size, s->cluster_size / REFTABLE_ENTRY_SIZE);
217
+ table_clusters = (table_size * REFTABLE_ENTRY_SIZE) / s->cluster_size;
218
219
if (table_size > QCOW_MAX_REFTABLE_SIZE) {
220
return -EFBIG;
221
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
222
if (table_size > s->max_refcount_table_index) {
223
/* We're actually growing the reftable */
224
memcpy(new_table, s->refcount_table,
225
- (s->max_refcount_table_index + 1) * sizeof(uint64_t));
226
+ (s->max_refcount_table_index + 1) * REFTABLE_ENTRY_SIZE);
227
} else {
228
/* Improbable case: We're shrinking the reftable. However, the caller
229
* has assured us that there is only empty space beyond @start_offset,
230
* so we can simply drop all of the refblocks that won't fit into the
231
* new reftable. */
232
- memcpy(new_table, s->refcount_table, table_size * sizeof(uint64_t));
233
+ memcpy(new_table, s->refcount_table, table_size * REFTABLE_ENTRY_SIZE);
234
}
235
236
if (new_refblock_offset) {
237
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
238
239
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
240
ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
241
- table_size * sizeof(uint64_t));
242
+ table_size * REFTABLE_ENTRY_SIZE);
243
if (ret < 0) {
244
goto fail;
245
}
246
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
247
update_max_refcount_table_index(s);
248
249
/* Free old table. */
250
- qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
251
+ qcow2_free_clusters(bs, old_table_offset,
252
+ old_table_size * REFTABLE_ENTRY_SIZE,
253
QCOW2_DISCARD_OTHER);
254
255
return end_offset;
256
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
257
258
l2_slice = NULL;
259
l1_table = NULL;
260
- l1_size2 = l1_size * sizeof(uint64_t);
261
+ l1_size2 = l1_size * L1E_SIZE;
262
slice_size2 = s->l2_slice_size * l2_entry_size(s);
263
n_slices = s->cluster_size / slice_size2;
264
265
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l1(BlockDriverState *bs,
266
uint64_t *l1_table = NULL, l2_offset, l1_size2;
267
int i, ret;
268
269
- l1_size2 = l1_size * sizeof(uint64_t);
270
+ l1_size2 = l1_size * L1E_SIZE;
271
272
/* Mark L1 table as used */
273
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
274
@@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
275
res->corruptions++;
276
continue;
277
}
278
- if (sn->l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
279
+ if (sn->l1_size > QCOW_MAX_L1_SIZE / L1E_SIZE) {
280
fprintf(stderr, "ERROR snapshot %s (%s) l1_size=%#" PRIx32 ": "
281
"L1 table is too large; snapshot table entry corrupted\n",
282
sn->id_str, sn->name, sn->l1_size);
283
@@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
284
/* refcount data */
285
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
286
s->refcount_table_offset,
287
- s->refcount_table_size * sizeof(uint64_t));
288
+ s->refcount_table_size *
289
+ REFTABLE_ENTRY_SIZE);
290
if (ret < 0) {
291
return ret;
292
}
293
@@ -XXX,XX +XXX,XX @@ write_refblocks:
294
uint32_t old_reftable_size = reftable_size;
295
uint64_t *new_on_disk_reftable;
296
297
- reftable_size = ROUND_UP((refblock_index + 1) * sizeof(uint64_t),
298
- s->cluster_size) / sizeof(uint64_t);
299
+ reftable_size = ROUND_UP((refblock_index + 1) * REFTABLE_ENTRY_SIZE,
300
+ s->cluster_size) / REFTABLE_ENTRY_SIZE;
301
new_on_disk_reftable = g_try_realloc(on_disk_reftable,
302
reftable_size *
303
- sizeof(uint64_t));
304
+ REFTABLE_ENTRY_SIZE);
305
if (!new_on_disk_reftable) {
306
res->check_errors++;
307
ret = -ENOMEM;
308
@@ -XXX,XX +XXX,XX @@ write_refblocks:
309
on_disk_reftable = new_on_disk_reftable;
310
311
memset(on_disk_reftable + old_reftable_size, 0,
312
- (reftable_size - old_reftable_size) * sizeof(uint64_t));
313
+ (reftable_size - old_reftable_size) * REFTABLE_ENTRY_SIZE);
314
315
/* The offset we have for the reftable is now no longer valid;
316
* this will leak that range, but we can easily fix that by running
317
@@ -XXX,XX +XXX,XX @@ write_refblocks:
318
reftable_offset < 0)
319
{
320
uint64_t reftable_clusters = size_to_clusters(s, reftable_size *
321
- sizeof(uint64_t));
322
+ REFTABLE_ENTRY_SIZE);
323
reftable_offset = alloc_clusters_imrt(bs, reftable_clusters,
324
refcount_table, nb_clusters,
325
&first_free_cluster);
326
@@ -XXX,XX +XXX,XX @@ write_refblocks:
327
uint64_t post_refblock_start, reftable_clusters;
328
329
post_refblock_start = ROUND_UP(*nb_clusters, s->refcount_block_size);
330
- reftable_clusters = size_to_clusters(s,
331
- reftable_size * sizeof(uint64_t));
332
+ reftable_clusters =
333
+ size_to_clusters(s, reftable_size * REFTABLE_ENTRY_SIZE);
334
/* Not pretty but simple */
335
if (first_free_cluster < post_refblock_start) {
336
first_free_cluster = post_refblock_start;
337
@@ -XXX,XX +XXX,XX @@ write_refblocks:
338
}
339
340
ret = qcow2_pre_write_overlap_check(bs, 0, reftable_offset,
341
- reftable_size * sizeof(uint64_t),
342
+ reftable_size * REFTABLE_ENTRY_SIZE,
343
false);
344
if (ret < 0) {
345
fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret));
346
goto fail;
347
}
348
349
- assert(reftable_size < INT_MAX / sizeof(uint64_t));
350
+ assert(reftable_size < INT_MAX / REFTABLE_ENTRY_SIZE);
351
ret = bdrv_pwrite(bs->file, reftable_offset, on_disk_reftable,
352
- reftable_size * sizeof(uint64_t));
353
+ reftable_size * REFTABLE_ENTRY_SIZE);
354
if (ret < 0) {
355
fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret));
356
goto fail;
357
@@ -XXX,XX +XXX,XX @@ write_refblocks:
358
/* Enter new reftable into the image header */
359
reftable_offset_and_clusters.reftable_offset = cpu_to_be64(reftable_offset);
360
reftable_offset_and_clusters.reftable_clusters =
361
- cpu_to_be32(size_to_clusters(s, reftable_size * sizeof(uint64_t)));
362
+ cpu_to_be32(size_to_clusters(s, reftable_size * REFTABLE_ENTRY_SIZE));
363
ret = bdrv_pwrite_sync(bs->file,
364
offsetof(QCowHeader, refcount_table_offset),
365
&reftable_offset_and_clusters,
366
@@ -XXX,XX +XXX,XX @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
367
offset = start_of_cluster(s, offset);
368
369
if ((chk & QCOW2_OL_ACTIVE_L1) && s->l1_size) {
370
- if (overlaps_with(s->l1_table_offset, s->l1_size * sizeof(uint64_t))) {
371
+ if (overlaps_with(s->l1_table_offset, s->l1_size * L1E_SIZE)) {
372
return QCOW2_OL_ACTIVE_L1;
373
}
374
}
375
376
if ((chk & QCOW2_OL_REFCOUNT_TABLE) && s->refcount_table_size) {
377
if (overlaps_with(s->refcount_table_offset,
378
- s->refcount_table_size * sizeof(uint64_t))) {
379
+ s->refcount_table_size * REFTABLE_ENTRY_SIZE)) {
380
return QCOW2_OL_REFCOUNT_TABLE;
381
}
382
}
383
@@ -XXX,XX +XXX,XX @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
384
for (i = 0; i < s->nb_snapshots; i++) {
385
if (s->snapshots[i].l1_size &&
386
overlaps_with(s->snapshots[i].l1_table_offset,
387
- s->snapshots[i].l1_size * sizeof(uint64_t))) {
388
+ s->snapshots[i].l1_size * L1E_SIZE)) {
389
return QCOW2_OL_INACTIVE_L1;
390
}
391
}
392
@@ -XXX,XX +XXX,XX @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
393
for (i = 0; i < s->nb_snapshots; i++) {
394
uint64_t l1_ofs = s->snapshots[i].l1_table_offset;
395
uint32_t l1_sz = s->snapshots[i].l1_size;
396
- uint64_t l1_sz2 = l1_sz * sizeof(uint64_t);
397
+ uint64_t l1_sz2 = l1_sz * L1E_SIZE;
398
uint64_t *l1;
399
int ret;
400
401
- ret = qcow2_validate_table(bs, l1_ofs, l1_sz, sizeof(uint64_t),
402
+ ret = qcow2_validate_table(bs, l1_ofs, l1_sz, L1E_SIZE,
403
QCOW_MAX_L1_SIZE, "", NULL);
404
if (ret < 0) {
405
return ret;
406
@@ -XXX,XX +XXX,XX @@ static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable,
407
uint64_t new_reftable_size;
408
409
new_reftable_size = ROUND_UP(reftable_index + 1,
410
- s->cluster_size / sizeof(uint64_t));
411
- if (new_reftable_size > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
412
+ s->cluster_size / REFTABLE_ENTRY_SIZE);
413
+ if (new_reftable_size > QCOW_MAX_REFTABLE_SIZE / REFTABLE_ENTRY_SIZE) {
414
error_setg(errp,
415
"This operation would make the refcount table grow "
416
"beyond the maximum size supported by QEMU, aborting");
417
@@ -XXX,XX +XXX,XX @@ static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable,
418
}
419
420
new_reftable = g_try_realloc(*reftable, new_reftable_size *
421
- sizeof(uint64_t));
422
+ REFTABLE_ENTRY_SIZE);
423
if (!new_reftable) {
424
error_setg(errp, "Failed to increase reftable buffer size");
425
return -ENOMEM;
426
}
427
428
memset(new_reftable + *reftable_size, 0,
429
- (new_reftable_size - *reftable_size) * sizeof(uint64_t));
430
+ (new_reftable_size - *reftable_size) * REFTABLE_ENTRY_SIZE);
431
432
*reftable = new_reftable;
433
*reftable_size = new_reftable_size;
434
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
435
436
if (new_allocation) {
437
if (new_reftable_offset) {
438
- qcow2_free_clusters(bs, new_reftable_offset,
439
- allocated_reftable_size * sizeof(uint64_t),
440
- QCOW2_DISCARD_NEVER);
441
+ qcow2_free_clusters(
442
+ bs, new_reftable_offset,
443
+ allocated_reftable_size * REFTABLE_ENTRY_SIZE,
444
+ QCOW2_DISCARD_NEVER);
445
}
446
447
new_reftable_offset = qcow2_alloc_clusters(bs, new_reftable_size *
448
- sizeof(uint64_t));
449
+ REFTABLE_ENTRY_SIZE);
450
if (new_reftable_offset < 0) {
451
error_setg_errno(errp, -new_reftable_offset,
452
"Failed to allocate the new reftable");
453
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
454
455
/* Write the new reftable */
456
ret = qcow2_pre_write_overlap_check(bs, 0, new_reftable_offset,
457
- new_reftable_size * sizeof(uint64_t),
458
+ new_reftable_size * REFTABLE_ENTRY_SIZE,
459
false);
460
if (ret < 0) {
461
error_setg_errno(errp, -ret, "Overlap check failed");
462
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
463
}
464
465
ret = bdrv_pwrite(bs->file, new_reftable_offset, new_reftable,
466
- new_reftable_size * sizeof(uint64_t));
467
+ new_reftable_size * REFTABLE_ENTRY_SIZE);
468
469
for (i = 0; i < new_reftable_size; i++) {
470
be64_to_cpus(&new_reftable[i]);
471
@@ -XXX,XX +XXX,XX @@ done:
472
473
if (new_reftable_offset > 0) {
474
qcow2_free_clusters(bs, new_reftable_offset,
475
- new_reftable_size * sizeof(uint64_t),
476
+ new_reftable_size * REFTABLE_ENTRY_SIZE,
477
QCOW2_DISCARD_OTHER);
478
}
479
}
480
@@ -XXX,XX +XXX,XX @@ int qcow2_shrink_reftable(BlockDriverState *bs)
100
{
481
{
101
Error *local_err = NULL;
482
BDRVQcow2State *s = bs->opaque;
483
uint64_t *reftable_tmp =
484
- g_malloc(s->refcount_table_size * sizeof(uint64_t));
485
+ g_malloc(s->refcount_table_size * REFTABLE_ENTRY_SIZE);
486
int i, ret;
487
488
for (i = 0; i < s->refcount_table_size; i++) {
489
@@ -XXX,XX +XXX,XX @@ int qcow2_shrink_reftable(BlockDriverState *bs)
490
}
491
492
ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset, reftable_tmp,
493
- s->refcount_table_size * sizeof(uint64_t));
494
+ s->refcount_table_size * REFTABLE_ENTRY_SIZE);
495
/*
496
* If the write in the reftable failed the image may contain a partially
497
* overwritten reftable. In this case it would be better to clear the
498
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
499
index XXXXXXX..XXXXXXX 100644
500
--- a/block/qcow2-snapshot.c
501
+++ b/block/qcow2-snapshot.c
502
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
503
sn->extra_data_size = sizeof(QCowSnapshotExtraData);
504
505
/* Allocate the L1 table of the snapshot and copy the current one there. */
506
- l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
507
+ l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * L1E_SIZE);
508
if (l1_table_offset < 0) {
509
ret = l1_table_offset;
510
goto fail;
511
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
512
}
513
514
ret = qcow2_pre_write_overlap_check(bs, 0, sn->l1_table_offset,
515
- s->l1_size * sizeof(uint64_t), false);
516
+ s->l1_size * L1E_SIZE, false);
517
if (ret < 0) {
518
goto fail;
519
}
520
521
ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
522
- s->l1_size * sizeof(uint64_t));
523
+ s->l1_size * L1E_SIZE);
524
if (ret < 0) {
525
goto fail;
526
}
527
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
528
sn = &s->snapshots[snapshot_index];
529
530
ret = qcow2_validate_table(bs, sn->l1_table_offset, sn->l1_size,
531
- sizeof(uint64_t), QCOW_MAX_L1_SIZE,
532
+ L1E_SIZE, QCOW_MAX_L1_SIZE,
533
"Snapshot L1 table", &local_err);
534
if (ret < 0) {
535
error_report_err(local_err);
536
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
537
goto fail;
538
}
539
540
- cur_l1_bytes = s->l1_size * sizeof(uint64_t);
541
- sn_l1_bytes = sn->l1_size * sizeof(uint64_t);
542
+ cur_l1_bytes = s->l1_size * L1E_SIZE;
543
+ sn_l1_bytes = sn->l1_size * L1E_SIZE;
544
545
/*
546
* Copy the snapshot L1 table to the current L1 table.
547
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_delete(BlockDriverState *bs,
548
sn = s->snapshots[snapshot_index];
549
550
ret = qcow2_validate_table(bs, sn.l1_table_offset, sn.l1_size,
551
- sizeof(uint64_t), QCOW_MAX_L1_SIZE,
552
+ L1E_SIZE, QCOW_MAX_L1_SIZE,
553
"Snapshot L1 table", errp);
554
if (ret < 0) {
555
return ret;
556
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_delete(BlockDriverState *bs,
557
error_setg_errno(errp, -ret, "Failed to free the cluster and L1 table");
558
return ret;
559
}
560
- qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t),
561
+ qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * L1E_SIZE,
562
QCOW2_DISCARD_SNAPSHOT);
563
564
/* must update the copied flag on the current cluster offsets */
565
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
566
567
/* Allocate and read in the snapshot's L1 table */
568
ret = qcow2_validate_table(bs, sn->l1_table_offset, sn->l1_size,
569
- sizeof(uint64_t), QCOW_MAX_L1_SIZE,
570
+ L1E_SIZE, QCOW_MAX_L1_SIZE,
571
"Snapshot L1 table", errp);
572
if (ret < 0) {
573
return ret;
574
}
575
- new_l1_bytes = sn->l1_size * sizeof(uint64_t);
576
+ new_l1_bytes = sn->l1_size * L1E_SIZE;
577
new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_bytes);
578
if (new_l1_table == NULL) {
579
return -ENOMEM;
580
diff --git a/block/qcow2.c b/block/qcow2.c
581
index XXXXXXX..XXXXXXX 100644
582
--- a/block/qcow2.c
583
+++ b/block/qcow2.c
584
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
585
586
/* read the level 1 table */
587
ret = qcow2_validate_table(bs, header.l1_table_offset,
588
- header.l1_size, sizeof(uint64_t),
589
+ header.l1_size, L1E_SIZE,
590
QCOW_MAX_L1_SIZE, "Active L1 table", errp);
591
if (ret < 0) {
592
goto fail;
593
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
594
}
595
596
if (s->l1_size > 0) {
597
- s->l1_table = qemu_try_blockalign(bs->file->bs,
598
- s->l1_size * sizeof(uint64_t));
599
+ s->l1_table = qemu_try_blockalign(bs->file->bs, s->l1_size * L1E_SIZE);
600
if (s->l1_table == NULL) {
601
error_setg(errp, "Could not allocate L1 table");
602
ret = -ENOMEM;
603
goto fail;
604
}
605
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
606
- s->l1_size * sizeof(uint64_t));
607
+ s->l1_size * L1E_SIZE);
608
if (ret < 0) {
609
error_setg_errno(errp, -ret, "Could not read L1 table");
610
goto fail;
611
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
612
* where no further refcount blocks or table clusters are required to
613
* reference count every cluster.
614
*/
615
- int64_t blocks_per_table_cluster = cluster_size / sizeof(uint64_t);
616
+ int64_t blocks_per_table_cluster = cluster_size / REFTABLE_ENTRY_SIZE;
617
int64_t refcounts_per_block = cluster_size * 8 / (1 << refcount_order);
618
int64_t table = 0; /* number of refcount table clusters */
619
int64_t blocks = 0; /* number of refcount block clusters */
620
@@ -XXX,XX +XXX,XX @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size,
621
622
/* total size of L1 tables */
623
nl1e = nl2e * l2e_size / cluster_size;
624
- nl1e = ROUND_UP(nl1e, cluster_size / sizeof(uint64_t));
625
- meta_size += nl1e * sizeof(uint64_t);
626
+ nl1e = ROUND_UP(nl1e, cluster_size / L1E_SIZE);
627
+ meta_size += nl1e * L1E_SIZE;
628
629
/* total size of refcount table and blocks */
630
meta_size += qcow2_refcount_metadata_size(
631
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
632
/* write updated header.size */
633
offset = cpu_to_be64(offset);
634
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
635
- &offset, sizeof(uint64_t));
636
+ &offset, sizeof(offset));
637
if (ret < 0) {
638
error_setg_errno(errp, -ret, "Failed to update the image size");
639
goto fail;
640
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
641
642
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
643
644
- l1_clusters = DIV_ROUND_UP(s->l1_size, s->cluster_size / sizeof(uint64_t));
645
- l1_size2 = (uint64_t)s->l1_size * sizeof(uint64_t);
646
+ l1_clusters = DIV_ROUND_UP(s->l1_size, s->cluster_size / L1E_SIZE);
647
+ l1_size2 = (uint64_t)s->l1_size * L1E_SIZE;
648
649
/* After this call, neither the in-memory nor the on-disk refcount
650
* information accurately describe the actual references */
651
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
652
653
s->l1_table_offset = 3 * s->cluster_size;
654
655
- new_reftable = g_try_new0(uint64_t, s->cluster_size / sizeof(uint64_t));
656
+ new_reftable = g_try_new0(uint64_t, s->cluster_size / REFTABLE_ENTRY_SIZE);
657
if (!new_reftable) {
658
ret = -ENOMEM;
659
goto fail_broken_refcounts;
660
}
661
662
s->refcount_table_offset = s->cluster_size;
663
- s->refcount_table_size = s->cluster_size / sizeof(uint64_t);
664
+ s->refcount_table_size = s->cluster_size / REFTABLE_ENTRY_SIZE;
665
s->max_refcount_table_index = 0;
666
667
g_free(s->refcount_table);
668
@@ -XXX,XX +XXX,XX @@ static int qcow2_make_empty(BlockDriverState *bs)
669
int step = QEMU_ALIGN_DOWN(INT_MAX, s->cluster_size);
670
int l1_clusters, ret = 0;
671
672
- l1_clusters = DIV_ROUND_UP(s->l1_size, s->cluster_size / sizeof(uint64_t));
673
+ l1_clusters = DIV_ROUND_UP(s->l1_size, s->cluster_size / L1E_SIZE);
674
675
if (s->qcow_version >= 3 && !s->snapshots && !s->nb_bitmaps &&
676
3 + l1_clusters <= s->refcount_block_size &&
677
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
678
l2e_size = extended_l2 ? L2E_SIZE_EXTENDED : L2E_SIZE_NORMAL;
679
l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,
680
cluster_size / l2e_size);
681
- if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) {
682
+ if (l2_tables * L1E_SIZE > QCOW_MAX_L1_SIZE) {
683
error_setg(&local_err, "The image size is too large "
684
"(try using a larger cluster size)");
685
goto err;
102
--
686
--
103
2.17.1
687
2.26.2
104
688
105
689
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Utilize the job_exit shim by not calling job_defer_to_main_loop, and
3
When a write request needs to allocate new clusters (or change the L2
4
where applicable, converting the deferred callback into the job_exit
4
bitmap of existing ones) a QCowL2Meta structure is created so the L2
5
callback.
5
metadata can be later updated and any copy-on-write can be performed
6
if necessary.
6
7
7
This converts backup, stream, create, and the unit tests all at once.
8
A write request can span a region consisting of an arbitrary
8
Most of these jobs do not see any changes to the order in which they
9
combination of previously unallocated and allocated clusters, and if
9
clean up their resources, except the test-blockjob-txn test, which
10
the unallocated ones can be put contiguous to the existing ones then
10
now puts down its bs before job_completed is called.
11
QEMU will do so in order to minimize the number of write operations.
11
12
12
This is safe for the same reason the reordering in the mirror job is
13
In practice this means that a write request has not just one but a
13
safe, because job_completed no longer runs under two locks, making
14
number of QCowL2Meta structures. All of them are added to the
14
the unref safe even if it causes a flush.
15
cluster_allocs list that is stored in BDRVQcow2State and is used to
16
detect overlapping requests. After the write request finishes all its
17
associated QCowL2Meta are removed from that list. calculate_l2_meta()
18
takes care of creating and putting those structures in the list, and
19
qcow2_handle_l2meta() takes care of removing them.
15
20
16
Signed-off-by: John Snow <jsnow@redhat.com>
21
The problem is that the error path in handle_alloc() also tries to
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
22
remove an item in that list, a remnant from the time when this was
18
Message-id: 20180830015734.19765-7-jsnow@redhat.com
23
handled there (that code would not even be correct anymore because
24
it only removes one struct and not all the ones from the same write
25
request).
26
27
This can trigger a double removal of the same item from the list,
28
causing a crash. This is not easy to reproduce in practice because
29
it requires that do_alloc_cluster_offset() fails after a successful
30
previous allocation during the same write request, but it can be
31
reproduced with the included test case.
32
33
Signed-off-by: Alberto Garcia <berto@igalia.com>
34
Message-Id: <3440a1c4d53c4fe48312b478c96accb338cbef7c.1599150873.git.berto@igalia.com>
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
35
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
---
36
---
21
block/backup.c | 16 ----------------
37
block/qcow2-cluster.c | 3 --
22
block/create.c | 14 +++-----------
38
tests/qemu-iotests/305 | 74 ++++++++++++++++++++++++++++++++++++++
23
block/stream.c | 22 +++++++---------------
39
tests/qemu-iotests/305.out | 16 +++++++++
24
tests/test-bdrv-drain.c | 6 ------
40
tests/qemu-iotests/group | 1 +
25
tests/test-blockjob-txn.c | 11 ++---------
41
4 files changed, 91 insertions(+), 3 deletions(-)
26
tests/test-blockjob.c | 10 ++++------
42
create mode 100755 tests/qemu-iotests/305
27
6 files changed, 16 insertions(+), 63 deletions(-)
43
create mode 100644 tests/qemu-iotests/305.out
28
44
29
diff --git a/block/backup.c b/block/backup.c
45
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
30
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
31
--- a/block/backup.c
47
--- a/block/qcow2-cluster.c
32
+++ b/block/backup.c
48
+++ b/block/qcow2-cluster.c
33
@@ -XXX,XX +XXX,XX @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
49
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
34
}
50
35
}
51
out:
36
52
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
37
-typedef struct {
53
- if (ret < 0 && *m && (*m)->nb_clusters > 0) {
38
- int ret;
54
- QLIST_REMOVE(*m, next_in_flight);
39
-} BackupCompleteData;
55
- }
40
-
41
-static void backup_complete(Job *job, void *opaque)
42
-{
43
- BackupCompleteData *data = opaque;
44
-
45
- job_completed(job, data->ret);
46
- g_free(data);
47
-}
48
-
49
static bool coroutine_fn yield_and_check(BackupBlockJob *job)
50
{
51
uint64_t delay_ns;
52
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
53
static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
54
{
55
BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job);
56
- BackupCompleteData *data;
57
BlockDriverState *bs = blk_bs(job->common.blk);
58
int64_t offset, nb_clusters;
59
int ret = 0;
60
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
61
qemu_co_rwlock_unlock(&job->flush_rwlock);
62
hbitmap_free(job->copy_bitmap);
63
64
- data = g_malloc(sizeof(*data));
65
- data->ret = ret;
66
- job_defer_to_main_loop(&job->common.job, backup_complete, data);
67
return ret;
56
return ret;
68
}
57
}
69
58
70
diff --git a/block/create.c b/block/create.c
59
diff --git a/tests/qemu-iotests/305 b/tests/qemu-iotests/305
60
new file mode 100755
61
index XXXXXXX..XXXXXXX
62
--- /dev/null
63
+++ b/tests/qemu-iotests/305
64
@@ -XXX,XX +XXX,XX @@
65
+#!/usr/bin/env bash
66
+#
67
+# Test the handling of errors in write requests with multiple allocations
68
+#
69
+# Copyright (C) 2020 Igalia, S.L.
70
+# Author: Alberto Garcia <berto@igalia.com>
71
+#
72
+# This program is free software; you can redistribute it and/or modify
73
+# it under the terms of the GNU General Public License as published by
74
+# the Free Software Foundation; either version 2 of the License, or
75
+# (at your option) any later version.
76
+#
77
+# This program is distributed in the hope that it will be useful,
78
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
79
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
80
+# GNU General Public License for more details.
81
+#
82
+# You should have received a copy of the GNU General Public License
83
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
84
+#
85
+
86
+# creator
87
+owner=berto@igalia.com
88
+
89
+seq=`basename $0`
90
+echo "QA output created by $seq"
91
+
92
+status=1 # failure is the default!
93
+
94
+_cleanup()
95
+{
96
+ _cleanup_test_img
97
+}
98
+trap "_cleanup; exit \$status" 0 1 2 3 15
99
+
100
+# get standard environment, filters and checks
101
+. ./common.rc
102
+. ./common.filter
103
+
104
+_supported_fmt qcow2
105
+_supported_proto file
106
+_supported_os Linux
107
+_unsupported_imgopts cluster_size refcount_bits extended_l2 compat=0.10 data_file
108
+
109
+echo '### Create the image'
110
+_make_test_img -o refcount_bits=64,cluster_size=1k 1M
111
+
112
+# The reference counts of the clusters for the first 123k of this
113
+# write request are stored in the first refcount block. The last
114
+# cluster (guest offset 123k) is referenced in the second refcount
115
+# block.
116
+echo '### Fill the first refcount block and one data cluster from the second'
117
+$QEMU_IO -c 'write 0 124k' "$TEST_IMG" | _filter_qemu_io
118
+
119
+echo '### Discard two of the last data clusters, leave one in the middle'
120
+$QEMU_IO -c 'discard 121k 1k' "$TEST_IMG" | _filter_qemu_io
121
+$QEMU_IO -c 'discard 123k 1k' "$TEST_IMG" | _filter_qemu_io
122
+
123
+echo '### Corrupt the offset of the second refcount block'
124
+refcount_table_offset=$(peek_file_be "$TEST_IMG" 48 8)
125
+poke_file "$TEST_IMG" $(($refcount_table_offset+14)) "\x06"
126
+
127
+# This tries to allocate the two clusters discarded earlier (guest
128
+# offsets 121k and 123k). Their reference counts are in the first and
129
+# second refcount blocks respectively, but only the first one can be
130
+# allocated correctly because the second entry of the refcount table
131
+# is corrupted.
132
+echo '### Try to allocate the discarded clusters again'
133
+$QEMU_IO -c 'write 121k 3k' "$TEST_IMG" | _filter_qemu_io
134
+
135
+# success, all done
136
+echo "*** done"
137
+rm -f $seq.full
138
+status=0
139
diff --git a/tests/qemu-iotests/305.out b/tests/qemu-iotests/305.out
140
new file mode 100644
141
index XXXXXXX..XXXXXXX
142
--- /dev/null
143
+++ b/tests/qemu-iotests/305.out
144
@@ -XXX,XX +XXX,XX @@
145
+QA output created by 305
146
+### Create the image
147
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
148
+### Fill the first refcount block and one data cluster from the second
149
+wrote 126976/126976 bytes at offset 0
150
+124 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
151
+### Discard two of the last data clusters, leave one in the middle
152
+discard 1024/1024 bytes at offset 123904
153
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
154
+discard 1024/1024 bytes at offset 125952
155
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
156
+### Corrupt the offset of the second refcount block
157
+### Try to allocate the discarded clusters again
158
+qcow2: Marking image as corrupt: Refblock offset 0x20600 unaligned (reftable index: 0x1); further corruption events will be suppressed
159
+write failed: Input/output error
160
+*** done
161
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
71
index XXXXXXX..XXXXXXX 100644
162
index XXXXXXX..XXXXXXX 100644
72
--- a/block/create.c
163
--- a/tests/qemu-iotests/group
73
+++ b/block/create.c
164
+++ b/tests/qemu-iotests/group
74
@@ -XXX,XX +XXX,XX @@ typedef struct BlockdevCreateJob {
165
@@ -XXX,XX +XXX,XX @@
75
Job common;
166
302 quick
76
BlockDriver *drv;
167
303 rw quick
77
BlockdevCreateOptions *opts;
168
304 rw quick
78
- int ret;
169
+305 rw quick
79
} BlockdevCreateJob;
80
81
-static void blockdev_create_complete(Job *job, void *opaque)
82
-{
83
- BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
84
-
85
- job_completed(job, s->ret);
86
-}
87
-
88
static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
89
{
90
BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
91
+ int ret;
92
93
job_progress_set_remaining(&s->common, 1);
94
- s->ret = s->drv->bdrv_co_create(s->opts, errp);
95
+ ret = s->drv->bdrv_co_create(s->opts, errp);
96
job_progress_update(&s->common, 1);
97
98
qapi_free_BlockdevCreateOptions(s->opts);
99
- job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL);
100
101
- return s->ret;
102
+ return ret;
103
}
104
105
static const JobDriver blockdev_create_job_driver = {
106
diff --git a/block/stream.c b/block/stream.c
107
index XXXXXXX..XXXXXXX 100644
108
--- a/block/stream.c
109
+++ b/block/stream.c
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_populate(BlockBackend *blk,
111
return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ);
112
}
113
114
-typedef struct {
115
- int ret;
116
-} StreamCompleteData;
117
-
118
-static void stream_complete(Job *job, void *opaque)
119
+static void stream_exit(Job *job)
120
{
121
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
122
BlockJob *bjob = &s->common;
123
- StreamCompleteData *data = opaque;
124
BlockDriverState *bs = blk_bs(bjob->blk);
125
BlockDriverState *base = s->base;
126
Error *local_err = NULL;
127
+ int ret = job->ret;
128
129
- if (!job_is_cancelled(job) && bs->backing && data->ret == 0) {
130
+ if (!job_is_cancelled(job) && bs->backing && ret == 0) {
131
const char *base_id = NULL, *base_fmt = NULL;
132
if (base) {
133
base_id = s->backing_file_str;
134
@@ -XXX,XX +XXX,XX @@ static void stream_complete(Job *job, void *opaque)
135
base_fmt = base->drv->format_name;
136
}
137
}
138
- data->ret = bdrv_change_backing_file(bs, base_id, base_fmt);
139
+ ret = bdrv_change_backing_file(bs, base_id, base_fmt);
140
bdrv_set_backing_hd(bs, base, &local_err);
141
if (local_err) {
142
error_report_err(local_err);
143
- data->ret = -EPERM;
144
+ ret = -EPERM;
145
goto out;
146
}
147
}
148
@@ -XXX,XX +XXX,XX @@ out:
149
}
150
151
g_free(s->backing_file_str);
152
- job_completed(job, data->ret);
153
- g_free(data);
154
+ job->ret = ret;
155
}
156
157
static int coroutine_fn stream_run(Job *job, Error **errp)
158
{
159
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
160
- StreamCompleteData *data;
161
BlockBackend *blk = s->common.blk;
162
BlockDriverState *bs = blk_bs(blk);
163
BlockDriverState *base = s->base;
164
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
165
166
out:
167
/* Modify backing chain and close BDSes in main loop */
168
- data = g_malloc(sizeof(*data));
169
- data->ret = ret;
170
- job_defer_to_main_loop(&s->common.job, stream_complete, data);
171
return ret;
172
}
173
174
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver stream_job_driver = {
175
.job_type = JOB_TYPE_STREAM,
176
.free = block_job_free,
177
.run = stream_run,
178
+ .exit = stream_exit,
179
.user_resume = block_job_user_resume,
180
.drain = block_job_drain,
181
},
182
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/tests/test-bdrv-drain.c
185
+++ b/tests/test-bdrv-drain.c
186
@@ -XXX,XX +XXX,XX @@ typedef struct TestBlockJob {
187
bool should_complete;
188
} TestBlockJob;
189
190
-static void test_job_completed(Job *job, void *opaque)
191
-{
192
- job_completed(job, 0);
193
-}
194
-
195
static int coroutine_fn test_job_run(Job *job, Error **errp)
196
{
197
TestBlockJob *s = container_of(job, TestBlockJob, common.job);
198
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
199
job_pause_point(&s->common.job);
200
}
201
202
- job_defer_to_main_loop(&s->common.job, test_job_completed, NULL);
203
return 0;
204
}
205
206
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
207
index XXXXXXX..XXXXXXX 100644
208
--- a/tests/test-blockjob-txn.c
209
+++ b/tests/test-blockjob-txn.c
210
@@ -XXX,XX +XXX,XX @@ typedef struct {
211
int *result;
212
} TestBlockJob;
213
214
-static void test_block_job_complete(Job *job, void *opaque)
215
+static void test_block_job_exit(Job *job)
216
{
217
BlockJob *bjob = container_of(job, BlockJob, job);
218
BlockDriverState *bs = blk_bs(bjob->blk);
219
- int rc = (intptr_t)opaque;
220
221
- if (job_is_cancelled(job)) {
222
- rc = -ECANCELED;
223
- }
224
-
225
- job_completed(job, rc);
226
bdrv_unref(bs);
227
}
228
229
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn test_block_job_run(Job *job, Error **errp)
230
}
231
}
232
233
- job_defer_to_main_loop(job, test_block_job_complete,
234
- (void *)(intptr_t)s->rc);
235
return s->rc;
236
}
237
238
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_block_job_driver = {
239
.user_resume = block_job_user_resume,
240
.drain = block_job_drain,
241
.run = test_block_job_run,
242
+ .exit = test_block_job_exit,
243
},
244
};
245
246
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
247
index XXXXXXX..XXXXXXX 100644
248
--- a/tests/test-blockjob.c
249
+++ b/tests/test-blockjob.c
250
@@ -XXX,XX +XXX,XX @@ typedef struct CancelJob {
251
bool completed;
252
} CancelJob;
253
254
-static void cancel_job_completed(Job *job, void *opaque)
255
+static void cancel_job_exit(Job *job)
256
{
257
- CancelJob *s = opaque;
258
+ CancelJob *s = container_of(job, CancelJob, common.job);
259
s->completed = true;
260
- job_completed(job, 0);
261
}
262
263
static void cancel_job_complete(Job *job, Error **errp)
264
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cancel_job_run(Job *job, Error **errp)
265
266
while (!s->should_complete) {
267
if (job_is_cancelled(&s->common.job)) {
268
- goto defer;
269
+ return 0;
270
}
271
272
if (!job_is_ready(&s->common.job) && s->should_converge) {
273
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cancel_job_run(Job *job, Error **errp)
274
job_sleep_ns(&s->common.job, 100000);
275
}
276
277
- defer:
278
- job_defer_to_main_loop(&s->common.job, cancel_job_completed, s);
279
return 0;
280
}
281
282
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_cancel_driver = {
283
.user_resume = block_job_user_resume,
284
.drain = block_job_drain,
285
.run = cancel_job_run,
286
+ .exit = cancel_job_exit,
287
.complete = cancel_job_complete,
288
},
289
};
290
--
170
--
291
2.17.1
171
2.26.2
292
172
293
173
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
In the past, when a new cluster was allocated the l2meta structure was
4
a variable in the stack so it was necessary to have a way to tell
5
whether it had been initialized and contained valid data or not. The
6
nb_clusters field was used for this purpose. Since commit f50f88b9fe
7
this is no longer the case, l2meta (nowadays a pointer to a list) is
8
only allocated when needed and nb_clusters is guaranteed to be > 0 so
9
this check is unnecessary.
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Message-Id: <ab0b67c29c7ba26e598db35f12aa5ab5982539c1.1599150873.git.berto@igalia.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/qcow2.c | 4 +---
16
1 file changed, 1 insertion(+), 3 deletions(-)
17
18
diff --git a/block/qcow2.c b/block/qcow2.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2.c
21
+++ b/block/qcow2.c
22
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs,
23
}
24
25
/* Take the request off the list of running requests */
26
- if (l2meta->nb_clusters != 0) {
27
- QLIST_REMOVE(l2meta, next_in_flight);
28
- }
29
+ QLIST_REMOVE(l2meta, next_in_flight);
30
31
qemu_co_queue_restart_all(&l2meta->dependent_requests);
32
33
--
34
2.26.2
35
36
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Change the manual deferment to mirror_exit into the implicit
3
The current text corresponds to an earlier, simpler version of this
4
callback to job_exit and the mirror_exit callback.
4
function and it does not explain how it works now.
5
5
6
This does change the order of some bdrv_unref calls and job_completed,
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
but thanks to the new context in which we call .exit, this is safe to
7
Message-Id: <bb5bd06f07c5a05b0818611de0d06ec5b66c8df3.1599150873.git.berto@igalia.com>
8
defer the possible flushing of any nodes to the job_finalize_single
9
cleanup stage.
10
11
Signed-off-by: John Snow <jsnow@redhat.com>
12
Message-id: 20180830015734.19765-6-jsnow@redhat.com
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Jeff Cody <jcody@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
9
---
17
block/mirror.c | 29 +++++++++++------------------
10
block/qcow2-cluster.c | 24 ++++++++++++++----------
18
1 file changed, 11 insertions(+), 18 deletions(-)
11
1 file changed, 14 insertions(+), 10 deletions(-)
19
12
20
diff --git a/block/mirror.c b/block/mirror.c
13
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
21
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
22
--- a/block/mirror.c
15
--- a/block/qcow2-cluster.c
23
+++ b/block/mirror.c
16
+++ b/block/qcow2-cluster.c
24
@@ -XXX,XX +XXX,XX @@ static void mirror_wait_for_all_io(MirrorBlockJob *s)
17
@@ -XXX,XX +XXX,XX @@ out:
25
}
26
}
18
}
27
19
28
-typedef struct {
20
/*
29
- int ret;
21
- * alloc_cluster_offset
30
-} MirrorExitData;
22
+ * For a given area on the virtual disk defined by @offset and @bytes,
31
-
23
+ * find the corresponding area on the qcow2 image, allocating new
32
-static void mirror_exit(Job *job, void *opaque)
24
+ * clusters (or subclusters) if necessary. The result can span a
33
+static void mirror_exit(Job *job)
25
+ * combination of allocated and previously unallocated clusters.
34
{
26
*
35
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
27
- * For a given offset on the virtual disk, find the cluster offset in qcow2
36
BlockJob *bjob = &s->common;
28
- * file. If the offset is not found, allocate a new cluster.
37
- MirrorExitData *data = opaque;
29
+ * On return, @host_offset is set to the beginning of the requested
38
MirrorBDSOpaque *bs_opaque = s->mirror_top_bs->opaque;
30
+ * area. This area is guaranteed to be contiguous on the qcow2 file
39
AioContext *replace_aio_context = NULL;
31
+ * but it can be smaller than initially requested. In this case @bytes
40
BlockDriverState *src = s->mirror_top_bs->backing->bs;
32
+ * is updated with the actual size.
41
BlockDriverState *target_bs = blk_bs(s->target);
33
*
42
BlockDriverState *mirror_top_bs = s->mirror_top_bs;
34
- * If the cluster was already allocated, m->nb_clusters is set to 0 and
43
Error *local_err = NULL;
35
- * other fields in m are meaningless.
44
+ int ret = job->ret;
36
- *
45
37
- * If the cluster is newly allocated, m->nb_clusters is set to the number of
46
bdrv_release_dirty_bitmap(src, s->dirty_bitmap);
38
- * contiguous clusters that have been allocated. In this case, the other
47
39
- * fields of m are valid and contain information about the first allocated
48
- /* Make sure that the source BDS doesn't go away before we called
40
- * cluster.
49
- * job_completed(). */
41
+ * If any clusters or subclusters were allocated then @m contains a
50
+ /* Make sure that the source BDS doesn't go away during bdrv_replace_node,
42
+ * list with the information of all the affected regions. Note that
51
+ * before we can call bdrv_drained_end */
43
+ * this can happen regardless of whether this function succeeds or
52
bdrv_ref(src);
44
+ * not. The caller is responsible for updating the L2 metadata of the
53
bdrv_ref(mirror_top_bs);
45
+ * allocated clusters (on success) or freeing them (on failure), and
54
bdrv_ref(target_bs);
46
+ * for clearing the contents of @m afterwards in both cases.
55
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
47
*
56
bdrv_set_backing_hd(target_bs, backing, &local_err);
48
* If the request conflicts with another write request in flight, the coroutine
57
if (local_err) {
49
* is queued and will be reentered when the dependency has completed.
58
error_report_err(local_err);
59
- data->ret = -EPERM;
60
+ ret = -EPERM;
61
}
62
}
63
}
64
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
65
aio_context_acquire(replace_aio_context);
66
}
67
68
- if (s->should_complete && data->ret == 0) {
69
+ if (s->should_complete && ret == 0) {
70
BlockDriverState *to_replace = src;
71
if (s->to_replace) {
72
to_replace = s->to_replace;
73
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
74
bdrv_drained_end(target_bs);
75
if (local_err) {
76
error_report_err(local_err);
77
- data->ret = -EPERM;
78
+ ret = -EPERM;
79
}
80
}
81
if (s->to_replace) {
82
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
83
blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort);
84
85
bs_opaque->job = NULL;
86
- job_completed(job, data->ret);
87
88
- g_free(data);
89
bdrv_drained_end(src);
90
bdrv_unref(mirror_top_bs);
91
bdrv_unref(src);
92
+
93
+ job->ret = ret;
94
}
95
96
static void mirror_throttle(MirrorBlockJob *s)
97
@@ -XXX,XX +XXX,XX @@ static int mirror_flush(MirrorBlockJob *s)
98
static int coroutine_fn mirror_run(Job *job, Error **errp)
99
{
100
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
101
- MirrorExitData *data;
102
BlockDriverState *bs = s->mirror_top_bs->backing->bs;
103
BlockDriverState *target_bs = blk_bs(s->target);
104
bool need_drain = true;
105
@@ -XXX,XX +XXX,XX @@ immediate_exit:
106
g_free(s->in_flight_bitmap);
107
bdrv_dirty_iter_free(s->dbi);
108
109
- data = g_malloc(sizeof(*data));
110
- data->ret = ret;
111
-
112
if (need_drain) {
113
bdrv_drained_begin(bs);
114
}
115
116
- job_defer_to_main_loop(&s->common.job, mirror_exit, data);
117
return ret;
118
}
119
120
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
121
.user_resume = block_job_user_resume,
122
.drain = block_job_drain,
123
.run = mirror_run,
124
+ .exit = mirror_exit,
125
.pause = mirror_pause,
126
.complete = mirror_complete,
127
},
128
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
129
.user_resume = block_job_user_resume,
130
.drain = block_job_drain,
131
.run = mirror_run,
132
+ .exit = mirror_exit,
133
.pause = mirror_pause,
134
.complete = mirror_complete,
135
},
136
--
50
--
137
2.17.1
51
2.26.2
138
52
139
53
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Yi Li <yili@winhong.com>
2
2
3
Presently we codify the entry point for a job as the "start" callback,
3
Signed-off-by: Yi Li <yili@winhong.com>
4
but a more apt name would be "run" to clarify the idea that when this
4
Message-Id: <20200819013607.32280-1-yili@winhong.com>
5
function returns we consider the job to have "finished," except for
5
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
any cleanup which occurs in separate callbacks later.
6
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
7
8
As part of this clarification, change the signature to include an error
9
object and a return code. The error ptr is not yet used, and the return
10
code while captured, will be overwritten by actions in the job_completed
11
function.
12
13
Signed-off-by: John Snow <jsnow@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Message-id: 20180830015734.19765-2-jsnow@redhat.com
16
Reviewed-by: Jeff Cody <jcody@redhat.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
8
---
19
include/qemu/job.h | 2 +-
9
qemu-img.c | 10 +++++-----
20
block/backup.c | 7 ++++---
10
1 file changed, 5 insertions(+), 5 deletions(-)
21
block/commit.c | 7 ++++---
22
block/create.c | 8 +++++---
23
block/mirror.c | 10 ++++++----
24
block/stream.c | 7 ++++---
25
job.c | 6 +++---
26
tests/test-bdrv-drain.c | 7 ++++---
27
tests/test-blockjob-txn.c | 16 ++++++++--------
28
tests/test-blockjob.c | 7 ++++---
29
10 files changed, 43 insertions(+), 34 deletions(-)
30
11
31
diff --git a/include/qemu/job.h b/include/qemu/job.h
12
diff --git a/qemu-img.c b/qemu-img.c
32
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
33
--- a/include/qemu/job.h
14
--- a/qemu-img.c
34
+++ b/include/qemu/job.h
15
+++ b/qemu-img.c
35
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
16
@@ -XXX,XX +XXX,XX @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum,
36
JobType job_type;
17
*pnum = 0;
37
18
return 0;
38
/** Mandatory: Entrypoint for the Coroutine. */
39
- CoroutineEntry *start;
40
+ int coroutine_fn (*run)(Job *job, Error **errp);
41
42
/**
43
* If the callback is not NULL, it will be invoked when the job transitions
44
diff --git a/block/backup.c b/block/backup.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block/backup.c
47
+++ b/block/backup.c
48
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
49
bdrv_dirty_iter_free(dbi);
50
}
51
52
-static void coroutine_fn backup_run(void *opaque)
53
+static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
54
{
55
- BackupBlockJob *job = opaque;
56
+ BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job);
57
BackupCompleteData *data;
58
BlockDriverState *bs = blk_bs(job->common.blk);
59
int64_t offset, nb_clusters;
60
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque)
61
data = g_malloc(sizeof(*data));
62
data->ret = ret;
63
job_defer_to_main_loop(&job->common.job, backup_complete, data);
64
+ return ret;
65
}
66
67
static const BlockJobDriver backup_job_driver = {
68
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver backup_job_driver = {
69
.free = block_job_free,
70
.user_resume = block_job_user_resume,
71
.drain = block_job_drain,
72
- .start = backup_run,
73
+ .run = backup_run,
74
.commit = backup_commit,
75
.abort = backup_abort,
76
.clean = backup_clean,
77
diff --git a/block/commit.c b/block/commit.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/block/commit.c
80
+++ b/block/commit.c
81
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
82
bdrv_unref(top);
83
}
84
85
-static void coroutine_fn commit_run(void *opaque)
86
+static int coroutine_fn commit_run(Job *job, Error **errp)
87
{
88
- CommitBlockJob *s = opaque;
89
+ CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
90
CommitCompleteData *data;
91
int64_t offset;
92
uint64_t delay_ns = 0;
93
@@ -XXX,XX +XXX,XX @@ out:
94
data = g_malloc(sizeof(*data));
95
data->ret = ret;
96
job_defer_to_main_loop(&s->common.job, commit_complete, data);
97
+ return ret;
98
}
99
100
static const BlockJobDriver commit_job_driver = {
101
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_job_driver = {
102
.free = block_job_free,
103
.user_resume = block_job_user_resume,
104
.drain = block_job_drain,
105
- .start = commit_run,
106
+ .run = commit_run,
107
},
108
};
109
110
diff --git a/block/create.c b/block/create.c
111
index XXXXXXX..XXXXXXX 100644
112
--- a/block/create.c
113
+++ b/block/create.c
114
@@ -XXX,XX +XXX,XX @@ static void blockdev_create_complete(Job *job, void *opaque)
115
job_completed(job, s->ret, s->err);
116
}
117
118
-static void coroutine_fn blockdev_create_run(void *opaque)
119
+static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
120
{
121
- BlockdevCreateJob *s = opaque;
122
+ BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
123
124
job_progress_set_remaining(&s->common, 1);
125
s->ret = s->drv->bdrv_co_create(s->opts, &s->err);
126
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blockdev_create_run(void *opaque)
127
128
qapi_free_BlockdevCreateOptions(s->opts);
129
job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL);
130
+
131
+ return s->ret;
132
}
133
134
static const JobDriver blockdev_create_job_driver = {
135
.instance_size = sizeof(BlockdevCreateJob),
136
.job_type = JOB_TYPE_CREATE,
137
- .start = blockdev_create_run,
138
+ .run = blockdev_create_run,
139
};
140
141
void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
142
diff --git a/block/mirror.c b/block/mirror.c
143
index XXXXXXX..XXXXXXX 100644
144
--- a/block/mirror.c
145
+++ b/block/mirror.c
146
@@ -XXX,XX +XXX,XX @@ static int mirror_flush(MirrorBlockJob *s)
147
return ret;
148
}
149
150
-static void coroutine_fn mirror_run(void *opaque)
151
+static int coroutine_fn mirror_run(Job *job, Error **errp)
152
{
153
- MirrorBlockJob *s = opaque;
154
+ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
155
MirrorExitData *data;
156
BlockDriverState *bs = s->mirror_top_bs->backing->bs;
157
BlockDriverState *target_bs = blk_bs(s->target);
158
@@ -XXX,XX +XXX,XX @@ immediate_exit:
159
if (need_drain) {
160
bdrv_drained_begin(bs);
161
}
19
}
162
+
20
- is_zero = buffer_is_zero(buf, 512);
163
job_defer_to_main_loop(&s->common.job, mirror_exit, data);
21
+ is_zero = buffer_is_zero(buf, BDRV_SECTOR_SIZE);
164
+ return ret;
22
for(i = 1; i < n; i++) {
165
}
23
- buf += 512;
166
24
- if (is_zero != buffer_is_zero(buf, 512)) {
167
static void mirror_complete(Job *job, Error **errp)
25
+ buf += BDRV_SECTOR_SIZE;
168
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
26
+ if (is_zero != buffer_is_zero(buf, BDRV_SECTOR_SIZE)) {
169
.free = block_job_free,
170
.user_resume = block_job_user_resume,
171
.drain = block_job_drain,
172
- .start = mirror_run,
173
+ .run = mirror_run,
174
.pause = mirror_pause,
175
.complete = mirror_complete,
176
},
177
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
178
.free = block_job_free,
179
.user_resume = block_job_user_resume,
180
.drain = block_job_drain,
181
- .start = mirror_run,
182
+ .run = mirror_run,
183
.pause = mirror_pause,
184
.complete = mirror_complete,
185
},
186
diff --git a/block/stream.c b/block/stream.c
187
index XXXXXXX..XXXXXXX 100644
188
--- a/block/stream.c
189
+++ b/block/stream.c
190
@@ -XXX,XX +XXX,XX @@ out:
191
g_free(data);
192
}
193
194
-static void coroutine_fn stream_run(void *opaque)
195
+static int coroutine_fn stream_run(Job *job, Error **errp)
196
{
197
- StreamBlockJob *s = opaque;
198
+ StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
199
StreamCompleteData *data;
200
BlockBackend *blk = s->common.blk;
201
BlockDriverState *bs = blk_bs(blk);
202
@@ -XXX,XX +XXX,XX @@ out:
203
data = g_malloc(sizeof(*data));
204
data->ret = ret;
205
job_defer_to_main_loop(&s->common.job, stream_complete, data);
206
+ return ret;
207
}
208
209
static const BlockJobDriver stream_job_driver = {
210
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver stream_job_driver = {
211
.instance_size = sizeof(StreamBlockJob),
212
.job_type = JOB_TYPE_STREAM,
213
.free = block_job_free,
214
- .start = stream_run,
215
+ .run = stream_run,
216
.user_resume = block_job_user_resume,
217
.drain = block_job_drain,
218
},
219
diff --git a/job.c b/job.c
220
index XXXXXXX..XXXXXXX 100644
221
--- a/job.c
222
+++ b/job.c
223
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
224
{
225
Job *job = opaque;
226
227
- assert(job && job->driver && job->driver->start);
228
+ assert(job && job->driver && job->driver->run);
229
job_pause_point(job);
230
- job->driver->start(job);
231
+ job->ret = job->driver->run(job, NULL);
232
}
233
234
235
void job_start(Job *job)
236
{
237
assert(job && !job_started(job) && job->paused &&
238
- job->driver && job->driver->start);
239
+ job->driver && job->driver->run);
240
job->co = qemu_coroutine_create(job_co_entry, job);
241
job->pause_count--;
242
job->busy = true;
243
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
244
index XXXXXXX..XXXXXXX 100644
245
--- a/tests/test-bdrv-drain.c
246
+++ b/tests/test-bdrv-drain.c
247
@@ -XXX,XX +XXX,XX @@ static void test_job_completed(Job *job, void *opaque)
248
job_completed(job, 0, NULL);
249
}
250
251
-static void coroutine_fn test_job_start(void *opaque)
252
+static int coroutine_fn test_job_run(Job *job, Error **errp)
253
{
254
- TestBlockJob *s = opaque;
255
+ TestBlockJob *s = container_of(job, TestBlockJob, common.job);
256
257
job_transition_to_ready(&s->common.job);
258
while (!s->should_complete) {
259
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_job_start(void *opaque)
260
}
261
262
job_defer_to_main_loop(&s->common.job, test_job_completed, NULL);
263
+ return 0;
264
}
265
266
static void test_job_complete(Job *job, Error **errp)
267
@@ -XXX,XX +XXX,XX @@ BlockJobDriver test_job_driver = {
268
.free = block_job_free,
269
.user_resume = block_job_user_resume,
270
.drain = block_job_drain,
271
- .start = test_job_start,
272
+ .run = test_job_run,
273
.complete = test_job_complete,
274
},
275
};
276
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
277
index XXXXXXX..XXXXXXX 100644
278
--- a/tests/test-blockjob-txn.c
279
+++ b/tests/test-blockjob-txn.c
280
@@ -XXX,XX +XXX,XX @@ static void test_block_job_complete(Job *job, void *opaque)
281
bdrv_unref(bs);
282
}
283
284
-static void coroutine_fn test_block_job_run(void *opaque)
285
+static int coroutine_fn test_block_job_run(Job *job, Error **errp)
286
{
287
- TestBlockJob *s = opaque;
288
- BlockJob *job = &s->common;
289
+ TestBlockJob *s = container_of(job, TestBlockJob, common.job);
290
291
while (s->iterations--) {
292
if (s->use_timer) {
293
- job_sleep_ns(&job->job, 0);
294
+ job_sleep_ns(job, 0);
295
} else {
296
- job_yield(&job->job);
297
+ job_yield(job);
298
}
299
300
- if (job_is_cancelled(&job->job)) {
301
+ if (job_is_cancelled(job)) {
302
break;
27
break;
303
}
28
}
304
}
29
}
305
30
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
306
- job_defer_to_main_loop(&job->job, test_block_job_complete,
31
}
307
+ job_defer_to_main_loop(job, test_block_job_complete,
32
}
308
(void *)(intptr_t)s->rc);
33
309
+ return s->rc;
34
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s.total_sectors * 512,
310
}
35
- &error_abort);
311
36
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
312
typedef struct {
37
+ s.total_sectors * BDRV_SECTOR_SIZE, &error_abort);
313
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_block_job_driver = {
38
ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL);
314
.free = block_job_free,
39
if (ret < 0) {
315
.user_resume = block_job_user_resume,
40
goto out;
316
.drain = block_job_drain,
317
- .start = test_block_job_run,
318
+ .run = test_block_job_run,
319
},
320
};
321
322
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
323
index XXXXXXX..XXXXXXX 100644
324
--- a/tests/test-blockjob.c
325
+++ b/tests/test-blockjob.c
326
@@ -XXX,XX +XXX,XX @@ static void cancel_job_complete(Job *job, Error **errp)
327
s->should_complete = true;
328
}
329
330
-static void coroutine_fn cancel_job_start(void *opaque)
331
+static int coroutine_fn cancel_job_run(Job *job, Error **errp)
332
{
333
- CancelJob *s = opaque;
334
+ CancelJob *s = container_of(job, CancelJob, common.job);
335
336
while (!s->should_complete) {
337
if (job_is_cancelled(&s->common.job)) {
338
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn cancel_job_start(void *opaque)
339
340
defer:
341
job_defer_to_main_loop(&s->common.job, cancel_job_completed, s);
342
+ return 0;
343
}
344
345
static const BlockJobDriver test_cancel_driver = {
346
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_cancel_driver = {
347
.free = block_job_free,
348
.user_resume = block_job_user_resume,
349
.drain = block_job_drain,
350
- .start = cancel_job_start,
351
+ .run = cancel_job_run,
352
.complete = cancel_job_complete,
353
},
354
};
355
--
41
--
356
2.17.1
42
2.26.2
357
43
358
44
diff view generated by jsdifflib
New patch
1
From: Thomas Huth <thuth@redhat.com>
1
2
3
The test_stream_parallel test still occasionally fails in the CI.
4
Thus let's disable it during "make check" for now so that it does
5
not cause trouble during merge tests. We can enable it again once
6
the problem has been resolved.
7
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Message-Id: <20200907113824.134788-1-thuth@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
tests/check-block.sh | 3 +++
13
tests/qemu-iotests/030 | 2 ++
14
2 files changed, 5 insertions(+)
15
16
diff --git a/tests/check-block.sh b/tests/check-block.sh
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/check-block.sh
19
+++ b/tests/check-block.sh
20
@@ -XXX,XX +XXX,XX @@ fi
21
22
cd tests/qemu-iotests
23
24
+# QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests
25
+export QEMU_CHECK_BLOCK_AUTO=1
26
+
27
ret=0
28
for fmt in $format_list ; do
29
./check -makecheck -$fmt $group || ret=1
30
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
31
index XXXXXXX..XXXXXXX 100755
32
--- a/tests/qemu-iotests/030
33
+++ b/tests/qemu-iotests/030
34
@@ -XXX,XX +XXX,XX @@
35
import time
36
import os
37
import iotests
38
+import unittest
39
from iotests import qemu_img, qemu_io
40
41
backing_img = os.path.join(iotests.test_dir, 'backing.img')
42
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
43
44
# Test that it's possible to run several block-stream operations
45
# in parallel in the same snapshot chain
46
+ @unittest.skipIf(os.environ.get('QEMU_CHECK_BLOCK_AUTO'), 'disabled in CI')
47
def test_stream_parallel(self):
48
self.assert_no_active_block_jobs()
49
50
--
51
2.26.2
52
53
diff view generated by jsdifflib
New patch
1
From: Swapnil Ingle <swapnil.ingle@nutanix.com>
1
2
3
block/vhdx uses qemu block layer where sector size is always 512 bytes.
4
This may have issues with 4K logical sector sized vhdx image.
5
6
For e.g qemu-img convert on such images fails with following assert:
7
8
$qemu-img convert -f vhdx -O raw 4KTest1.vhdx test.raw
9
qemu-img: util/iov.c:388: qiov_slice: Assertion `offset + len <=
10
qiov->size' failed.
11
Aborted
12
13
This patch adds an check to return ENOTSUP for vhdx images which
14
have logical sector size other than 512 bytes.
15
16
Signed-off-by: Swapnil Ingle <swapnil.ingle@nutanix.com>
17
Message-Id: <1596794594-44531-1-git-send-email-swapnil.ingle@nutanix.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
block/vhdx.c | 6 +++---
21
1 file changed, 3 insertions(+), 3 deletions(-)
22
23
diff --git a/block/vhdx.c b/block/vhdx.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/vhdx.c
26
+++ b/block/vhdx.c
27
@@ -XXX,XX +XXX,XX @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
28
goto exit;
29
}
30
31
- /* only 2 supported sector sizes */
32
- if (s->logical_sector_size != 512 && s->logical_sector_size != 4096) {
33
- ret = -EINVAL;
34
+ /* Currently we only support 512 */
35
+ if (s->logical_sector_size != 512) {
36
+ ret = -ENOTSUP;
37
goto exit;
38
}
39
40
--
41
2.26.2
42
43
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Rename opaque_job to job to be consistent with other job implementations.
3
If qcow2_alloc_cluster_offset() or qcow2_alloc_cluster_link_l2() fail
4
Rename 'job', the BackupBlockJob object, to 's' to also be consistent.
4
then this function simply returns the error code, potentially leaking
5
the QCowL2Meta structure and leaving stale items in s->cluster_allocs.
5
6
6
Suggested-by: Eric Blake <eblake@redhat.com>
7
A second problem is that this function calls qcow2_free_any_clusters()
7
Signed-off-by: John Snow <jsnow@redhat.com>
8
on failure but passing a host cluster offset instead of an L2 entry.
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Luckily for normal uncompressed clusters a raw offset also works like
9
Message-id: 20180830015734.19765-8-jsnow@redhat.com
10
a valid L2 entry so it works just the same, but we should be using
11
qcow2_free_clusters() instead.
12
13
This patch fixes both problems by using qcow2_handle_l2meta().
14
15
Signed-off-by: Alberto Garcia <berto@igalia.com>
16
Message-Id: <cd3a6b9abd43f9c0b60be413d760f0cacc67eb66.1599573989.git.berto@igalia.com>
17
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
19
---
12
block/backup.c | 62 +++++++++++++++++++++++++-------------------------
20
block/qcow2.c | 40 +++++++++++++++++-----------------------
13
1 file changed, 31 insertions(+), 31 deletions(-)
21
1 file changed, 17 insertions(+), 23 deletions(-)
14
22
15
diff --git a/block/backup.c b/block/backup.c
23
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
17
--- a/block/backup.c
25
--- a/block/qcow2.c
18
+++ b/block/backup.c
26
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
27
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs,
20
bdrv_dirty_iter_free(dbi);
28
QCowL2Meta *next;
21
}
29
22
30
if (link_l2) {
23
-static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
31
- assert(!l2meta->prealloc);
24
+static int coroutine_fn backup_run(Job *job, Error **errp)
32
ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
25
{
33
if (ret) {
26
- BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job);
34
goto out;
27
- BlockDriverState *bs = blk_bs(job->common.blk);
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
28
+ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
36
int64_t file_length;
29
+ BlockDriverState *bs = blk_bs(s->common.blk);
37
unsigned int cur_bytes;
30
int64_t offset, nb_clusters;
38
int ret;
31
int ret = 0;
39
- QCowL2Meta *meta;
32
40
+ QCowL2Meta *meta = NULL, *m;
33
- QLIST_INIT(&job->inflight_reqs);
41
34
- qemu_co_rwlock_init(&job->flush_rwlock);
42
assert(offset <= new_length);
35
+ QLIST_INIT(&s->inflight_reqs);
43
bytes = new_length - offset;
36
+ qemu_co_rwlock_init(&s->flush_rwlock);
44
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
37
45
&host_offset, &meta);
38
- nb_clusters = DIV_ROUND_UP(job->len, job->cluster_size);
46
if (ret < 0) {
39
- job_progress_set_remaining(&job->common.job, job->len);
47
error_setg_errno(errp, -ret, "Allocating clusters failed");
40
+ nb_clusters = DIV_ROUND_UP(s->len, s->cluster_size);
48
- return ret;
41
+ job_progress_set_remaining(job, s->len);
49
+ goto out;
42
50
}
43
- job->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
51
44
- if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
52
- while (meta) {
45
- backup_incremental_init_copy_bitmap(job);
53
- QCowL2Meta *next = meta->next;
46
+ s->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
54
- meta->prealloc = true;
47
+ if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
55
-
48
+ backup_incremental_init_copy_bitmap(s);
56
- ret = qcow2_alloc_cluster_link_l2(bs, meta);
49
} else {
57
- if (ret < 0) {
50
- hbitmap_set(job->copy_bitmap, 0, nb_clusters);
58
- error_setg_errno(errp, -ret, "Mapping clusters failed");
51
+ hbitmap_set(s->copy_bitmap, 0, nb_clusters);
59
- qcow2_free_any_clusters(bs, meta->alloc_offset,
60
- meta->nb_clusters, QCOW2_DISCARD_NEVER);
61
- return ret;
62
- }
63
-
64
- /* There are no dependent requests, but we need to remove our
65
- * request from the list of in-flight requests */
66
- QLIST_REMOVE(meta, next_in_flight);
67
+ for (m = meta; m != NULL; m = m->next) {
68
+ m->prealloc = true;
69
+ }
70
71
- g_free(meta);
72
- meta = next;
73
+ ret = qcow2_handle_l2meta(bs, &meta, true);
74
+ if (ret < 0) {
75
+ error_setg_errno(errp, -ret, "Mapping clusters failed");
76
+ goto out;
77
}
78
79
/* TODO Preallocate data if requested */
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
81
file_length = bdrv_getlength(s->data_file->bs);
82
if (file_length < 0) {
83
error_setg_errno(errp, -file_length, "Could not get file size");
84
- return file_length;
85
+ ret = file_length;
86
+ goto out;
52
}
87
}
53
88
54
89
if (host_offset + cur_bytes > file_length) {
55
- job->before_write.notify = backup_before_write_notify;
90
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
56
- bdrv_add_before_write_notifier(bs, &job->before_write);
91
ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false,
57
+ s->before_write.notify = backup_before_write_notify;
92
mode, 0, errp);
58
+ bdrv_add_before_write_notifier(bs, &s->before_write);
93
if (ret < 0) {
59
94
- return ret;
60
- if (job->sync_mode == MIRROR_SYNC_MODE_NONE) {
95
+ goto out;
61
+ if (s->sync_mode == MIRROR_SYNC_MODE_NONE) {
62
/* All bits are set in copy_bitmap to allow any cluster to be copied.
63
* This does not actually require them to be copied. */
64
- while (!job_is_cancelled(&job->common.job)) {
65
+ while (!job_is_cancelled(job)) {
66
/* Yield until the job is cancelled. We just let our before_write
67
* notify callback service CoW requests. */
68
- job_yield(&job->common.job);
69
+ job_yield(job);
70
}
71
- } else if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
72
- ret = backup_run_incremental(job);
73
+ } else if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
74
+ ret = backup_run_incremental(s);
75
} else {
76
/* Both FULL and TOP SYNC_MODE's require copying.. */
77
- for (offset = 0; offset < job->len;
78
- offset += job->cluster_size) {
79
+ for (offset = 0; offset < s->len;
80
+ offset += s->cluster_size) {
81
bool error_is_read;
82
int alloced = 0;
83
84
- if (yield_and_check(job)) {
85
+ if (yield_and_check(s)) {
86
break;
87
}
88
89
- if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
90
+ if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
91
int i;
92
int64_t n;
93
94
/* Check to see if these blocks are already in the
95
* backing file. */
96
97
- for (i = 0; i < job->cluster_size;) {
98
+ for (i = 0; i < s->cluster_size;) {
99
/* bdrv_is_allocated() only returns true/false based
100
* on the first set of sectors it comes across that
101
* are are all in the same state.
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
103
* needed but at some point that is always the case. */
104
alloced =
105
bdrv_is_allocated(bs, offset + i,
106
- job->cluster_size - i, &n);
107
+ s->cluster_size - i, &n);
108
i += n;
109
110
if (alloced || n == 0) {
111
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
112
if (alloced < 0) {
113
ret = alloced;
114
} else {
115
- ret = backup_do_cow(job, offset, job->cluster_size,
116
+ ret = backup_do_cow(s, offset, s->cluster_size,
117
&error_is_read, false);
118
}
119
if (ret < 0) {
120
/* Depending on error action, fail now or retry cluster */
121
BlockErrorAction action =
122
- backup_error_action(job, error_is_read, -ret);
123
+ backup_error_action(s, error_is_read, -ret);
124
if (action == BLOCK_ERROR_ACTION_REPORT) {
125
break;
126
} else {
127
- offset -= job->cluster_size;
128
+ offset -= s->cluster_size;
129
continue;
130
}
131
}
132
}
96
}
133
}
97
}
134
98
135
- notifier_with_return_remove(&job->before_write);
99
- return 0;
136
+ notifier_with_return_remove(&s->before_write);
100
+ ret = 0;
137
101
+
138
/* wait until pending backup_do_cow() calls have completed */
102
+out:
139
- qemu_co_rwlock_wrlock(&job->flush_rwlock);
103
+ qcow2_handle_l2meta(bs, &meta, false);
140
- qemu_co_rwlock_unlock(&job->flush_rwlock);
104
+ return ret;
141
- hbitmap_free(job->copy_bitmap);
142
+ qemu_co_rwlock_wrlock(&s->flush_rwlock);
143
+ qemu_co_rwlock_unlock(&s->flush_rwlock);
144
+ hbitmap_free(s->copy_bitmap);
145
146
return ret;
147
}
105
}
106
107
/* qcow2_refcount_metadata_size:
148
--
108
--
149
2.17.1
109
2.26.2
150
110
151
111
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
If we know we've already locked the bytes, don't do it again; similarly
3
This function takes an L2 entry and a number of clusters to free.
4
don't unlock a byte if we haven't locked it. This doesn't change the
4
Although in principle it can free any type of cluster (using the L2
5
behavior, but fixes a corner case explained below.
5
entry to determine its type) in practice the API is broken because
6
compressed clusters have a variable size and there is no way to free
7
more than one without having the L2 entry of each one of them.
6
8
7
Libvirt had an error handling bug that an image can get its (ownership,
9
The good news all callers are passing nb_clusters=1 so we can simply
8
file mode, SELinux) permissions changed (RHBZ 1584982) by mistake behind
10
get rid of that parameter.
9
QEMU. Specifically, an image in use by Libvirt VM has:
10
11
11
$ ls -lhZ b.img
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
-rw-r--r--. qemu qemu system_u:object_r:svirt_image_t:s0:c600,c690 b.img
13
Message-Id: <77cea0f4616f921d37e971b3c5b18a2faa24b173.1599573989.git.berto@igalia.com>
14
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
block/qcow2.h | 4 ++--
18
block/qcow2-cluster.c | 6 +++---
19
block/qcow2-refcount.c | 8 ++++----
20
3 files changed, 9 insertions(+), 9 deletions(-)
13
21
14
Trying to attach it a second time won't work because of image locking.
22
diff --git a/block/qcow2.h b/block/qcow2.h
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
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
32
---
33
block/file-posix.c | 41 +++++++++++++++++++++++++++++++----------
34
1 file changed, 31 insertions(+), 10 deletions(-)
35
36
diff --git a/block/file-posix.c b/block/file-posix.c
37
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
38
--- a/block/file-posix.c
24
--- a/block/qcow2.h
39
+++ b/block/file-posix.c
25
+++ b/block/qcow2.h
40
@@ -XXX,XX +XXX,XX @@ typedef enum {
26
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
41
* file; if @unlock == true, also unlock the unneeded bytes.
27
void qcow2_free_clusters(BlockDriverState *bs,
42
* @shared_perm_lock_bits is the mask of all permissions that are NOT shared.
28
int64_t offset, int64_t size,
29
enum qcow2_discard_type type);
30
-void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
31
- int nb_clusters, enum qcow2_discard_type type);
32
+void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry,
33
+ enum qcow2_discard_type type);
34
35
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
36
int64_t l1_table_offset, int l1_size, int addend);
37
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/block/qcow2-cluster.c
40
+++ b/block/qcow2-cluster.c
41
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
42
*/
43
if (!m->keep_old_clusters && j != 0) {
44
for (i = 0; i < j; i++) {
45
- qcow2_free_any_clusters(bs, old_cluster[i], 1, QCOW2_DISCARD_NEVER);
46
+ qcow2_free_any_cluster(bs, old_cluster[i], QCOW2_DISCARD_NEVER);
47
}
48
}
49
50
@@ -XXX,XX +XXX,XX @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
51
set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap);
52
}
53
/* Then decrease the refcount */
54
- qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
55
+ qcow2_free_any_cluster(bs, old_l2_entry, type);
56
}
57
58
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
59
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
60
61
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
62
if (unmap) {
63
- qcow2_free_any_clusters(bs, old_l2_entry, 1, QCOW2_DISCARD_REQUEST);
64
+ qcow2_free_any_cluster(bs, old_l2_entry, QCOW2_DISCARD_REQUEST);
65
}
66
set_l2_entry(s, l2_slice, l2_index + i, new_l2_entry);
67
if (has_subclusters(s)) {
68
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/block/qcow2-refcount.c
71
+++ b/block/qcow2-refcount.c
72
@@ -XXX,XX +XXX,XX @@ void qcow2_free_clusters(BlockDriverState *bs,
73
* Free a cluster using its L2 entry (handles clusters of all types, e.g.
74
* normal cluster, compressed cluster, etc.)
43
*/
75
*/
44
-static int raw_apply_lock_bytes(int fd,
76
-void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
45
+static int raw_apply_lock_bytes(BDRVRawState *s, int fd,
77
- int nb_clusters, enum qcow2_discard_type type)
46
uint64_t perm_lock_bits,
78
+void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry,
47
uint64_t shared_perm_lock_bits,
79
+ enum qcow2_discard_type type)
48
bool unlock, Error **errp)
49
{
80
{
50
int ret;
81
BDRVQcow2State *s = bs->opaque;
51
int i;
82
QCow2ClusterType ctype = qcow2_get_cluster_type(bs, l2_entry);
52
+ uint64_t locked_perm, locked_shared_perm;
83
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
53
+
84
ctype == QCOW2_CLUSTER_ZERO_ALLOC))
54
+ if (s) {
85
{
55
+ locked_perm = s->perm;
86
bdrv_pdiscard(s->data_file, l2_entry & L2E_OFFSET_MASK,
56
+ locked_shared_perm = ~s->shared_perm & BLK_PERM_ALL;
87
- nb_clusters << s->cluster_bits);
57
+ } else {
88
+ s->cluster_size);
58
+ /*
89
}
59
+ * We don't have the previous bits, just lock/unlock for each of the
90
return;
60
+ * requested bits.
61
+ */
62
+ if (unlock) {
63
+ locked_perm = BLK_PERM_ALL;
64
+ locked_shared_perm = BLK_PERM_ALL;
65
+ } else {
66
+ locked_perm = 0;
67
+ locked_shared_perm = 0;
68
+ }
69
+ }
70
71
PERM_FOREACH(i) {
72
int off = RAW_LOCK_PERM_BASE + i;
73
- if (perm_lock_bits & (1ULL << i)) {
74
+ uint64_t bit = (1ULL << i);
75
+ if ((perm_lock_bits & bit) && !(locked_perm & bit)) {
76
ret = qemu_lock_fd(fd, off, 1, false);
77
if (ret) {
78
error_setg(errp, "Failed to lock byte %d", off);
79
return ret;
80
}
81
- } else if (unlock) {
82
+ } else if (unlock && (locked_perm & bit) && !(perm_lock_bits & bit)) {
83
ret = qemu_unlock_fd(fd, off, 1);
84
if (ret) {
85
error_setg(errp, "Failed to unlock byte %d", off);
86
@@ -XXX,XX +XXX,XX @@ static int raw_apply_lock_bytes(int fd,
87
}
91
}
88
PERM_FOREACH(i) {
92
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
89
int off = RAW_LOCK_SHARED_BASE + i;
93
l2_entry & L2E_OFFSET_MASK);
90
- if (shared_perm_lock_bits & (1ULL << i)) {
94
} else {
91
+ uint64_t bit = (1ULL << i);
95
qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
92
+ if ((shared_perm_lock_bits & bit) && !(locked_shared_perm & bit)) {
96
- nb_clusters << s->cluster_bits, type);
93
ret = qemu_lock_fd(fd, off, 1, false);
97
+ s->cluster_size, type);
94
if (ret) {
95
error_setg(errp, "Failed to lock byte %d", off);
96
return ret;
97
}
98
- } else if (unlock) {
99
+ } else if (unlock && (locked_shared_perm & bit) &&
100
+ !(shared_perm_lock_bits & bit)) {
101
ret = qemu_unlock_fd(fd, off, 1);
102
if (ret) {
103
error_setg(errp, "Failed to unlock byte %d", off);
104
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
105
106
switch (op) {
107
case RAW_PL_PREPARE:
108
- ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm,
109
+ ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm,
110
~s->shared_perm | ~new_shared,
111
false, errp);
112
if (!ret) {
113
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
114
op = RAW_PL_ABORT;
115
/* fall through to unlock bytes. */
116
case RAW_PL_ABORT:
117
- raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm,
118
+ raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm,
119
true, &local_err);
120
if (local_err) {
121
/* Theoretically the above call only unlocks bytes and it cannot
122
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
123
}
98
}
124
break;
99
break;
125
case RAW_PL_COMMIT:
100
case QCOW2_CLUSTER_ZERO_PLAIN:
126
- raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared,
127
+ raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared,
128
true, &local_err);
129
if (local_err) {
130
/* Theoretically the above call only unlocks bytes and it cannot
131
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
132
shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
133
134
/* Step one: Take locks */
135
- result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp);
136
+ result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp);
137
if (result < 0) {
138
goto out_close;
139
}
140
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
141
}
142
143
out_unlock:
144
- raw_apply_lock_bytes(fd, 0, 0, true, &local_err);
145
+ raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err);
146
if (local_err) {
147
/* The above call should not fail, and if it does, that does
148
* not mean the whole creation operation has failed. So
149
--
101
--
150
2.17.1
102
2.26.2
151
103
152
104
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This function checks the current status of a (sub)cluster in order to
4
see if an unaligned 'write zeroes' request can be done efficiently by
5
simply updating the L2 metadata and without having to write actual
6
zeroes to disk.
7
8
If the situation does not allow using the fast path then the function
9
returns -ENOTSUP and the caller falls back to writing zeroes.
10
11
If can happen however that the aforementioned check returns an actual
12
error code so in this case we should pass it to the caller.
13
14
Signed-off-by: Alberto Garcia <berto@igalia.com>
15
Message-Id: <20200909123739.719-1-berto@igalia.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
18
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
---
21
block/qcow2.c | 2 +-
22
1 file changed, 1 insertion(+), 1 deletion(-)
23
24
diff --git a/block/qcow2.c b/block/qcow2.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block/qcow2.c
27
+++ b/block/qcow2.c
28
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
29
type != QCOW2_SUBCLUSTER_ZERO_PLAIN &&
30
type != QCOW2_SUBCLUSTER_ZERO_ALLOC)) {
31
qemu_co_mutex_unlock(&s->lock);
32
- return -ENOTSUP;
33
+ return ret < 0 ? ret : -ENOTSUP;
34
}
35
} else {
36
qemu_co_mutex_lock(&s->lock);
37
--
38
2.26.2
39
40
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: John Snow <jsnow@redhat.com>
2
2
3
Jobs presently use both an Error object in the case of the create job,
3
This saw its last use in 4bfb274165ba.
4
and char strings in the case of generic errors elsewhere.
5
6
Unify the two paths as just j->err, and remove the extra argument from
7
job_completed. The integer error code for job_completed is kept for now,
8
to be removed shortly in a separate patch.
9
4
10
Signed-off-by: John Snow <jsnow@redhat.com>
5
Signed-off-by: John Snow <jsnow@redhat.com>
11
Message-id: 20180830015734.19765-3-jsnow@redhat.com
6
Message-Id: <20200806211345.2925343-2-jsnow@redhat.com>
12
[mreitz: Dropped a superfluous g_strdup()]
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
8
---
16
include/qemu/job.h | 14 ++++++++------
9
block/rbd.c | 42 ------------------------------------------
17
block/backup.c | 2 +-
10
1 file changed, 42 deletions(-)
18
block/commit.c | 2 +-
19
block/create.c | 5 ++---
20
block/mirror.c | 2 +-
21
block/stream.c | 2 +-
22
job-qmp.c | 5 +++--
23
job.c | 18 ++++++------------
24
tests/test-bdrv-drain.c | 2 +-
25
tests/test-blockjob-txn.c | 2 +-
26
tests/test-blockjob.c | 2 +-
27
11 files changed, 26 insertions(+), 30 deletions(-)
28
11
29
diff --git a/include/qemu/job.h b/include/qemu/job.h
12
diff --git a/block/rbd.c b/block/rbd.c
30
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
31
--- a/include/qemu/job.h
14
--- a/block/rbd.c
32
+++ b/include/qemu/job.h
15
+++ b/block/rbd.c
33
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
16
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
34
/** Estimated progress_current value at the completion of the job */
35
int64_t progress_total;
36
37
- /** Error string for a failed job (NULL if, and only if, job->ret == 0) */
38
- char *error;
39
-
40
/** ret code passed to job_completed. */
41
int ret;
42
43
+ /**
44
+ * Error object for a failed job.
45
+ * If job->ret is nonzero and an error object was not set, it will be set
46
+ * to strerror(-job->ret) during job_completed.
47
+ */
48
+ Error *err;
49
+
50
/** The completion function that will be called when the job completes. */
51
BlockCompletionFunc *cb;
52
53
@@ -XXX,XX +XXX,XX @@ void job_transition_to_ready(Job *job);
54
/**
55
* @job: The job being completed.
56
* @ret: The status code.
57
- * @error: The error message for a failing job (only with @ret < 0). If @ret is
58
- * negative, but NULL is given for @error, strerror() is used.
59
*
60
* Marks @job as completed. If @ret is non-zero, the job transaction it is part
61
* of is aborted. If @ret is zero, the job moves into the WAITING state. If it
62
* is the last job to complete in its transaction, all jobs in the transaction
63
* move from WAITING to PENDING.
64
*/
65
-void job_completed(Job *job, int ret, Error *error);
66
+void job_completed(Job *job, int ret);
67
68
/** Asynchronously complete the specified @job. */
69
void job_complete(Job *job, Error **errp);
70
diff --git a/block/backup.c b/block/backup.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/backup.c
73
+++ b/block/backup.c
74
@@ -XXX,XX +XXX,XX @@ static void backup_complete(Job *job, void *opaque)
75
{
76
BackupCompleteData *data = opaque;
77
78
- job_completed(job, data->ret, NULL);
79
+ job_completed(job, data->ret);
80
g_free(data);
81
}
82
83
diff --git a/block/commit.c b/block/commit.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/block/commit.c
86
+++ b/block/commit.c
87
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
88
* bdrv_set_backing_hd() to fail. */
89
block_job_remove_all_bdrv(bjob);
90
91
- job_completed(job, ret, NULL);
92
+ job_completed(job, ret);
93
g_free(data);
94
95
/* If bdrv_drop_intermediate() didn't already do that, remove the commit
96
diff --git a/block/create.c b/block/create.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/block/create.c
99
+++ b/block/create.c
100
@@ -XXX,XX +XXX,XX @@ typedef struct BlockdevCreateJob {
101
BlockDriver *drv;
102
BlockdevCreateOptions *opts;
103
int ret;
104
- Error *err;
105
} BlockdevCreateJob;
106
107
static void blockdev_create_complete(Job *job, void *opaque)
108
{
109
BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
110
111
- job_completed(job, s->ret, s->err);
112
+ job_completed(job, s->ret);
113
}
114
115
static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
116
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
117
BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
118
119
job_progress_set_remaining(&s->common, 1);
120
- s->ret = s->drv->bdrv_co_create(s->opts, &s->err);
121
+ s->ret = s->drv->bdrv_co_create(s->opts, errp);
122
job_progress_update(&s->common, 1);
123
124
qapi_free_BlockdevCreateOptions(s->opts);
125
diff --git a/block/mirror.c b/block/mirror.c
126
index XXXXXXX..XXXXXXX 100644
127
--- a/block/mirror.c
128
+++ b/block/mirror.c
129
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
130
blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort);
131
132
bs_opaque->job = NULL;
133
- job_completed(job, data->ret, NULL);
134
+ job_completed(job, data->ret);
135
136
g_free(data);
137
bdrv_drained_end(src);
138
diff --git a/block/stream.c b/block/stream.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/stream.c
141
+++ b/block/stream.c
142
@@ -XXX,XX +XXX,XX @@ out:
143
}
144
145
g_free(s->backing_file_str);
146
- job_completed(job, data->ret, NULL);
147
+ job_completed(job, data->ret);
148
g_free(data);
149
}
150
151
diff --git a/job-qmp.c b/job-qmp.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/job-qmp.c
154
+++ b/job-qmp.c
155
@@ -XXX,XX +XXX,XX @@ static JobInfo *job_query_single(Job *job, Error **errp)
156
.status = job->status,
157
.current_progress = job->progress_current,
158
.total_progress = job->progress_total,
159
- .has_error = !!job->error,
160
- .error = g_strdup(job->error),
161
+ .has_error = !!job->err,
162
+ .error = job->err ? \
163
+ g_strdup(error_get_pretty(job->err)) : NULL,
164
};
165
166
return info;
167
diff --git a/job.c b/job.c
168
index XXXXXXX..XXXXXXX 100644
169
--- a/job.c
170
+++ b/job.c
171
@@ -XXX,XX +XXX,XX @@ void job_unref(Job *job)
172
173
QLIST_REMOVE(job, job_list);
174
175
- g_free(job->error);
176
+ error_free(job->err);
177
g_free(job->id);
178
g_free(job);
179
}
180
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
181
182
assert(job && job->driver && job->driver->run);
183
job_pause_point(job);
184
- job->ret = job->driver->run(job, NULL);
185
+ job->ret = job->driver->run(job, &job->err);
186
}
187
188
189
@@ -XXX,XX +XXX,XX @@ static void job_update_rc(Job *job)
190
job->ret = -ECANCELED;
191
}
192
if (job->ret) {
193
- if (!job->error) {
194
- job->error = g_strdup(strerror(-job->ret));
195
+ if (!job->err) {
196
+ error_setg(&job->err, "%s", strerror(-job->ret));
197
}
198
job_state_transition(job, JOB_STATUS_ABORTING);
199
}
200
@@ -XXX,XX +XXX,XX @@ static void job_completed_txn_success(Job *job)
201
}
17
}
202
}
18
}
203
19
204
-void job_completed(Job *job, int ret, Error *error)
20
-static QemuOptsList runtime_opts = {
205
+void job_completed(Job *job, int ret)
21
- .name = "rbd",
206
{
22
- .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
207
assert(job && job->txn && !job_is_completed(job));
23
- .desc = {
208
24
- {
209
job->ret = ret;
25
- .name = "pool",
210
- if (error) {
26
- .type = QEMU_OPT_STRING,
211
- assert(job->ret < 0);
27
- .help = "Rados pool name",
212
- job->error = g_strdup(error_get_pretty(error));
28
- },
213
- error_free(error);
29
- {
214
- }
30
- .name = "namespace",
31
- .type = QEMU_OPT_STRING,
32
- .help = "Rados namespace name in the pool",
33
- },
34
- {
35
- .name = "image",
36
- .type = QEMU_OPT_STRING,
37
- .help = "Image name in the pool",
38
- },
39
- {
40
- .name = "conf",
41
- .type = QEMU_OPT_STRING,
42
- .help = "Rados config file location",
43
- },
44
- {
45
- .name = "snapshot",
46
- .type = QEMU_OPT_STRING,
47
- .help = "Ceph snapshot name",
48
- },
49
- {
50
- /* maps to 'id' in rados_create() */
51
- .name = "user",
52
- .type = QEMU_OPT_STRING,
53
- .help = "Rados id name",
54
- },
55
- /*
56
- * server.* extracted manually, see qemu_rbd_mon_host()
57
- */
58
- { /* end of list */ }
59
- },
60
-};
215
-
61
-
216
job_update_rc(job);
62
/* FIXME Deprecate and remove keypairs or make it available in QMP. */
217
trace_job_completed(job, ret, job->ret);
63
static int qemu_rbd_do_create(BlockdevCreateOptions *options,
218
if (job->ret) {
64
const char *keypairs, const char *password_secret,
219
@@ -XXX,XX +XXX,XX @@ void job_cancel(Job *job, bool force)
220
}
221
job_cancel_async(job, force);
222
if (!job_started(job)) {
223
- job_completed(job, -ECANCELED, NULL);
224
+ job_completed(job, -ECANCELED);
225
} else if (job->deferred_to_main_loop) {
226
job_completed_txn_abort(job);
227
} else {
228
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
229
index XXXXXXX..XXXXXXX 100644
230
--- a/tests/test-bdrv-drain.c
231
+++ b/tests/test-bdrv-drain.c
232
@@ -XXX,XX +XXX,XX @@ typedef struct TestBlockJob {
233
234
static void test_job_completed(Job *job, void *opaque)
235
{
236
- job_completed(job, 0, NULL);
237
+ job_completed(job, 0);
238
}
239
240
static int coroutine_fn test_job_run(Job *job, Error **errp)
241
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
242
index XXXXXXX..XXXXXXX 100644
243
--- a/tests/test-blockjob-txn.c
244
+++ b/tests/test-blockjob-txn.c
245
@@ -XXX,XX +XXX,XX @@ static void test_block_job_complete(Job *job, void *opaque)
246
rc = -ECANCELED;
247
}
248
249
- job_completed(job, rc, NULL);
250
+ job_completed(job, rc);
251
bdrv_unref(bs);
252
}
253
254
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
255
index XXXXXXX..XXXXXXX 100644
256
--- a/tests/test-blockjob.c
257
+++ b/tests/test-blockjob.c
258
@@ -XXX,XX +XXX,XX @@ static void cancel_job_completed(Job *job, void *opaque)
259
{
260
CancelJob *s = opaque;
261
s->completed = true;
262
- job_completed(job, 0, NULL);
263
+ job_completed(job, 0);
264
}
265
266
static void cancel_job_complete(Job *job, Error **errp)
267
--
65
--
268
2.17.1
66
2.26.2
269
67
270
68
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: John Snow <jsnow@redhat.com>
2
2
3
Change the manual deferment to commit_complete into the implicit
3
Introduced by d85f4222b468,
4
callback to job_exit, renaming commit_complete to commit_exit.
4
These were seemingly never used at all.
5
6
This conversion does change the timing of when job_completed is
7
called to after the bdrv_replace_node and bdrv_unref calls, which
8
could have implications for bjob->blk which will now be put down
9
after this cleanup.
10
11
Kevin highlights that we did not take any permissions for that backend
12
at job creation time, so it is safe to reorder these operations.
13
5
14
Signed-off-by: John Snow <jsnow@redhat.com>
6
Signed-off-by: John Snow <jsnow@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-Id: <20200806211345.2925343-3-jsnow@redhat.com>
16
Message-id: 20180830015734.19765-5-jsnow@redhat.com
17
Reviewed-by: Jeff Cody <jcody@redhat.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
9
---
20
block/commit.c | 22 +++++-----------------
10
block/qcow.c | 9 ---------
21
1 file changed, 5 insertions(+), 17 deletions(-)
11
1 file changed, 9 deletions(-)
22
12
23
diff --git a/block/commit.c b/block/commit.c
13
diff --git a/block/qcow.c b/block/qcow.c
24
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
25
--- a/block/commit.c
15
--- a/block/qcow.c
26
+++ b/block/commit.c
16
+++ b/block/qcow.c
27
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
17
@@ -XXX,XX +XXX,XX @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
28
return 0;
18
return 0;
29
}
19
}
30
20
31
-typedef struct {
21
-static QemuOptsList qcow_runtime_opts = {
32
- int ret;
22
- .name = "qcow",
33
-} CommitCompleteData;
23
- .head = QTAILQ_HEAD_INITIALIZER(qcow_runtime_opts.head),
24
- .desc = {
25
- BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."),
26
- { /* end of list */ }
27
- },
28
-};
34
-
29
-
35
-static void commit_complete(Job *job, void *opaque)
30
static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
36
+static void commit_exit(Job *job)
31
Error **errp)
37
{
32
{
38
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
39
BlockJob *bjob = &s->common;
40
- CommitCompleteData *data = opaque;
41
BlockDriverState *top = blk_bs(s->top);
42
BlockDriverState *base = blk_bs(s->base);
43
BlockDriverState *commit_top_bs = s->commit_top_bs;
44
- int ret = data->ret;
45
bool remove_commit_top_bs = false;
46
47
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
48
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
49
* the normal backing chain can be restored. */
50
blk_unref(s->base);
51
52
- if (!job_is_cancelled(job) && ret == 0) {
53
+ if (!job_is_cancelled(job) && job->ret == 0) {
54
/* success */
55
- ret = bdrv_drop_intermediate(s->commit_top_bs, base,
56
- s->backing_file_str);
57
+ job->ret = bdrv_drop_intermediate(s->commit_top_bs, base,
58
+ s->backing_file_str);
59
} else {
60
/* XXX Can (or should) we somehow keep 'consistent read' blocked even
61
* after the failed/cancelled commit job is gone? If we already wrote
62
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
63
* bdrv_set_backing_hd() to fail. */
64
block_job_remove_all_bdrv(bjob);
65
66
- job_completed(job, ret);
67
- g_free(data);
68
-
69
/* If bdrv_drop_intermediate() didn't already do that, remove the commit
70
* filter driver from the backing chain. Do this as the final step so that
71
* the 'consistent read' permission can be granted. */
72
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
73
static int coroutine_fn commit_run(Job *job, Error **errp)
74
{
75
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
76
- CommitCompleteData *data;
77
int64_t offset;
78
uint64_t delay_ns = 0;
79
int ret = 0;
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
81
out:
82
qemu_vfree(buf);
83
84
- data = g_malloc(sizeof(*data));
85
- data->ret = ret;
86
- job_defer_to_main_loop(&s->common.job, commit_complete, data);
87
return ret;
88
}
89
90
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_job_driver = {
91
.user_resume = block_job_user_resume,
92
.drain = block_job_drain,
93
.run = commit_run,
94
+ .exit = commit_exit,
95
},
96
};
97
98
--
33
--
99
2.17.1
34
2.26.2
100
35
101
36
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This function preallocates metadata structures and then extends the
4
image to its new size, but that new size calculation is wrong because
5
it doesn't take into account that the host_offset variable is always
6
cluster-aligned.
7
8
This problem can be reproduced with preallocation=metadata when the
9
original size is not cluster-aligned but the new size is. In this case
10
the final image size will be shorter than expected.
11
12
qemu-img create -f qcow2 img.qcow2 31k
13
qemu-img resize --preallocation=metadata img.qcow2 128k
14
15
Signed-off-by: Alberto Garcia <berto@igalia.com>
16
Message-Id: <adeb8b059917b141d5f5b3bd2a016262d3052c79.1599833007.git.berto@igalia.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
[mreitz: Mark compat=0.10 unsupported for iotest 125]
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
---
21
block/qcow2.c | 1 +
22
tests/qemu-iotests/125 | 44 ++++++++++++++++++++++----------------
23
tests/qemu-iotests/125.out | 28 ++++++++++++++++++++++--
24
3 files changed, 53 insertions(+), 20 deletions(-)
25
26
diff --git a/block/qcow2.c b/block/qcow2.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/qcow2.c
29
+++ b/block/qcow2.c
30
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
31
error_setg_errno(errp, -ret, "Allocating clusters failed");
32
goto out;
33
}
34
+ host_offset += offset_into_cluster(s, offset);
35
36
for (m = meta; m != NULL; m = m->next) {
37
m->prealloc = true;
38
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
39
index XXXXXXX..XXXXXXX 100755
40
--- a/tests/qemu-iotests/125
41
+++ b/tests/qemu-iotests/125
42
@@ -XXX,XX +XXX,XX @@ get_image_size_on_host()
43
44
_supported_fmt qcow2
45
_supported_proto file
46
+# Growing a file with a backing file (without preallocation=full or
47
+# =falloc) requires zeroing the newly added area, which is impossible
48
+# to do quickly for v2 images, and hence is unsupported.
49
+_unsupported_imgopts 'compat=0.10'
50
51
if [ -z "$TEST_IMG_FILE" ]; then
52
TEST_IMG_FILE=$TEST_IMG
53
@@ -XXX,XX +XXX,XX @@ done
54
$QEMU_IMG create -f raw "$TEST_IMG.base" 128k | _filter_img_create
55
$QEMU_IO -c 'write -q -P 1 0 128k' -f raw "$TEST_IMG.base"
56
for orig_size in 31k 33k; do
57
- echo "--- Resizing image from $orig_size to 96k ---"
58
- _make_test_img -F raw -b "$TEST_IMG.base" -o cluster_size=64k "$orig_size"
59
- $QEMU_IMG resize -f "$IMGFMT" --preallocation=full "$TEST_IMG" 96k
60
- # The first part of the image should contain data from the backing file
61
- $QEMU_IO -c "read -q -P 1 0 ${orig_size}" "$TEST_IMG"
62
- # The resized part of the image should contain zeroes
63
- $QEMU_IO -c "read -q -P 0 ${orig_size} 63k" "$TEST_IMG"
64
- # If the image does not have an external data file we can also verify its
65
- # actual size. The resized image should have 7 clusters:
66
- # header, L1 table, L2 table, refcount table, refcount block, 2 data clusters
67
- if ! _get_data_file "$TEST_IMG" > /dev/null; then
68
- expected_file_length=$((65536 * 7))
69
- file_length=$(stat -c '%s' "$TEST_IMG_FILE")
70
- if [ "$file_length" != "$expected_file_length" ]; then
71
- echo "ERROR: file length $file_length (expected $expected_file_length)"
72
- fi
73
- fi
74
- echo
75
+ for dst_size in 96k 128k; do
76
+ for prealloc in metadata full; do
77
+ echo "--- Resizing image from $orig_size to $dst_size (preallocation=$prealloc) ---"
78
+ _make_test_img -F raw -b "$TEST_IMG.base" -o cluster_size=64k "$orig_size"
79
+ $QEMU_IMG resize -f "$IMGFMT" --preallocation="$prealloc" "$TEST_IMG" "$dst_size"
80
+ # The first part of the image should contain data from the backing file
81
+ $QEMU_IO -c "read -q -P 1 0 ${orig_size}" "$TEST_IMG"
82
+ # The resized part of the image should contain zeroes
83
+ $QEMU_IO -c "read -q -P 0 ${orig_size} 63k" "$TEST_IMG"
84
+ # If the image does not have an external data file we can also verify its
85
+ # actual size. The resized image should have 7 clusters:
86
+ # header, L1 table, L2 table, refcount table, refcount block, 2 data clusters
87
+ if ! _get_data_file "$TEST_IMG" > /dev/null; then
88
+ expected_file_length=$((65536 * 7))
89
+ file_length=$(stat -c '%s' "$TEST_IMG_FILE")
90
+ if [ "$file_length" != "$expected_file_length" ]; then
91
+ echo "ERROR: file length $file_length (expected $expected_file_length)"
92
+ fi
93
+ fi
94
+ echo
95
+ done
96
+ done
97
done
98
99
# success, all done
100
diff --git a/tests/qemu-iotests/125.out b/tests/qemu-iotests/125.out
101
index XXXXXXX..XXXXXXX 100644
102
--- a/tests/qemu-iotests/125.out
103
+++ b/tests/qemu-iotests/125.out
104
@@ -XXX,XX +XXX,XX @@ wrote 81920/81920 bytes at offset 2048000
105
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
106
107
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=raw size=131072
108
---- Resizing image from 31k to 96k ---
109
+--- Resizing image from 31k to 96k (preallocation=metadata) ---
110
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=31744 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
111
Image resized.
112
113
---- Resizing image from 33k to 96k ---
114
+--- Resizing image from 31k to 96k (preallocation=full) ---
115
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=31744 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
116
+Image resized.
117
+
118
+--- Resizing image from 31k to 128k (preallocation=metadata) ---
119
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=31744 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
120
+Image resized.
121
+
122
+--- Resizing image from 31k to 128k (preallocation=full) ---
123
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=31744 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
124
+Image resized.
125
+
126
+--- Resizing image from 33k to 96k (preallocation=metadata) ---
127
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33792 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
128
+Image resized.
129
+
130
+--- Resizing image from 33k to 96k (preallocation=full) ---
131
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33792 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
132
+Image resized.
133
+
134
+--- Resizing image from 33k to 128k (preallocation=metadata) ---
135
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33792 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
136
+Image resized.
137
+
138
+--- Resizing image from 33k to 128k (preallocation=full) ---
139
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33792 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
140
Image resized.
141
142
--
143
2.26.2
144
145
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Jobs are now expected to return their retcode on the stack, from the
3
qcow2_alloc_cluster_offset() takes an (unaligned) guest offset and
4
.run callback, so we can remove that argument.
4
returns the (aligned) offset of the corresponding cluster in the qcow2
5
image.
5
6
6
job_cancel does not need to set -ECANCELED because job_completed will
7
In practice none of the callers need to know where the cluster starts
7
update the return code itself if the job was canceled.
8
so this patch makes the function calculate and return the final host
9
offset directly. The function is also renamed accordingly.
8
10
9
While we're here, make job_completed static to job.c and remove it from
11
See 388e581615 for a similar change to qcow2_get_cluster_offset().
10
job.h; move the documentation of return code to the .run() callback and
11
to the job->ret property, accordingly.
12
12
13
Signed-off-by: John Snow <jsnow@redhat.com>
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Message-id: 20180830015734.19765-9-jsnow@redhat.com
14
Message-Id: <9bfef50ec9200d752413be4fc2aeb22a28378817.1599833007.git.berto@igalia.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
17
---
18
include/qemu/job.h | 28 +++++++++++++++-------------
18
block/qcow2.h | 6 +++---
19
job.c | 11 ++++++-----
19
block/qcow2-cluster.c | 14 ++++++++++----
20
trace-events | 2 +-
20
block/qcow2.c | 36 +++++++++++++-----------------------
21
3 files changed, 22 insertions(+), 19 deletions(-)
21
3 files changed, 26 insertions(+), 30 deletions(-)
22
22
23
diff --git a/include/qemu/job.h b/include/qemu/job.h
23
diff --git a/block/qcow2.h b/block/qcow2.h
24
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
25
--- a/include/qemu/job.h
25
--- a/block/qcow2.h
26
+++ b/include/qemu/job.h
26
+++ b/block/qcow2.h
27
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
27
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
28
/** Estimated progress_current value at the completion of the job */
28
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
29
int64_t progress_total;
29
unsigned int *bytes, uint64_t *host_offset,
30
30
QCow2SubclusterType *subcluster_type);
31
- /** ret code passed to job_completed. */
31
-int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
32
+ /**
32
- unsigned int *bytes, uint64_t *host_offset,
33
+ * Return code from @run and/or @prepare callback(s).
33
- QCowL2Meta **m);
34
+ * Not final until the job has reached the CONCLUDED status.
34
+int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
35
+ * 0 on success, -errno on failure.
35
+ unsigned int *bytes, uint64_t *host_offset,
36
+ */
36
+ QCowL2Meta **m);
37
int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
38
uint64_t offset,
39
int compressed_size,
40
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/block/qcow2-cluster.c
43
+++ b/block/qcow2-cluster.c
44
@@ -XXX,XX +XXX,XX @@ out:
45
* clusters (or subclusters) if necessary. The result can span a
46
* combination of allocated and previously unallocated clusters.
47
*
48
+ * Note that offset may not be cluster aligned. In this case, the returned
49
+ * *host_offset points to exact byte referenced by offset and therefore
50
+ * isn't cluster aligned as well.
51
+ *
52
* On return, @host_offset is set to the beginning of the requested
53
* area. This area is guaranteed to be contiguous on the qcow2 file
54
* but it can be smaller than initially requested. In this case @bytes
55
@@ -XXX,XX +XXX,XX @@ out:
56
*
57
* Return 0 on success and -errno in error cases
58
*/
59
-int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
60
- unsigned int *bytes, uint64_t *host_offset,
61
- QCowL2Meta **m)
62
+int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
63
+ unsigned int *bytes, uint64_t *host_offset,
64
+ QCowL2Meta **m)
65
{
66
BDRVQcow2State *s = bs->opaque;
67
uint64_t start, remaining;
68
@@ -XXX,XX +XXX,XX @@ again:
69
while (true) {
70
71
if (*host_offset == INV_OFFSET && cluster_offset != INV_OFFSET) {
72
- *host_offset = start_of_cluster(s, cluster_offset);
73
+ *host_offset = cluster_offset;
74
}
75
76
assert(remaining >= cur_bytes);
77
@@ -XXX,XX +XXX,XX @@ again:
78
*bytes -= remaining;
79
assert(*bytes > 0);
80
assert(*host_offset != INV_OFFSET);
81
+ assert(offset_into_cluster(s, *host_offset) ==
82
+ offset_into_cluster(s, offset));
83
84
return 0;
85
}
86
diff --git a/block/qcow2.c b/block/qcow2.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/qcow2.c
89
+++ b/block/qcow2.c
90
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part(
91
int offset_in_cluster;
37
int ret;
92
int ret;
38
93
unsigned int cur_bytes; /* number of sectors in current iteration */
39
/**
94
- uint64_t cluster_offset;
40
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
95
+ uint64_t host_offset;
41
/** Enum describing the operation */
96
QCowL2Meta *l2meta = NULL;
42
JobType job_type;
97
AioTaskPool *aio = NULL;
43
98
44
- /** Mandatory: Entrypoint for the Coroutine. */
99
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part(
45
+ /**
100
46
+ * Mandatory: Entrypoint for the Coroutine.
101
qemu_co_mutex_lock(&s->lock);
47
+ *
102
48
+ * This callback will be invoked when moving from CREATED to RUNNING.
103
- ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
49
+ *
104
- &cluster_offset, &l2meta);
50
+ * If this callback returns nonzero, the job transaction it is part of is
105
+ ret = qcow2_alloc_host_offset(bs, offset, &cur_bytes,
51
+ * aborted. If it returns zero, the job moves into the WAITING state. If it
106
+ &host_offset, &l2meta);
52
+ * is the last job to complete in its transaction, all jobs in the
107
if (ret < 0) {
53
+ * transaction move from WAITING to PENDING.
108
goto out_locked;
54
+ */
109
}
55
int coroutine_fn (*run)(Job *job, Error **errp);
110
56
111
- assert(offset_into_cluster(s, cluster_offset) == 0);
57
/**
58
@@ -XXX,XX +XXX,XX @@ void job_early_fail(Job *job);
59
/** Moves the @job from RUNNING to READY */
60
void job_transition_to_ready(Job *job);
61
62
-/**
63
- * @job: The job being completed.
64
- * @ret: The status code.
65
- *
66
- * Marks @job as completed. If @ret is non-zero, the job transaction it is part
67
- * of is aborted. If @ret is zero, the job moves into the WAITING state. If it
68
- * is the last job to complete in its transaction, all jobs in the transaction
69
- * move from WAITING to PENDING.
70
- */
71
-void job_completed(Job *job, int ret);
72
-
112
-
73
/** Asynchronously complete the specified @job. */
113
- ret = qcow2_pre_write_overlap_check(bs, 0,
74
void job_complete(Job *job, Error **errp);
114
- cluster_offset + offset_in_cluster,
75
115
+ ret = qcow2_pre_write_overlap_check(bs, 0, host_offset,
76
diff --git a/job.c b/job.c
116
cur_bytes, true);
77
index XXXXXXX..XXXXXXX 100644
117
if (ret < 0) {
78
--- a/job.c
118
goto out_locked;
79
+++ b/job.c
119
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part(
80
@@ -XXX,XX +XXX,XX @@ void job_drain(Job *job)
120
aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
81
}
121
}
82
}
122
ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_task_entry, 0,
83
123
- cluster_offset + offset_in_cluster, offset,
84
+static void job_completed(Job *job);
124
+ host_offset, offset,
85
+
125
cur_bytes, qiov, qiov_offset, l2meta);
86
static void job_exit(void *opaque)
126
l2meta = NULL; /* l2meta is consumed by qcow2_co_pwritev_task() */
127
if (ret < 0) {
128
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
129
130
while (bytes) {
131
cur_bytes = MIN(bytes, QEMU_ALIGN_DOWN(INT_MAX, s->cluster_size));
132
- ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
133
- &host_offset, &meta);
134
+ ret = qcow2_alloc_host_offset(bs, offset, &cur_bytes,
135
+ &host_offset, &meta);
136
if (ret < 0) {
137
error_setg_errno(errp, -ret, "Allocating clusters failed");
138
goto out;
139
}
140
- host_offset += offset_into_cluster(s, offset);
141
142
for (m = meta; m != NULL; m = m->next) {
143
m->prealloc = true;
144
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
145
BdrvRequestFlags write_flags)
87
{
146
{
88
Job *job = (Job *)opaque;
147
BDRVQcow2State *s = bs->opaque;
89
@@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque)
148
- int offset_in_cluster;
90
job->driver->exit(job);
149
int ret;
91
aio_context_release(aio_context);
150
unsigned int cur_bytes; /* number of sectors in current iteration */
92
}
151
- uint64_t cluster_offset;
93
- job_completed(job, job->ret);
152
+ uint64_t host_offset;
94
+ job_completed(job);
153
QCowL2Meta *l2meta = NULL;
95
}
154
96
155
assert(!bs->encrypted);
97
/**
156
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
98
@@ -XXX,XX +XXX,XX @@ static void job_completed_txn_success(Job *job)
157
99
}
158
l2meta = NULL;
100
}
159
101
160
- offset_in_cluster = offset_into_cluster(s, dst_offset);
102
-void job_completed(Job *job, int ret)
161
cur_bytes = MIN(bytes, INT_MAX);
103
+static void job_completed(Job *job)
162
104
{
163
/* TODO:
105
assert(job && job->txn && !job_is_completed(job));
164
* If src->bs == dst->bs, we could simply copy by incrementing
106
165
* the refcnt, without copying user data.
107
- job->ret = ret;
166
* Or if src->bs == dst->bs->backing->bs, we could copy by discarding. */
108
job_update_rc(job);
167
- ret = qcow2_alloc_cluster_offset(bs, dst_offset, &cur_bytes,
109
- trace_job_completed(job, ret, job->ret);
168
- &cluster_offset, &l2meta);
110
+ trace_job_completed(job, job->ret);
169
+ ret = qcow2_alloc_host_offset(bs, dst_offset, &cur_bytes,
111
if (job->ret) {
170
+ &host_offset, &l2meta);
112
job_completed_txn_abort(job);
171
if (ret < 0) {
113
} else {
172
goto fail;
114
@@ -XXX,XX +XXX,XX @@ void job_cancel(Job *job, bool force)
173
}
115
}
174
116
job_cancel_async(job, force);
175
- assert(offset_into_cluster(s, cluster_offset) == 0);
117
if (!job_started(job)) {
176
-
118
- job_completed(job, -ECANCELED);
177
- ret = qcow2_pre_write_overlap_check(bs, 0,
119
+ job_completed(job);
178
- cluster_offset + offset_in_cluster, cur_bytes, true);
120
} else if (job->deferred_to_main_loop) {
179
+ ret = qcow2_pre_write_overlap_check(bs, 0, host_offset, cur_bytes,
121
job_completed_txn_abort(job);
180
+ true);
122
} else {
181
if (ret < 0) {
123
diff --git a/trace-events b/trace-events
182
goto fail;
124
index XXXXXXX..XXXXXXX 100644
183
}
125
--- a/trace-events
184
126
+++ b/trace-events
185
qemu_co_mutex_unlock(&s->lock);
127
@@ -XXX,XX +XXX,XX @@ gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packe
186
- ret = bdrv_co_copy_range_to(src, src_offset,
128
# job.c
187
- s->data_file,
129
job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
188
- cluster_offset + offset_in_cluster,
130
job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)"
189
+ ret = bdrv_co_copy_range_to(src, src_offset, s->data_file, host_offset,
131
-job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d"
190
cur_bytes, read_flags, write_flags);
132
+job_completed(void *job, int ret) "job %p ret %d"
191
qemu_co_mutex_lock(&s->lock);
133
192
if (ret < 0) {
134
# job-qmp.c
135
qmp_job_cancel(void *job) "job %p"
136
--
193
--
137
2.17.1
194
2.26.2
138
195
139
196
diff view generated by jsdifflib
1
From: Marc-André Lureau <marcandre.lureau@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Spotted by ASAN:
3
Commit 19ae9ae014 ("block/rbd: Add support for ceph namespaces")
4
introduced namespace support for RBD, but we forgot to add the
5
new 'namespace' options to qemu_rbd_strong_runtime_opts[].
4
6
5
=================================================================
7
The 'namespace' is used to identify the image, so it is a strong
6
==5378==ERROR: LeakSanitizer: detected memory leaks
8
option since it can changes the data of a BDS.
7
9
8
Direct leak of 65536 byte(s) in 1 object(s) allocated from:
10
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1821528
9
#0 0x7f788f83bc48 in malloc (/lib64/libasan.so.5+0xeec48)
11
Fixes: 19ae9ae014 ("block/rbd: Add support for ceph namespaces")
10
#1 0x7f788c9923c5 in g_malloc (/lib64/libglib-2.0.so.0+0x523c5)
12
Cc: Florian Florensa <fflorensa@online.net>
11
#2 0x5622a1fe37bc in coroutine_trampoline /home/elmarco/src/qq/util/coroutine-ucontext.c:116
13
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
12
#3 0x7f788a15d75f in __correctly_grouped_prefixwc (/lib64/libc.so.6+0x4c75f)
14
Message-Id: <20200914190553.74871-1-sgarzare@redhat.com>
13
15
Reviewed-by: Jason Dillaman <dillaman@redhat.com>
14
(Broken in commit 4c8158e359d.)
15
16
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
17
Message-id: 20180809114417.28718-3-marcandre.lureau@redhat.com
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
17
---
20
tests/test-bdrv-drain.c | 1 +
18
block/rbd.c | 1 +
21
1 file changed, 1 insertion(+)
19
1 file changed, 1 insertion(+)
22
20
23
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
21
diff --git a/block/rbd.c b/block/rbd.c
24
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
25
--- a/tests/test-bdrv-drain.c
23
--- a/block/rbd.c
26
+++ b/tests/test-bdrv-drain.c
24
+++ b/block/rbd.c
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
25
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qemu_rbd_create_opts = {
28
}
26
29
27
static const char *const qemu_rbd_strong_runtime_opts[] = {
30
dbdd->done = true;
28
"pool",
31
+ g_free(buffer);
29
+ "namespace",
32
}
30
"image",
33
31
"conf",
34
/**
32
"snapshot",
35
--
33
--
36
2.17.1
34
2.26.2
37
35
38
36
diff view generated by jsdifflib