1
The following changes since commit 4c8c1cc544dbd5e2564868e61c5037258e393832:
1
The following changes since commit ae49fbbcd8e4e9d8bf7131add34773f579e1aff7:
2
2
3
Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.10-pull-request' into staging (2017-06-22 19:01:58 +0100)
3
Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20171025' into staging (2017-10-25 16:38:57 +0100)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
8
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
9
8
10
for you to fetch changes up to 1512008812410ca4054506a7c44343088abdd977:
9
for you to fetch changes up to 4254d01ce4eec9a3ccf320d14e2da132b8ad4a51:
11
10
12
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-06-23' into queue-block (2017-06-23 14:09:12 +0200)
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-10-26' into queue-block (2017-10-26 15:02:40 +0200)
13
12
14
----------------------------------------------------------------
13
----------------------------------------------------------------
15
16
Block layer patches
14
Block layer patches
17
15
18
----------------------------------------------------------------
16
----------------------------------------------------------------
19
Alberto Garcia (9):
17
Alberto Garcia (1):
20
throttle: Update throttle-groups.c documentation
18
qcow2: Use BDRV_SECTOR_BITS instead of its literal value
21
qcow2: Remove unused Error variable in do_perform_cow()
22
qcow2: Use unsigned int for both members of Qcow2COWRegion
23
qcow2: Make perform_cow() call do_perform_cow() twice
24
qcow2: Split do_perform_cow() into _read(), _encrypt() and _write()
25
qcow2: Allow reading both COW regions with only one request
26
qcow2: Pass a QEMUIOVector to do_perform_cow_{read,write}()
27
qcow2: Merge the writing of the COW regions with the guest data
28
qcow2: Use offset_into_cluster() and offset_to_l2_index()
29
19
30
Kevin Wolf (37):
20
Eric Blake (24):
31
commit: Fix completion with extra reference
21
block: Allow NULL file for bdrv_get_block_status()
32
qemu-iotests: Allow starting new qemu after cleanup
22
block: Add flag to avoid wasted work in bdrv_is_allocated()
33
qemu-iotests: Test exiting qemu with running job
23
block: Make bdrv_round_to_clusters() signature more useful
34
doc: Document generic -blockdev options
24
qcow2: Switch is_zero_sectors() to byte-based
35
doc: Document driver-specific -blockdev options
25
block: Switch bdrv_make_zero() to byte-based
36
qed: Use bottom half to resume waiting requests
26
qemu-img: Switch get_block_status() to byte-based
37
qed: Make qed_read_table() synchronous
27
block: Convert bdrv_get_block_status() to bytes
38
qed: Remove callback from qed_read_table()
28
block: Switch bdrv_co_get_block_status() to byte-based
39
qed: Remove callback from qed_read_l2_table()
29
block: Switch BdrvCoGetBlockStatusData to byte-based
40
qed: Remove callback from qed_find_cluster()
30
block: Switch bdrv_common_block_status_above() to byte-based
41
qed: Make qed_read_backing_file() synchronous
31
block: Switch bdrv_co_get_block_status_above() to byte-based
42
qed: Make qed_copy_from_backing_file() synchronous
32
block: Convert bdrv_get_block_status_above() to bytes
43
qed: Remove callback from qed_copy_from_backing_file()
33
qemu-img: Simplify logic in img_compare()
44
qed: Make qed_write_header() synchronous
34
qemu-img: Speed up compare on pre-allocated larger file
45
qed: Remove callback from qed_write_header()
35
qemu-img: Add find_nonzero()
46
qed: Make qed_write_table() synchronous
36
qemu-img: Drop redundant error message in compare
47
qed: Remove GenericCB
37
qemu-img: Change check_empty_sectors() to byte-based
48
qed: Remove callback from qed_write_table()
38
qemu-img: Change compare_sectors() to be byte-based
49
qed: Make qed_aio_read_data() synchronous
39
qemu-img: Change img_rebase() to be byte-based
50
qed: Make qed_aio_write_main() synchronous
40
qemu-img: Change img_compare() to be byte-based
51
qed: Inline qed_commit_l2_update()
41
block: Align block status requests
52
qed: Add return value to qed_aio_write_l1_update()
42
block: Reduce bdrv_aligned_preadv() rounding
53
qed: Add return value to qed_aio_write_l2_update()
43
qcow2: Reduce is_zero() rounding
54
qed: Add return value to qed_aio_write_main()
44
qemu-io: Relax 'alloc' now that block-status doesn't assert
55
qed: Add return value to qed_aio_write_cow()
56
qed: Add return value to qed_aio_write_inplace/alloc()
57
qed: Add return value to qed_aio_read/write_data()
58
qed: Remove ret argument from qed_aio_next_io()
59
qed: Remove recursion in qed_aio_next_io()
60
qed: Implement .bdrv_co_readv/writev
61
qed: Use CoQueue for serialising allocations
62
qed: Simplify request handling
63
qed: Use a coroutine for need_check_timer
64
qed: Add coroutine_fn to I/O path functions
65
qed: Use bdrv_co_* for coroutine_fns
66
block: Remove bdrv_aio_readv/writev/flush()
67
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-06-23' into queue-block
68
45
69
Manos Pitsidianakis (1):
46
Kevin Wolf (2):
70
block: change variable names in BlockDriverState
47
qemu-iotests: Test backing_fmt with backing node reference
48
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-10-26' into queue-block
71
49
72
Max Reitz (3):
50
Max Reitz (8):
73
blkdebug: Catch bs->exact_filename overflow
51
qemu-img.1: Image invalidation on qemu-img commit
74
blkverify: Catch bs->exact_filename overflow
52
iotests: Add test for dataplane mirroring
75
block: Do not strcmp() with NULL uri->scheme
53
iotests: Pull _filter_actual_image_size from 67/87
54
iotests: Filter actual image size in 184 and 191
55
qcow2: Emit errp when truncating the image tail
56
qcow2: Fix unaligned preallocated truncation
57
qcow2: Always execute preallocate() in a coroutine
58
iotests: Add cluster_size=64k to 125
76
59
77
Stefan Hajnoczi (10):
60
Peter Krempa (1):
78
block: count bdrv_co_rw_vmstate() requests
61
block: don't add 'driver' to options when referring to backing via node name
79
block: use BDRV_POLL_WHILE() in bdrv_rw_vmstate()
80
migration: avoid recursive AioContext locking in save_vmstate()
81
migration: use bdrv_drain_all_begin/end() instead bdrv_drain_all()
82
virtio-pci: use ioeventfd even when KVM is disabled
83
migration: hold AioContext lock for loadvm qemu_fclose()
84
qemu-iotests: 068: extract _qemu() function
85
qemu-iotests: 068: use -drive/-device instead of -hda
86
qemu-iotests: 068: test iothread mode
87
qemu-img: don't shadow opts variable in img_dd()
88
62
89
Stephen Bates (1):
63
include/block/block.h | 29 ++-
90
nvme: Add support for Read Data and Write Data in CMBs.
64
include/block/block_int.h | 11 +-
65
block.c | 3 +-
66
block/blkdebug.c | 13 +-
67
block/io.c | 334 ++++++++++++++++-----------
68
block/mirror.c | 26 +--
69
block/qcow2-cluster.c | 2 +-
70
block/qcow2.c | 116 ++++++----
71
qemu-img.c | 381 ++++++++++++++-----------------
72
qemu-io-cmds.c | 13 --
73
block/trace-events | 2 +-
74
qemu-img.texi | 9 +-
75
tests/qemu-iotests/067 | 2 +-
76
tests/qemu-iotests/074.out | 2 -
77
tests/qemu-iotests/087 | 2 +-
78
tests/qemu-iotests/125 | 7 +-
79
tests/qemu-iotests/125.out | 480 +++++++++++++++++++++++++++++++++++----
80
tests/qemu-iotests/127 | 97 ++++++++
81
tests/qemu-iotests/127.out | 14 ++
82
tests/qemu-iotests/177 | 12 +-
83
tests/qemu-iotests/177.out | 19 +-
84
tests/qemu-iotests/184 | 3 +-
85
tests/qemu-iotests/184.out | 6 +-
86
tests/qemu-iotests/191 | 7 +-
87
tests/qemu-iotests/191.out | 48 ++--
88
tests/qemu-iotests/common.filter | 6 +
89
tests/qemu-iotests/group | 1 +
90
27 files changed, 1102 insertions(+), 543 deletions(-)
91
create mode 100755 tests/qemu-iotests/127
92
create mode 100644 tests/qemu-iotests/127.out
91
93
92
sochin.jiang (1):
93
fix: avoid an infinite loop or a dangling pointer problem in img_commit
94
95
block/Makefile.objs | 2 +-
96
block/blkdebug.c | 46 +--
97
block/blkreplay.c | 8 +-
98
block/blkverify.c | 12 +-
99
block/block-backend.c | 22 +-
100
block/commit.c | 7 +
101
block/file-posix.c | 34 +-
102
block/io.c | 240 ++-----------
103
block/iscsi.c | 20 +-
104
block/mirror.c | 8 +-
105
block/nbd-client.c | 8 +-
106
block/nbd-client.h | 4 +-
107
block/nbd.c | 6 +-
108
block/nfs.c | 2 +-
109
block/qcow2-cluster.c | 201 ++++++++---
110
block/qcow2.c | 94 +++--
111
block/qcow2.h | 11 +-
112
block/qed-cluster.c | 124 +++----
113
block/qed-gencb.c | 33 --
114
block/qed-table.c | 261 +++++---------
115
block/qed.c | 779 ++++++++++++++++-------------------------
116
block/qed.h | 54 +--
117
block/raw-format.c | 8 +-
118
block/rbd.c | 4 +-
119
block/sheepdog.c | 12 +-
120
block/ssh.c | 2 +-
121
block/throttle-groups.c | 2 +-
122
block/trace-events | 3 -
123
blockjob.c | 4 +-
124
hw/block/nvme.c | 83 +++--
125
hw/block/nvme.h | 1 +
126
hw/virtio/virtio-pci.c | 2 +-
127
include/block/block.h | 16 +-
128
include/block/block_int.h | 6 +-
129
include/block/blockjob.h | 18 +
130
include/sysemu/block-backend.h | 20 +-
131
migration/savevm.c | 32 +-
132
qemu-img.c | 29 +-
133
qemu-io-cmds.c | 46 +--
134
qemu-options.hx | 221 ++++++++++--
135
tests/qemu-iotests/068 | 37 +-
136
tests/qemu-iotests/068.out | 11 +-
137
tests/qemu-iotests/185 | 206 +++++++++++
138
tests/qemu-iotests/185.out | 59 ++++
139
tests/qemu-iotests/common.qemu | 3 +
140
tests/qemu-iotests/group | 1 +
141
46 files changed, 1477 insertions(+), 1325 deletions(-)
142
delete mode 100644 block/qed-gencb.c
143
create mode 100755 tests/qemu-iotests/185
144
create mode 100644 tests/qemu-iotests/185.out
145
diff view generated by jsdifflib
Deleted patch
1
commit_complete() can't assume that after its block_job_completed() the
2
job is actually immediately freed; someone else may still be holding
3
references. In this case, the op blockers on the intermediate nodes make
4
the graph reconfiguration in the completion code fail.
5
1
6
Call block_job_remove_all_bdrv() manually so that we know for sure that
7
any blockers on intermediate nodes are given up.
8
9
Cc: qemu-stable@nongnu.org
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/commit.c | 7 +++++++
15
1 file changed, 7 insertions(+)
16
17
diff --git a/block/commit.c b/block/commit.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/commit.c
20
+++ b/block/commit.c
21
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
22
}
23
g_free(s->backing_file_str);
24
blk_unref(s->top);
25
+
26
+ /* If there is more than one reference to the job (e.g. if called from
27
+ * block_job_finish_sync()), block_job_completed() won't free it and
28
+ * therefore the blockers on the intermediate nodes remain. This would
29
+ * cause bdrv_set_backing_hd() to fail. */
30
+ block_job_remove_all_bdrv(job);
31
+
32
block_job_completed(&s->common, ret);
33
g_free(data);
34
35
--
36
1.8.3.1
37
38
diff view generated by jsdifflib
Deleted patch
1
After _cleanup_qemu(), test cases should be able to start the next qemu
2
process and call _cleanup_qemu() for that one as well. For this to work
3
cleanly, we need to improve the cleanup so that the second invocation
4
doesn't try to kill the qemu instances from the first invocation a
5
second time (which would result in error messages).
6
1
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/common.qemu | 3 +++
12
1 file changed, 3 insertions(+)
13
14
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/common.qemu
17
+++ b/tests/qemu-iotests/common.qemu
18
@@ -XXX,XX +XXX,XX @@ function _cleanup_qemu()
19
rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}"
20
eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors
21
eval "exec ${QEMU_OUT[$i]}<&-"
22
+
23
+ unset QEMU_IN[$i]
24
+ unset QEMU_OUT[$i]
25
done
26
}
27
--
28
1.8.3.1
29
30
diff view generated by jsdifflib
1
Now that we're running in coroutine context, the ad-hoc serialisation
1
From: Peter Krempa <pkrempa@redhat.com>
2
code (which drops a request that has to wait out of coroutine context)
3
can be replaced by a CoQueue.
4
2
5
This means that when we resume a serialised request, it is running in
3
When referring to a backing file of an image via node name
6
coroutine context again and its I/O isn't blocking any more.
4
bdrv_open_backing_file would add the 'driver' option to the option list
5
filling it with the backing format driver. This breaks construction of
6
the backing chain via -blockdev, as bdrv_open_inherit reports an error
7
if both 'reference' and 'options' are provided.
7
8
9
$ qemu-img create -f raw /tmp/backing.raw 64M
10
$ qemu-img create -f qcow2 -F raw -b /tmp/backing.raw /tmp/test.qcow2
11
$ qemu-system-x86_64 \
12
-blockdev driver=file,filename=/tmp/backing.raw,node-name=backing \
13
-blockdev driver=qcow2,file.driver=file,file.filename=/tmp/test.qcow2,node-name=root,backing=backing
14
qemu-system-x86_64: -blockdev driver=qcow2,file.driver=file,file.filename=/tmp/test.qcow2,node-name=root,backing=backing: Could not open backing file: Cannot reference an existing block device with additional options or a new filename
15
16
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
18
---
11
block/qed.c | 49 +++++++++++++++++--------------------------------
19
block.c | 3 ++-
12
block/qed.h | 3 ++-
20
1 file changed, 2 insertions(+), 1 deletion(-)
13
2 files changed, 19 insertions(+), 33 deletions(-)
14
21
15
diff --git a/block/qed.c b/block/qed.c
22
diff --git a/block.c b/block.c
16
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qed.c
24
--- a/block.c
18
+++ b/block/qed.c
25
+++ b/block.c
19
@@ -XXX,XX +XXX,XX @@ static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
26
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
20
27
goto free_exit;
21
static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
22
{
23
- QEDAIOCB *acb;
24
-
25
assert(s->allocating_write_reqs_plugged);
26
27
s->allocating_write_reqs_plugged = false;
28
-
29
- acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
30
- if (acb) {
31
- qed_aio_start_io(acb);
32
- }
33
+ qemu_co_enter_next(&s->allocating_write_reqs);
34
}
35
36
static void qed_clear_need_check(void *opaque, int ret)
37
@@ -XXX,XX +XXX,XX @@ static void qed_need_check_timer_cb(void *opaque)
38
BDRVQEDState *s = opaque;
39
40
/* The timer should only fire when allocating writes have drained */
41
- assert(!QSIMPLEQ_FIRST(&s->allocating_write_reqs));
42
+ assert(!s->allocating_acb);
43
44
trace_qed_need_check_timer_cb(s);
45
46
@@ -XXX,XX +XXX,XX @@ static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
47
int ret;
48
49
s->bs = bs;
50
- QSIMPLEQ_INIT(&s->allocating_write_reqs);
51
+ qemu_co_queue_init(&s->allocating_write_reqs);
52
53
ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
54
if (ret < 0) {
55
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete_bh(void *opaque)
56
qed_release(s);
57
}
58
59
-static void qed_resume_alloc_bh(void *opaque)
60
-{
61
- qed_aio_start_io(opaque);
62
-}
63
-
64
static void qed_aio_complete(QEDAIOCB *acb, int ret)
65
{
66
BDRVQEDState *s = acb_to_s(acb);
67
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
68
* next request in the queue. This ensures that we don't cycle through
69
* requests multiple times but rather finish one at a time completely.
70
*/
71
- if (acb == QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
72
- QEDAIOCB *next_acb;
73
- QSIMPLEQ_REMOVE_HEAD(&s->allocating_write_reqs, next);
74
- next_acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
75
- if (next_acb) {
76
- aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
77
- qed_resume_alloc_bh, next_acb);
78
+ if (acb == s->allocating_acb) {
79
+ s->allocating_acb = NULL;
80
+ if (!qemu_co_queue_empty(&s->allocating_write_reqs)) {
81
+ qemu_co_enter_next(&s->allocating_write_reqs);
82
} else if (s->header.features & QED_F_NEED_CHECK) {
83
qed_start_need_check_timer(s);
84
}
85
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
86
int ret;
87
88
/* Cancel timer when the first allocating request comes in */
89
- if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
90
+ if (s->allocating_acb == NULL) {
91
qed_cancel_need_check_timer(s);
92
}
28
}
93
29
94
/* Freeze this request if another allocating write is in progress */
30
- if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
95
- if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
31
+ if (!reference &&
96
- QSIMPLEQ_INSERT_TAIL(&s->allocating_write_reqs, acb, next);
32
+ bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
97
- }
33
qdict_put_str(options, "driver", bs->backing_format);
98
- if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs) ||
99
- s->allocating_write_reqs_plugged) {
100
- return -EINPROGRESS; /* wait for existing request to finish */
101
+ if (s->allocating_acb != acb || s->allocating_write_reqs_plugged) {
102
+ if (s->allocating_acb != NULL) {
103
+ qemu_co_queue_wait(&s->allocating_write_reqs, NULL);
104
+ assert(s->allocating_acb == NULL);
105
+ }
106
+ s->allocating_acb = acb;
107
+ return -EAGAIN; /* start over with looking up table entries */
108
}
34
}
109
35
110
acb->cur_nclusters = qed_bytes_to_clusters(s,
111
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb)
112
ret = qed_aio_read_data(acb, ret, offset, len);
113
}
114
115
- if (ret < 0) {
116
- if (ret != -EINPROGRESS) {
117
- qed_aio_complete(acb, ret);
118
- }
119
+ if (ret < 0 && ret != -EAGAIN) {
120
+ qed_aio_complete(acb, ret);
121
return;
122
}
123
}
124
diff --git a/block/qed.h b/block/qed.h
125
index XXXXXXX..XXXXXXX 100644
126
--- a/block/qed.h
127
+++ b/block/qed.h
128
@@ -XXX,XX +XXX,XX @@ typedef struct {
129
uint32_t l2_mask;
130
131
/* Allocating write request queue */
132
- QSIMPLEQ_HEAD(, QEDAIOCB) allocating_write_reqs;
133
+ QEDAIOCB *allocating_acb;
134
+ CoQueue allocating_write_reqs;
135
bool allocating_write_reqs_plugged;
136
137
/* Periodic flush and clear need check flag */
138
--
36
--
139
1.8.3.1
37
2.13.6
140
38
141
39
diff view generated by jsdifflib
1
This documents the driver-specific options for the raw, qcow2 and file
1
This changes test case 191 to include a backing image that has
2
block drivers for the man page. For everything else, we refer to the
2
backing_fmt set in the image file, but is referenced by node name in the
3
QAPI documentation.
3
qemu command line.
4
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
7
---
9
qemu-options.hx | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
8
tests/qemu-iotests/191 | 3 ++-
10
1 file changed, 114 insertions(+), 1 deletion(-)
9
tests/qemu-iotests/191.out | 2 +-
10
2 files changed, 3 insertions(+), 2 deletions(-)
11
11
12
diff --git a/qemu-options.hx b/qemu-options.hx
12
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/191
15
+++ b/tests/qemu-iotests/191
16
@@ -XXX,XX +XXX,XX @@ echo === Preparing and starting VM ===
17
echo
18
19
TEST_IMG="${TEST_IMG}.base" _make_test_img $size
20
-TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
21
+IMGOPTS=$(_optstr_add "$IMGOPTS" "backing_fmt=$IMGFMT") \
22
+ TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
23
_make_test_img -b "${TEST_IMG}.mid"
24
TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid"
25
26
diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out
13
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
14
--- a/qemu-options.hx
28
--- a/tests/qemu-iotests/191.out
15
+++ b/qemu-options.hx
29
+++ b/tests/qemu-iotests/191.out
16
@@ -XXX,XX +XXX,XX @@ STEXI
30
@@ -XXX,XX +XXX,XX @@ QA output created by 191
17
@item -blockdev @var{option}[,@var{option}[,@var{option}[,...]]]
31
=== Preparing and starting VM ===
18
@findex -blockdev
32
19
33
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
20
-Define a new block driver node.
34
-Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
21
+Define a new block driver node. Some of the options apply to all block drivers,
35
+Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
22
+other options are only accepted for a specific block driver. See below for a
36
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
23
+list of generic options and options for the most common block drivers.
37
Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
24
+
38
wrote 65536/65536 bytes at offset 1048576
25
+Options that expect a reference to another node (e.g. @code{file}) can be
26
+given in two ways. Either you specify the node name of an already existing node
27
+(file=@var{node-name}), or you define a new node inline, adding options
28
+for the referenced node after a dot (file.filename=@var{path},file.aio=native).
29
+
30
+A block driver node created with @option{-blockdev} can be used for a guest
31
+device by specifying its node name for the @code{drive} property in a
32
+@option{-device} argument that defines a block device.
33
34
@table @option
35
@item Valid options for any block driver node:
36
@@ -XXX,XX +XXX,XX @@ zero write commands. You may even choose "unmap" if @var{discard} is set
37
to "unmap" to allow a zero write to be converted to an @code{unmap} operation.
38
@end table
39
40
+@item Driver-specific options for @code{file}
41
+
42
+This is the protocol-level block driver for accessing regular files.
43
+
44
+@table @code
45
+@item filename
46
+The path to the image file in the local filesystem
47
+@item aio
48
+Specifies the AIO backend (threads/native, default: threads)
49
+@end table
50
+Example:
51
+@example
52
+-blockdev driver=file,node-name=disk,filename=disk.img
53
+@end example
54
+
55
+@item Driver-specific options for @code{raw}
56
+
57
+This is the image format block driver for raw images. It is usually
58
+stacked on top of a protocol level block driver such as @code{file}.
59
+
60
+@table @code
61
+@item file
62
+Reference to or definition of the data source block driver node
63
+(e.g. a @code{file} driver node)
64
+@end table
65
+Example 1:
66
+@example
67
+-blockdev driver=file,node-name=disk_file,filename=disk.img
68
+-blockdev driver=raw,node-name=disk,file=disk_file
69
+@end example
70
+Example 2:
71
+@example
72
+-blockdev driver=raw,node-name=disk,file.driver=file,file.filename=disk.img
73
+@end example
74
+
75
+@item Driver-specific options for @code{qcow2}
76
+
77
+This is the image format block driver for qcow2 images. It is usually
78
+stacked on top of a protocol level block driver such as @code{file}.
79
+
80
+@table @code
81
+@item file
82
+Reference to or definition of the data source block driver node
83
+(e.g. a @code{file} driver node)
84
+
85
+@item backing
86
+Reference to or definition of the backing file block device (default is taken
87
+from the image file). It is allowed to pass an empty string here in order to
88
+disable the default backing file.
89
+
90
+@item lazy-refcounts
91
+Whether to enable the lazy refcounts feature (on/off; default is taken from the
92
+image file)
93
+
94
+@item cache-size
95
+The maximum total size of the L2 table and refcount block caches in bytes
96
+(default: 1048576 bytes or 8 clusters, whichever is larger)
97
+
98
+@item l2-cache-size
99
+The maximum size of the L2 table cache in bytes
100
+(default: 4/5 of the total cache size)
101
+
102
+@item refcount-cache-size
103
+The maximum size of the refcount block cache in bytes
104
+(default: 1/5 of the total cache size)
105
+
106
+@item cache-clean-interval
107
+Clean unused entries in the L2 and refcount caches. The interval is in seconds.
108
+The default value is 0 and it disables this feature.
109
+
110
+@item pass-discard-request
111
+Whether discard requests to the qcow2 device should be forwarded to the data
112
+source (on/off; default: on if discard=unmap is specified, off otherwise)
113
+
114
+@item pass-discard-snapshot
115
+Whether discard requests for the data source should be issued when a snapshot
116
+operation (e.g. deleting a snapshot) frees clusters in the qcow2 file (on/off;
117
+default: on)
118
+
119
+@item pass-discard-other
120
+Whether discard requests for the data source should be issued on other
121
+occasions where a cluster gets freed (on/off; default: off)
122
+
123
+@item overlap-check
124
+Which overlap checks to perform for writes to the image
125
+(none/constant/cached/all; default: cached). For details or finer
126
+granularity control refer to the QAPI documentation of @code{blockdev-add}.
127
+@end table
128
+
129
+Example 1:
130
+@example
131
+-blockdev driver=file,node-name=my_file,filename=/tmp/disk.qcow2
132
+-blockdev driver=qcow2,node-name=hda,file=my_file,overlap-check=none,cache-size=16777216
133
+@end example
134
+Example 2:
135
+@example
136
+-blockdev driver=qcow2,node-name=disk,file.driver=http,file.filename=http://example.com/image.qcow2
137
+@end example
138
+
139
+@item Driver-specific options for other drivers
140
+Please refer to the QAPI documentation of the @code{blockdev-add} QMP command.
141
+
142
@end table
143
144
ETEXI
145
--
39
--
146
1.8.3.1
40
2.13.6
147
41
148
42
diff view generated by jsdifflib
1
This fixes the last place where we degraded from AIO to actual blocking
1
From: Eric Blake <eblake@redhat.com>
2
synchronous I/O requests. Putting it into a coroutine means that instead
2
3
of blocking, the coroutine simply yields while doing I/O.
3
Not all callers care about which BDS owns the mapping for a given
4
4
range of the file. This patch merely simplifies the callers by
5
consolidating the logic in the common call point, while guaranteeing
6
a non-NULL file to all the driver callbacks, for no semantic change.
7
The only caller that does not care about pnum is bdrv_is_allocated,
8
as invoked by vvfat; we can likewise add assertions that the rest
9
of the stack does not have to worry about a NULL pnum.
10
11
Furthermore, this will also set the stage for a future cleanup: when
12
a caller does not care about which BDS owns an offset, it would be
13
nice to allow the driver to optimize things to not have to return
14
BDRV_BLOCK_OFFSET_VALID in the first place. In the case of fragmented
15
allocation (for example, it's fairly easy to create a qcow2 image
16
where consecutive guest addresses are not at consecutive host
17
addresses), the current contract requires bdrv_get_block_status()
18
to clamp *pnum to the limit where host addresses are no longer
19
consecutive, but allowing a NULL file means that *pnum could be
20
set to the full length of known-allocated data.
21
22
Signed-off-by: Eric Blake <eblake@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
24
---
8
block/qed.c | 33 +++++++++++++++++----------------
25
include/block/block_int.h | 10 ++++++----
9
1 file changed, 17 insertions(+), 16 deletions(-)
26
block/io.c | 49 ++++++++++++++++++++++++++---------------------
10
27
block/mirror.c | 3 +--
11
diff --git a/block/qed.c b/block/qed.c
28
block/qcow2.c | 8 ++------
12
index XXXXXXX..XXXXXXX 100644
29
qemu-img.c | 10 ++++------
13
--- a/block/qed.c
30
5 files changed, 40 insertions(+), 40 deletions(-)
14
+++ b/block/qed.c
31
15
@@ -XXX,XX +XXX,XX @@ static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
16
qemu_co_enter_next(&s->allocating_write_reqs);
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int.h
35
+++ b/include/block/block_int.h
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
37
int64_t offset, int bytes);
38
39
/*
40
- * Building block for bdrv_block_status[_above]. The driver should
41
- * answer only according to the current layer, and should not
42
- * set BDRV_BLOCK_ALLOCATED, but may set BDRV_BLOCK_RAW. See block.h
43
- * for the meaning of _DATA, _ZERO, and _OFFSET_VALID.
44
+ * Building block for bdrv_block_status[_above] and
45
+ * bdrv_is_allocated[_above]. The driver should answer only
46
+ * according to the current layer, and should not set
47
+ * BDRV_BLOCK_ALLOCATED, but may set BDRV_BLOCK_RAW. See block.h
48
+ * for the meaning of _DATA, _ZERO, and _OFFSET_VALID. The block
49
+ * layer guarantees non-NULL pnum and file.
50
*/
51
int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs,
52
int64_t sector_num, int nb_sectors, int *pnum,
53
diff --git a/block/io.c b/block/io.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/io.c
56
+++ b/block/io.c
57
@@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
58
{
59
int64_t target_sectors, ret, nb_sectors, sector_num = 0;
60
BlockDriverState *bs = child->bs;
61
- BlockDriverState *file;
62
int n;
63
64
target_sectors = bdrv_nb_sectors(bs);
65
@@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
66
if (nb_sectors <= 0) {
67
return 0;
68
}
69
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, &file);
70
+ ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, NULL);
71
if (ret < 0) {
72
error_report("error getting block status at sector %" PRId64 ": %s",
73
sector_num, strerror(-ret));
74
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
75
* beyond the end of the disk image it will be clamped; if 'pnum' is set to
76
* the end of the image, then the returned value will include BDRV_BLOCK_EOF.
77
*
78
- * If returned value is positive and BDRV_BLOCK_OFFSET_VALID bit is set, 'file'
79
- * points to the BDS which the sector range is allocated in.
80
+ * If returned value is positive, BDRV_BLOCK_OFFSET_VALID bit is set, and
81
+ * 'file' is non-NULL, then '*file' points to the BDS which the sector range
82
+ * is allocated in.
83
*/
84
static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
85
int64_t sector_num,
86
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
87
int64_t total_sectors;
88
int64_t n;
89
int64_t ret, ret2;
90
+ BlockDriverState *local_file = NULL;
91
92
- *file = NULL;
93
+ assert(pnum);
94
+ *pnum = 0;
95
total_sectors = bdrv_nb_sectors(bs);
96
if (total_sectors < 0) {
97
- return total_sectors;
98
+ ret = total_sectors;
99
+ goto early_out;
100
}
101
102
if (sector_num >= total_sectors) {
103
- *pnum = 0;
104
- return BDRV_BLOCK_EOF;
105
+ ret = BDRV_BLOCK_EOF;
106
+ goto early_out;
107
}
108
if (!nb_sectors) {
109
- *pnum = 0;
110
- return 0;
111
+ ret = 0;
112
+ goto early_out;
113
}
114
115
n = total_sectors - sector_num;
116
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
117
}
118
if (bs->drv->protocol_name) {
119
ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
120
- *file = bs;
121
+ local_file = bs;
122
}
123
- return ret;
124
+ goto early_out;
125
}
126
127
bdrv_inc_in_flight(bs);
128
ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
129
- file);
130
+ &local_file);
131
if (ret < 0) {
132
*pnum = 0;
133
goto out;
134
}
135
136
if (ret & BDRV_BLOCK_RAW) {
137
- assert(ret & BDRV_BLOCK_OFFSET_VALID && *file);
138
- ret = bdrv_co_get_block_status(*file, ret >> BDRV_SECTOR_BITS,
139
- *pnum, pnum, file);
140
+ assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
141
+ ret = bdrv_co_get_block_status(local_file, ret >> BDRV_SECTOR_BITS,
142
+ *pnum, pnum, &local_file);
143
goto out;
144
}
145
146
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
147
}
148
}
149
150
- if (*file && *file != bs &&
151
+ if (local_file && local_file != bs &&
152
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
153
(ret & BDRV_BLOCK_OFFSET_VALID)) {
154
- BlockDriverState *file2;
155
int file_pnum;
156
157
- ret2 = bdrv_co_get_block_status(*file, ret >> BDRV_SECTOR_BITS,
158
- *pnum, &file_pnum, &file2);
159
+ ret2 = bdrv_co_get_block_status(local_file, ret >> BDRV_SECTOR_BITS,
160
+ *pnum, &file_pnum, NULL);
161
if (ret2 >= 0) {
162
/* Ignore errors. This is just providing extra information, it
163
* is useful but not necessary.
164
@@ -XXX,XX +XXX,XX @@ out:
165
if (ret >= 0 && sector_num + *pnum == total_sectors) {
166
ret |= BDRV_BLOCK_EOF;
167
}
168
+early_out:
169
+ if (file) {
170
+ *file = local_file;
171
+ }
172
return ret;
17
}
173
}
18
174
19
-static void qed_clear_need_check(void *opaque, int ret)
175
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status(BlockDriverState *bs,
20
+static void qed_need_check_timer_entry(void *opaque)
176
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
177
int64_t bytes, int64_t *pnum)
21
{
178
{
22
BDRVQEDState *s = opaque;
179
- BlockDriverState *file;
23
+ int ret;
180
int64_t sector_num = offset >> BDRV_SECTOR_BITS;
24
181
int nb_sectors = bytes >> BDRV_SECTOR_BITS;
25
- if (ret) {
182
int64_t ret;
26
+ /* The timer should only fire when allocating writes have drained */
183
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
27
+ assert(!s->allocating_acb);
184
assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
28
+
185
assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE) && bytes < INT_MAX);
29
+ trace_qed_need_check_timer_cb(s);
186
ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &psectors,
30
+
187
- &file);
31
+ qed_acquire(s);
188
+ NULL);
32
+ qed_plug_allocating_write_reqs(s);
189
if (ret < 0) {
33
+
190
return ret;
34
+ /* Ensure writes are on disk before clearing flag */
191
}
35
+ ret = bdrv_co_flush(s->bs->file->bs);
192
diff --git a/block/mirror.c b/block/mirror.c
36
+ qed_release(s);
193
index XXXXXXX..XXXXXXX 100644
37
+ if (ret < 0) {
194
--- a/block/mirror.c
38
qed_unplug_allocating_write_reqs(s);
195
+++ b/block/mirror.c
39
return;
196
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
40
}
197
int io_sectors;
41
@@ -XXX,XX +XXX,XX @@ static void qed_clear_need_check(void *opaque, int ret)
198
unsigned int io_bytes;
42
199
int64_t io_bytes_acct;
43
qed_unplug_allocating_write_reqs(s);
200
- BlockDriverState *file;
44
201
enum MirrorMethod {
45
- ret = bdrv_flush(s->bs);
202
MIRROR_METHOD_COPY,
46
+ ret = bdrv_co_flush(s->bs);
203
MIRROR_METHOD_ZERO,
47
(void) ret;
204
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
205
ret = bdrv_get_block_status_above(source, NULL,
206
offset >> BDRV_SECTOR_BITS,
207
nb_chunks * sectors_per_chunk,
208
- &io_sectors, &file);
209
+ &io_sectors, NULL);
210
io_bytes = io_sectors * BDRV_SECTOR_SIZE;
211
if (ret < 0) {
212
io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes);
213
diff --git a/block/qcow2.c b/block/qcow2.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/block/qcow2.c
216
+++ b/block/qcow2.c
217
@@ -XXX,XX +XXX,XX @@ static bool is_zero_sectors(BlockDriverState *bs, int64_t start,
218
uint32_t count)
219
{
220
int nr;
221
- BlockDriverState *file;
222
int64_t res;
223
224
if (start + count > bs->total_sectors) {
225
@@ -XXX,XX +XXX,XX @@ static bool is_zero_sectors(BlockDriverState *bs, int64_t start,
226
if (!count) {
227
return true;
228
}
229
- res = bdrv_get_block_status_above(bs, NULL, start, count,
230
- &nr, &file);
231
+ res = bdrv_get_block_status_above(bs, NULL, start, count, &nr, NULL);
232
return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == count;
48
}
233
}
49
234
50
static void qed_need_check_timer_cb(void *opaque)
235
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
51
{
236
offset += pnum * BDRV_SECTOR_SIZE) {
52
- BDRVQEDState *s = opaque;
237
int nb_sectors = MIN(ssize - offset,
53
-
238
BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;
54
- /* The timer should only fire when allocating writes have drained */
239
- BlockDriverState *file;
55
- assert(!s->allocating_acb);
240
int64_t ret;
56
-
241
57
- trace_qed_need_check_timer_cb(s);
242
ret = bdrv_get_block_status_above(in_bs, NULL,
58
-
243
offset >> BDRV_SECTOR_BITS,
59
- qed_acquire(s);
244
- nb_sectors,
60
- qed_plug_allocating_write_reqs(s);
245
- &pnum, &file);
61
-
246
+ nb_sectors, &pnum, NULL);
62
- /* Ensure writes are on disk before clearing flag */
247
if (ret < 0) {
63
- bdrv_aio_flush(s->bs->file->bs, qed_clear_need_check, s);
248
error_setg_errno(&local_err, -ret,
64
- qed_release(s);
249
"Unable to get block status");
65
+ Coroutine *co = qemu_coroutine_create(qed_need_check_timer_entry, opaque);
250
diff --git a/qemu-img.c b/qemu-img.c
66
+ qemu_coroutine_enter(co);
251
index XXXXXXX..XXXXXXX 100644
67
}
252
--- a/qemu-img.c
68
253
+++ b/qemu-img.c
69
void qed_acquire(BDRVQEDState *s)
254
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
255
256
for (;;) {
257
int64_t status1, status2;
258
- BlockDriverState *file;
259
260
nb_sectors = sectors_to_process(total_sectors, sector_num);
261
if (nb_sectors <= 0) {
262
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
263
}
264
status1 = bdrv_get_block_status_above(bs1, NULL, sector_num,
265
total_sectors1 - sector_num,
266
- &pnum1, &file);
267
+ &pnum1, NULL);
268
if (status1 < 0) {
269
ret = 3;
270
error_report("Sector allocation test failed for %s", filename1);
271
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
272
273
status2 = bdrv_get_block_status_above(bs2, NULL, sector_num,
274
total_sectors2 - sector_num,
275
- &pnum2, &file);
276
+ &pnum2, NULL);
277
if (status2 < 0) {
278
ret = 3;
279
error_report("Sector allocation test failed for %s", filename2);
280
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
281
n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
282
283
if (s->sector_next_status <= sector_num) {
284
- BlockDriverState *file;
285
if (s->target_has_backing) {
286
ret = bdrv_get_block_status(blk_bs(s->src[src_cur]),
287
sector_num - src_cur_offset,
288
- n, &n, &file);
289
+ n, &n, NULL);
290
} else {
291
ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL,
292
sector_num - src_cur_offset,
293
- n, &n, &file);
294
+ n, &n, NULL);
295
}
296
if (ret < 0) {
297
return ret;
70
--
298
--
71
1.8.3.1
299
2.13.6
72
300
73
301
diff view generated by jsdifflib
1
All functions that are marked coroutine_fn can directly call the
1
From: Eric Blake <eblake@redhat.com>
2
bdrv_co_* version of functions instead of going through the wrapper.
2
3
3
Not all callers care about which BDS owns the mapping for a given
4
range of the file, or where the zeroes lie within that mapping. In
5
particular, bdrv_is_allocated() cares more about finding the
6
largest run of allocated data from the guest perspective, whether
7
or not that data is consecutive from the host perspective, and
8
whether or not the data reads as zero. Therefore, doing subsequent
9
refinements such as checking how much of the format-layer
10
allocation also satisfies BDRV_BLOCK_ZERO at the protocol layer is
11
wasted work - in the best case, it just costs extra CPU cycles
12
during a single bdrv_is_allocated(), but in the worst case, it
13
results in a smaller *pnum, and forces callers to iterate through
14
more status probes when visiting the entire file for even more
15
extra CPU cycles.
16
17
This patch only optimizes the block layer (no behavior change when
18
want_zero is true, but skip unnecessary effort when it is false).
19
Then when subsequent patches tweak the driver callback to be
20
byte-based, we can also pass this hint through to the driver.
21
22
Tweak BdrvCoGetBlockStatusData to declare arguments in parameter
23
order, rather than mixing things up (minimizing padding is not
24
necessary here).
25
26
Signed-off-by: Eric Blake <eblake@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
28
---
8
block/qed.c | 16 +++++++++-------
29
block/io.c | 57 +++++++++++++++++++++++++++++++++++++++++----------------
9
1 file changed, 9 insertions(+), 7 deletions(-)
30
1 file changed, 41 insertions(+), 16 deletions(-)
10
31
11
diff --git a/block/qed.c b/block/qed.c
32
diff --git a/block/io.c b/block/io.c
12
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qed.c
34
--- a/block/io.c
14
+++ b/block/qed.c
35
+++ b/block/io.c
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_write_header(BDRVQEDState *s)
36
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
16
};
37
typedef struct BdrvCoGetBlockStatusData {
17
qemu_iovec_init_external(&qiov, &iov, 1);
38
BlockDriverState *bs;
18
39
BlockDriverState *base;
19
- ret = bdrv_preadv(s->bs->file, 0, &qiov);
40
- BlockDriverState **file;
20
+ ret = bdrv_co_preadv(s->bs->file, 0, qiov.size, &qiov, 0);
41
+ bool want_zero;
21
if (ret < 0) {
42
int64_t sector_num;
43
int nb_sectors;
44
int *pnum;
45
+ BlockDriverState **file;
46
int64_t ret;
47
bool done;
48
} BdrvCoGetBlockStatusData;
49
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
50
* Drivers not implementing the functionality are assumed to not support
51
* backing files, hence all their sectors are reported as allocated.
52
*
53
+ * If 'want_zero' is true, the caller is querying for mapping purposes,
54
+ * and the result should include BDRV_BLOCK_OFFSET_VALID and
55
+ * BDRV_BLOCK_ZERO where possible; otherwise, the result may omit those
56
+ * bits particularly if it allows for a larger value in 'pnum'.
57
+ *
58
* If 'sector_num' is beyond the end of the disk image the return value is
59
* BDRV_BLOCK_EOF and 'pnum' is set to 0.
60
*
61
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
62
* is allocated in.
63
*/
64
static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
65
+ bool want_zero,
66
int64_t sector_num,
67
int nb_sectors, int *pnum,
68
BlockDriverState **file)
69
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
70
71
if (ret & BDRV_BLOCK_RAW) {
72
assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
73
- ret = bdrv_co_get_block_status(local_file, ret >> BDRV_SECTOR_BITS,
74
+ ret = bdrv_co_get_block_status(local_file, want_zero,
75
+ ret >> BDRV_SECTOR_BITS,
76
*pnum, pnum, &local_file);
22
goto out;
77
goto out;
23
}
78
}
24
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_write_header(BDRVQEDState *s)
79
25
/* Update header */
80
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
26
qed_header_cpu_to_le(&s->header, (QEDHeader *) buf);
81
ret |= BDRV_BLOCK_ALLOCATED;
27
82
- } else {
28
- ret = bdrv_pwritev(s->bs->file, 0, &qiov);
83
+ } else if (want_zero) {
29
+ ret = bdrv_co_pwritev(s->bs->file, 0, qiov.size, &qiov, 0);
84
if (bdrv_unallocated_blocks_are_zero(bs)) {
30
if (ret < 0) {
85
ret |= BDRV_BLOCK_ZERO;
31
goto out;
86
} else if (bs->backing) {
87
BlockDriverState *bs2 = bs->backing->bs;
88
int64_t nb_sectors2 = bdrv_nb_sectors(bs2);
89
+
90
if (nb_sectors2 >= 0 && sector_num >= nb_sectors2) {
91
ret |= BDRV_BLOCK_ZERO;
92
}
93
}
32
}
94
}
33
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
95
34
qemu_iovec_concat(*backing_qiov, qiov, 0, size);
96
- if (local_file && local_file != bs &&
35
97
+ if (want_zero && local_file && local_file != bs &&
36
BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
98
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
37
- ret = bdrv_preadv(s->bs->backing, pos, *backing_qiov);
99
(ret & BDRV_BLOCK_OFFSET_VALID)) {
38
+ ret = bdrv_co_preadv(s->bs->backing, pos, size, *backing_qiov, 0);
100
int file_pnum;
39
if (ret < 0) {
101
40
return ret;
102
- ret2 = bdrv_co_get_block_status(local_file, ret >> BDRV_SECTOR_BITS,
41
}
103
+ ret2 = bdrv_co_get_block_status(local_file, want_zero,
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
104
+ ret >> BDRV_SECTOR_BITS,
43
}
105
*pnum, &file_pnum, NULL);
44
106
if (ret2 >= 0) {
45
BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
107
/* Ignore errors. This is just providing extra information, it
46
- ret = bdrv_pwritev(s->bs->file, offset, &qiov);
108
@@ -XXX,XX +XXX,XX @@ early_out:
47
+ ret = bdrv_co_pwritev(s->bs->file, offset, qiov.size, &qiov, 0);
109
48
if (ret < 0) {
110
static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
49
goto out;
111
BlockDriverState *base,
50
}
112
+ bool want_zero,
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
113
int64_t sector_num,
52
trace_qed_aio_write_main(s, acb, 0, offset, acb->cur_qiov.size);
114
int nb_sectors,
53
115
int *pnum,
54
BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
116
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
55
- ret = bdrv_pwritev(s->bs->file, offset, &acb->cur_qiov);
117
56
+ ret = bdrv_co_pwritev(s->bs->file, offset, acb->cur_qiov.size,
118
assert(bs != base);
57
+ &acb->cur_qiov, 0);
119
for (p = bs; p != base; p = backing_bs(p)) {
58
if (ret < 0) {
120
- ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum, file);
59
return ret;
121
+ ret = bdrv_co_get_block_status(p, want_zero, sector_num, nb_sectors,
60
}
122
+ pnum, file);
61
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
123
if (ret < 0) {
62
* region. The solution is to flush after writing a new data
124
break;
63
* cluster and before updating the L2 table.
125
}
64
*/
126
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
65
- ret = bdrv_flush(s->bs->file->bs);
127
BdrvCoGetBlockStatusData *data = opaque;
66
+ ret = bdrv_co_flush(s->bs->file->bs);
128
67
if (ret < 0) {
129
data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
68
return ret;
130
+ data->want_zero,
69
}
131
data->sector_num,
70
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
132
data->nb_sectors,
71
}
133
data->pnum,
72
134
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
73
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
135
*
74
- ret = bdrv_preadv(bs->file, offset, &acb->cur_qiov);
136
* See bdrv_co_get_block_status_above() for details.
75
+ ret = bdrv_co_preadv(bs->file, offset, acb->cur_qiov.size,
137
*/
76
+ &acb->cur_qiov, 0);
138
-int64_t bdrv_get_block_status_above(BlockDriverState *bs,
139
- BlockDriverState *base,
140
- int64_t sector_num,
141
- int nb_sectors, int *pnum,
142
- BlockDriverState **file)
143
+static int64_t bdrv_common_block_status_above(BlockDriverState *bs,
144
+ BlockDriverState *base,
145
+ bool want_zero,
146
+ int64_t sector_num,
147
+ int nb_sectors, int *pnum,
148
+ BlockDriverState **file)
149
{
150
Coroutine *co;
151
BdrvCoGetBlockStatusData data = {
152
.bs = bs,
153
.base = base,
154
- .file = file,
155
+ .want_zero = want_zero,
156
.sector_num = sector_num,
157
.nb_sectors = nb_sectors,
158
.pnum = pnum,
159
+ .file = file,
160
.done = false,
161
};
162
163
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs,
164
return data.ret;
165
}
166
167
+int64_t bdrv_get_block_status_above(BlockDriverState *bs,
168
+ BlockDriverState *base,
169
+ int64_t sector_num,
170
+ int nb_sectors, int *pnum,
171
+ BlockDriverState **file)
172
+{
173
+ return bdrv_common_block_status_above(bs, base, true, sector_num,
174
+ nb_sectors, pnum, file);
175
+}
176
+
177
int64_t bdrv_get_block_status(BlockDriverState *bs,
178
int64_t sector_num,
179
int nb_sectors, int *pnum,
180
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status(BlockDriverState *bs,
181
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
182
int64_t bytes, int64_t *pnum)
183
{
184
- int64_t sector_num = offset >> BDRV_SECTOR_BITS;
185
- int nb_sectors = bytes >> BDRV_SECTOR_BITS;
186
int64_t ret;
187
int psectors;
188
189
assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
190
assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE) && bytes < INT_MAX);
191
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &psectors,
192
- NULL);
193
+ ret = bdrv_common_block_status_above(bs, backing_bs(bs), false,
194
+ offset >> BDRV_SECTOR_BITS,
195
+ bytes >> BDRV_SECTOR_BITS, &psectors,
196
+ NULL);
77
if (ret < 0) {
197
if (ret < 0) {
78
return ret;
198
return ret;
79
}
199
}
80
--
200
--
81
1.8.3.1
201
2.13.6
82
202
83
203
diff view generated by jsdifflib
1
Now that we stay in coroutine context for the whole request when doing
1
From: Eric Blake <eblake@redhat.com>
2
reads or writes, we can add coroutine_fn annotations to many functions
3
that can do I/O or yield directly.
4
2
3
In the process of converting sector-based interfaces to bytes,
4
I'm finding it easier to represent a byte count as a 64-bit
5
integer at the block layer (even if we are internally capped
6
by SIZE_MAX or even INT_MAX for individual transactions, it's
7
still nicer to not have to worry about truncation/overflow
8
issues on as many variables). Update the signature of
9
bdrv_round_to_clusters() to uniformly use int64_t, matching
10
the signature already chosen for bdrv_is_allocated and the
11
fact that off_t is also a signed type, then adjust clients
12
according to the required fallout (even where the result could
13
now exceed 32 bits, no client is directly assigning the result
14
into a 32-bit value without breaking things into a loop first).
15
16
Signed-off-by: Eric Blake <eblake@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
18
---
8
block/qed-cluster.c | 5 +++--
19
include/block/block.h | 4 ++--
9
block/qed.c | 44 ++++++++++++++++++++++++--------------------
20
block/io.c | 6 +++---
10
block/qed.h | 5 +++--
21
block/mirror.c | 7 +++----
11
3 files changed, 30 insertions(+), 24 deletions(-)
22
block/trace-events | 2 +-
23
4 files changed, 9 insertions(+), 10 deletions(-)
12
24
13
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
25
diff --git a/include/block/block.h b/include/block/block.h
14
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qed-cluster.c
27
--- a/include/block/block.h
16
+++ b/block/qed-cluster.c
28
+++ b/include/block/block.h
17
@@ -XXX,XX +XXX,XX @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
29
@@ -XXX,XX +XXX,XX @@ int bdrv_get_flags(BlockDriverState *bs);
18
* On failure QED_CLUSTER_L2 or QED_CLUSTER_L1 is returned for missing L2 or L1
30
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
19
* table offset, respectively. len is number of contiguous unallocated bytes.
31
ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs);
32
void bdrv_round_to_clusters(BlockDriverState *bs,
33
- int64_t offset, unsigned int bytes,
34
+ int64_t offset, int64_t bytes,
35
int64_t *cluster_offset,
36
- unsigned int *cluster_bytes);
37
+ int64_t *cluster_bytes);
38
39
const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
40
void bdrv_get_backing_filename(BlockDriverState *bs,
41
diff --git a/block/io.c b/block/io.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block/io.c
44
+++ b/block/io.c
45
@@ -XXX,XX +XXX,XX @@ static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
46
* Round a region to cluster boundaries
20
*/
47
*/
21
-int qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
48
void bdrv_round_to_clusters(BlockDriverState *bs,
22
- size_t *len, uint64_t *img_offset)
49
- int64_t offset, unsigned int bytes,
23
+int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
50
+ int64_t offset, int64_t bytes,
24
+ uint64_t pos, size_t *len,
51
int64_t *cluster_offset,
25
+ uint64_t *img_offset)
52
- unsigned int *cluster_bytes)
53
+ int64_t *cluster_bytes)
26
{
54
{
27
uint64_t l2_offset;
55
BlockDriverInfo bdi;
28
uint64_t offset = 0;
56
29
diff --git a/block/qed.c b/block/qed.c
57
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
58
struct iovec iov;
59
QEMUIOVector local_qiov;
60
int64_t cluster_offset;
61
- unsigned int cluster_bytes;
62
+ int64_t cluster_bytes;
63
size_t skip_bytes;
64
int ret;
65
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
66
diff --git a/block/mirror.c b/block/mirror.c
30
index XXXXXXX..XXXXXXX 100644
67
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qed.c
68
--- a/block/mirror.c
32
+++ b/block/qed.c
69
+++ b/block/mirror.c
33
@@ -XXX,XX +XXX,XX @@ int qed_write_header_sync(BDRVQEDState *s)
70
@@ -XXX,XX +XXX,XX @@ static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset,
34
* This function only updates known header fields in-place and does not affect
71
bool need_cow;
35
* extra data after the QED header.
72
int ret = 0;
36
*/
73
int64_t align_offset = *offset;
37
-static int qed_write_header(BDRVQEDState *s)
74
- unsigned int align_bytes = *bytes;
38
+static int coroutine_fn qed_write_header(BDRVQEDState *s)
75
+ int64_t align_bytes = *bytes;
39
{
76
int max_bytes = s->granularity * s->max_iov;
40
/* We must write full sectors for O_DIRECT but cannot necessarily generate
77
41
* the data following the header if an unrecognized compat feature is
78
- assert(*bytes < INT_MAX);
42
@@ -XXX,XX +XXX,XX @@ static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
79
need_cow = !test_bit(*offset / s->granularity, s->cow_bitmap);
43
qemu_co_enter_next(&s->allocating_write_reqs);
80
need_cow |= !test_bit((*offset + *bytes - 1) / s->granularity,
44
}
81
s->cow_bitmap);
45
82
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
46
-static void qed_need_check_timer_entry(void *opaque)
83
while (nb_chunks > 0 && offset < s->bdev_length) {
47
+static void coroutine_fn qed_need_check_timer_entry(void *opaque)
84
int64_t ret;
48
{
85
int io_sectors;
49
BDRVQEDState *s = opaque;
86
- unsigned int io_bytes;
50
int ret;
87
+ int64_t io_bytes;
51
@@ -XXX,XX +XXX,XX @@ static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
88
int64_t io_bytes_acct;
52
* This function reads qiov->size bytes starting at pos from the backing file.
89
enum MirrorMethod {
53
* If there is no backing file then zeroes are read.
90
MIRROR_METHOD_COPY,
54
*/
91
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
55
-static int qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
92
io_bytes = s->granularity;
56
- QEMUIOVector *qiov,
93
} else if (ret >= 0 && !(ret & BDRV_BLOCK_DATA)) {
57
- QEMUIOVector **backing_qiov)
94
int64_t target_offset;
58
+static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
95
- unsigned int target_bytes;
59
+ QEMUIOVector *qiov,
96
+ int64_t target_bytes;
60
+ QEMUIOVector **backing_qiov)
97
bdrv_round_to_clusters(blk_bs(s->target), offset, io_bytes,
61
{
98
&target_offset, &target_bytes);
62
uint64_t backing_length = 0;
99
if (target_offset == offset &&
63
size_t size;
100
diff --git a/block/trace-events b/block/trace-events
64
@@ -XXX,XX +XXX,XX @@ static int qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
65
* @len: Number of bytes
66
* @offset: Byte offset in image file
67
*/
68
-static int qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
69
- uint64_t len, uint64_t offset)
70
+static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
71
+ uint64_t pos, uint64_t len,
72
+ uint64_t offset)
73
{
74
QEMUIOVector qiov;
75
QEMUIOVector *backing_qiov = NULL;
76
@@ -XXX,XX +XXX,XX @@ out:
77
* The cluster offset may be an allocated byte offset in the image file, the
78
* zero cluster marker, or the unallocated cluster marker.
79
*/
80
-static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
81
- unsigned int n, uint64_t cluster)
82
+static void coroutine_fn qed_update_l2_table(BDRVQEDState *s, QEDTable *table,
83
+ int index, unsigned int n,
84
+ uint64_t cluster)
85
{
86
int i;
87
for (i = index; i < index + n; i++) {
88
@@ -XXX,XX +XXX,XX @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
89
}
90
}
91
92
-static void qed_aio_complete(QEDAIOCB *acb)
93
+static void coroutine_fn qed_aio_complete(QEDAIOCB *acb)
94
{
95
BDRVQEDState *s = acb_to_s(acb);
96
97
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb)
98
/**
99
* Update L1 table with new L2 table offset and write it out
100
*/
101
-static int qed_aio_write_l1_update(QEDAIOCB *acb)
102
+static int coroutine_fn qed_aio_write_l1_update(QEDAIOCB *acb)
103
{
104
BDRVQEDState *s = acb_to_s(acb);
105
CachedL2Table *l2_table = acb->request.l2_table;
106
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_l1_update(QEDAIOCB *acb)
107
/**
108
* Update L2 table with new cluster offsets and write them out
109
*/
110
-static int qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
111
+static int coroutine_fn qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
112
{
113
BDRVQEDState *s = acb_to_s(acb);
114
bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
115
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
116
/**
117
* Write data to the image file
118
*/
119
-static int qed_aio_write_main(QEDAIOCB *acb)
120
+static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
121
{
122
BDRVQEDState *s = acb_to_s(acb);
123
uint64_t offset = acb->cur_cluster +
124
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_main(QEDAIOCB *acb)
125
/**
126
* Populate untouched regions of new data cluster
127
*/
128
-static int qed_aio_write_cow(QEDAIOCB *acb)
129
+static int coroutine_fn qed_aio_write_cow(QEDAIOCB *acb)
130
{
131
BDRVQEDState *s = acb_to_s(acb);
132
uint64_t start, len, offset;
133
@@ -XXX,XX +XXX,XX @@ static bool qed_should_set_need_check(BDRVQEDState *s)
134
*
135
* This path is taken when writing to previously unallocated clusters.
136
*/
137
-static int qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
138
+static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
139
{
140
BDRVQEDState *s = acb_to_s(acb);
141
int ret;
142
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
143
*
144
* This path is taken when writing to already allocated clusters.
145
*/
146
-static int qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
147
+static int coroutine_fn qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset,
148
+ size_t len)
149
{
150
/* Allocate buffer for zero writes */
151
if (acb->flags & QED_AIOCB_ZERO) {
152
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
153
* @offset: Cluster offset in bytes
154
* @len: Length in bytes
155
*/
156
-static int qed_aio_write_data(void *opaque, int ret,
157
- uint64_t offset, size_t len)
158
+static int coroutine_fn qed_aio_write_data(void *opaque, int ret,
159
+ uint64_t offset, size_t len)
160
{
161
QEDAIOCB *acb = opaque;
162
163
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_data(void *opaque, int ret,
164
* @offset: Cluster offset in bytes
165
* @len: Length in bytes
166
*/
167
-static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
168
+static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
169
+ uint64_t offset, size_t len)
170
{
171
QEDAIOCB *acb = opaque;
172
BDRVQEDState *s = acb_to_s(acb);
173
@@ -XXX,XX +XXX,XX @@ static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
174
/**
175
* Begin next I/O or complete the request
176
*/
177
-static int qed_aio_next_io(QEDAIOCB *acb)
178
+static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb)
179
{
180
BDRVQEDState *s = acb_to_s(acb);
181
uint64_t offset;
182
diff --git a/block/qed.h b/block/qed.h
183
index XXXXXXX..XXXXXXX 100644
101
index XXXXXXX..XXXXXXX 100644
184
--- a/block/qed.h
102
--- a/block/trace-events
185
+++ b/block/qed.h
103
+++ b/block/trace-events
186
@@ -XXX,XX +XXX,XX @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
104
@@ -XXX,XX +XXX,XX @@ blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flag
187
/**
105
bdrv_co_preadv(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x"
188
* Cluster functions
106
bdrv_co_pwritev(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x"
189
*/
107
bdrv_co_pwrite_zeroes(void *bs, int64_t offset, int count, int flags) "bs %p offset %"PRId64" count %d flags 0x%x"
190
-int qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
108
-bdrv_co_do_copy_on_readv(void *bs, int64_t offset, unsigned int bytes, int64_t cluster_offset, unsigned int cluster_bytes) "bs %p offset %"PRId64" bytes %u cluster_offset %"PRId64" cluster_bytes %u"
191
- size_t *len, uint64_t *img_offset);
109
+bdrv_co_do_copy_on_readv(void *bs, int64_t offset, unsigned int bytes, int64_t cluster_offset, int64_t cluster_bytes) "bs %p offset %"PRId64" bytes %u cluster_offset %"PRId64" cluster_bytes %"PRId64
192
+int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
110
193
+ uint64_t pos, size_t *len,
111
# block/stream.c
194
+ uint64_t *img_offset);
112
stream_one_iteration(void *s, int64_t offset, uint64_t bytes, int is_allocated) "s %p offset %" PRId64 " bytes %" PRIu64 " is_allocated %d"
195
196
/**
197
* Consistency check
198
--
113
--
199
1.8.3.1
114
2.13.6
200
115
201
116
diff view generated by jsdifflib
1
With this change, qed_aio_write_prefill() and qed_aio_write_postfill()
1
From: Eric Blake <eblake@redhat.com>
2
collapse into a single function. This is reflected by a rename of the
3
combined function to qed_aio_write_cow().
4
2
3
We are gradually converting to byte-based interfaces, as they are
4
easier to reason about than sector-based. Convert another internal
5
function (no semantic change), and rename it to is_zero() in the
6
process.
7
8
Signed-off-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Fam Zheng <famz@redhat.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
12
---
9
block/qed.c | 57 +++++++++++++++++++++++----------------------------------
13
block/qcow2.c | 33 +++++++++++++++++++--------------
10
1 file changed, 23 insertions(+), 34 deletions(-)
14
1 file changed, 19 insertions(+), 14 deletions(-)
11
15
12
diff --git a/block/qed.c b/block/qed.c
16
diff --git a/block/qcow2.c b/block/qcow2.c
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/block/qed.c
18
--- a/block/qcow2.c
15
+++ b/block/qed.c
19
+++ b/block/qcow2.c
16
@@ -XXX,XX +XXX,XX @@ static int qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
20
@@ -XXX,XX +XXX,XX @@ finish:
17
* @pos: Byte position in device
21
}
18
* @len: Number of bytes
22
19
* @offset: Byte offset in image file
23
20
- * @cb: Completion function
24
-static bool is_zero_sectors(BlockDriverState *bs, int64_t start,
21
- * @opaque: User data for completion function
25
- uint32_t count)
22
*/
26
+static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
23
-static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
24
- uint64_t len, uint64_t offset,
25
- BlockCompletionFunc *cb,
26
- void *opaque)
27
+static int qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
28
+ uint64_t len, uint64_t offset)
29
{
27
{
30
QEMUIOVector qiov;
28
int nr;
31
QEMUIOVector *backing_qiov = NULL;
29
int64_t res;
32
@@ -XXX,XX +XXX,XX @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
30
+ int64_t start;
33
31
34
/* Skip copy entirely if there is no work to do */
32
- if (start + count > bs->total_sectors) {
35
if (len == 0) {
33
- count = bs->total_sectors - start;
36
- cb(opaque, 0);
34
+ /* TODO: Widening to sector boundaries should only be needed as
37
- return;
35
+ * long as we can't query finer granularity. */
38
+ return 0;
36
+ start = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
37
+ bytes = QEMU_ALIGN_UP(offset + bytes, BDRV_SECTOR_SIZE) - start;
38
+
39
+ /* Clamp to image length, before checking status of underlying sectors */
40
+ if (start + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) {
41
+ bytes = bs->total_sectors * BDRV_SECTOR_SIZE - start;
39
}
42
}
40
43
41
iov = (struct iovec) {
44
- if (!count) {
42
@@ -XXX,XX +XXX,XX @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
45
+ if (!bytes) {
43
ret = 0;
46
return true;
44
out:
47
}
45
qemu_vfree(iov.iov_base);
48
- res = bdrv_get_block_status_above(bs, NULL, start, count, &nr, NULL);
46
- cb(opaque, ret);
49
- return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == count;
47
+ return ret;
50
+ res = bdrv_get_block_status_above(bs, NULL, start >> BDRV_SECTOR_BITS,
51
+ bytes >> BDRV_SECTOR_BITS, &nr, NULL);
52
+ return res >= 0 && (res & BDRV_BLOCK_ZERO) &&
53
+ nr * BDRV_SECTOR_SIZE == bytes;
48
}
54
}
49
55
50
/**
56
static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
51
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
57
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
52
}
53
54
/**
55
- * Populate back untouched region of new data cluster
56
+ * Populate untouched regions of new data cluster
57
*/
58
-static void qed_aio_write_postfill(void *opaque, int ret)
59
+static void qed_aio_write_cow(void *opaque, int ret)
60
{
61
QEDAIOCB *acb = opaque;
62
BDRVQEDState *s = acb_to_s(acb);
63
- uint64_t start = acb->cur_pos + acb->cur_qiov.size;
64
- uint64_t len =
65
- qed_start_of_cluster(s, start + s->header.cluster_size - 1) - start;
66
- uint64_t offset = acb->cur_cluster +
67
- qed_offset_into_cluster(s, acb->cur_pos) +
68
- acb->cur_qiov.size;
69
+ uint64_t start, len, offset;
70
+
71
+ /* Populate front untouched region of new data cluster */
72
+ start = qed_start_of_cluster(s, acb->cur_pos);
73
+ len = qed_offset_into_cluster(s, acb->cur_pos);
74
75
+ trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
76
+ ret = qed_copy_from_backing_file(s, start, len, acb->cur_cluster);
77
if (ret) {
78
qed_aio_complete(acb, ret);
79
return;
80
}
58
}
81
59
82
- trace_qed_aio_write_postfill(s, acb, start, len, offset);
60
if (head || tail) {
83
- qed_copy_from_backing_file(s, start, len, offset,
61
- int64_t cl_start = (offset - head) >> BDRV_SECTOR_BITS;
84
- qed_aio_write_main, acb);
62
uint64_t off;
85
-}
63
unsigned int nr;
86
+ /* Populate back untouched region of new data cluster */
64
87
+ start = acb->cur_pos + acb->cur_qiov.size;
65
assert(head + bytes <= s->cluster_size);
88
+ len = qed_start_of_cluster(s, start + s->header.cluster_size - 1) - start;
66
89
+ offset = acb->cur_cluster +
67
/* check whether remainder of cluster already reads as zero */
90
+ qed_offset_into_cluster(s, acb->cur_pos) +
68
- if (!(is_zero_sectors(bs, cl_start,
91
+ acb->cur_qiov.size;
69
- DIV_ROUND_UP(head, BDRV_SECTOR_SIZE)) &&
92
70
- is_zero_sectors(bs, (offset + bytes) >> BDRV_SECTOR_BITS,
93
-/**
71
- DIV_ROUND_UP(-tail & (s->cluster_size - 1),
94
- * Populate front untouched region of new data cluster
72
- BDRV_SECTOR_SIZE)))) {
95
- */
73
+ if (!(is_zero(bs, offset - head, head) &&
96
-static void qed_aio_write_prefill(void *opaque, int ret)
74
+ is_zero(bs, offset + bytes,
97
-{
75
+ tail ? s->cluster_size - tail : 0))) {
98
- QEDAIOCB *acb = opaque;
76
return -ENOTSUP;
99
- BDRVQEDState *s = acb_to_s(acb);
77
}
100
- uint64_t start = qed_start_of_cluster(s, acb->cur_pos);
78
101
- uint64_t len = qed_offset_into_cluster(s, acb->cur_pos);
79
qemu_co_mutex_lock(&s->lock);
102
+ trace_qed_aio_write_postfill(s, acb, start, len, offset);
80
/* We can have new write after previous check */
103
+ ret = qed_copy_from_backing_file(s, start, len, offset);
81
- offset = cl_start << BDRV_SECTOR_BITS;
104
82
+ offset = QEMU_ALIGN_DOWN(offset, s->cluster_size);
105
- trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
83
bytes = s->cluster_size;
106
- qed_copy_from_backing_file(s, start, len, acb->cur_cluster,
84
nr = s->cluster_size;
107
- qed_aio_write_postfill, acb);
85
ret = qcow2_get_cluster_offset(bs, offset, &nr, &off);
108
+ qed_aio_write_main(acb, ret);
109
}
110
111
/**
112
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
113
114
cb = qed_aio_write_zero_cluster;
115
} else {
116
- cb = qed_aio_write_prefill;
117
+ cb = qed_aio_write_cow;
118
acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
119
}
120
121
--
86
--
122
1.8.3.1
87
2.13.6
123
88
124
89
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Calling aio_poll() directly may have been fine previously, but this is
3
We are gradually converting to byte-based interfaces, as they are
4
the future, man! The difference between an aio_poll() loop and
4
easier to reason about than sector-based. Change the internal
5
BDRV_POLL_WHILE() is that BDRV_POLL_WHILE() releases the AioContext
5
loop iteration of zeroing a device to track by bytes instead of
6
around aio_poll().
6
sectors (although we are still guaranteed that we iterate by steps
7
that are sector-aligned).
7
8
8
This allows the IOThread to run fd handlers or BHs to complete the
9
Signed-off-by: Eric Blake <eblake@redhat.com>
9
request. Failure to release the AioContext causes deadlocks.
10
Reviewed-by: Fam Zheng <famz@redhat.com>
10
11
Reviewed-by: John Snow <jsnow@redhat.com>
11
Using BDRV_POLL_WHILE() partially fixes a 'savevm' hang with -object
12
iothread.
13
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
13
---
19
block/io.c | 4 +---
14
block/io.c | 32 ++++++++++++++++----------------
20
1 file changed, 1 insertion(+), 3 deletions(-)
15
1 file changed, 16 insertions(+), 16 deletions(-)
21
16
22
diff --git a/block/io.c b/block/io.c
17
diff --git a/block/io.c b/block/io.c
23
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
24
--- a/block/io.c
19
--- a/block/io.c
25
+++ b/block/io.c
20
+++ b/block/io.c
26
@@ -XXX,XX +XXX,XX @@ bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
21
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
27
Coroutine *co = qemu_coroutine_create(bdrv_co_rw_vmstate_entry, &data);
22
*/
28
23
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
29
bdrv_coroutine_enter(bs, co);
24
{
30
- while (data.ret == -EINPROGRESS) {
25
- int64_t target_sectors, ret, nb_sectors, sector_num = 0;
31
- aio_poll(bdrv_get_aio_context(bs), true);
26
+ int64_t target_size, ret, bytes, offset = 0;
32
- }
27
BlockDriverState *bs = child->bs;
33
+ BDRV_POLL_WHILE(bs, data.ret == -EINPROGRESS);
28
- int n;
34
return data.ret;
29
+ int n; /* sectors */
30
31
- target_sectors = bdrv_nb_sectors(bs);
32
- if (target_sectors < 0) {
33
- return target_sectors;
34
+ target_size = bdrv_getlength(bs);
35
+ if (target_size < 0) {
36
+ return target_size;
37
}
38
39
for (;;) {
40
- nb_sectors = MIN(target_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
41
- if (nb_sectors <= 0) {
42
+ bytes = MIN(target_size - offset, BDRV_REQUEST_MAX_BYTES);
43
+ if (bytes <= 0) {
44
return 0;
45
}
46
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, NULL);
47
+ ret = bdrv_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
48
+ bytes >> BDRV_SECTOR_BITS, &n, NULL);
49
if (ret < 0) {
50
- error_report("error getting block status at sector %" PRId64 ": %s",
51
- sector_num, strerror(-ret));
52
+ error_report("error getting block status at offset %" PRId64 ": %s",
53
+ offset, strerror(-ret));
54
return ret;
55
}
56
if (ret & BDRV_BLOCK_ZERO) {
57
- sector_num += n;
58
+ offset += n * BDRV_SECTOR_BITS;
59
continue;
60
}
61
- ret = bdrv_pwrite_zeroes(child, sector_num << BDRV_SECTOR_BITS,
62
- n << BDRV_SECTOR_BITS, flags);
63
+ ret = bdrv_pwrite_zeroes(child, offset, n * BDRV_SECTOR_SIZE, flags);
64
if (ret < 0) {
65
- error_report("error writing zeroes at sector %" PRId64 ": %s",
66
- sector_num, strerror(-ret));
67
+ error_report("error writing zeroes at offset %" PRId64 ": %s",
68
+ offset, strerror(-ret));
69
return ret;
70
}
71
- sector_num += n;
72
+ offset += n * BDRV_SECTOR_SIZE;
35
}
73
}
36
}
74
}
75
37
--
76
--
38
1.8.3.1
77
2.13.6
39
78
40
79
diff view generated by jsdifflib
1
From: Stephen Bates <sbates@raithlin.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Add the ability for the NVMe model to support both the RDS and WDS
3
We are gradually converting to byte-based interfaces, as they are
4
modes in the Controller Memory Buffer.
4
easier to reason about than sector-based. Continue by converting
5
an internal function (no semantic change), and simplifying its
6
caller accordingly.
5
7
6
Although not currently supported in the upstreamed Linux kernel a fork
8
Signed-off-by: Eric Blake <eblake@redhat.com>
7
with support exists [1] and user-space test programs that build on
9
Reviewed-by: Fam Zheng <famz@redhat.com>
8
this also exist [2].
10
Reviewed-by: John Snow <jsnow@redhat.com>
9
10
Useful for testing CMB functionality in preperation for real CMB
11
enabled NVMe devices (coming soon).
12
13
[1] https://github.com/sbates130272/linux-p2pmem
14
[2] https://github.com/sbates130272/p2pmem-test
15
16
Signed-off-by: Stephen Bates <sbates@raithlin.com>
17
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
18
Reviewed-by: Keith Busch <keith.busch@intel.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
12
---
21
hw/block/nvme.c | 83 +++++++++++++++++++++++++++++++++++++++------------------
13
qemu-img.c | 24 +++++++++++-------------
22
hw/block/nvme.h | 1 +
14
1 file changed, 11 insertions(+), 13 deletions(-)
23
2 files changed, 58 insertions(+), 26 deletions(-)
24
15
25
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
16
diff --git a/qemu-img.c b/qemu-img.c
26
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/block/nvme.c
18
--- a/qemu-img.c
28
+++ b/hw/block/nvme.c
19
+++ b/qemu-img.c
29
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static void dump_map_entry(OutputFormat output_format, MapEntry *e,
30
* cmb_size_mb=<cmb_size_mb[optional]>
31
*
32
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
33
- * offset 0 in BAR2 and supports SQS only for now.
34
+ * offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
35
*/
36
37
#include "qemu/osdep.h"
38
@@ -XXX,XX +XXX,XX @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
39
}
21
}
40
}
22
}
41
23
42
-static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
24
-static int get_block_status(BlockDriverState *bs, int64_t sector_num,
43
- uint32_t len, NvmeCtrl *n)
25
- int nb_sectors, MapEntry *e)
44
+static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
26
+static int get_block_status(BlockDriverState *bs, int64_t offset,
45
+ uint64_t prp2, uint32_t len, NvmeCtrl *n)
27
+ int64_t bytes, MapEntry *e)
46
{
28
{
47
hwaddr trans_len = n->page_size - (prp1 % n->page_size);
29
int64_t ret;
48
trans_len = MIN(len, trans_len);
30
int depth;
49
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
31
BlockDriverState *file;
50
32
bool has_offset;
51
if (!prp1) {
33
+ int nb_sectors = bytes >> BDRV_SECTOR_BITS;
52
return NVME_INVALID_FIELD | NVME_DNR;
34
53
+ } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
35
+ assert(bytes < INT_MAX);
54
+ prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
36
/* As an optimization, we could cache the current range of unallocated
55
+ qsg->nsg = 0;
37
* clusters in each file of the chain, and avoid querying the same
56
+ qemu_iovec_init(iov, num_prps);
38
* range repeatedly.
57
+ qemu_iovec_add(iov, (void *)&n->cmbuf[prp1 - n->ctrl_mem.addr], trans_len);
39
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num,
58
+ } else {
40
59
+ pci_dma_sglist_init(qsg, &n->parent_obj, num_prps);
41
depth = 0;
60
+ qemu_sglist_add(qsg, prp1, trans_len);
42
for (;;) {
61
}
43
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors,
44
- &file);
45
+ ret = bdrv_get_block_status(bs, offset >> BDRV_SECTOR_BITS, nb_sectors,
46
+ &nb_sectors, &file);
47
if (ret < 0) {
48
return ret;
49
}
50
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num,
51
has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
52
53
*e = (MapEntry) {
54
- .start = sector_num * BDRV_SECTOR_SIZE,
55
+ .start = offset,
56
.length = nb_sectors * BDRV_SECTOR_SIZE,
57
.data = !!(ret & BDRV_BLOCK_DATA),
58
.zero = !!(ret & BDRV_BLOCK_ZERO),
59
@@ -XXX,XX +XXX,XX @@ static int img_map(int argc, char **argv)
60
61
length = blk_getlength(blk);
62
while (curr.start + curr.length < length) {
63
- int64_t nsectors_left;
64
- int64_t sector_num;
65
- int n;
62
-
66
-
63
- pci_dma_sglist_init(qsg, &n->parent_obj, num_prps);
67
- sector_num = (curr.start + curr.length) >> BDRV_SECTOR_BITS;
64
- qemu_sglist_add(qsg, prp1, trans_len);
68
+ int64_t offset = curr.start + curr.length;
65
len -= trans_len;
69
+ int64_t n;
66
if (len) {
70
67
if (!prp2) {
71
/* Probe up to 1 GiB at a time. */
68
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
72
- nsectors_left = DIV_ROUND_UP(length, BDRV_SECTOR_SIZE) - sector_num;
69
73
- n = MIN(1 << (30 - BDRV_SECTOR_BITS), nsectors_left);
70
nents = (len + n->page_size - 1) >> n->page_bits;
74
- ret = get_block_status(bs, sector_num, n, &next);
71
prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
75
+ n = QEMU_ALIGN_DOWN(MIN(1 << 30, length - offset), BDRV_SECTOR_SIZE);
72
- pci_dma_read(&n->parent_obj, prp2, (void *)prp_list, prp_trans);
76
+ ret = get_block_status(bs, offset, n, &next);
73
+ nvme_addr_read(n, prp2, (void *)prp_list, prp_trans);
77
74
while (len != 0) {
78
if (ret < 0) {
75
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
79
error_report("Could not read file metadata: %s", strerror(-ret));
76
77
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
78
i = 0;
79
nents = (len + n->page_size - 1) >> n->page_bits;
80
prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
81
- pci_dma_read(&n->parent_obj, prp_ent, (void *)prp_list,
82
+ nvme_addr_read(n, prp_ent, (void *)prp_list,
83
prp_trans);
84
prp_ent = le64_to_cpu(prp_list[i]);
85
}
86
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
87
}
88
89
trans_len = MIN(len, n->page_size);
90
- qemu_sglist_add(qsg, prp_ent, trans_len);
91
+ if (qsg->nsg){
92
+ qemu_sglist_add(qsg, prp_ent, trans_len);
93
+ } else {
94
+ qemu_iovec_add(iov, (void *)&n->cmbuf[prp_ent - n->ctrl_mem.addr], trans_len);
95
+ }
96
len -= trans_len;
97
i++;
98
}
99
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
100
if (prp2 & (n->page_size - 1)) {
101
goto unmap;
102
}
103
- qemu_sglist_add(qsg, prp2, len);
104
+ if (qsg->nsg) {
105
+ qemu_sglist_add(qsg, prp2, len);
106
+ } else {
107
+ qemu_iovec_add(iov, (void *)&n->cmbuf[prp2 - n->ctrl_mem.addr], trans_len);
108
+ }
109
}
110
}
111
return NVME_SUCCESS;
112
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
113
uint64_t prp1, uint64_t prp2)
114
{
115
QEMUSGList qsg;
116
+ QEMUIOVector iov;
117
+ uint16_t status = NVME_SUCCESS;
118
119
- if (nvme_map_prp(&qsg, prp1, prp2, len, n)) {
120
+ if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
121
return NVME_INVALID_FIELD | NVME_DNR;
122
}
123
- if (dma_buf_read(ptr, len, &qsg)) {
124
+ if (qsg.nsg > 0) {
125
+ if (dma_buf_read(ptr, len, &qsg)) {
126
+ status = NVME_INVALID_FIELD | NVME_DNR;
127
+ }
128
qemu_sglist_destroy(&qsg);
129
- return NVME_INVALID_FIELD | NVME_DNR;
130
+ } else {
131
+ if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
132
+ status = NVME_INVALID_FIELD | NVME_DNR;
133
+ }
134
+ qemu_iovec_destroy(&iov);
135
}
136
- qemu_sglist_destroy(&qsg);
137
- return NVME_SUCCESS;
138
+ return status;
139
}
140
141
static void nvme_post_cqes(void *opaque)
142
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
143
return NVME_LBA_RANGE | NVME_DNR;
144
}
145
146
- if (nvme_map_prp(&req->qsg, prp1, prp2, data_size, n)) {
147
+ if (nvme_map_prp(&req->qsg, &req->iov, prp1, prp2, data_size, n)) {
148
block_acct_invalid(blk_get_stats(n->conf.blk), acct);
149
return NVME_INVALID_FIELD | NVME_DNR;
150
}
151
152
- assert((nlb << data_shift) == req->qsg.size);
153
-
154
- req->has_sg = true;
155
dma_acct_start(n->conf.blk, &req->acct, &req->qsg, acct);
156
- req->aiocb = is_write ?
157
- dma_blk_write(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
158
- nvme_rw_cb, req) :
159
- dma_blk_read(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
160
- nvme_rw_cb, req);
161
+ if (req->qsg.nsg > 0) {
162
+ req->has_sg = true;
163
+ req->aiocb = is_write ?
164
+ dma_blk_write(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
165
+ nvme_rw_cb, req) :
166
+ dma_blk_read(n->conf.blk, &req->qsg, data_offset, BDRV_SECTOR_SIZE,
167
+ nvme_rw_cb, req);
168
+ } else {
169
+ req->has_sg = false;
170
+ req->aiocb = is_write ?
171
+ blk_aio_pwritev(n->conf.blk, data_offset, &req->iov, 0, nvme_rw_cb,
172
+ req) :
173
+ blk_aio_preadv(n->conf.blk, data_offset, &req->iov, 0, nvme_rw_cb,
174
+ req);
175
+ }
176
177
return NVME_NO_COMPLETE;
178
}
179
@@ -XXX,XX +XXX,XX @@ static int nvme_init(PCIDevice *pci_dev)
180
NVME_CMBSZ_SET_SQS(n->bar.cmbsz, 1);
181
NVME_CMBSZ_SET_CQS(n->bar.cmbsz, 0);
182
NVME_CMBSZ_SET_LISTS(n->bar.cmbsz, 0);
183
- NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 0);
184
- NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 0);
185
+ NVME_CMBSZ_SET_RDS(n->bar.cmbsz, 1);
186
+ NVME_CMBSZ_SET_WDS(n->bar.cmbsz, 1);
187
NVME_CMBSZ_SET_SZU(n->bar.cmbsz, 2); /* MBs */
188
NVME_CMBSZ_SET_SZ(n->bar.cmbsz, n->cmb_size_mb);
189
190
+ n->cmbloc = n->bar.cmbloc;
191
+ n->cmbsz = n->bar.cmbsz;
192
+
193
n->cmbuf = g_malloc0(NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
194
memory_region_init_io(&n->ctrl_mem, OBJECT(n), &nvme_cmb_ops, n,
195
"nvme-cmb", NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
196
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
197
index XXXXXXX..XXXXXXX 100644
198
--- a/hw/block/nvme.h
199
+++ b/hw/block/nvme.h
200
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeRequest {
201
NvmeCqe cqe;
202
BlockAcctCookie acct;
203
QEMUSGList qsg;
204
+ QEMUIOVector iov;
205
QTAILQ_ENTRY(NvmeRequest)entry;
206
} NvmeRequest;
207
208
--
80
--
209
1.8.3.1
81
2.13.6
210
82
211
83
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Qcow2COWRegion has two attributes:
3
We are gradually moving away from sector-based interfaces, towards
4
4
byte-based. In the common case, allocation is unlikely to ever use
5
- The offset of the COW region from the start of the first cluster
5
values that are not naturally sector-aligned, but it is possible
6
touched by the I/O request. Since it's always going to be positive
6
that byte-based values will let us be more precise about allocation
7
and the maximum request size is at most INT_MAX, we can use a
7
at the end of an unaligned file that can do byte-based access.
8
regular unsigned int to store this offset.
8
9
9
Changing the name of the function from bdrv_get_block_status() to
10
- The size of the COW region in bytes. This is guaranteed to be >= 0,
10
bdrv_block_status() ensures that the compiler enforces that all
11
so we should use an unsigned type instead.
11
callers are updated. For now, the io.c layer still assert()s that
12
12
all callers are sector-aligned, but that can be relaxed when a later
13
In x86_64 this reduces the size of Qcow2COWRegion from 16 to 8 bytes.
13
patch implements byte-based block status in the drivers.
14
It will also help keep some assertions simpler now that we know that
14
15
there are no negative numbers.
15
There was an inherent limitation in returning the offset via the
16
16
return value: we only have room for BDRV_BLOCK_OFFSET_MASK bits, which
17
The prototype of do_perform_cow() is also updated to reflect these
17
means an offset can only be mapped for sector-aligned queries (or,
18
changes.
18
if we declare that non-aligned input is at the same relative position
19
19
modulo 512 of the answer), so the new interface also changes things to
20
Signed-off-by: Alberto Garcia <berto@igalia.com>
20
return the offset via output through a parameter by reference rather
21
Reviewed-by: Eric Blake <eblake@redhat.com>
21
than mashed into the return value. We'll have some glue code that
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
22
munges between the two styles until we finish converting all uses.
23
24
For the most part this patch is just the addition of scaling at the
25
callers followed by inverse scaling at bdrv_block_status(), coupled
26
with the tweak in calling convention. But some code, particularly
27
bdrv_is_allocated(), gets a lot simpler because it no longer has to
28
mess with sectors.
29
30
For ease of review, bdrv_get_block_status_above() will be tackled
31
separately.
32
33
Signed-off-by: Eric Blake <eblake@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
35
---
25
block/qcow2-cluster.c | 4 ++--
36
include/block/block.h | 17 +++++++++--------
26
block/qcow2.h | 4 ++--
37
block/io.c | 47 ++++++++++++++++++++++++++++++++++-------------
27
2 files changed, 4 insertions(+), 4 deletions(-)
38
block/qcow2-cluster.c | 2 +-
28
39
qemu-img.c | 25 ++++++++++++++-----------
40
4 files changed, 58 insertions(+), 33 deletions(-)
41
42
diff --git a/include/block/block.h b/include/block/block.h
43
index XXXXXXX..XXXXXXX 100644
44
--- a/include/block/block.h
45
+++ b/include/block/block.h
46
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
47
#define BDRV_REQUEST_MAX_BYTES (BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS)
48
49
/*
50
- * Allocation status flags for bdrv_get_block_status() and friends.
51
+ * Allocation status flags for bdrv_block_status() and friends.
52
*
53
* Public flags:
54
* BDRV_BLOCK_DATA: allocation for data at offset is tied to this layer
55
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
56
* that the block layer recompute the answer from the returned
57
* BDS; must be accompanied by just BDRV_BLOCK_OFFSET_VALID.
58
*
59
- * If BDRV_BLOCK_OFFSET_VALID is set, bits 9-62 (BDRV_BLOCK_OFFSET_MASK)
60
- * represent the offset in the returned BDS that is allocated for the
61
- * corresponding raw data; however, whether that offset actually contains
62
- * data also depends on BDRV_BLOCK_DATA and BDRV_BLOCK_ZERO, as follows:
63
+ * If BDRV_BLOCK_OFFSET_VALID is set, bits 9-62 (BDRV_BLOCK_OFFSET_MASK) of
64
+ * the return value (old interface) or the entire map parameter (new
65
+ * interface) represent the offset in the returned BDS that is allocated for
66
+ * the corresponding raw data. However, whether that offset actually
67
+ * contains data also depends on BDRV_BLOCK_DATA, as follows:
68
*
69
* DATA ZERO OFFSET_VALID
70
* t t t sectors read as zero, returned file is zero at offset
71
@@ -XXX,XX +XXX,XX @@ int bdrv_has_zero_init_1(BlockDriverState *bs);
72
int bdrv_has_zero_init(BlockDriverState *bs);
73
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
74
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
75
-int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
76
- int nb_sectors, int *pnum,
77
- BlockDriverState **file);
78
+int bdrv_block_status(BlockDriverState *bs, int64_t offset,
79
+ int64_t bytes, int64_t *pnum, int64_t *map,
80
+ BlockDriverState **file);
81
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
82
BlockDriverState *base,
83
int64_t sector_num,
84
diff --git a/block/io.c b/block/io.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/block/io.c
87
+++ b/block/io.c
88
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
89
*/
90
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
91
{
92
- int64_t target_size, ret, bytes, offset = 0;
93
+ int ret;
94
+ int64_t target_size, bytes, offset = 0;
95
BlockDriverState *bs = child->bs;
96
- int n; /* sectors */
97
98
target_size = bdrv_getlength(bs);
99
if (target_size < 0) {
100
@@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
101
if (bytes <= 0) {
102
return 0;
103
}
104
- ret = bdrv_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
105
- bytes >> BDRV_SECTOR_BITS, &n, NULL);
106
+ ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL);
107
if (ret < 0) {
108
error_report("error getting block status at offset %" PRId64 ": %s",
109
offset, strerror(-ret));
110
return ret;
111
}
112
if (ret & BDRV_BLOCK_ZERO) {
113
- offset += n * BDRV_SECTOR_BITS;
114
+ offset += bytes;
115
continue;
116
}
117
- ret = bdrv_pwrite_zeroes(child, offset, n * BDRV_SECTOR_SIZE, flags);
118
+ ret = bdrv_pwrite_zeroes(child, offset, bytes, flags);
119
if (ret < 0) {
120
error_report("error writing zeroes at offset %" PRId64 ": %s",
121
offset, strerror(-ret));
122
return ret;
123
}
124
- offset += n * BDRV_SECTOR_SIZE;
125
+ offset += bytes;
126
}
127
}
128
129
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs,
130
nb_sectors, pnum, file);
131
}
132
133
-int64_t bdrv_get_block_status(BlockDriverState *bs,
134
- int64_t sector_num,
135
- int nb_sectors, int *pnum,
136
- BlockDriverState **file)
137
+int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
138
+ int64_t *pnum, int64_t *map, BlockDriverState **file)
139
{
140
- return bdrv_get_block_status_above(bs, backing_bs(bs),
141
- sector_num, nb_sectors, pnum, file);
142
+ int64_t ret;
143
+ int n;
144
+
145
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
146
+ assert(pnum);
147
+ /*
148
+ * The contract allows us to return pnum smaller than bytes, even
149
+ * if the next query would see the same status; we truncate the
150
+ * request to avoid overflowing the driver's 32-bit interface.
151
+ */
152
+ bytes = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
153
+ ret = bdrv_get_block_status_above(bs, backing_bs(bs),
154
+ offset >> BDRV_SECTOR_BITS,
155
+ bytes >> BDRV_SECTOR_BITS, &n, file);
156
+ if (ret < 0) {
157
+ assert(INT_MIN <= ret);
158
+ *pnum = 0;
159
+ return ret;
160
+ }
161
+ *pnum = n * BDRV_SECTOR_SIZE;
162
+ if (map) {
163
+ *map = ret & BDRV_BLOCK_OFFSET_MASK;
164
+ } else {
165
+ ret &= ~BDRV_BLOCK_OFFSET_VALID;
166
+ }
167
+ return ret & ~BDRV_BLOCK_OFFSET_MASK;
168
}
169
170
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
29
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
171
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
30
index XXXXXXX..XXXXXXX 100644
172
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2-cluster.c
173
--- a/block/qcow2-cluster.c
32
+++ b/block/qcow2-cluster.c
174
+++ b/block/qcow2-cluster.c
33
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
175
@@ -XXX,XX +XXX,XX @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
34
static int coroutine_fn do_perform_cow(BlockDriverState *bs,
176
* cluster is already marked as zero, or if it's unallocated and we
35
uint64_t src_cluster_offset,
177
* don't have a backing file.
36
uint64_t cluster_offset,
178
*
37
- int offset_in_cluster,
179
- * TODO We might want to use bdrv_get_block_status(bs) here, but we're
38
- int bytes)
180
+ * TODO We might want to use bdrv_block_status(bs) here, but we're
39
+ unsigned offset_in_cluster,
181
* holding s->lock, so that doesn't work today.
40
+ unsigned bytes)
182
*
183
* If full_discard is true, the sector should not read back as zeroes,
184
diff --git a/qemu-img.c b/qemu-img.c
185
index XXXXXXX..XXXXXXX 100644
186
--- a/qemu-img.c
187
+++ b/qemu-img.c
188
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
189
190
if (s->sector_next_status <= sector_num) {
191
if (s->target_has_backing) {
192
- ret = bdrv_get_block_status(blk_bs(s->src[src_cur]),
193
- sector_num - src_cur_offset,
194
- n, &n, NULL);
195
+ int64_t count = n * BDRV_SECTOR_SIZE;
196
+
197
+ ret = bdrv_block_status(blk_bs(s->src[src_cur]),
198
+ (sector_num - src_cur_offset) *
199
+ BDRV_SECTOR_SIZE,
200
+ count, &count, NULL, NULL);
201
+ assert(ret < 0 || QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
202
+ n = count >> BDRV_SECTOR_BITS;
203
} else {
204
ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL,
205
sector_num - src_cur_offset,
206
@@ -XXX,XX +XXX,XX @@ static void dump_map_entry(OutputFormat output_format, MapEntry *e,
207
static int get_block_status(BlockDriverState *bs, int64_t offset,
208
int64_t bytes, MapEntry *e)
41
{
209
{
42
BDRVQcow2State *s = bs->opaque;
210
- int64_t ret;
43
QEMUIOVector qiov;
211
+ int ret;
44
diff --git a/block/qcow2.h b/block/qcow2.h
212
int depth;
45
index XXXXXXX..XXXXXXX 100644
213
BlockDriverState *file;
46
--- a/block/qcow2.h
214
bool has_offset;
47
+++ b/block/qcow2.h
215
- int nb_sectors = bytes >> BDRV_SECTOR_BITS;
48
@@ -XXX,XX +XXX,XX @@ typedef struct Qcow2COWRegion {
216
+ int64_t map;
49
* Offset of the COW region in bytes from the start of the first cluster
217
50
* touched by the request.
218
- assert(bytes < INT_MAX);
51
*/
219
/* As an optimization, we could cache the current range of unallocated
52
- uint64_t offset;
220
* clusters in each file of the chain, and avoid querying the same
53
+ unsigned offset;
221
* range repeatedly.
54
222
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
55
/** Number of bytes to copy */
223
56
- int nb_bytes;
224
depth = 0;
57
+ unsigned nb_bytes;
225
for (;;) {
58
} Qcow2COWRegion;
226
- ret = bdrv_get_block_status(bs, offset >> BDRV_SECTOR_BITS, nb_sectors,
59
227
- &nb_sectors, &file);
60
/**
228
+ ret = bdrv_block_status(bs, offset, bytes, &bytes, &map, &file);
229
if (ret < 0) {
230
return ret;
231
}
232
- assert(nb_sectors);
233
+ assert(bytes);
234
if (ret & (BDRV_BLOCK_ZERO|BDRV_BLOCK_DATA)) {
235
break;
236
}
237
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
238
239
*e = (MapEntry) {
240
.start = offset,
241
- .length = nb_sectors * BDRV_SECTOR_SIZE,
242
+ .length = bytes,
243
.data = !!(ret & BDRV_BLOCK_DATA),
244
.zero = !!(ret & BDRV_BLOCK_ZERO),
245
- .offset = ret & BDRV_BLOCK_OFFSET_MASK,
246
+ .offset = map,
247
.has_offset = has_offset,
248
.depth = depth,
249
.has_filename = file && has_offset,
61
--
250
--
62
1.8.3.1
251
2.13.6
63
252
64
253
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
2
3
We are gradually converting to byte-based interfaces, as they are
4
easier to reason about than sector-based. Convert another internal
5
function (no semantic change); and as with its public counterpart,
6
rename to bdrv_co_block_status() and split the offset return, to
7
make the compiler enforce that we catch all uses. For now, we
8
assert that callers and the return value still use aligned data,
9
but ultimately, this will be the function where we hand off to a
10
byte-based driver callback, and will eventually need to add logic
11
to ensure we round calls according to the driver's
12
request_alignment then touch up the result handed back to the
13
caller, to start permitting a caller to pass unaligned offsets.
14
15
Note that we are now prepared to accepts 'bytes' larger than INT_MAX;
16
this is okay as long as we clamp things internally before violating
17
any 32-bit limits, and makes no difference to how a client will
18
use the information (clients looping over the entire file must
19
already be prepared for consecutive calls to return the same status,
20
as drivers are already free to return shorter-than-maximal status
21
due to any other convenient split points, such as when the L2 table
22
crosses cluster boundaries in qcow2).
23
24
Signed-off-by: Eric Blake <eblake@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
---
26
---
5
block/qed-cluster.c | 94 ++++++++++++++++++-----------------------------------
27
block/io.c | 124 ++++++++++++++++++++++++++++++++++++++++---------------------
6
block/qed-table.c | 15 +++------
28
1 file changed, 81 insertions(+), 43 deletions(-)
7
block/qed.h | 3 +-
29
8
3 files changed, 36 insertions(+), 76 deletions(-)
30
diff --git a/block/io.c b/block/io.c
9
10
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
11
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed-cluster.c
32
--- a/block/io.c
13
+++ b/block/qed-cluster.c
33
+++ b/block/io.c
14
@@ -XXX,XX +XXX,XX @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
34
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
15
return i - index;
35
* BDRV_BLOCK_ZERO where possible; otherwise, the result may omit those
16
}
36
* bits particularly if it allows for a larger value in 'pnum'.
17
37
*
18
-typedef struct {
38
- * If 'sector_num' is beyond the end of the disk image the return value is
19
- BDRVQEDState *s;
39
+ * If 'offset' is beyond the end of the disk image the return value is
20
- uint64_t pos;
40
* BDRV_BLOCK_EOF and 'pnum' is set to 0.
21
- size_t len;
41
*
22
-
42
- * 'pnum' is set to the number of sectors (including and immediately following
23
- QEDRequest *request;
43
- * the specified sector) that are known to be in the same
24
-
44
- * allocated/unallocated state.
25
- /* User callback */
45
- *
26
- QEDFindClusterFunc *cb;
46
- * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
27
- void *opaque;
47
+ * 'bytes' is the max value 'pnum' should be set to. If bytes goes
28
-} QEDFindClusterCB;
48
* beyond the end of the disk image it will be clamped; if 'pnum' is set to
29
-
49
* the end of the image, then the returned value will include BDRV_BLOCK_EOF.
30
-static void qed_find_cluster_cb(void *opaque, int ret)
50
*
51
- * If returned value is positive, BDRV_BLOCK_OFFSET_VALID bit is set, and
52
- * 'file' is non-NULL, then '*file' points to the BDS which the sector range
53
- * is allocated in.
54
+ * 'pnum' is set to the number of bytes (including and immediately
55
+ * following the specified offset) that are easily known to be in the
56
+ * same allocated/unallocated state. Note that a second call starting
57
+ * at the original offset plus returned pnum may have the same status.
58
+ * The returned value is non-zero on success except at end-of-file.
59
+ *
60
+ * Returns negative errno on failure. Otherwise, if the
61
+ * BDRV_BLOCK_OFFSET_VALID bit is set, 'map' and 'file' (if non-NULL) are
62
+ * set to the host mapping and BDS corresponding to the guest offset.
63
*/
64
-static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
65
- bool want_zero,
66
- int64_t sector_num,
67
- int nb_sectors, int *pnum,
68
- BlockDriverState **file)
31
-{
69
-{
32
- QEDFindClusterCB *find_cluster_cb = opaque;
70
- int64_t total_sectors;
33
- BDRVQEDState *s = find_cluster_cb->s;
71
- int64_t n;
34
- QEDRequest *request = find_cluster_cb->request;
72
- int64_t ret, ret2;
35
- uint64_t offset = 0;
73
+static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
36
- size_t len = 0;
74
+ bool want_zero,
37
- unsigned int index;
75
+ int64_t offset, int64_t bytes,
38
- unsigned int n;
76
+ int64_t *pnum, int64_t *map,
39
-
77
+ BlockDriverState **file)
40
- qed_acquire(s);
78
+{
41
- if (ret) {
79
+ int64_t total_size;
42
- goto out;
80
+ int64_t n; /* bytes */
43
- }
81
+ int64_t ret;
44
-
82
+ int64_t local_map = 0;
45
- index = qed_l2_index(s, find_cluster_cb->pos);
83
BlockDriverState *local_file = NULL;
46
- n = qed_bytes_to_clusters(s,
84
+ int count; /* sectors */
47
- qed_offset_into_cluster(s, find_cluster_cb->pos) +
85
48
- find_cluster_cb->len);
86
assert(pnum);
49
- n = qed_count_contiguous_clusters(s, request->l2_table->table,
87
*pnum = 0;
50
- index, n, &offset);
88
- total_sectors = bdrv_nb_sectors(bs);
51
-
89
- if (total_sectors < 0) {
52
- if (qed_offset_is_unalloc_cluster(offset)) {
90
- ret = total_sectors;
53
- ret = QED_CLUSTER_L2;
91
+ total_size = bdrv_getlength(bs);
54
- } else if (qed_offset_is_zero_cluster(offset)) {
92
+ if (total_size < 0) {
55
- ret = QED_CLUSTER_ZERO;
93
+ ret = total_size;
56
- } else if (qed_check_cluster_offset(s, offset)) {
94
goto early_out;
57
- ret = QED_CLUSTER_FOUND;
95
}
58
- } else {
96
59
- ret = -EINVAL;
97
- if (sector_num >= total_sectors) {
60
- }
98
+ if (offset >= total_size) {
61
-
99
ret = BDRV_BLOCK_EOF;
62
- len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
100
goto early_out;
63
- qed_offset_into_cluster(s, find_cluster_cb->pos));
101
}
64
-
102
- if (!nb_sectors) {
65
-out:
103
+ if (!bytes) {
66
- find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
104
ret = 0;
67
- qed_release(s);
105
goto early_out;
68
- g_free(find_cluster_cb);
106
}
69
-}
107
70
-
108
- n = total_sectors - sector_num;
71
/**
109
- if (n < nb_sectors) {
72
* Find the offset of a data cluster
110
- nb_sectors = n;
73
*
111
+ n = total_size - offset;
74
@@ -XXX,XX +XXX,XX @@ out:
112
+ if (n < bytes) {
75
void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
113
+ bytes = n;
76
size_t len, QEDFindClusterFunc *cb, void *opaque)
114
}
77
{
115
78
- QEDFindClusterCB *find_cluster_cb;
116
if (!bs->drv->bdrv_co_get_block_status) {
79
uint64_t l2_offset;
117
- *pnum = nb_sectors;
80
+ uint64_t offset = 0;
118
+ *pnum = bytes;
81
+ unsigned int index;
119
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
82
+ unsigned int n;
120
- if (sector_num + nb_sectors == total_sectors) {
83
+ int ret;
121
+ if (offset + bytes == total_size) {
84
122
ret |= BDRV_BLOCK_EOF;
85
/* Limit length to L2 boundary. Requests are broken up at the L2 boundary
123
}
86
* so that a request acts on one L2 table at a time.
124
if (bs->drv->protocol_name) {
87
@@ -XXX,XX +XXX,XX @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
125
- ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
88
return;
126
+ ret |= BDRV_BLOCK_OFFSET_VALID;
89
}
127
+ local_map = offset;
90
128
local_file = bs;
91
- find_cluster_cb = g_malloc(sizeof(*find_cluster_cb));
129
}
92
- find_cluster_cb->s = s;
130
goto early_out;
93
- find_cluster_cb->pos = pos;
131
}
94
- find_cluster_cb->len = len;
132
95
- find_cluster_cb->cb = cb;
133
bdrv_inc_in_flight(bs);
96
- find_cluster_cb->opaque = opaque;
134
- ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
97
- find_cluster_cb->request = request;
135
+ /*
98
+ ret = qed_read_l2_table(s, request, l2_offset);
136
+ * TODO: Rather than require aligned offsets, we could instead
99
+ qed_acquire(s);
137
+ * round to the driver's request_alignment here, then touch up
100
+ if (ret) {
138
+ * count afterwards back to the caller's expectations.
101
+ goto out;
139
+ */
140
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
141
+ /*
142
+ * The contract allows us to return pnum smaller than bytes, even
143
+ * if the next query would see the same status; we truncate the
144
+ * request to avoid overflowing the driver's 32-bit interface.
145
+ */
146
+ bytes = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
147
+ ret = bs->drv->bdrv_co_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
148
+ bytes >> BDRV_SECTOR_BITS, &count,
149
&local_file);
150
if (ret < 0) {
151
- *pnum = 0;
152
goto out;
153
}
154
+ if (ret & BDRV_BLOCK_OFFSET_VALID) {
155
+ local_map = ret & BDRV_BLOCK_OFFSET_MASK;
102
+ }
156
+ }
103
+
157
+ *pnum = count * BDRV_SECTOR_SIZE;
104
+ index = qed_l2_index(s, pos);
158
105
+ n = qed_bytes_to_clusters(s,
159
if (ret & BDRV_BLOCK_RAW) {
106
+ qed_offset_into_cluster(s, pos) + len);
160
assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
107
+ n = qed_count_contiguous_clusters(s, request->l2_table->table,
161
- ret = bdrv_co_get_block_status(local_file, want_zero,
108
+ index, n, &offset);
162
- ret >> BDRV_SECTOR_BITS,
109
+
163
- *pnum, pnum, &local_file);
110
+ if (qed_offset_is_unalloc_cluster(offset)) {
164
+ ret = bdrv_co_block_status(local_file, want_zero, local_map,
111
+ ret = QED_CLUSTER_L2;
165
+ *pnum, pnum, &local_map, &local_file);
112
+ } else if (qed_offset_is_zero_cluster(offset)) {
166
+ assert(ret < 0 ||
113
+ ret = QED_CLUSTER_ZERO;
167
+ QEMU_IS_ALIGNED(*pnum | local_map, BDRV_SECTOR_SIZE));
114
+ } else if (qed_check_cluster_offset(s, offset)) {
168
goto out;
115
+ ret = QED_CLUSTER_FOUND;
169
}
170
171
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
172
ret |= BDRV_BLOCK_ZERO;
173
} else if (bs->backing) {
174
BlockDriverState *bs2 = bs->backing->bs;
175
- int64_t nb_sectors2 = bdrv_nb_sectors(bs2);
176
+ int64_t size2 = bdrv_getlength(bs2);
177
178
- if (nb_sectors2 >= 0 && sector_num >= nb_sectors2) {
179
+ if (size2 >= 0 && offset >= size2) {
180
ret |= BDRV_BLOCK_ZERO;
181
}
182
}
183
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
184
if (want_zero && local_file && local_file != bs &&
185
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
186
(ret & BDRV_BLOCK_OFFSET_VALID)) {
187
- int file_pnum;
188
+ int64_t file_pnum;
189
+ int ret2;
190
191
- ret2 = bdrv_co_get_block_status(local_file, want_zero,
192
- ret >> BDRV_SECTOR_BITS,
193
- *pnum, &file_pnum, NULL);
194
+ ret2 = bdrv_co_block_status(local_file, want_zero, local_map,
195
+ *pnum, &file_pnum, NULL, NULL);
196
if (ret2 >= 0) {
197
/* Ignore errors. This is just providing extra information, it
198
* is useful but not necessary.
199
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
200
201
out:
202
bdrv_dec_in_flight(bs);
203
- if (ret >= 0 && sector_num + *pnum == total_sectors) {
204
+ if (ret >= 0 && offset + *pnum == total_size) {
205
ret |= BDRV_BLOCK_EOF;
206
}
207
early_out:
208
if (file) {
209
*file = local_file;
210
}
211
+ if (map) {
212
+ *map = local_map;
213
+ }
214
+ if (ret >= 0) {
215
+ ret &= ~BDRV_BLOCK_OFFSET_MASK;
116
+ } else {
216
+ } else {
117
+ ret = -EINVAL;
217
+ assert(INT_MIN <= ret);
118
+ }
218
+ }
119
+
120
+ len = MIN(len,
121
+ n * s->header.cluster_size - qed_offset_into_cluster(s, pos));
122
123
- qed_read_l2_table(s, request, l2_offset,
124
- qed_find_cluster_cb, find_cluster_cb);
125
+out:
126
+ cb(opaque, ret, offset, len);
127
+ qed_release(s);
128
}
129
diff --git a/block/qed-table.c b/block/qed-table.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/qed-table.c
132
+++ b/block/qed-table.c
133
@@ -XXX,XX +XXX,XX @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
134
return ret;
219
return ret;
135
}
220
}
136
221
137
-void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
222
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
138
- BlockCompletionFunc *cb, void *opaque)
223
BlockDriverState *p;
139
+int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
224
int64_t ret = 0;
140
{
225
bool first = true;
141
int ret;
226
+ int64_t map = 0;
142
227
143
@@ -XXX,XX +XXX,XX @@ void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
228
assert(bs != base);
144
/* Check for cached L2 entry */
229
for (p = bs; p != base; p = backing_bs(p)) {
145
request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
230
- ret = bdrv_co_get_block_status(p, want_zero, sector_num, nb_sectors,
146
if (request->l2_table) {
231
- pnum, file);
147
- cb(opaque, 0);
232
+ int64_t count;
148
- return;
233
+
149
+ return 0;
234
+ ret = bdrv_co_block_status(p, want_zero,
150
}
235
+ sector_num * BDRV_SECTOR_SIZE,
151
236
+ nb_sectors * BDRV_SECTOR_SIZE, &count,
152
request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
237
+ &map, file);
153
@@ -XXX,XX +XXX,XX @@ void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
238
if (ret < 0) {
154
}
239
break;
155
qed_release(s);
240
}
156
241
+ assert(QEMU_IS_ALIGNED(count | map, BDRV_SECTOR_SIZE));
157
- cb(opaque, ret);
242
+ ret |= map;
158
+ return ret;
243
+ *pnum = count >> BDRV_SECTOR_BITS;
159
}
244
if (ret & BDRV_BLOCK_ZERO && ret & BDRV_BLOCK_EOF && !first) {
160
245
/*
161
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
246
* Reading beyond the end of the file continues to read
162
{
163
- int ret = -EINPROGRESS;
164
-
165
- qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
166
- BDRV_POLL_WHILE(s->bs, ret == -EINPROGRESS);
167
-
168
- return ret;
169
+ return qed_read_l2_table(s, request, offset);
170
}
171
172
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
173
diff --git a/block/qed.h b/block/qed.h
174
index XXXXXXX..XXXXXXX 100644
175
--- a/block/qed.h
176
+++ b/block/qed.h
177
@@ -XXX,XX +XXX,XX @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
178
unsigned int n);
179
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
180
uint64_t offset);
181
-void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
182
- BlockCompletionFunc *cb, void *opaque);
183
+int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset);
184
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
185
unsigned int index, unsigned int n, bool flush,
186
BlockCompletionFunc *cb, void *opaque);
187
--
247
--
188
1.8.3.1
248
2.13.6
189
249
190
250
diff view generated by jsdifflib
1
All callers pass ret = 0, so we can just remove it.
1
From: Eric Blake <eblake@redhat.com>
2
2
3
We are gradually converting to byte-based interfaces, as they are
4
easier to reason about than sector-based. Convert another internal
5
type (no semantic change), and rename it to match the corresponding
6
public function rename.
7
8
Signed-off-by: Eric Blake <eblake@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
---
10
---
6
block/qed.c | 17 ++++++-----------
11
block/io.c | 56 ++++++++++++++++++++++++++++++++++++++------------------
7
1 file changed, 6 insertions(+), 11 deletions(-)
12
1 file changed, 38 insertions(+), 18 deletions(-)
8
13
9
diff --git a/block/qed.c b/block/qed.c
14
diff --git a/block/io.c b/block/io.c
10
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
11
--- a/block/qed.c
16
--- a/block/io.c
12
+++ b/block/qed.c
17
+++ b/block/io.c
13
@@ -XXX,XX +XXX,XX @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
18
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
14
return l2_table;
15
}
19
}
16
20
17
-static void qed_aio_next_io(QEDAIOCB *acb, int ret);
21
18
+static void qed_aio_next_io(QEDAIOCB *acb);
22
-typedef struct BdrvCoGetBlockStatusData {
19
23
+typedef struct BdrvCoBlockStatusData {
20
static void qed_aio_start_io(QEDAIOCB *acb)
24
BlockDriverState *bs;
25
BlockDriverState *base;
26
bool want_zero;
27
- int64_t sector_num;
28
- int nb_sectors;
29
- int *pnum;
30
+ int64_t offset;
31
+ int64_t bytes;
32
+ int64_t *pnum;
33
+ int64_t *map;
34
BlockDriverState **file;
35
- int64_t ret;
36
+ int ret;
37
bool done;
38
-} BdrvCoGetBlockStatusData;
39
+} BdrvCoBlockStatusData;
40
41
int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *bs,
42
int64_t sector_num,
43
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
44
/* Coroutine wrapper for bdrv_get_block_status_above() */
45
static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
21
{
46
{
22
- qed_aio_next_io(acb, 0);
47
- BdrvCoGetBlockStatusData *data = opaque;
23
+ qed_aio_next_io(acb);
48
+ BdrvCoBlockStatusData *data = opaque;
49
+ int n = 0;
50
+ int64_t ret;
51
52
- data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
53
- data->want_zero,
54
- data->sector_num,
55
- data->nb_sectors,
56
- data->pnum,
57
- data->file);
58
+ ret = bdrv_co_get_block_status_above(data->bs, data->base,
59
+ data->want_zero,
60
+ data->offset >> BDRV_SECTOR_BITS,
61
+ data->bytes >> BDRV_SECTOR_BITS,
62
+ &n,
63
+ data->file);
64
+ if (ret < 0) {
65
+ assert(INT_MIN <= ret);
66
+ data->ret = ret;
67
+ } else {
68
+ *data->pnum = n * BDRV_SECTOR_SIZE;
69
+ *data->map = ret & BDRV_BLOCK_OFFSET_MASK;
70
+ data->ret = ret & ~BDRV_BLOCK_OFFSET_MASK;
71
+ }
72
data->done = true;
24
}
73
}
25
74
26
static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
75
@@ -XXX,XX +XXX,XX @@ static int64_t bdrv_common_block_status_above(BlockDriverState *bs,
27
@@ -XXX,XX +XXX,XX @@ static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
76
BlockDriverState **file)
28
/**
29
* Begin next I/O or complete the request
30
*/
31
-static void qed_aio_next_io(QEDAIOCB *acb, int ret)
32
+static void qed_aio_next_io(QEDAIOCB *acb)
33
{
77
{
34
BDRVQEDState *s = acb_to_s(acb);
78
Coroutine *co;
35
uint64_t offset;
79
- BdrvCoGetBlockStatusData data = {
36
size_t len;
80
+ int64_t n;
37
+ int ret;
81
+ int64_t map;
38
82
+ BdrvCoBlockStatusData data = {
39
- trace_qed_aio_next_io(s, acb, ret, acb->cur_pos + acb->cur_qiov.size);
83
.bs = bs,
40
+ trace_qed_aio_next_io(s, acb, 0, acb->cur_pos + acb->cur_qiov.size);
84
.base = base,
41
85
.want_zero = want_zero,
42
if (acb->backing_qiov) {
86
- .sector_num = sector_num,
43
qemu_iovec_destroy(acb->backing_qiov);
87
- .nb_sectors = nb_sectors,
44
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb, int ret)
88
- .pnum = pnum,
45
acb->backing_qiov = NULL;
89
+ .offset = sector_num * BDRV_SECTOR_SIZE,
90
+ .bytes = nb_sectors * BDRV_SECTOR_SIZE,
91
+ .pnum = &n,
92
+ .map = &map,
93
.file = file,
94
.done = false,
95
};
96
@@ -XXX,XX +XXX,XX @@ static int64_t bdrv_common_block_status_above(BlockDriverState *bs,
97
bdrv_coroutine_enter(bs, co);
98
BDRV_POLL_WHILE(bs, !data.done);
46
}
99
}
47
100
- return data.ret;
48
- /* Handle I/O error */
101
+ if (data.ret < 0) {
49
- if (ret) {
102
+ *pnum = 0;
50
- qed_aio_complete(acb, ret);
103
+ return data.ret;
51
- return;
104
+ }
52
- }
105
+ assert(QEMU_IS_ALIGNED(n | map, BDRV_SECTOR_SIZE));
53
-
106
+ *pnum = n >> BDRV_SECTOR_BITS;
54
acb->qiov_offset += acb->cur_qiov.size;
107
+ return data.ret | map;
55
acb->cur_pos += acb->cur_qiov.size;
56
qemu_iovec_reset(&acb->cur_qiov);
57
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb, int ret)
58
}
59
return;
60
}
61
- qed_aio_next_io(acb, 0);
62
+ qed_aio_next_io(acb);
63
}
108
}
64
109
65
static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
110
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
66
--
111
--
67
1.8.3.1
112
2.13.6
68
113
69
114
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Instead of passing a single buffer pointer to do_perform_cow_write(),
3
We are gradually converting to byte-based interfaces, as they are
4
pass a QEMUIOVector. This will allow us to merge the write requests
4
easier to reason about than sector-based. Convert another internal
5
for the COW regions and the actual data into a single one.
5
function (no semantic change).
6
6
7
Although do_perform_cow_read() does not strictly need to change its
7
Signed-off-by: Eric Blake <eblake@redhat.com>
8
API, we're doing it here as well for consistency.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
9
---
14
block/qcow2-cluster.c | 51 ++++++++++++++++++++++++---------------------------
10
block/io.c | 61 ++++++++++++++++++++++++++++++-------------------------------
15
1 file changed, 24 insertions(+), 27 deletions(-)
11
1 file changed, 30 insertions(+), 31 deletions(-)
16
12
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
13
diff --git a/block/io.c b/block/io.c
18
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-cluster.c
15
--- a/block/io.c
20
+++ b/block/qcow2-cluster.c
16
+++ b/block/io.c
21
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
17
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
22
static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
18
*
23
uint64_t src_cluster_offset,
19
* See bdrv_co_get_block_status_above() for details.
24
unsigned offset_in_cluster,
20
*/
25
- uint8_t *buffer,
21
-static int64_t bdrv_common_block_status_above(BlockDriverState *bs,
26
- unsigned bytes)
22
- BlockDriverState *base,
27
+ QEMUIOVector *qiov)
23
- bool want_zero,
24
- int64_t sector_num,
25
- int nb_sectors, int *pnum,
26
- BlockDriverState **file)
27
+static int bdrv_common_block_status_above(BlockDriverState *bs,
28
+ BlockDriverState *base,
29
+ bool want_zero, int64_t offset,
30
+ int64_t bytes, int64_t *pnum,
31
+ int64_t *map,
32
+ BlockDriverState **file)
28
{
33
{
29
- QEMUIOVector qiov;
34
Coroutine *co;
30
- struct iovec iov = { .iov_base = buffer, .iov_len = bytes };
35
- int64_t n;
31
int ret;
36
- int64_t map;
32
37
BdrvCoBlockStatusData data = {
33
- if (bytes == 0) {
38
.bs = bs,
34
+ if (qiov->size == 0) {
39
.base = base,
35
return 0;
40
.want_zero = want_zero,
41
- .offset = sector_num * BDRV_SECTOR_SIZE,
42
- .bytes = nb_sectors * BDRV_SECTOR_SIZE,
43
- .pnum = &n,
44
- .map = &map,
45
+ .offset = offset,
46
+ .bytes = bytes,
47
+ .pnum = pnum,
48
+ .map = map,
49
.file = file,
50
.done = false,
51
};
52
@@ -XXX,XX +XXX,XX @@ static int64_t bdrv_common_block_status_above(BlockDriverState *bs,
53
bdrv_coroutine_enter(bs, co);
54
BDRV_POLL_WHILE(bs, !data.done);
36
}
55
}
37
56
- if (data.ret < 0) {
38
- qemu_iovec_init_external(&qiov, &iov, 1);
57
- *pnum = 0;
39
-
58
- return data.ret;
40
BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
59
- }
41
60
- assert(QEMU_IS_ALIGNED(n | map, BDRV_SECTOR_SIZE));
42
if (!bs->drv) {
61
- *pnum = n >> BDRV_SECTOR_BITS;
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
62
- return data.ret | map;
44
* which can lead to deadlock when block layer copy-on-read is enabled.
63
+ return data.ret;
45
*/
64
}
46
ret = bs->drv->bdrv_co_preadv(bs, src_cluster_offset + offset_in_cluster,
65
47
- bytes, &qiov, 0);
66
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
48
+ qiov->size, qiov, 0);
67
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs,
68
int nb_sectors, int *pnum,
69
BlockDriverState **file)
70
{
71
- return bdrv_common_block_status_above(bs, base, true, sector_num,
72
- nb_sectors, pnum, file);
73
+ int64_t ret;
74
+ int64_t n;
75
+ int64_t map;
76
+
77
+ ret = bdrv_common_block_status_above(bs, base, true,
78
+ sector_num * BDRV_SECTOR_SIZE,
79
+ nb_sectors * BDRV_SECTOR_SIZE,
80
+ &n, &map, file);
81
+ if (ret < 0) {
82
+ *pnum = 0;
83
+ return ret;
84
+ }
85
+ assert(QEMU_IS_ALIGNED(n | map, BDRV_SECTOR_SIZE));
86
+ *pnum = n >> BDRV_SECTOR_BITS;
87
+ return ret | map;
88
}
89
90
int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
91
@@ -XXX,XX +XXX,XX @@ int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
92
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
93
int64_t bytes, int64_t *pnum)
94
{
95
- int64_t ret;
96
- int psectors;
97
+ int ret;
98
+ int64_t dummy;
99
100
- assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
101
- assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE) && bytes < INT_MAX);
102
- ret = bdrv_common_block_status_above(bs, backing_bs(bs), false,
103
- offset >> BDRV_SECTOR_BITS,
104
- bytes >> BDRV_SECTOR_BITS, &psectors,
105
+ ret = bdrv_common_block_status_above(bs, backing_bs(bs), false, offset,
106
+ bytes, pnum ? pnum : &dummy, NULL,
107
NULL);
49
if (ret < 0) {
108
if (ret < 0) {
50
return ret;
109
return ret;
51
}
110
}
52
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
111
- if (pnum) {
53
static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
112
- *pnum = psectors * BDRV_SECTOR_SIZE;
54
uint64_t cluster_offset,
113
- }
55
unsigned offset_in_cluster,
114
return !!(ret & BDRV_BLOCK_ALLOCATED);
56
- uint8_t *buffer,
57
- unsigned bytes)
58
+ QEMUIOVector *qiov)
59
{
60
- QEMUIOVector qiov;
61
- struct iovec iov = { .iov_base = buffer, .iov_len = bytes };
62
int ret;
63
64
- if (bytes == 0) {
65
+ if (qiov->size == 0) {
66
return 0;
67
}
68
69
- qemu_iovec_init_external(&qiov, &iov, 1);
70
-
71
ret = qcow2_pre_write_overlap_check(bs, 0,
72
- cluster_offset + offset_in_cluster, bytes);
73
+ cluster_offset + offset_in_cluster, qiov->size);
74
if (ret < 0) {
75
return ret;
76
}
77
78
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
79
ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
80
- bytes, &qiov, 0);
81
+ qiov->size, qiov, 0);
82
if (ret < 0) {
83
return ret;
84
}
85
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
86
unsigned data_bytes = end->offset - (start->offset + start->nb_bytes);
87
bool merge_reads;
88
uint8_t *start_buffer, *end_buffer;
89
+ QEMUIOVector qiov;
90
int ret;
91
92
assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
93
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
94
/* The part of the buffer where the end region is located */
95
end_buffer = start_buffer + buffer_size - end->nb_bytes;
96
97
+ qemu_iovec_init(&qiov, 1);
98
+
99
qemu_co_mutex_unlock(&s->lock);
100
/* First we read the existing data from both COW regions. We
101
* either read the whole region in one go, or the start and end
102
* regions separately. */
103
if (merge_reads) {
104
- ret = do_perform_cow_read(bs, m->offset, start->offset,
105
- start_buffer, buffer_size);
106
+ qemu_iovec_add(&qiov, start_buffer, buffer_size);
107
+ ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);
108
} else {
109
- ret = do_perform_cow_read(bs, m->offset, start->offset,
110
- start_buffer, start->nb_bytes);
111
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
112
+ ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);
113
if (ret < 0) {
114
goto fail;
115
}
116
117
- ret = do_perform_cow_read(bs, m->offset, end->offset,
118
- end_buffer, end->nb_bytes);
119
+ qemu_iovec_reset(&qiov);
120
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
121
+ ret = do_perform_cow_read(bs, m->offset, end->offset, &qiov);
122
}
123
if (ret < 0) {
124
goto fail;
125
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
126
}
127
128
/* And now we can write everything */
129
- ret = do_perform_cow_write(bs, m->alloc_offset, start->offset,
130
- start_buffer, start->nb_bytes);
131
+ qemu_iovec_reset(&qiov);
132
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
133
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
134
if (ret < 0) {
135
goto fail;
136
}
137
138
- ret = do_perform_cow_write(bs, m->alloc_offset, end->offset,
139
- end_buffer, end->nb_bytes);
140
+ qemu_iovec_reset(&qiov);
141
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
142
+ ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);
143
fail:
144
qemu_co_mutex_lock(&s->lock);
145
146
@@ -XXX,XX +XXX,XX @@ fail:
147
}
148
149
qemu_vfree(start_buffer);
150
+ qemu_iovec_destroy(&qiov);
151
return ret;
152
}
115
}
153
116
154
--
117
--
155
1.8.3.1
118
2.13.6
156
119
157
120
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Instead of calling perform_cow() twice with a different COW region
3
We are gradually converting to byte-based interfaces, as they are
4
each time, call it just once and make perform_cow() handle both
4
easier to reason about than sector-based. Convert another internal
5
regions.
5
type (no semantic change), and rename it to match the corresponding
6
public function rename.
6
7
7
This patch simply moves code around. The next one will do the actual
8
Signed-off-by: Eric Blake <eblake@redhat.com>
8
reordering of the COW operations.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
10
---
15
block/qcow2-cluster.c | 36 ++++++++++++++++++++++--------------
11
block/io.c | 68 ++++++++++++++++++++++----------------------------------------
16
1 file changed, 22 insertions(+), 14 deletions(-)
12
1 file changed, 24 insertions(+), 44 deletions(-)
17
13
18
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
14
diff --git a/block/io.c b/block/io.c
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2-cluster.c
16
--- a/block/io.c
21
+++ b/block/qcow2-cluster.c
17
+++ b/block/io.c
22
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow(BlockDriverState *bs,
18
@@ -XXX,XX +XXX,XX @@ early_out:
23
struct iovec iov;
19
return ret;
24
int ret;
25
26
+ if (bytes == 0) {
27
+ return 0;
28
+ }
29
+
30
iov.iov_len = bytes;
31
iov.iov_base = qemu_try_blockalign(bs, iov.iov_len);
32
if (iov.iov_base == NULL) {
33
@@ -XXX,XX +XXX,XX @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
34
return cluster_offset;
35
}
20
}
36
21
37
-static int perform_cow(BlockDriverState *bs, QCowL2Meta *m, Qcow2COWRegion *r)
22
-static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
38
+static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
23
- BlockDriverState *base,
24
- bool want_zero,
25
- int64_t sector_num,
26
- int nb_sectors,
27
- int *pnum,
28
- BlockDriverState **file)
29
+static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
30
+ BlockDriverState *base,
31
+ bool want_zero,
32
+ int64_t offset,
33
+ int64_t bytes,
34
+ int64_t *pnum,
35
+ int64_t *map,
36
+ BlockDriverState **file)
39
{
37
{
40
BDRVQcow2State *s = bs->opaque;
38
BlockDriverState *p;
41
+ Qcow2COWRegion *start = &m->cow_start;
39
- int64_t ret = 0;
42
+ Qcow2COWRegion *end = &m->cow_end;
40
+ int ret = 0;
43
int ret;
41
bool first = true;
44
42
- int64_t map = 0;
45
- if (r->nb_bytes == 0) {
43
46
+ if (start->nb_bytes == 0 && end->nb_bytes == 0) {
44
assert(bs != base);
47
return 0;
45
for (p = bs; p != base; p = backing_bs(p)) {
46
- int64_t count;
47
-
48
- ret = bdrv_co_block_status(p, want_zero,
49
- sector_num * BDRV_SECTOR_SIZE,
50
- nb_sectors * BDRV_SECTOR_SIZE, &count,
51
- &map, file);
52
+ ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map,
53
+ file);
54
if (ret < 0) {
55
break;
56
}
57
- assert(QEMU_IS_ALIGNED(count | map, BDRV_SECTOR_SIZE));
58
- ret |= map;
59
- *pnum = count >> BDRV_SECTOR_BITS;
60
if (ret & BDRV_BLOCK_ZERO && ret & BDRV_BLOCK_EOF && !first) {
61
/*
62
* Reading beyond the end of the file continues to read
63
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
64
* unallocated length we learned from an earlier
65
* iteration.
66
*/
67
- *pnum = nb_sectors;
68
+ *pnum = bytes;
69
}
70
if (ret & (BDRV_BLOCK_ZERO | BDRV_BLOCK_DATA)) {
71
break;
72
}
73
- /* [sector_num, pnum] unallocated on this layer, which could be only
74
- * the first part of [sector_num, nb_sectors]. */
75
- nb_sectors = MIN(nb_sectors, *pnum);
76
+ /* [offset, pnum] unallocated on this layer, which could be only
77
+ * the first part of [offset, bytes]. */
78
+ bytes = MIN(bytes, *pnum);
79
first = false;
48
}
80
}
49
81
return ret;
50
qemu_co_mutex_unlock(&s->lock);
51
- ret = do_perform_cow(bs, m->offset, m->alloc_offset, r->offset, r->nb_bytes);
52
- qemu_co_mutex_lock(&s->lock);
53
-
54
+ ret = do_perform_cow(bs, m->offset, m->alloc_offset,
55
+ start->offset, start->nb_bytes);
56
if (ret < 0) {
57
- return ret;
58
+ goto fail;
59
}
60
61
+ ret = do_perform_cow(bs, m->offset, m->alloc_offset,
62
+ end->offset, end->nb_bytes);
63
+
64
+fail:
65
+ qemu_co_mutex_lock(&s->lock);
66
+
67
/*
68
* Before we update the L2 table to actually point to the new cluster, we
69
* need to be sure that the refcounts have been increased and COW was
70
* handled.
71
*/
72
- qcow2_cache_depends_on_flush(s->l2_table_cache);
73
+ if (ret == 0) {
74
+ qcow2_cache_depends_on_flush(s->l2_table_cache);
75
+ }
76
77
- return 0;
78
+ return ret;
79
}
82
}
80
83
81
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
84
/* Coroutine wrapper for bdrv_get_block_status_above() */
82
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
85
-static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
83
}
86
+static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
84
87
{
85
/* copy content of unmodified sectors */
88
BdrvCoBlockStatusData *data = opaque;
86
- ret = perform_cow(bs, m, &m->cow_start);
89
- int n = 0;
90
- int64_t ret;
91
92
- ret = bdrv_co_get_block_status_above(data->bs, data->base,
93
- data->want_zero,
94
- data->offset >> BDRV_SECTOR_BITS,
95
- data->bytes >> BDRV_SECTOR_BITS,
96
- &n,
97
- data->file);
87
- if (ret < 0) {
98
- if (ret < 0) {
88
- goto err;
99
- assert(INT_MIN <= ret);
100
- data->ret = ret;
101
- } else {
102
- *data->pnum = n * BDRV_SECTOR_SIZE;
103
- *data->map = ret & BDRV_BLOCK_OFFSET_MASK;
104
- data->ret = ret & ~BDRV_BLOCK_OFFSET_MASK;
89
- }
105
- }
90
-
106
+ data->ret = bdrv_co_block_status_above(data->bs, data->base,
91
- ret = perform_cow(bs, m, &m->cow_end);
107
+ data->want_zero,
92
+ ret = perform_cow(bs, m);
108
+ data->offset, data->bytes,
93
if (ret < 0) {
109
+ data->pnum, data->map, data->file);
94
goto err;
110
data->done = true;
111
}
112
113
/*
114
- * Synchronous wrapper around bdrv_co_get_block_status_above().
115
+ * Synchronous wrapper around bdrv_co_block_status_above().
116
*
117
- * See bdrv_co_get_block_status_above() for details.
118
+ * See bdrv_co_block_status_above() for details.
119
*/
120
static int bdrv_common_block_status_above(BlockDriverState *bs,
121
BlockDriverState *base,
122
@@ -XXX,XX +XXX,XX @@ static int bdrv_common_block_status_above(BlockDriverState *bs,
123
124
if (qemu_in_coroutine()) {
125
/* Fast-path if already in coroutine context */
126
- bdrv_get_block_status_above_co_entry(&data);
127
+ bdrv_block_status_above_co_entry(&data);
128
} else {
129
- co = qemu_coroutine_create(bdrv_get_block_status_above_co_entry,
130
- &data);
131
+ co = qemu_coroutine_create(bdrv_block_status_above_co_entry, &data);
132
bdrv_coroutine_enter(bs, co);
133
BDRV_POLL_WHILE(bs, !data.done);
95
}
134
}
96
--
135
--
97
1.8.3.1
136
2.13.6
98
137
99
138
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
If the guest tries to write data that results on the allocation of a
3
We are gradually moving away from sector-based interfaces, towards
4
new cluster, instead of writing the guest data first and then the data
4
byte-based. In the common case, allocation is unlikely to ever use
5
from the COW regions, write everything together using one single I/O
5
values that are not naturally sector-aligned, but it is possible
6
operation.
6
that byte-based values will let us be more precise about allocation
7
7
at the end of an unaligned file that can do byte-based access.
8
This can improve the write performance by 25% or more, depending on
8
9
several factors such as the media type, the cluster size and the I/O
9
Changing the name of the function from bdrv_get_block_status_above()
10
request size.
10
to bdrv_block_status_above() ensures that the compiler enforces that
11
11
all callers are updated. Likewise, since it a byte interface allows
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
an offset mapping that might not be sector aligned, split the mapping
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
out of the return value and into a pass-by-reference parameter. For
14
now, the io.c layer still assert()s that all uses are sector-aligned,
15
but that can be relaxed when a later patch implements byte-based
16
block status in the drivers.
17
18
For the most part this patch is just the addition of scaling at the
19
callers followed by inverse scaling at bdrv_block_status(), plus
20
updates for the new split return interface. But some code,
21
particularly bdrv_block_status(), gets a lot simpler because it no
22
longer has to mess with sectors. Likewise, mirror code no longer
23
computes s->granularity >> BDRV_SECTOR_BITS, and can therefore drop
24
an assertion about alignment because the loop no longer depends on
25
alignment (never mind that we don't really have a driver that
26
reports sub-sector alignments, so it's not really possible to test
27
the effect of sub-sector mirroring). Fix a neighboring assertion to
28
use is_power_of_2 while there.
29
30
For ease of review, bdrv_get_block_status() was tackled separately.
31
32
Signed-off-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
33
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
34
---
16
block/qcow2-cluster.c | 40 ++++++++++++++++++++++++--------
35
include/block/block.h | 8 +++-----
17
block/qcow2.c | 64 +++++++++++++++++++++++++++++++++++++++++++--------
36
block/io.c | 55 ++++++++-------------------------------------------
18
block/qcow2.h | 7 ++++++
37
block/mirror.c | 18 ++++++-----------
19
3 files changed, 91 insertions(+), 20 deletions(-)
38
block/qcow2.c | 30 +++++++++++-----------------
20
39
qemu-img.c | 49 +++++++++++++++++++++++++--------------------
21
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
40
5 files changed, 57 insertions(+), 103 deletions(-)
22
index XXXXXXX..XXXXXXX 100644
41
23
--- a/block/qcow2-cluster.c
42
diff --git a/include/block/block.h b/include/block/block.h
24
+++ b/block/qcow2-cluster.c
43
index XXXXXXX..XXXXXXX 100644
25
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
44
--- a/include/block/block.h
26
assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
45
+++ b/include/block/block.h
27
assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - data_bytes);
46
@@ -XXX,XX +XXX,XX @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
28
assert(start->offset + start->nb_bytes <= end->offset);
47
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
29
+ assert(!m->data_qiov || m->data_qiov->size == data_bytes);
48
int64_t bytes, int64_t *pnum, int64_t *map,
30
49
BlockDriverState **file);
31
if (start->nb_bytes == 0 && end->nb_bytes == 0) {
50
-int64_t bdrv_get_block_status_above(BlockDriverState *bs,
32
return 0;
51
- BlockDriverState *base,
33
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
52
- int64_t sector_num,
34
/* The part of the buffer where the end region is located */
53
- int nb_sectors, int *pnum,
35
end_buffer = start_buffer + buffer_size - end->nb_bytes;
54
- BlockDriverState **file);
36
55
+int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
37
- qemu_iovec_init(&qiov, 1);
56
+ int64_t offset, int64_t bytes, int64_t *pnum,
38
+ qemu_iovec_init(&qiov, 2 + (m->data_qiov ? m->data_qiov->niov : 0));
57
+ int64_t *map, BlockDriverState **file);
39
58
int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
40
qemu_co_mutex_unlock(&s->lock);
59
int64_t *pnum);
41
/* First we read the existing data from both COW regions. We
60
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
42
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
61
diff --git a/block/io.c b/block/io.c
43
}
62
index XXXXXXX..XXXXXXX 100644
63
--- a/block/io.c
64
+++ b/block/io.c
65
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
66
return ret;
67
}
68
69
-/* Coroutine wrapper for bdrv_get_block_status_above() */
70
+/* Coroutine wrapper for bdrv_block_status_above() */
71
static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
72
{
73
BdrvCoBlockStatusData *data = opaque;
74
@@ -XXX,XX +XXX,XX @@ static int bdrv_common_block_status_above(BlockDriverState *bs,
75
return data.ret;
76
}
77
78
-int64_t bdrv_get_block_status_above(BlockDriverState *bs,
79
- BlockDriverState *base,
80
- int64_t sector_num,
81
- int nb_sectors, int *pnum,
82
- BlockDriverState **file)
83
+int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
84
+ int64_t offset, int64_t bytes, int64_t *pnum,
85
+ int64_t *map, BlockDriverState **file)
86
{
87
- int64_t ret;
88
- int64_t n;
89
- int64_t map;
90
-
91
- ret = bdrv_common_block_status_above(bs, base, true,
92
- sector_num * BDRV_SECTOR_SIZE,
93
- nb_sectors * BDRV_SECTOR_SIZE,
94
- &n, &map, file);
95
- if (ret < 0) {
96
- *pnum = 0;
97
- return ret;
98
- }
99
- assert(QEMU_IS_ALIGNED(n | map, BDRV_SECTOR_SIZE));
100
- *pnum = n >> BDRV_SECTOR_BITS;
101
- return ret | map;
102
+ return bdrv_common_block_status_above(bs, base, true, offset, bytes,
103
+ pnum, map, file);
104
}
105
106
int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
107
int64_t *pnum, int64_t *map, BlockDriverState **file)
108
{
109
- int64_t ret;
110
- int n;
111
-
112
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
113
- assert(pnum);
114
- /*
115
- * The contract allows us to return pnum smaller than bytes, even
116
- * if the next query would see the same status; we truncate the
117
- * request to avoid overflowing the driver's 32-bit interface.
118
- */
119
- bytes = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
120
- ret = bdrv_get_block_status_above(bs, backing_bs(bs),
121
- offset >> BDRV_SECTOR_BITS,
122
- bytes >> BDRV_SECTOR_BITS, &n, file);
123
- if (ret < 0) {
124
- assert(INT_MIN <= ret);
125
- *pnum = 0;
126
- return ret;
127
- }
128
- *pnum = n * BDRV_SECTOR_SIZE;
129
- if (map) {
130
- *map = ret & BDRV_BLOCK_OFFSET_MASK;
131
- } else {
132
- ret &= ~BDRV_BLOCK_OFFSET_VALID;
133
- }
134
- return ret & ~BDRV_BLOCK_OFFSET_MASK;
135
+ return bdrv_block_status_above(bs, backing_bs(bs),
136
+ offset, bytes, pnum, map, file);
137
}
138
139
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
140
diff --git a/block/mirror.c b/block/mirror.c
141
index XXXXXXX..XXXXXXX 100644
142
--- a/block/mirror.c
143
+++ b/block/mirror.c
144
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
145
uint64_t delay_ns = 0;
146
/* At least the first dirty chunk is mirrored in one iteration. */
147
int nb_chunks = 1;
148
- int sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
149
bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target));
150
int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES);
151
152
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
44
}
153
}
45
154
46
- /* And now we can write everything */
155
/* Clear dirty bits before querying the block status, because
47
- qemu_iovec_reset(&qiov);
156
- * calling bdrv_get_block_status_above could yield - if some blocks are
48
- qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
157
+ * calling bdrv_block_status_above could yield - if some blocks are
49
- ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
158
* marked dirty in this window, we need to know.
50
- if (ret < 0) {
159
*/
51
- goto fail;
160
bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset,
52
+ /* And now we can write everything. If we have the guest data we
161
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
53
+ * can write everything in one single operation */
162
54
+ if (m->data_qiov) {
163
bitmap_set(s->in_flight_bitmap, offset / s->granularity, nb_chunks);
55
+ qemu_iovec_reset(&qiov);
164
while (nb_chunks > 0 && offset < s->bdev_length) {
56
+ if (start->nb_bytes) {
165
- int64_t ret;
57
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
166
- int io_sectors;
58
+ }
167
+ int ret;
59
+ qemu_iovec_concat(&qiov, m->data_qiov, 0, data_bytes);
168
int64_t io_bytes;
60
+ if (end->nb_bytes) {
169
int64_t io_bytes_acct;
61
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
170
enum MirrorMethod {
62
+ }
171
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
63
+ /* NOTE: we have a write_aio blkdebug event here followed by
172
} mirror_method = MIRROR_METHOD_COPY;
64
+ * a cow_write one in do_perform_cow_write(), but there's only
173
65
+ * one single I/O operation */
174
assert(!(offset % s->granularity));
66
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
175
- ret = bdrv_get_block_status_above(source, NULL,
67
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
176
- offset >> BDRV_SECTOR_BITS,
68
+ } else {
177
- nb_chunks * sectors_per_chunk,
69
+ /* If there's no guest data then write both COW regions separately */
178
- &io_sectors, NULL);
70
+ qemu_iovec_reset(&qiov);
179
- io_bytes = io_sectors * BDRV_SECTOR_SIZE;
71
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
180
+ ret = bdrv_block_status_above(source, NULL, offset,
72
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
181
+ nb_chunks * s->granularity,
73
+ if (ret < 0) {
182
+ &io_bytes, NULL, NULL);
74
+ goto fail;
183
if (ret < 0) {
75
+ }
184
io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes);
76
+
185
} else if (ret & BDRV_BLOCK_DATA) {
77
+ qemu_iovec_reset(&qiov);
186
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
78
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
187
granularity = bdrv_get_default_bitmap_granularity(target);
79
+ ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);
80
}
188
}
81
189
82
- qemu_iovec_reset(&qiov);
190
- assert ((granularity & (granularity - 1)) == 0);
83
- qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
191
- /* Granularity must be large enough for sector-based dirty bitmap */
84
- ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);
192
- assert(granularity >= BDRV_SECTOR_SIZE);
85
fail:
193
+ assert(is_power_of_2(granularity));
86
qemu_co_mutex_lock(&s->lock);
194
87
195
if (buf_size < 0) {
196
error_setg(errp, "Invalid parameter 'buf-size'");
88
diff --git a/block/qcow2.c b/block/qcow2.c
197
diff --git a/block/qcow2.c b/block/qcow2.c
89
index XXXXXXX..XXXXXXX 100644
198
index XXXXXXX..XXXXXXX 100644
90
--- a/block/qcow2.c
199
--- a/block/qcow2.c
91
+++ b/block/qcow2.c
200
+++ b/block/qcow2.c
92
@@ -XXX,XX +XXX,XX @@ fail:
201
@@ -XXX,XX +XXX,XX @@ finish:
93
return ret;
202
94
}
203
static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
95
204
{
96
+/* Check if it's possible to merge a write request with the writing of
205
- int nr;
97
+ * the data from the COW regions */
206
- int64_t res;
98
+static bool merge_cow(uint64_t offset, unsigned bytes,
207
+ int64_t nr;
99
+ QEMUIOVector *hd_qiov, QCowL2Meta *l2meta)
208
+ int res;
100
+{
209
int64_t start;
101
+ QCowL2Meta *m;
210
211
/* TODO: Widening to sector boundaries should only be needed as
212
@@ -XXX,XX +XXX,XX @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
213
if (!bytes) {
214
return true;
215
}
216
- res = bdrv_get_block_status_above(bs, NULL, start >> BDRV_SECTOR_BITS,
217
- bytes >> BDRV_SECTOR_BITS, &nr, NULL);
218
- return res >= 0 && (res & BDRV_BLOCK_ZERO) &&
219
- nr * BDRV_SECTOR_SIZE == bytes;
220
+ res = bdrv_block_status_above(bs, NULL, start, bytes, &nr, NULL, NULL);
221
+ return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == bytes;
222
}
223
224
static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
225
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
226
required = virtual_size;
227
} else {
228
int64_t offset;
229
- int pnum = 0;
230
+ int64_t pnum = 0;
231
232
- for (offset = 0; offset < ssize;
233
- offset += pnum * BDRV_SECTOR_SIZE) {
234
- int nb_sectors = MIN(ssize - offset,
235
- BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;
236
- int64_t ret;
237
+ for (offset = 0; offset < ssize; offset += pnum) {
238
+ int ret;
239
240
- ret = bdrv_get_block_status_above(in_bs, NULL,
241
- offset >> BDRV_SECTOR_BITS,
242
- nb_sectors, &pnum, NULL);
243
+ ret = bdrv_block_status_above(in_bs, NULL, offset,
244
+ ssize - offset, &pnum, NULL,
245
+ NULL);
246
if (ret < 0) {
247
error_setg_errno(&local_err, -ret,
248
"Unable to get block status");
249
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
250
} else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) ==
251
(BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {
252
/* Extend pnum to end of cluster for next iteration */
253
- pnum = (ROUND_UP(offset + pnum * BDRV_SECTOR_SIZE,
254
- cluster_size) - offset) >> BDRV_SECTOR_BITS;
255
+ pnum = ROUND_UP(offset + pnum, cluster_size) - offset;
256
257
/* Count clusters we've seen */
258
- required += offset % cluster_size + pnum * BDRV_SECTOR_SIZE;
259
+ required += offset % cluster_size + pnum;
260
}
261
}
262
}
263
diff --git a/qemu-img.c b/qemu-img.c
264
index XXXXXXX..XXXXXXX 100644
265
--- a/qemu-img.c
266
+++ b/qemu-img.c
267
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
268
BlockDriverState *bs1, *bs2;
269
int64_t total_sectors1, total_sectors2;
270
uint8_t *buf1 = NULL, *buf2 = NULL;
271
- int pnum1, pnum2;
272
+ int64_t pnum1, pnum2;
273
int allocated1, allocated2;
274
int ret = 0; /* return value - 0 Ident, 1 Different, >1 Error */
275
bool progress = false, quiet = false, strict = false;
276
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
277
}
278
279
for (;;) {
280
- int64_t status1, status2;
281
+ int status1, status2;
282
283
nb_sectors = sectors_to_process(total_sectors, sector_num);
284
if (nb_sectors <= 0) {
285
break;
286
}
287
- status1 = bdrv_get_block_status_above(bs1, NULL, sector_num,
288
- total_sectors1 - sector_num,
289
- &pnum1, NULL);
290
+ status1 = bdrv_block_status_above(bs1, NULL,
291
+ sector_num * BDRV_SECTOR_SIZE,
292
+ (total_sectors1 - sector_num) *
293
+ BDRV_SECTOR_SIZE,
294
+ &pnum1, NULL, NULL);
295
if (status1 < 0) {
296
ret = 3;
297
error_report("Sector allocation test failed for %s", filename1);
298
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
299
}
300
allocated1 = status1 & BDRV_BLOCK_ALLOCATED;
301
302
- status2 = bdrv_get_block_status_above(bs2, NULL, sector_num,
303
- total_sectors2 - sector_num,
304
- &pnum2, NULL);
305
+ status2 = bdrv_block_status_above(bs2, NULL,
306
+ sector_num * BDRV_SECTOR_SIZE,
307
+ (total_sectors2 - sector_num) *
308
+ BDRV_SECTOR_SIZE,
309
+ &pnum2, NULL, NULL);
310
if (status2 < 0) {
311
ret = 3;
312
error_report("Sector allocation test failed for %s", filename2);
313
goto out;
314
}
315
allocated2 = status2 & BDRV_BLOCK_ALLOCATED;
316
+ /* TODO: Relax this once comparison is byte-based, and we no longer
317
+ * have to worry about sector alignment */
318
+ assert(QEMU_IS_ALIGNED(pnum1 | pnum2, BDRV_SECTOR_SIZE));
319
if (pnum1) {
320
- nb_sectors = MIN(nb_sectors, pnum1);
321
+ nb_sectors = MIN(nb_sectors, pnum1 >> BDRV_SECTOR_BITS);
322
}
323
if (pnum2) {
324
- nb_sectors = MIN(nb_sectors, pnum2);
325
+ nb_sectors = MIN(nb_sectors, pnum2 >> BDRV_SECTOR_BITS);
326
}
327
328
if (strict) {
329
- if ((status1 & ~BDRV_BLOCK_OFFSET_MASK) !=
330
- (status2 & ~BDRV_BLOCK_OFFSET_MASK)) {
331
+ if (status1 != status2) {
332
ret = 1;
333
qprintf(quiet, "Strict mode: Offset %" PRId64
334
" block status mismatch!\n",
335
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
336
}
337
}
338
if ((status1 & BDRV_BLOCK_ZERO) && (status2 & BDRV_BLOCK_ZERO)) {
339
- nb_sectors = MIN(pnum1, pnum2);
340
+ nb_sectors = DIV_ROUND_UP(MIN(pnum1, pnum2), BDRV_SECTOR_SIZE);
341
} else if (allocated1 == allocated2) {
342
if (allocated1) {
343
ret = blk_pread(blk1, sector_num << BDRV_SECTOR_BITS, buf1,
344
@@ -XXX,XX +XXX,XX @@ static void convert_select_part(ImgConvertState *s, int64_t sector_num,
345
346
static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
347
{
348
- int64_t ret, src_cur_offset;
349
- int n, src_cur;
350
+ int64_t src_cur_offset;
351
+ int ret, n, src_cur;
352
353
convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
354
355
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
356
n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
357
358
if (s->sector_next_status <= sector_num) {
359
+ int64_t count = n * BDRV_SECTOR_SIZE;
102
+
360
+
103
+ for (m = l2meta; m != NULL; m = m->next) {
361
if (s->target_has_backing) {
104
+ /* If both COW regions are empty then there's nothing to merge */
362
- int64_t count = n * BDRV_SECTOR_SIZE;
105
+ if (m->cow_start.nb_bytes == 0 && m->cow_end.nb_bytes == 0) {
363
106
+ continue;
364
ret = bdrv_block_status(blk_bs(s->src[src_cur]),
107
+ }
365
(sector_num - src_cur_offset) *
108
+
366
BDRV_SECTOR_SIZE,
109
+ /* The data (middle) region must be immediately after the
367
count, &count, NULL, NULL);
110
+ * start region */
368
- assert(ret < 0 || QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
111
+ if (l2meta_cow_start(m) + m->cow_start.nb_bytes != offset) {
369
- n = count >> BDRV_SECTOR_BITS;
112
+ continue;
370
} else {
113
+ }
371
- ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL,
114
+
372
- sector_num - src_cur_offset,
115
+ /* The end region must be immediately after the data (middle)
373
- n, &n, NULL);
116
+ * region */
374
+ ret = bdrv_block_status_above(blk_bs(s->src[src_cur]), NULL,
117
+ if (m->offset + m->cow_end.offset != offset + bytes) {
375
+ (sector_num - src_cur_offset) *
118
+ continue;
376
+ BDRV_SECTOR_SIZE,
119
+ }
377
+ count, &count, NULL, NULL);
120
+
378
}
121
+ /* Make sure that adding both COW regions to the QEMUIOVector
379
if (ret < 0) {
122
+ * does not exceed IOV_MAX */
380
return ret;
123
+ if (hd_qiov->niov > IOV_MAX - 2) {
381
}
124
+ continue;
382
+ n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE);
125
+ }
383
126
+
384
if (ret & BDRV_BLOCK_ZERO) {
127
+ m->data_qiov = hd_qiov;
385
s->status = BLK_ZERO;
128
+ return true;
129
+ }
130
+
131
+ return false;
132
+}
133
+
134
static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
135
uint64_t bytes, QEMUIOVector *qiov,
136
int flags)
137
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
138
goto fail;
139
}
140
141
- qemu_co_mutex_unlock(&s->lock);
142
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
143
- trace_qcow2_writev_data(qemu_coroutine_self(),
144
- cluster_offset + offset_in_cluster);
145
- ret = bdrv_co_pwritev(bs->file,
146
- cluster_offset + offset_in_cluster,
147
- cur_bytes, &hd_qiov, 0);
148
- qemu_co_mutex_lock(&s->lock);
149
- if (ret < 0) {
150
- goto fail;
151
+ /* If we need to do COW, check if it's possible to merge the
152
+ * writing of the guest data together with that of the COW regions.
153
+ * If it's not possible (or not necessary) then write the
154
+ * guest data now. */
155
+ if (!merge_cow(offset, cur_bytes, &hd_qiov, l2meta)) {
156
+ qemu_co_mutex_unlock(&s->lock);
157
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
158
+ trace_qcow2_writev_data(qemu_coroutine_self(),
159
+ cluster_offset + offset_in_cluster);
160
+ ret = bdrv_co_pwritev(bs->file,
161
+ cluster_offset + offset_in_cluster,
162
+ cur_bytes, &hd_qiov, 0);
163
+ qemu_co_mutex_lock(&s->lock);
164
+ if (ret < 0) {
165
+ goto fail;
166
+ }
167
}
168
169
while (l2meta != NULL) {
170
diff --git a/block/qcow2.h b/block/qcow2.h
171
index XXXXXXX..XXXXXXX 100644
172
--- a/block/qcow2.h
173
+++ b/block/qcow2.h
174
@@ -XXX,XX +XXX,XX @@ typedef struct QCowL2Meta
175
*/
176
Qcow2COWRegion cow_end;
177
178
+ /**
179
+ * The I/O vector with the data from the actual guest write request.
180
+ * If non-NULL, this is meant to be merged together with the data
181
+ * from @cow_start and @cow_end into one single write operation.
182
+ */
183
+ QEMUIOVector *data_qiov;
184
+
185
/** Pointer to next L2Meta of the same write request */
186
struct QCowL2Meta *next;
187
188
--
386
--
189
1.8.3.1
387
2.13.6
190
388
191
389
diff view generated by jsdifflib
1
Now that we process a request in the same coroutine from beginning to
1
From: Eric Blake <eblake@redhat.com>
2
end and don't drop out of it any more, we can look like a proper
3
coroutine-based driver and simply call qed_aio_next_io() and get a
4
return value from it instead of spawning an additional coroutine that
5
reenters the parent when it's done.
6
2
3
As long as we are querying the status for a chunk smaller than
4
the known image size, we are guaranteed that a successful return
5
will have set pnum to a non-zero size (pnum is zero only for
6
queries beyond the end of the file). Use that to slightly
7
simplify the calculation of the current chunk size being compared.
8
Likewise, we don't have to shrink the amount of data operated on
9
until we know we have to read the file, and therefore have to fit
10
in the bounds of our buffer. Also, note that 'total_sectors_over'
11
is equivalent to 'progress_base'.
12
13
With these changes in place, sectors_to_process() is now dead code,
14
and can be removed.
15
16
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
18
---
10
block/qed.c | 101 +++++++++++++-----------------------------------------------
19
qemu-img.c | 38 +++++++++++---------------------------
11
block/qed.h | 3 +-
20
1 file changed, 11 insertions(+), 27 deletions(-)
12
2 files changed, 22 insertions(+), 82 deletions(-)
13
21
14
diff --git a/block/qed.c b/block/qed.c
22
diff --git a/qemu-img.c b/qemu-img.c
15
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qed.c
24
--- a/qemu-img.c
17
+++ b/block/qed.c
25
+++ b/qemu-img.c
18
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@ static int64_t sectors_to_bytes(int64_t sectors)
19
#include "qapi/qmp/qerror.h"
27
return sectors << BDRV_SECTOR_BITS;
20
#include "sysemu/block-backend.h"
21
22
-static const AIOCBInfo qed_aiocb_info = {
23
- .aiocb_size = sizeof(QEDAIOCB),
24
-};
25
-
26
static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
27
const char *filename)
28
{
29
@@ -XXX,XX +XXX,XX @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
30
return l2_table;
31
}
28
}
32
29
33
-static void qed_aio_next_io(QEDAIOCB *acb);
30
-static int64_t sectors_to_process(int64_t total, int64_t from)
34
-
35
-static void qed_aio_start_io(QEDAIOCB *acb)
36
-{
31
-{
37
- qed_aio_next_io(acb);
32
- return MIN(total - from, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
38
-}
33
-}
39
-
34
-
40
static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
35
/*
41
{
36
* Check if passed sectors are empty (not allocated or contain only 0 bytes)
42
assert(!s->allocating_write_reqs_plugged);
37
*
43
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
38
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
44
39
goto out;
45
static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
46
{
47
- return acb->common.bs->opaque;
48
+ return acb->bs->opaque;
49
}
50
51
/**
52
@@ -XXX,XX +XXX,XX @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
53
}
40
}
54
}
41
55
42
- for (;;) {
56
-static void qed_aio_complete_bh(void *opaque)
43
+ while (sector_num < total_sectors) {
57
-{
44
int status1, status2;
58
- QEDAIOCB *acb = opaque;
45
59
- BDRVQEDState *s = acb_to_s(acb);
46
- nb_sectors = sectors_to_process(total_sectors, sector_num);
60
- BlockCompletionFunc *cb = acb->common.cb;
47
- if (nb_sectors <= 0) {
61
- void *user_opaque = acb->common.opaque;
48
- break;
62
- int ret = acb->bh_ret;
49
- }
50
status1 = bdrv_block_status_above(bs1, NULL,
51
sector_num * BDRV_SECTOR_SIZE,
52
(total_sectors1 - sector_num) *
53
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
54
/* TODO: Relax this once comparison is byte-based, and we no longer
55
* have to worry about sector alignment */
56
assert(QEMU_IS_ALIGNED(pnum1 | pnum2, BDRV_SECTOR_SIZE));
57
- if (pnum1) {
58
- nb_sectors = MIN(nb_sectors, pnum1 >> BDRV_SECTOR_BITS);
59
- }
60
- if (pnum2) {
61
- nb_sectors = MIN(nb_sectors, pnum2 >> BDRV_SECTOR_BITS);
62
- }
63
+
64
+ assert(pnum1 && pnum2);
65
+ nb_sectors = MIN(pnum1, pnum2) >> BDRV_SECTOR_BITS;
66
67
if (strict) {
68
if (status1 != status2) {
69
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
70
}
71
}
72
if ((status1 & BDRV_BLOCK_ZERO) && (status2 & BDRV_BLOCK_ZERO)) {
73
- nb_sectors = DIV_ROUND_UP(MIN(pnum1, pnum2), BDRV_SECTOR_SIZE);
74
+ /* nothing to do */
75
} else if (allocated1 == allocated2) {
76
if (allocated1) {
77
+ nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
78
ret = blk_pread(blk1, sector_num << BDRV_SECTOR_BITS, buf1,
79
nb_sectors << BDRV_SECTOR_BITS);
80
if (ret < 0) {
81
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
82
}
83
}
84
} else {
63
-
85
-
64
- qemu_aio_unref(acb);
86
+ nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
65
-
87
if (allocated1) {
66
- /* Invoke callback */
88
ret = check_empty_sectors(blk1, sector_num, nb_sectors,
67
- qed_acquire(s);
89
filename1, buf1, quiet);
68
- cb(user_opaque, ret);
90
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
69
- qed_release(s);
91
70
-}
92
if (total_sectors1 != total_sectors2) {
71
-
93
BlockBackend *blk_over;
72
-static void qed_aio_complete(QEDAIOCB *acb, int ret)
94
- int64_t total_sectors_over;
73
+static void qed_aio_complete(QEDAIOCB *acb)
95
const char *filename_over;
74
{
96
75
BDRVQEDState *s = acb_to_s(acb);
97
qprintf(quiet, "Warning: Image size mismatch!\n");
76
98
if (total_sectors1 > total_sectors2) {
77
- trace_qed_aio_complete(s, acb, ret);
99
- total_sectors_over = total_sectors1;
78
-
100
blk_over = blk1;
79
/* Free resources */
101
filename_over = filename1;
80
qemu_iovec_destroy(&acb->cur_qiov);
102
} else {
81
qed_unref_l2_cache_entry(acb->request.l2_table);
103
- total_sectors_over = total_sectors2;
82
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
104
blk_over = blk2;
83
acb->qiov->iov[0].iov_base = NULL;
105
filename_over = filename2;
84
}
85
86
- /* Arrange for a bh to invoke the completion function */
87
- acb->bh_ret = ret;
88
- aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
89
- qed_aio_complete_bh, acb);
90
-
91
/* Start next allocating write request waiting behind this one. Note that
92
* requests enqueue themselves when they first hit an unallocated cluster
93
* but they wait until the entire request is finished before waking up the
94
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
95
struct iovec *iov = acb->qiov->iov;
96
97
if (!iov->iov_base) {
98
- iov->iov_base = qemu_try_blockalign(acb->common.bs, iov->iov_len);
99
+ iov->iov_base = qemu_try_blockalign(acb->bs, iov->iov_len);
100
if (iov->iov_base == NULL) {
101
return -ENOMEM;
102
}
103
@@ -XXX,XX +XXX,XX @@ static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
104
{
105
QEDAIOCB *acb = opaque;
106
BDRVQEDState *s = acb_to_s(acb);
107
- BlockDriverState *bs = acb->common.bs;
108
+ BlockDriverState *bs = acb->bs;
109
110
/* Adjust offset into cluster */
111
offset += qed_offset_into_cluster(s, acb->cur_pos);
112
@@ -XXX,XX +XXX,XX @@ static int qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
113
/**
114
* Begin next I/O or complete the request
115
*/
116
-static void qed_aio_next_io(QEDAIOCB *acb)
117
+static int qed_aio_next_io(QEDAIOCB *acb)
118
{
119
BDRVQEDState *s = acb_to_s(acb);
120
uint64_t offset;
121
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb)
122
123
/* Complete request */
124
if (acb->cur_pos >= acb->end_pos) {
125
- qed_aio_complete(acb, 0);
126
- return;
127
+ ret = 0;
128
+ break;
129
}
106
}
130
107
131
/* Find next cluster and start I/O */
108
- for (;;) {
132
len = acb->end_pos - acb->cur_pos;
109
+ while (sector_num < progress_base) {
133
ret = qed_find_cluster(s, &acb->request, acb->cur_pos, &len, &offset);
110
int64_t count;
134
if (ret < 0) {
111
135
- qed_aio_complete(acb, ret);
112
- nb_sectors = sectors_to_process(total_sectors_over, sector_num);
136
- return;
113
- if (nb_sectors <= 0) {
137
+ break;
114
- break;
138
}
115
- }
139
116
ret = bdrv_is_allocated_above(blk_bs(blk_over), NULL,
140
if (acb->flags & QED_AIOCB_WRITE) {
117
sector_num * BDRV_SECTOR_SIZE,
141
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb)
118
- nb_sectors * BDRV_SECTOR_SIZE,
142
}
119
+ (progress_base - sector_num) *
143
120
+ BDRV_SECTOR_SIZE,
144
if (ret < 0 && ret != -EAGAIN) {
121
&count);
145
- qed_aio_complete(acb, ret);
122
if (ret < 0) {
146
- return;
123
ret = 3;
147
+ break;
124
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
148
}
125
assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
149
}
126
nb_sectors = count >> BDRV_SECTOR_BITS;
150
-}
127
if (ret) {
151
128
+ nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
152
-typedef struct QEDRequestCo {
129
ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
153
- Coroutine *co;
130
filename_over, buf1, quiet);
154
- bool done;
131
if (ret) {
155
- int ret;
156
-} QEDRequestCo;
157
-
158
-static void qed_co_request_cb(void *opaque, int ret)
159
-{
160
- QEDRequestCo *co = opaque;
161
-
162
- co->done = true;
163
- co->ret = ret;
164
- qemu_coroutine_enter_if_inactive(co->co);
165
+ trace_qed_aio_complete(s, acb, ret);
166
+ qed_aio_complete(acb);
167
+ return ret;
168
}
169
170
static int coroutine_fn qed_co_request(BlockDriverState *bs, int64_t sector_num,
171
QEMUIOVector *qiov, int nb_sectors,
172
int flags)
173
{
174
- QEDRequestCo co = {
175
- .co = qemu_coroutine_self(),
176
- .done = false,
177
+ QEDAIOCB acb = {
178
+ .bs = bs,
179
+ .cur_pos = (uint64_t) sector_num * BDRV_SECTOR_SIZE,
180
+ .end_pos = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE,
181
+ .qiov = qiov,
182
+ .flags = flags,
183
};
184
- QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, qed_co_request_cb, &co);
185
-
186
- trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors, &co, flags);
187
+ qemu_iovec_init(&acb.cur_qiov, qiov->niov);
188
189
- acb->flags = flags;
190
- acb->qiov = qiov;
191
- acb->qiov_offset = 0;
192
- acb->cur_pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
193
- acb->end_pos = acb->cur_pos + nb_sectors * BDRV_SECTOR_SIZE;
194
- acb->backing_qiov = NULL;
195
- acb->request.l2_table = NULL;
196
- qemu_iovec_init(&acb->cur_qiov, qiov->niov);
197
+ trace_qed_aio_setup(bs->opaque, &acb, sector_num, nb_sectors, NULL, flags);
198
199
/* Start request */
200
- qed_aio_start_io(acb);
201
-
202
- if (!co.done) {
203
- qemu_coroutine_yield();
204
- }
205
-
206
- return co.ret;
207
+ return qed_aio_next_io(&acb);
208
}
209
210
static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs,
211
diff --git a/block/qed.h b/block/qed.h
212
index XXXXXXX..XXXXXXX 100644
213
--- a/block/qed.h
214
+++ b/block/qed.h
215
@@ -XXX,XX +XXX,XX @@ enum {
216
};
217
218
typedef struct QEDAIOCB {
219
- BlockAIOCB common;
220
- int bh_ret; /* final return status for completion bh */
221
+ BlockDriverState *bs;
222
QSIMPLEQ_ENTRY(QEDAIOCB) next; /* next request */
223
int flags; /* QED_AIOCB_* bits ORed together */
224
uint64_t end_pos; /* request end on block device, in bytes */
225
--
132
--
226
1.8.3.1
133
2.13.6
227
134
228
135
diff view generated by jsdifflib
1
From: "sochin.jiang" <sochin.jiang@huawei.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
img_commit could fall into an infinite loop calling run_block_job() if
3
Compare the following images with all-zero contents:
4
its blockjob fails on any I/O error, fix this already known problem.
4
$ truncate --size 1M A
5
$ qemu-img create -f qcow2 -o preallocation=off B 1G
6
$ qemu-img create -f qcow2 -o preallocation=metadata C 1G
5
7
6
Signed-off-by: sochin.jiang <sochin.jiang@huawei.com>
8
On my machine, the difference is noticeable for pre-patch speeds,
7
Message-id: 1497509253-28941-1-git-send-email-sochin.jiang@huawei.com
9
with more than an order of magnitude in difference caused by the
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
choice of preallocation in the qcow2 file:
11
12
$ time ./qemu-img compare -f raw -F qcow2 A B
13
Warning: Image size mismatch!
14
Images are identical.
15
16
real    0m0.014s
17
user    0m0.007s
18
sys    0m0.007s
19
20
$ time ./qemu-img compare -f raw -F qcow2 A C
21
Warning: Image size mismatch!
22
Images are identical.
23
24
real    0m0.341s
25
user    0m0.144s
26
sys    0m0.188s
27
28
Why? Because bdrv_is_allocated() returns false for image B but
29
true for image C, throwing away the fact that both images know
30
via lseek(SEEK_HOLE) that the entire image still reads as zero.
31
From there, qemu-img ends up calling bdrv_pread() for every byte
32
of the tail, instead of quickly looking for the next allocation.
33
The solution: use block_status instead of is_allocated, giving:
34
35
$ time ./qemu-img compare -f raw -F qcow2 A C
36
Warning: Image size mismatch!
37
Images are identical.
38
39
real    0m0.014s
40
user    0m0.011s
41
sys    0m0.003s
42
43
which is on par with the speeds for no pre-allocation.
44
45
Signed-off-by: Eric Blake <eblake@redhat.com>
46
Reviewed-by: John Snow <jsnow@redhat.com>
47
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
48
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
49
---
10
blockjob.c | 4 ++--
50
qemu-img.c | 8 ++++----
11
include/block/blockjob.h | 18 ++++++++++++++++++
51
1 file changed, 4 insertions(+), 4 deletions(-)
12
qemu-img.c | 20 +++++++++++++-------
13
3 files changed, 33 insertions(+), 9 deletions(-)
14
52
15
diff --git a/blockjob.c b/blockjob.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/blockjob.c
18
+++ b/blockjob.c
19
@@ -XXX,XX +XXX,XX @@ static void block_job_resume(BlockJob *job)
20
block_job_enter(job);
21
}
22
23
-static void block_job_ref(BlockJob *job)
24
+void block_job_ref(BlockJob *job)
25
{
26
++job->refcnt;
27
}
28
@@ -XXX,XX +XXX,XX @@ static void block_job_attached_aio_context(AioContext *new_context,
29
void *opaque);
30
static void block_job_detach_aio_context(void *opaque);
31
32
-static void block_job_unref(BlockJob *job)
33
+void block_job_unref(BlockJob *job)
34
{
35
if (--job->refcnt == 0) {
36
BlockDriverState *bs = blk_bs(job->blk);
37
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/blockjob.h
40
+++ b/include/block/blockjob.h
41
@@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset(BlockJob *job);
42
BlockJobTxn *block_job_txn_new(void);
43
44
/**
45
+ * block_job_ref:
46
+ *
47
+ * Add a reference to BlockJob refcnt, it will be decreased with
48
+ * block_job_unref, and then be freed if it comes to be the last
49
+ * reference.
50
+ */
51
+void block_job_ref(BlockJob *job);
52
+
53
+/**
54
+ * block_job_unref:
55
+ *
56
+ * Release a reference that was previously acquired with block_job_ref
57
+ * or block_job_create. If it's the last reference to the object, it will be
58
+ * freed.
59
+ */
60
+void block_job_unref(BlockJob *job);
61
+
62
+/**
63
* block_job_txn_unref:
64
*
65
* Release a reference that was previously acquired with block_job_txn_add_job
66
diff --git a/qemu-img.c b/qemu-img.c
53
diff --git a/qemu-img.c b/qemu-img.c
67
index XXXXXXX..XXXXXXX 100644
54
index XXXXXXX..XXXXXXX 100644
68
--- a/qemu-img.c
55
--- a/qemu-img.c
69
+++ b/qemu-img.c
56
+++ b/qemu-img.c
70
@@ -XXX,XX +XXX,XX @@ static void common_block_job_cb(void *opaque, int ret)
57
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
71
static void run_block_job(BlockJob *job, Error **errp)
58
while (sector_num < progress_base) {
72
{
59
int64_t count;
73
AioContext *aio_context = blk_get_aio_context(job->blk);
60
74
+ int ret = 0;
61
- ret = bdrv_is_allocated_above(blk_bs(blk_over), NULL,
75
62
+ ret = bdrv_block_status_above(blk_bs(blk_over), NULL,
76
- /* FIXME In error cases, the job simply goes away and we access a dangling
63
sector_num * BDRV_SECTOR_SIZE,
77
- * pointer below. */
64
(progress_base - sector_num) *
78
aio_context_acquire(aio_context);
65
BDRV_SECTOR_SIZE,
79
+ block_job_ref(job);
66
- &count);
80
do {
67
+ &count, NULL, NULL);
81
aio_poll(aio_context, true);
68
if (ret < 0) {
82
qemu_progress_print(job->len ?
69
ret = 3;
83
((float)job->offset / job->len * 100.f) : 0.0f, 0);
70
error_report("Sector allocation test failed for %s",
84
- } while (!job->ready);
71
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
85
+ } while (!job->ready && !job->completed);
72
goto out;
86
73
87
- block_job_complete_sync(job, errp);
74
}
88
+ if (!job->completed) {
75
- /* TODO relax this once bdrv_is_allocated_above does not enforce
89
+ ret = block_job_complete_sync(job, errp);
76
+ /* TODO relax this once bdrv_block_status_above does not enforce
90
+ } else {
77
* sector alignment */
91
+ ret = job->ret;
78
assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
92
+ }
79
nb_sectors = count >> BDRV_SECTOR_BITS;
93
+ block_job_unref(job);
80
- if (ret) {
94
aio_context_release(aio_context);
81
+ if (ret & BDRV_BLOCK_ALLOCATED && !(ret & BDRV_BLOCK_ZERO)) {
95
82
nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
96
- /* A block job may finish instantaneously without publishing any progress,
83
ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
97
- * so just signal completion here */
84
filename_over, buf1, quiet);
98
- qemu_progress_print(100.f, 0);
99
+ /* publish completion progress only when success */
100
+ if (!ret) {
101
+ qemu_progress_print(100.f, 0);
102
+ }
103
}
104
105
static int img_commit(int argc, char **argv)
106
--
85
--
107
1.8.3.1
86
2.13.6
108
87
109
88
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Avoid duplicating the QEMU command-line.
3
During 'qemu-img compare', when we are checking that an allocated
4
portion of one file is all zeros, we don't need to waste time
5
computing how many additional sectors after the first non-zero
6
byte are also non-zero. Create a new helper find_nonzero() to do
7
the check for a first non-zero sector, and rebase
8
check_empty_sectors() to use it.
4
9
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
The new interface intentionally uses bytes in its interface, even
11
though it still crawls the buffer a sector at a time; it is robust
12
to a partial sector at the end of the buffer.
13
14
Signed-off-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: John Snow <jsnow@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
17
---
8
tests/qemu-iotests/068 | 15 +++++++++------
18
qemu-img.c | 32 ++++++++++++++++++++++++++++----
9
1 file changed, 9 insertions(+), 6 deletions(-)
19
1 file changed, 28 insertions(+), 4 deletions(-)
10
20
11
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
21
diff --git a/qemu-img.c b/qemu-img.c
12
index XXXXXXX..XXXXXXX 100755
22
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/068
23
--- a/qemu-img.c
14
+++ b/tests/qemu-iotests/068
24
+++ b/qemu-img.c
15
@@ -XXX,XX +XXX,XX @@ case "$QEMU_DEFAULT_MACHINE" in
25
@@ -XXX,XX +XXX,XX @@ done:
16
;;
26
}
17
esac
27
18
28
/*
19
-# Give qemu some time to boot before saving the VM state
29
+ * Returns -1 if 'buf' contains only zeroes, otherwise the byte index
20
-bash -c 'sleep 1; echo -e "savevm 0\nquit"' |\
30
+ * of the first sector boundary within buf where the sector contains a
21
- $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\
31
+ * non-zero byte. This function is robust to a buffer that is not
22
+_qemu()
32
+ * sector-aligned.
33
+ */
34
+static int64_t find_nonzero(const uint8_t *buf, int64_t n)
23
+{
35
+{
24
+ $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" \
36
+ int64_t i;
25
+ "$@" |\
37
+ int64_t end = QEMU_ALIGN_DOWN(n, BDRV_SECTOR_SIZE);
26
_filter_qemu | _filter_hmp
38
+
39
+ for (i = 0; i < end; i += BDRV_SECTOR_SIZE) {
40
+ if (!buffer_is_zero(buf + i, BDRV_SECTOR_SIZE)) {
41
+ return i;
42
+ }
43
+ }
44
+ if (i < n && !buffer_is_zero(buf + i, n - end)) {
45
+ return i;
46
+ }
47
+ return -1;
27
+}
48
+}
28
+
49
+
29
+# Give qemu some time to boot before saving the VM state
50
+/*
30
+bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu
51
* Returns true iff the first sector pointed to by 'buf' contains at least
31
# Now try to continue from that VM state (this should just work)
52
* a non-NUL byte.
32
-echo quit |\
53
*
33
- $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\
54
@@ -XXX,XX +XXX,XX @@ static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
34
- _filter_qemu | _filter_hmp
55
int sect_count, const char *filename,
35
+echo quit | _qemu -loadvm 0
56
uint8_t *buffer, bool quiet)
36
57
{
37
# success, all done
58
- int pnum, ret = 0;
38
echo "*** done"
59
+ int ret = 0;
60
+ int64_t idx;
61
+
62
ret = blk_pread(blk, sect_num << BDRV_SECTOR_BITS, buffer,
63
sect_count << BDRV_SECTOR_BITS);
64
if (ret < 0) {
65
@@ -XXX,XX +XXX,XX @@ static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
66
sectors_to_bytes(sect_num), filename, strerror(-ret));
67
return ret;
68
}
69
- ret = is_allocated_sectors(buffer, sect_count, &pnum);
70
- if (ret || pnum != sect_count) {
71
+ idx = find_nonzero(buffer, sect_count * BDRV_SECTOR_SIZE);
72
+ if (idx >= 0) {
73
qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
74
- sectors_to_bytes(ret ? sect_num : sect_num + pnum));
75
+ sectors_to_bytes(sect_num) + idx);
76
return 1;
77
}
78
39
--
79
--
40
1.8.3.1
80
2.13.6
41
81
42
82
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
migration_incoming_state_destroy() uses qemu_fclose() on the vmstate
3
If a read error is encountered during 'qemu-img compare', we
4
file. Make sure to call it inside an AioContext acquire/release region.
4
were printing the "Error while reading offset ..." message twice;
5
this was because our helper function was awkward, printing output
6
on some but not all paths. Fix it to consistently report errors
7
on all paths, so that the callers do not risk a redundant message,
8
and update the testsuite for the improved output.
5
9
6
This fixes an 'qemu: qemu_mutex_unlock: Operation not permitted' abort
10
Further simplify the code by hoisting the conversion from an error
7
in loadvm.
11
message to an exit code into the helper function, rather than
12
repeating that logic at all callers (yes, the helper function is
13
now less generic, but it's a net win in lines of code).
8
14
9
This patch closes the vmstate file before ending the drained region.
15
Signed-off-by: Eric Blake <eblake@redhat.com>
10
Previously we closed the vmstate file after ending the drained region.
16
Reviewed-by: John Snow <jsnow@redhat.com>
11
The order does not matter.
12
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
18
---
16
migration/savevm.c | 2 +-
19
qemu-img.c | 19 +++++--------------
17
1 file changed, 1 insertion(+), 1 deletion(-)
20
tests/qemu-iotests/074.out | 2 --
21
2 files changed, 5 insertions(+), 16 deletions(-)
18
22
19
diff --git a/migration/savevm.c b/migration/savevm.c
23
diff --git a/qemu-img.c b/qemu-img.c
20
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
21
--- a/migration/savevm.c
25
--- a/qemu-img.c
22
+++ b/migration/savevm.c
26
+++ b/qemu-img.c
23
@@ -XXX,XX +XXX,XX @@ int load_snapshot(const char *name, Error **errp)
27
@@ -XXX,XX +XXX,XX @@ static int64_t sectors_to_bytes(int64_t sectors)
24
28
/*
25
aio_context_acquire(aio_context);
29
* Check if passed sectors are empty (not allocated or contain only 0 bytes)
26
ret = qemu_loadvm_state(f);
30
*
27
+ migration_incoming_state_destroy();
31
- * Returns 0 in case sectors are filled with 0, 1 if sectors contain non-zero
28
aio_context_release(aio_context);
32
- * data and negative value on error.
29
33
+ * Intended for use by 'qemu-img compare': Returns 0 in case sectors are
30
bdrv_drain_all_end();
34
+ * filled with 0, 1 if sectors contain non-zero data (this is a comparison
31
35
+ * failure), and 4 on error (the exit status for read errors), after emitting
32
- migration_incoming_state_destroy();
36
+ * an error message.
37
*
38
* @param blk: BlockBackend for the image
39
* @param sect_num: Number of first sector to check
40
@@ -XXX,XX +XXX,XX @@ static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
33
if (ret < 0) {
41
if (ret < 0) {
34
error_setg(errp, "Error %d while loading VM state", ret);
42
error_report("Error while reading offset %" PRId64 " of %s: %s",
35
return ret;
43
sectors_to_bytes(sect_num), filename, strerror(-ret));
44
- return ret;
45
+ return 4;
46
}
47
idx = find_nonzero(buffer, sect_count * BDRV_SECTOR_SIZE);
48
if (idx >= 0) {
49
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
50
filename2, buf1, quiet);
51
}
52
if (ret) {
53
- if (ret < 0) {
54
- error_report("Error while reading offset %" PRId64 ": %s",
55
- sectors_to_bytes(sector_num), strerror(-ret));
56
- ret = 4;
57
- }
58
goto out;
59
}
60
}
61
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
62
ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
63
filename_over, buf1, quiet);
64
if (ret) {
65
- if (ret < 0) {
66
- error_report("Error while reading offset %" PRId64
67
- " of %s: %s", sectors_to_bytes(sector_num),
68
- filename_over, strerror(-ret));
69
- ret = 4;
70
- }
71
goto out;
72
}
73
}
74
diff --git a/tests/qemu-iotests/074.out b/tests/qemu-iotests/074.out
75
index XXXXXXX..XXXXXXX 100644
76
--- a/tests/qemu-iotests/074.out
77
+++ b/tests/qemu-iotests/074.out
78
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
79
wrote 512/512 bytes at offset 512
80
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
81
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
82
-qemu-img: Error while reading offset 0: Input/output error
83
4
84
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
85
Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=0
86
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=0
87
wrote 512/512 bytes at offset 512
88
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
89
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
90
-qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
91
Warning: Image size mismatch!
92
4
93
Cleanup
36
--
94
--
37
1.8.3.1
95
2.13.6
38
96
39
97
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
2
3
Continue on the quest to make more things byte-based instead of
4
sector-based.
5
6
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
---
9
---
4
block/qed.c | 32 ++++++++++++--------------------
10
qemu-img.c | 27 +++++++++++++++------------
5
1 file changed, 12 insertions(+), 20 deletions(-)
11
1 file changed, 15 insertions(+), 12 deletions(-)
6
12
7
diff --git a/block/qed.c b/block/qed.c
13
diff --git a/qemu-img.c b/qemu-img.c
8
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
9
--- a/block/qed.c
15
--- a/qemu-img.c
10
+++ b/block/qed.c
16
+++ b/qemu-img.c
11
@@ -XXX,XX +XXX,XX @@ int qed_write_header_sync(BDRVQEDState *s)
17
@@ -XXX,XX +XXX,XX @@ static int64_t sectors_to_bytes(int64_t sectors)
12
* This function only updates known header fields in-place and does not affect
18
* an error message.
13
* extra data after the QED header.
19
*
20
* @param blk: BlockBackend for the image
21
- * @param sect_num: Number of first sector to check
22
- * @param sect_count: Number of sectors to check
23
+ * @param offset: Starting offset to check
24
+ * @param bytes: Number of bytes to check
25
* @param filename: Name of disk file we are checking (logging purpose)
26
* @param buffer: Allocated buffer for storing read data
27
* @param quiet: Flag for quiet mode
14
*/
28
*/
15
-static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
29
-static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
16
- void *opaque)
30
- int sect_count, const char *filename,
17
+static int qed_write_header(BDRVQEDState *s)
31
+static int check_empty_sectors(BlockBackend *blk, int64_t offset,
32
+ int64_t bytes, const char *filename,
33
uint8_t *buffer, bool quiet)
18
{
34
{
19
/* We must write full sectors for O_DIRECT but cannot necessarily generate
35
int ret = 0;
20
* the data following the header if an unrecognized compat feature is
36
int64_t idx;
21
@@ -XXX,XX +XXX,XX @@ static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
37
22
ret = 0;
38
- ret = blk_pread(blk, sect_num << BDRV_SECTOR_BITS, buffer,
23
out:
39
- sect_count << BDRV_SECTOR_BITS);
24
qemu_vfree(buf);
40
+ ret = blk_pread(blk, offset, buffer, bytes);
25
- cb(opaque, ret);
41
if (ret < 0) {
26
+ return ret;
42
error_report("Error while reading offset %" PRId64 " of %s: %s",
27
}
43
- sectors_to_bytes(sect_num), filename, strerror(-ret));
28
44
+ offset, filename, strerror(-ret));
29
static uint64_t qed_max_image_size(uint32_t cluster_size, uint32_t table_size)
45
return 4;
30
@@ -XXX,XX +XXX,XX @@ static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
31
}
46
}
32
}
47
- idx = find_nonzero(buffer, sect_count * BDRV_SECTOR_SIZE);
33
48
+ idx = find_nonzero(buffer, bytes);
34
-static void qed_finish_clear_need_check(void *opaque, int ret)
49
if (idx >= 0) {
35
-{
50
qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
36
- /* Do nothing */
51
- sectors_to_bytes(sect_num) + idx);
37
-}
52
+ offset + idx);
38
-
53
return 1;
39
-static void qed_flush_after_clear_need_check(void *opaque, int ret)
40
-{
41
- BDRVQEDState *s = opaque;
42
-
43
- bdrv_aio_flush(s->bs, qed_finish_clear_need_check, s);
44
-
45
- /* No need to wait until flush completes */
46
- qed_unplug_allocating_write_reqs(s);
47
-}
48
-
49
static void qed_clear_need_check(void *opaque, int ret)
50
{
51
BDRVQEDState *s = opaque;
52
@@ -XXX,XX +XXX,XX @@ static void qed_clear_need_check(void *opaque, int ret)
53
}
54
}
54
55
55
s->header.features &= ~QED_F_NEED_CHECK;
56
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
56
- qed_write_header(s, qed_flush_after_clear_need_check, s);
57
} else {
57
+ ret = qed_write_header(s);
58
nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
58
+ (void) ret;
59
if (allocated1) {
59
+
60
- ret = check_empty_sectors(blk1, sector_num, nb_sectors,
60
+ qed_unplug_allocating_write_reqs(s);
61
+ ret = check_empty_sectors(blk1, sector_num * BDRV_SECTOR_SIZE,
61
+
62
+ nb_sectors * BDRV_SECTOR_SIZE,
62
+ ret = bdrv_flush(s->bs);
63
filename1, buf1, quiet);
63
+ (void) ret;
64
} else {
64
}
65
- ret = check_empty_sectors(blk2, sector_num, nb_sectors,
65
66
+ ret = check_empty_sectors(blk2, sector_num * BDRV_SECTOR_SIZE,
66
static void qed_need_check_timer_cb(void *opaque)
67
+ nb_sectors * BDRV_SECTOR_SIZE,
67
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
68
filename2, buf1, quiet);
68
{
69
}
69
BDRVQEDState *s = acb_to_s(acb);
70
if (ret) {
70
BlockCompletionFunc *cb;
71
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
71
+ int ret;
72
nb_sectors = count >> BDRV_SECTOR_BITS;
72
73
if (ret & BDRV_BLOCK_ALLOCATED && !(ret & BDRV_BLOCK_ZERO)) {
73
/* Cancel timer when the first allocating request comes in */
74
nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
74
if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
75
- ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
75
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
76
+ ret = check_empty_sectors(blk_over,
76
77
+ sector_num * BDRV_SECTOR_SIZE,
77
if (qed_should_set_need_check(s)) {
78
+ nb_sectors * BDRV_SECTOR_SIZE,
78
s->header.features |= QED_F_NEED_CHECK;
79
filename_over, buf1, quiet);
79
- qed_write_header(s, cb, acb);
80
if (ret) {
80
+ ret = qed_write_header(s);
81
goto out;
81
+ cb(acb, ret);
82
} else {
83
cb(acb, 0);
84
}
85
--
82
--
86
1.8.3.1
83
2.13.6
87
84
88
85
diff view generated by jsdifflib
1
Note that this code is generally not running in coroutine context, so
1
From: Eric Blake <eblake@redhat.com>
2
this is an actual blocking synchronous operation. We'll fix this in a
3
moment.
4
2
3
In the continuing quest to make more things byte-based, change
4
compare_sectors(), renaming it to compare_buffers() in the
5
process. Note that one caller (qemu-img compare) only cares
6
about the first difference, while the other (qemu-img rebase)
7
cares about how many consecutive sectors have the same
8
equal/different status; however, this patch does not bother to
9
micro-optimize the compare case to avoid the comparisons of
10
sectors beyond the first mismatch. Both callers are always
11
passing valid buffers in, so the initial check for buffer size
12
can be turned into an assertion.
13
14
Signed-off-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: John Snow <jsnow@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
17
---
8
block/qed.c | 61 +++++++++++++++++++------------------------------------------
18
qemu-img.c | 55 +++++++++++++++++++++++++++----------------------------
9
1 file changed, 19 insertions(+), 42 deletions(-)
19
1 file changed, 27 insertions(+), 28 deletions(-)
10
20
11
diff --git a/block/qed.c b/block/qed.c
21
diff --git a/qemu-img.c b/qemu-img.c
12
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
13
--- a/block/qed.c
23
--- a/qemu-img.c
14
+++ b/block/qed.c
24
+++ b/qemu-img.c
15
@@ -XXX,XX +XXX,XX @@ static void qed_aio_start_io(QEDAIOCB *acb)
25
@@ -XXX,XX +XXX,XX @@ static int is_allocated_sectors_min(const uint8_t *buf, int n, int *pnum,
16
qed_aio_next_io(acb, 0);
17
}
26
}
18
27
19
-static void qed_aio_next_io_cb(void *opaque, int ret)
28
/*
20
-{
29
- * Compares two buffers sector by sector. Returns 0 if the first sector of both
21
- QEDAIOCB *acb = opaque;
30
- * buffers matches, non-zero otherwise.
22
-
31
+ * Compares two buffers sector by sector. Returns 0 if the first
23
- qed_aio_next_io(acb, ret);
32
+ * sector of each buffer matches, non-zero otherwise.
24
-}
33
*
25
-
34
- * pnum is set to the number of sectors (including and immediately following
26
static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
35
- * the first one) that are known to have the same comparison result
36
+ * pnum is set to the sector-aligned size of the buffer prefix that
37
+ * has the same matching status as the first sector.
38
*/
39
-static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
40
- int *pnum)
41
+static int compare_buffers(const uint8_t *buf1, const uint8_t *buf2,
42
+ int64_t bytes, int64_t *pnum)
27
{
43
{
28
assert(!s->allocating_write_reqs_plugged);
44
bool res;
29
@@ -XXX,XX +XXX,XX @@ err:
45
- int i;
30
qed_aio_complete(acb, ret);
46
+ int64_t i = MIN(bytes, BDRV_SECTOR_SIZE);
31
}
47
32
48
- if (n <= 0) {
33
-static void qed_aio_write_l2_update_cb(void *opaque, int ret)
49
- *pnum = 0;
34
-{
50
- return 0;
35
- QEDAIOCB *acb = opaque;
36
- qed_aio_write_l2_update(acb, ret, acb->cur_cluster);
37
-}
38
-
39
-/**
40
- * Flush new data clusters before updating the L2 table
41
- *
42
- * This flush is necessary when a backing file is in use. A crash during an
43
- * allocating write could result in empty clusters in the image. If the write
44
- * only touched a subregion of the cluster, then backing image sectors have
45
- * been lost in the untouched region. The solution is to flush after writing a
46
- * new data cluster and before updating the L2 table.
47
- */
48
-static void qed_aio_write_flush_before_l2_update(void *opaque, int ret)
49
-{
50
- QEDAIOCB *acb = opaque;
51
- BDRVQEDState *s = acb_to_s(acb);
52
-
53
- if (!bdrv_aio_flush(s->bs->file->bs, qed_aio_write_l2_update_cb, opaque)) {
54
- qed_aio_complete(acb, -EIO);
55
- }
51
- }
56
-}
52
+ assert(bytes > 0);
57
-
53
58
/**
54
- res = !!memcmp(buf1, buf2, 512);
59
* Write data to the image file
55
- for(i = 1; i < n; i++) {
60
*/
56
- buf1 += 512;
61
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
57
- buf2 += 512;
62
BDRVQEDState *s = acb_to_s(acb);
58
+ res = !!memcmp(buf1, buf2, i);
63
uint64_t offset = acb->cur_cluster +
59
+ while (i < bytes) {
64
qed_offset_into_cluster(s, acb->cur_pos);
60
+ int64_t len = MIN(bytes - i, BDRV_SECTOR_SIZE);
65
- BlockCompletionFunc *next_fn;
61
66
62
- if (!!memcmp(buf1, buf2, 512) != res) {
67
trace_qed_aio_write_main(s, acb, ret, offset, acb->cur_qiov.size);
63
+ if (!!memcmp(buf1 + i, buf2 + i, len) != res) {
68
64
break;
69
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
65
}
70
return;
66
+ i += len;
71
}
67
}
72
68
73
+ BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
69
*pnum = i;
74
+ ret = bdrv_pwritev(s->bs->file, offset, &acb->cur_qiov);
70
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
75
+ if (ret >= 0) {
71
int64_t total_sectors;
76
+ ret = 0;
72
int64_t sector_num = 0;
77
+ }
73
int64_t nb_sectors;
74
- int c, pnum;
75
+ int c;
76
uint64_t progress_base;
77
bool image_opts = false;
78
bool force_share = false;
79
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
80
/* nothing to do */
81
} else if (allocated1 == allocated2) {
82
if (allocated1) {
83
+ int64_t pnum;
78
+
84
+
79
if (acb->find_cluster_ret == QED_CLUSTER_FOUND) {
85
nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
80
- next_fn = qed_aio_next_io_cb;
86
ret = blk_pread(blk1, sector_num << BDRV_SECTOR_BITS, buf1,
81
+ qed_aio_next_io(acb, ret);
87
nb_sectors << BDRV_SECTOR_BITS);
82
} else {
88
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
83
if (s->bs->backing) {
89
ret = 4;
84
- next_fn = qed_aio_write_flush_before_l2_update;
90
goto out;
85
- } else {
91
}
86
- next_fn = qed_aio_write_l2_update_cb;
92
- ret = compare_sectors(buf1, buf2, nb_sectors, &pnum);
87
+ /*
93
- if (ret || pnum != nb_sectors) {
88
+ * Flush new data clusters before updating the L2 table
94
+ ret = compare_buffers(buf1, buf2,
89
+ *
95
+ nb_sectors * BDRV_SECTOR_SIZE, &pnum);
90
+ * This flush is necessary when a backing file is in use. A crash
96
+ if (ret || pnum != nb_sectors * BDRV_SECTOR_SIZE) {
91
+ * during an allocating write could result in empty clusters in the
97
qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
92
+ * image. If the write only touched a subregion of the cluster,
98
- sectors_to_bytes(
93
+ * then backing image sectors have been lost in the untouched
99
- ret ? sector_num : sector_num + pnum));
94
+ * region. The solution is to flush after writing a new data
100
+ sectors_to_bytes(sector_num) + (ret ? 0 : pnum));
95
+ * cluster and before updating the L2 table.
101
ret = 1;
96
+ */
102
goto out;
97
+ ret = bdrv_flush(s->bs->file->bs);
103
}
98
}
104
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
99
+ qed_aio_write_l2_update(acb, ret, acb->cur_cluster);
105
/* If they differ, we need to write to the COW file */
100
}
106
uint64_t written = 0;
101
-
107
102
- BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
108
- while (written < n) {
103
- bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
109
- int pnum;
104
- &acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
110
+ while (written < n * BDRV_SECTOR_SIZE) {
105
- next_fn, acb);
111
+ int64_t pnum;
106
}
112
107
113
- if (compare_sectors(buf_old + written * 512,
108
/**
114
- buf_new + written * 512, n - written, &pnum))
115
+ if (compare_buffers(buf_old + written,
116
+ buf_new + written,
117
+ n * BDRV_SECTOR_SIZE - written, &pnum))
118
{
119
ret = blk_pwrite(blk,
120
- (sector + written) << BDRV_SECTOR_BITS,
121
- buf_old + written * 512,
122
- pnum << BDRV_SECTOR_BITS, 0);
123
+ (sector << BDRV_SECTOR_BITS) + written,
124
+ buf_old + written, pnum, 0);
125
if (ret < 0) {
126
error_report("Error while writing to COW image: %s",
127
strerror(-ret));
109
--
128
--
110
1.8.3.1
129
2.13.6
111
130
112
131
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
blk/bdrv_drain_all() only takes effect for a single instant and then
3
In the continuing quest to make more things byte-based, change
4
resumes block jobs, guest devices, and other external clients like the
4
the internal iteration of img_rebase(). We can finally drop the
5
NBD server. This can be handy when performing a synchronous drain
5
TODO assertion added earlier, now that the entire algorithm is
6
before terminating the program, for example.
6
byte-based and no longer has to shift from bytes to sectors.
7
7
8
Monitor commands usually need to quiesce I/O across an entire code
8
Most of the change is mechanical ('num_sectors' becomes 'size',
9
region so blk/bdrv_drain_all() is not suitable. They must use
9
'sector' becomes 'offset', 'n' goes from sectors to bytes); some
10
bdrv_drain_all_begin/end() to mark the region. This prevents new I/O
10
of it is also a cleanup (use of MIN() instead of open-coding,
11
requests from slipping in or worse - block jobs completing and modifying
11
loss of variable 'count' added earlier in commit d6a644bb).
12
the graph.
13
12
14
I audited other blk/bdrv_drain_all() callers but did not find anything
13
Signed-off-by: Eric Blake <eblake@redhat.com>
15
that needs a similar fix. This patch fixes the savevm/loadvm commands.
14
Reviewed-by: John Snow <jsnow@redhat.com>
16
Although I haven't encountered a read world issue this makes the code
17
safer.
18
19
Suggested-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
16
---
24
migration/savevm.c | 18 +++++++++++++++---
17
qemu-img.c | 84 +++++++++++++++++++++++++-------------------------------------
25
1 file changed, 15 insertions(+), 3 deletions(-)
18
1 file changed, 34 insertions(+), 50 deletions(-)
26
19
27
diff --git a/migration/savevm.c b/migration/savevm.c
20
diff --git a/qemu-img.c b/qemu-img.c
28
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
29
--- a/migration/savevm.c
22
--- a/qemu-img.c
30
+++ b/migration/savevm.c
23
+++ b/qemu-img.c
31
@@ -XXX,XX +XXX,XX @@ int save_snapshot(const char *name, Error **errp)
24
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
32
}
25
* the image is the same as the original one at any time.
33
vm_stop(RUN_STATE_SAVE_VM);
26
*/
34
27
if (!unsafe) {
35
+ bdrv_drain_all_begin();
28
- int64_t num_sectors;
36
+
29
- int64_t old_backing_num_sectors;
37
aio_context_acquire(aio_context);
30
- int64_t new_backing_num_sectors = 0;
38
31
- uint64_t sector;
39
memset(sn, 0, sizeof(*sn));
32
- int n;
40
@@ -XXX,XX +XXX,XX @@ int save_snapshot(const char *name, Error **errp)
33
- int64_t count;
41
if (aio_context) {
34
+ int64_t size;
42
aio_context_release(aio_context);
35
+ int64_t old_backing_size;
43
}
36
+ int64_t new_backing_size = 0;
44
+
37
+ uint64_t offset;
45
+ bdrv_drain_all_end();
38
+ int64_t n;
46
+
39
float local_progress = 0;
47
if (saved_vm_running) {
40
48
vm_start();
41
buf_old = blk_blockalign(blk, IO_BUF_SIZE);
49
}
42
buf_new = blk_blockalign(blk, IO_BUF_SIZE);
50
@@ -XXX,XX +XXX,XX @@ int load_snapshot(const char *name, Error **errp)
43
51
}
44
- num_sectors = blk_nb_sectors(blk);
52
45
- if (num_sectors < 0) {
53
/* Flush all IO requests so they don't interfere with the new state. */
46
+ size = blk_getlength(blk);
54
- bdrv_drain_all();
47
+ if (size < 0) {
55
+ bdrv_drain_all_begin();
48
error_report("Could not get size of '%s': %s",
56
49
- filename, strerror(-num_sectors));
57
ret = bdrv_all_goto_snapshot(name, &bs);
50
+ filename, strerror(-size));
58
if (ret < 0) {
51
ret = -1;
59
error_setg(errp, "Error %d while activating snapshot '%s' on '%s'",
52
goto out;
60
ret, name, bdrv_get_device_name(bs));
53
}
61
- return ret;
54
- old_backing_num_sectors = blk_nb_sectors(blk_old_backing);
62
+ goto err_drain;
55
- if (old_backing_num_sectors < 0) {
63
}
56
+ old_backing_size = blk_getlength(blk_old_backing);
64
57
+ if (old_backing_size < 0) {
65
/* restore the VM state */
58
char backing_name[PATH_MAX];
66
f = qemu_fopen_bdrv(bs_vm_state, 0);
59
67
if (!f) {
60
bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
68
error_setg(errp, "Could not open VM state file");
61
error_report("Could not get size of '%s': %s",
69
- return -EINVAL;
62
- backing_name, strerror(-old_backing_num_sectors));
70
+ ret = -EINVAL;
63
+ backing_name, strerror(-old_backing_size));
71
+ goto err_drain;
64
ret = -1;
72
}
65
goto out;
73
66
}
74
qemu_system_reset(SHUTDOWN_CAUSE_NONE);
67
if (blk_new_backing) {
75
@@ -XXX,XX +XXX,XX @@ int load_snapshot(const char *name, Error **errp)
68
- new_backing_num_sectors = blk_nb_sectors(blk_new_backing);
76
ret = qemu_loadvm_state(f);
69
- if (new_backing_num_sectors < 0) {
77
aio_context_release(aio_context);
70
+ new_backing_size = blk_getlength(blk_new_backing);
78
71
+ if (new_backing_size < 0) {
79
+ bdrv_drain_all_end();
72
error_report("Could not get size of '%s': %s",
80
+
73
- out_baseimg, strerror(-new_backing_num_sectors));
81
migration_incoming_state_destroy();
74
+ out_baseimg, strerror(-new_backing_size));
82
if (ret < 0) {
75
ret = -1;
83
error_setg(errp, "Error %d while loading VM state", ret);
76
goto out;
84
@@ -XXX,XX +XXX,XX @@ int load_snapshot(const char *name, Error **errp)
77
}
85
}
78
}
86
79
87
return 0;
80
- if (num_sectors != 0) {
88
+
81
- local_progress = (float)100 /
89
+err_drain:
82
- (num_sectors / MIN(num_sectors, IO_BUF_SIZE / 512));
90
+ bdrv_drain_all_end();
83
+ if (size != 0) {
91
+ return ret;
84
+ local_progress = (float)100 / (size / MIN(size, IO_BUF_SIZE));
92
}
85
}
93
86
94
void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev)
87
- for (sector = 0; sector < num_sectors; sector += n) {
88
-
89
- /* How many sectors can we handle with the next read? */
90
- if (sector + (IO_BUF_SIZE / 512) <= num_sectors) {
91
- n = (IO_BUF_SIZE / 512);
92
- } else {
93
- n = num_sectors - sector;
94
- }
95
+ for (offset = 0; offset < size; offset += n) {
96
+ /* How many bytes can we handle with the next read? */
97
+ n = MIN(IO_BUF_SIZE, size - offset);
98
99
/* If the cluster is allocated, we don't need to take action */
100
- ret = bdrv_is_allocated(bs, sector << BDRV_SECTOR_BITS,
101
- n << BDRV_SECTOR_BITS, &count);
102
+ ret = bdrv_is_allocated(bs, offset, n, &n);
103
if (ret < 0) {
104
error_report("error while reading image metadata: %s",
105
strerror(-ret));
106
goto out;
107
}
108
- /* TODO relax this once bdrv_is_allocated does not enforce
109
- * sector alignment */
110
- assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
111
- n = count >> BDRV_SECTOR_BITS;
112
if (ret) {
113
continue;
114
}
115
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
116
* Read old and new backing file and take into consideration that
117
* backing files may be smaller than the COW image.
118
*/
119
- if (sector >= old_backing_num_sectors) {
120
- memset(buf_old, 0, n * BDRV_SECTOR_SIZE);
121
+ if (offset >= old_backing_size) {
122
+ memset(buf_old, 0, n);
123
} else {
124
- if (sector + n > old_backing_num_sectors) {
125
- n = old_backing_num_sectors - sector;
126
+ if (offset + n > old_backing_size) {
127
+ n = old_backing_size - offset;
128
}
129
130
- ret = blk_pread(blk_old_backing, sector << BDRV_SECTOR_BITS,
131
- buf_old, n << BDRV_SECTOR_BITS);
132
+ ret = blk_pread(blk_old_backing, offset, buf_old, n);
133
if (ret < 0) {
134
error_report("error while reading from old backing file");
135
goto out;
136
}
137
}
138
139
- if (sector >= new_backing_num_sectors || !blk_new_backing) {
140
- memset(buf_new, 0, n * BDRV_SECTOR_SIZE);
141
+ if (offset >= new_backing_size || !blk_new_backing) {
142
+ memset(buf_new, 0, n);
143
} else {
144
- if (sector + n > new_backing_num_sectors) {
145
- n = new_backing_num_sectors - sector;
146
+ if (offset + n > new_backing_size) {
147
+ n = new_backing_size - offset;
148
}
149
150
- ret = blk_pread(blk_new_backing, sector << BDRV_SECTOR_BITS,
151
- buf_new, n << BDRV_SECTOR_BITS);
152
+ ret = blk_pread(blk_new_backing, offset, buf_new, n);
153
if (ret < 0) {
154
error_report("error while reading from new backing file");
155
goto out;
156
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
157
/* If they differ, we need to write to the COW file */
158
uint64_t written = 0;
159
160
- while (written < n * BDRV_SECTOR_SIZE) {
161
+ while (written < n) {
162
int64_t pnum;
163
164
- if (compare_buffers(buf_old + written,
165
- buf_new + written,
166
- n * BDRV_SECTOR_SIZE - written, &pnum))
167
+ if (compare_buffers(buf_old + written, buf_new + written,
168
+ n - written, &pnum))
169
{
170
- ret = blk_pwrite(blk,
171
- (sector << BDRV_SECTOR_BITS) + written,
172
+ ret = blk_pwrite(blk, offset + written,
173
buf_old + written, pnum, 0);
174
if (ret < 0) {
175
error_report("Error while writing to COW image: %s",
95
--
176
--
96
1.8.3.1
177
2.13.6
97
178
98
179
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
2
3
In the continuing quest to make more things byte-based, change
4
the internal iteration of img_compare(). We can finally drop the
5
TODO assertions added earlier, now that the entire algorithm is
6
byte-based and no longer has to shift from bytes to sectors.
7
8
Most of the change is mechanical ('total_sectors' becomes
9
'total_size', 'sector_num' becomes 'offset', 'nb_sectors' becomes
10
'chunk', 'progress_base' goes from sectors to bytes); some of it
11
is also a cleanup (sectors_to_bytes() is now unused, loss of
12
variable 'count' added earlier in commit 51b0a488).
13
14
Signed-off-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: John Snow <jsnow@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
---
17
---
4
block/qed-table.c | 47 ++++++++++++-----------------------------------
18
qemu-img.c | 124 ++++++++++++++++++++++++-------------------------------------
5
block/qed.c | 12 +++++++-----
19
1 file changed, 48 insertions(+), 76 deletions(-)
6
block/qed.h | 8 +++-----
20
7
3 files changed, 22 insertions(+), 45 deletions(-)
21
diff --git a/qemu-img.c b/qemu-img.c
8
9
diff --git a/block/qed-table.c b/block/qed-table.c
10
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
11
--- a/block/qed-table.c
23
--- a/qemu-img.c
12
+++ b/block/qed-table.c
24
+++ b/qemu-img.c
13
@@ -XXX,XX +XXX,XX @@ out:
25
@@ -XXX,XX +XXX,XX @@ static int compare_buffers(const uint8_t *buf1, const uint8_t *buf2,
14
* @index: Index of first element
26
15
* @n: Number of elements
27
#define IO_BUF_SIZE (2 * 1024 * 1024)
16
* @flush: Whether or not to sync to disk
28
17
- * @cb: Completion function
29
-static int64_t sectors_to_bytes(int64_t sectors)
18
- * @opaque: Argument for completion function
30
-{
19
*/
31
- return sectors << BDRV_SECTOR_BITS;
20
-static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
21
- unsigned int index, unsigned int n, bool flush,
22
- BlockCompletionFunc *cb, void *opaque)
23
+static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
24
+ unsigned int index, unsigned int n, bool flush)
25
{
26
unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
27
unsigned int start, end, i;
28
@@ -XXX,XX +XXX,XX @@ static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
29
ret = 0;
30
out:
31
qemu_vfree(new_table);
32
- cb(opaque, ret);
33
-}
32
-}
34
-
33
-
35
-/**
34
/*
36
- * Propagate return value from async callback
35
* Check if passed sectors are empty (not allocated or contain only 0 bytes)
37
- */
36
*
38
-static void qed_sync_cb(void *opaque, int ret)
37
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
39
-{
38
const char *fmt1 = NULL, *fmt2 = NULL, *cache, *filename1, *filename2;
40
- *(int *)opaque = ret;
39
BlockBackend *blk1, *blk2;
41
+ return ret;
40
BlockDriverState *bs1, *bs2;
42
}
41
- int64_t total_sectors1, total_sectors2;
43
42
+ int64_t total_size1, total_size2;
44
int qed_read_l1_table_sync(BDRVQEDState *s)
43
uint8_t *buf1 = NULL, *buf2 = NULL;
45
@@ -XXX,XX +XXX,XX @@ int qed_read_l1_table_sync(BDRVQEDState *s)
44
int64_t pnum1, pnum2;
46
return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
45
int allocated1, allocated2;
47
}
46
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
48
47
bool progress = false, quiet = false, strict = false;
49
-void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
48
int flags;
50
- BlockCompletionFunc *cb, void *opaque)
49
bool writethrough;
51
+int qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n)
50
- int64_t total_sectors;
52
{
51
- int64_t sector_num = 0;
53
BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
52
- int64_t nb_sectors;
54
- qed_write_table(s, s->header.l1_table_offset,
53
+ int64_t total_size;
55
- s->l1_table, index, n, false, cb, opaque);
54
+ int64_t offset = 0;
56
+ return qed_write_table(s, s->header.l1_table_offset,
55
+ int64_t chunk;
57
+ s->l1_table, index, n, false);
56
int c;
58
}
57
uint64_t progress_base;
59
58
bool image_opts = false;
60
int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
59
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
61
unsigned int n)
60
62
{
61
buf1 = blk_blockalign(blk1, IO_BUF_SIZE);
63
- int ret = -EINPROGRESS;
62
buf2 = blk_blockalign(blk2, IO_BUF_SIZE);
63
- total_sectors1 = blk_nb_sectors(blk1);
64
- if (total_sectors1 < 0) {
65
+ total_size1 = blk_getlength(blk1);
66
+ if (total_size1 < 0) {
67
error_report("Can't get size of %s: %s",
68
- filename1, strerror(-total_sectors1));
69
+ filename1, strerror(-total_size1));
70
ret = 4;
71
goto out;
72
}
73
- total_sectors2 = blk_nb_sectors(blk2);
74
- if (total_sectors2 < 0) {
75
+ total_size2 = blk_getlength(blk2);
76
+ if (total_size2 < 0) {
77
error_report("Can't get size of %s: %s",
78
- filename2, strerror(-total_sectors2));
79
+ filename2, strerror(-total_size2));
80
ret = 4;
81
goto out;
82
}
83
- total_sectors = MIN(total_sectors1, total_sectors2);
84
- progress_base = MAX(total_sectors1, total_sectors2);
85
+ total_size = MIN(total_size1, total_size2);
86
+ progress_base = MAX(total_size1, total_size2);
87
88
qemu_progress_print(0, 100);
89
90
- if (strict && total_sectors1 != total_sectors2) {
91
+ if (strict && total_size1 != total_size2) {
92
ret = 1;
93
qprintf(quiet, "Strict mode: Image size mismatch!\n");
94
goto out;
95
}
96
97
- while (sector_num < total_sectors) {
98
+ while (offset < total_size) {
99
int status1, status2;
100
101
- status1 = bdrv_block_status_above(bs1, NULL,
102
- sector_num * BDRV_SECTOR_SIZE,
103
- (total_sectors1 - sector_num) *
104
- BDRV_SECTOR_SIZE,
105
- &pnum1, NULL, NULL);
106
+ status1 = bdrv_block_status_above(bs1, NULL, offset,
107
+ total_size1 - offset, &pnum1, NULL,
108
+ NULL);
109
if (status1 < 0) {
110
ret = 3;
111
error_report("Sector allocation test failed for %s", filename1);
112
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
113
}
114
allocated1 = status1 & BDRV_BLOCK_ALLOCATED;
115
116
- status2 = bdrv_block_status_above(bs2, NULL,
117
- sector_num * BDRV_SECTOR_SIZE,
118
- (total_sectors2 - sector_num) *
119
- BDRV_SECTOR_SIZE,
120
- &pnum2, NULL, NULL);
121
+ status2 = bdrv_block_status_above(bs2, NULL, offset,
122
+ total_size2 - offset, &pnum2, NULL,
123
+ NULL);
124
if (status2 < 0) {
125
ret = 3;
126
error_report("Sector allocation test failed for %s", filename2);
127
goto out;
128
}
129
allocated2 = status2 & BDRV_BLOCK_ALLOCATED;
130
- /* TODO: Relax this once comparison is byte-based, and we no longer
131
- * have to worry about sector alignment */
132
- assert(QEMU_IS_ALIGNED(pnum1 | pnum2, BDRV_SECTOR_SIZE));
133
134
assert(pnum1 && pnum2);
135
- nb_sectors = MIN(pnum1, pnum2) >> BDRV_SECTOR_BITS;
136
+ chunk = MIN(pnum1, pnum2);
137
138
if (strict) {
139
if (status1 != status2) {
140
ret = 1;
141
qprintf(quiet, "Strict mode: Offset %" PRId64
142
- " block status mismatch!\n",
143
- sectors_to_bytes(sector_num));
144
+ " block status mismatch!\n", offset);
145
goto out;
146
}
147
}
148
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
149
if (allocated1) {
150
int64_t pnum;
151
152
- nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
153
- ret = blk_pread(blk1, sector_num << BDRV_SECTOR_BITS, buf1,
154
- nb_sectors << BDRV_SECTOR_BITS);
155
+ chunk = MIN(chunk, IO_BUF_SIZE);
156
+ ret = blk_pread(blk1, offset, buf1, chunk);
157
if (ret < 0) {
158
- error_report("Error while reading offset %" PRId64 " of %s:"
159
- " %s", sectors_to_bytes(sector_num), filename1,
160
- strerror(-ret));
161
+ error_report("Error while reading offset %" PRId64
162
+ " of %s: %s",
163
+ offset, filename1, strerror(-ret));
164
ret = 4;
165
goto out;
166
}
167
- ret = blk_pread(blk2, sector_num << BDRV_SECTOR_BITS, buf2,
168
- nb_sectors << BDRV_SECTOR_BITS);
169
+ ret = blk_pread(blk2, offset, buf2, chunk);
170
if (ret < 0) {
171
error_report("Error while reading offset %" PRId64
172
- " of %s: %s", sectors_to_bytes(sector_num),
173
- filename2, strerror(-ret));
174
+ " of %s: %s",
175
+ offset, filename2, strerror(-ret));
176
ret = 4;
177
goto out;
178
}
179
- ret = compare_buffers(buf1, buf2,
180
- nb_sectors * BDRV_SECTOR_SIZE, &pnum);
181
- if (ret || pnum != nb_sectors * BDRV_SECTOR_SIZE) {
182
+ ret = compare_buffers(buf1, buf2, chunk, &pnum);
183
+ if (ret || pnum != chunk) {
184
qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
185
- sectors_to_bytes(sector_num) + (ret ? 0 : pnum));
186
+ offset + (ret ? 0 : pnum));
187
ret = 1;
188
goto out;
189
}
190
}
191
} else {
192
- nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
193
+ chunk = MIN(chunk, IO_BUF_SIZE);
194
if (allocated1) {
195
- ret = check_empty_sectors(blk1, sector_num * BDRV_SECTOR_SIZE,
196
- nb_sectors * BDRV_SECTOR_SIZE,
197
+ ret = check_empty_sectors(blk1, offset, chunk,
198
filename1, buf1, quiet);
199
} else {
200
- ret = check_empty_sectors(blk2, sector_num * BDRV_SECTOR_SIZE,
201
- nb_sectors * BDRV_SECTOR_SIZE,
202
+ ret = check_empty_sectors(blk2, offset, chunk,
203
filename2, buf1, quiet);
204
}
205
if (ret) {
206
goto out;
207
}
208
}
209
- sector_num += nb_sectors;
210
- qemu_progress_print(((float) nb_sectors / progress_base)*100, 100);
211
+ offset += chunk;
212
+ qemu_progress_print(((float) chunk / progress_base) * 100, 100);
213
}
214
215
- if (total_sectors1 != total_sectors2) {
216
+ if (total_size1 != total_size2) {
217
BlockBackend *blk_over;
218
const char *filename_over;
219
220
qprintf(quiet, "Warning: Image size mismatch!\n");
221
- if (total_sectors1 > total_sectors2) {
222
+ if (total_size1 > total_size2) {
223
blk_over = blk1;
224
filename_over = filename1;
225
} else {
226
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
227
filename_over = filename2;
228
}
229
230
- while (sector_num < progress_base) {
231
- int64_t count;
64
-
232
-
65
- qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
233
- ret = bdrv_block_status_above(blk_bs(blk_over), NULL,
66
- BDRV_POLL_WHILE(s->bs, ret == -EINPROGRESS);
234
- sector_num * BDRV_SECTOR_SIZE,
67
-
235
- (progress_base - sector_num) *
68
- return ret;
236
- BDRV_SECTOR_SIZE,
69
+ return qed_write_l1_table(s, index, n);
237
- &count, NULL, NULL);
70
}
238
+ while (offset < progress_base) {
71
239
+ ret = bdrv_block_status_above(blk_bs(blk_over), NULL, offset,
72
int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
240
+ progress_base - offset, &chunk,
73
@@ -XXX,XX +XXX,XX @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
241
+ NULL, NULL);
74
return qed_read_l2_table(s, request, offset);
242
if (ret < 0) {
75
}
243
ret = 3;
76
244
error_report("Sector allocation test failed for %s",
77
-void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
245
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
78
- unsigned int index, unsigned int n, bool flush,
246
goto out;
79
- BlockCompletionFunc *cb, void *opaque)
247
80
+int qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
248
}
81
+ unsigned int index, unsigned int n, bool flush)
249
- /* TODO relax this once bdrv_block_status_above does not enforce
82
{
250
- * sector alignment */
83
BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
251
- assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
84
- qed_write_table(s, request->l2_table->offset,
252
- nb_sectors = count >> BDRV_SECTOR_BITS;
85
- request->l2_table->table, index, n, flush, cb, opaque);
253
if (ret & BDRV_BLOCK_ALLOCATED && !(ret & BDRV_BLOCK_ZERO)) {
86
+ return qed_write_table(s, request->l2_table->offset,
254
- nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
87
+ request->l2_table->table, index, n, flush);
255
- ret = check_empty_sectors(blk_over,
88
}
256
- sector_num * BDRV_SECTOR_SIZE,
89
257
- nb_sectors * BDRV_SECTOR_SIZE,
90
int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
258
+ chunk = MIN(chunk, IO_BUF_SIZE);
91
unsigned int index, unsigned int n, bool flush)
259
+ ret = check_empty_sectors(blk_over, offset, chunk,
92
{
260
filename_over, buf1, quiet);
93
- int ret = -EINPROGRESS;
261
if (ret) {
94
-
262
goto out;
95
- qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
263
}
96
- BDRV_POLL_WHILE(s->bs, ret == -EINPROGRESS);
264
}
97
-
265
- sector_num += nb_sectors;
98
- return ret;
266
- qemu_progress_print(((float) nb_sectors / progress_base)*100, 100);
99
+ return qed_write_l2_table(s, request, index, n, flush);
267
+ offset += chunk;
100
}
268
+ qemu_progress_print(((float) chunk / progress_base) * 100, 100);
101
diff --git a/block/qed.c b/block/qed.c
269
}
102
index XXXXXXX..XXXXXXX 100644
270
}
103
--- a/block/qed.c
104
+++ b/block/qed.c
105
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l1_update(void *opaque, int ret)
106
index = qed_l1_index(s, acb->cur_pos);
107
s->l1_table->offsets[index] = acb->request.l2_table->offset;
108
109
- qed_write_l1_table(s, index, 1, qed_commit_l2_update, acb);
110
+ ret = qed_write_l1_table(s, index, 1);
111
+ qed_commit_l2_update(acb, ret);
112
}
113
114
/**
115
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
116
117
if (need_alloc) {
118
/* Write out the whole new L2 table */
119
- qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true,
120
- qed_aio_write_l1_update, acb);
121
+ ret = qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true);
122
+ qed_aio_write_l1_update(acb, ret);
123
} else {
124
/* Write out only the updated part of the L2 table */
125
- qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters, false,
126
- qed_aio_next_io_cb, acb);
127
+ ret = qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters,
128
+ false);
129
+ qed_aio_next_io(acb, ret);
130
}
131
return;
132
133
diff --git a/block/qed.h b/block/qed.h
134
index XXXXXXX..XXXXXXX 100644
135
--- a/block/qed.h
136
+++ b/block/qed.h
137
@@ -XXX,XX +XXX,XX @@ void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
138
* Table I/O functions
139
*/
140
int qed_read_l1_table_sync(BDRVQEDState *s);
141
-void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
142
- BlockCompletionFunc *cb, void *opaque);
143
+int qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n);
144
int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
145
unsigned int n);
146
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
147
uint64_t offset);
148
int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset);
149
-void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
150
- unsigned int index, unsigned int n, bool flush,
151
- BlockCompletionFunc *cb, void *opaque);
152
+int qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
153
+ unsigned int index, unsigned int n, bool flush);
154
int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
155
unsigned int index, unsigned int n, bool flush);
156
271
157
--
272
--
158
1.8.3.1
273
2.13.6
159
274
160
275
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
This patch splits do_perform_cow() into three separate functions to
3
Any device that has request_alignment greater than 512 should be
4
read, encrypt and write the COW regions.
4
unable to report status at a finer granularity; it may also be
5
simpler for such devices to be guaranteed that the block layer
6
has rounded things out to the granularity boundary (the way the
7
block layer already rounds all other I/O out). Besides, getting
8
the code correct for super-sector alignment also benefits us
9
for the fact that our public interface now has byte granularity,
10
even though none of our drivers have byte-level callbacks.
5
11
6
perform_cow() can now read both regions first, then encrypt them and
12
Add an assertion in blkdebug that proves that the block layer
7
finally write them to disk. The memory allocation is also done in
13
never requests status of unaligned sections, similar to what it
8
this function now, using one single buffer large enough to hold both
14
does on other requests (while still keeping the generic helper
9
regions.
15
in place for when future patches add a throttle driver). Note
16
that iotest 177 already covers this (it would fail if you use
17
just the blkdebug.c hunk without the io.c changes). Meanwhile,
18
we can drop assertions in callers that no longer have to pass
19
in sector-aligned addresses.
10
20
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
21
There is a mid-function scope added for 'count' and 'longret',
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
22
for a couple of reasons: first, an upcoming patch will add an
23
'if' statement that checks whether a driver has an old- or
24
new-style callback, and can conveniently use the same scope for
25
less indentation churn at that time. Second, since we are
26
trying to get rid of sector-based computations, wrapping things
27
in a scope makes it easier to group and see what will be
28
deleted in a final cleanup patch once all drivers have been
29
converted to the new-style callback.
30
31
Signed-off-by: Eric Blake <eblake@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
32
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
33
---
15
block/qcow2-cluster.c | 117 +++++++++++++++++++++++++++++++++++++-------------
34
include/block/block_int.h | 3 +-
16
1 file changed, 87 insertions(+), 30 deletions(-)
35
block/blkdebug.c | 13 ++++++++-
36
block/io.c | 71 ++++++++++++++++++++++++++++++-----------------
37
3 files changed, 59 insertions(+), 28 deletions(-)
17
38
18
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
39
diff --git a/include/block/block_int.h b/include/block/block_int.h
19
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2-cluster.c
41
--- a/include/block/block_int.h
21
+++ b/block/qcow2-cluster.c
42
+++ b/include/block/block_int.h
22
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
43
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
23
return 0;
44
* according to the current layer, and should not set
45
* BDRV_BLOCK_ALLOCATED, but may set BDRV_BLOCK_RAW. See block.h
46
* for the meaning of _DATA, _ZERO, and _OFFSET_VALID. The block
47
- * layer guarantees non-NULL pnum and file.
48
+ * layer guarantees input aligned to request_alignment, as well as
49
+ * non-NULL pnum and file.
50
*/
51
int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs,
52
int64_t sector_num, int nb_sectors, int *pnum,
53
diff --git a/block/blkdebug.c b/block/blkdebug.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/blkdebug.c
56
+++ b/block/blkdebug.c
57
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
58
return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
24
}
59
}
25
60
26
-static int coroutine_fn do_perform_cow(BlockDriverState *bs,
61
+static int64_t coroutine_fn blkdebug_co_get_block_status(
27
- uint64_t src_cluster_offset,
62
+ BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
28
- uint64_t cluster_offset,
63
+ BlockDriverState **file)
29
- unsigned offset_in_cluster,
64
+{
30
- unsigned bytes)
65
+ assert(QEMU_IS_ALIGNED(sector_num | nb_sectors,
31
+static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
66
+ DIV_ROUND_UP(bs->bl.request_alignment,
32
+ uint64_t src_cluster_offset,
67
+ BDRV_SECTOR_SIZE)));
33
+ unsigned offset_in_cluster,
68
+ return bdrv_co_get_block_status_from_file(bs, sector_num, nb_sectors,
34
+ uint8_t *buffer,
69
+ pnum, file);
35
+ unsigned bytes)
36
{
37
- BDRVQcow2State *s = bs->opaque;
38
QEMUIOVector qiov;
39
- struct iovec iov;
40
+ struct iovec iov = { .iov_base = buffer, .iov_len = bytes };
41
int ret;
42
43
if (bytes == 0) {
44
return 0;
45
}
46
47
- iov.iov_len = bytes;
48
- iov.iov_base = qemu_try_blockalign(bs, iov.iov_len);
49
- if (iov.iov_base == NULL) {
50
- return -ENOMEM;
51
- }
52
-
53
qemu_iovec_init_external(&qiov, &iov, 1);
54
55
BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
56
57
if (!bs->drv) {
58
- ret = -ENOMEDIUM;
59
- goto out;
60
+ return -ENOMEDIUM;
61
}
62
63
/* Call .bdrv_co_readv() directly instead of using the public block-layer
64
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow(BlockDriverState *bs,
65
ret = bs->drv->bdrv_co_preadv(bs, src_cluster_offset + offset_in_cluster,
66
bytes, &qiov, 0);
67
if (ret < 0) {
68
- goto out;
69
+ return ret;
70
}
71
72
- if (bs->encrypted) {
73
+ return 0;
74
+}
70
+}
75
+
71
+
76
+static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
72
static void blkdebug_close(BlockDriverState *bs)
77
+ uint64_t src_cluster_offset,
73
{
78
+ unsigned offset_in_cluster,
74
BDRVBlkdebugState *s = bs->opaque;
79
+ uint8_t *buffer,
75
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
80
+ unsigned bytes)
76
.bdrv_co_flush_to_disk = blkdebug_co_flush,
81
+{
77
.bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes,
82
+ if (bytes && bs->encrypted) {
78
.bdrv_co_pdiscard = blkdebug_co_pdiscard,
83
+ BDRVQcow2State *s = bs->opaque;
79
- .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
84
int64_t sector = (src_cluster_offset + offset_in_cluster)
80
+ .bdrv_co_get_block_status = blkdebug_co_get_block_status,
85
>> BDRV_SECTOR_BITS;
81
86
assert(s->cipher);
82
.bdrv_debug_event = blkdebug_debug_event,
87
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
83
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
88
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
84
diff --git a/block/io.c b/block/io.c
89
- if (qcow2_encrypt_sectors(s, sector, iov.iov_base, iov.iov_base,
85
index XXXXXXX..XXXXXXX 100644
90
+ if (qcow2_encrypt_sectors(s, sector, buffer, buffer,
86
--- a/block/io.c
91
bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) {
87
+++ b/block/io.c
92
- ret = -EIO;
88
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
93
- goto out;
89
{
94
+ return false;
90
int64_t total_size;
95
}
91
int64_t n; /* bytes */
92
- int64_t ret;
93
+ int ret;
94
int64_t local_map = 0;
95
BlockDriverState *local_file = NULL;
96
- int count; /* sectors */
97
+ int64_t aligned_offset, aligned_bytes;
98
+ uint32_t align;
99
100
assert(pnum);
101
*pnum = 0;
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
96
}
103
}
97
+ return true;
104
98
+}
105
bdrv_inc_in_flight(bs);
99
+
106
+
100
+static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
107
+ /* Round out to request_alignment boundaries */
101
+ uint64_t cluster_offset,
108
+ /* TODO: until we have a byte-based driver callback, we also have to
102
+ unsigned offset_in_cluster,
109
+ * round out to sectors, even if that is bigger than request_alignment */
103
+ uint8_t *buffer,
110
+ align = MAX(bs->bl.request_alignment, BDRV_SECTOR_SIZE);
104
+ unsigned bytes)
111
+ aligned_offset = QEMU_ALIGN_DOWN(offset, align);
105
+{
112
+ aligned_bytes = ROUND_UP(offset + bytes, align) - aligned_offset;
106
+ QEMUIOVector qiov;
107
+ struct iovec iov = { .iov_base = buffer, .iov_len = bytes };
108
+ int ret;
109
+
113
+
110
+ if (bytes == 0) {
114
+ {
111
+ return 0;
115
+ int count; /* sectors */
116
+ int64_t longret;
117
+
118
+ assert(QEMU_IS_ALIGNED(aligned_offset | aligned_bytes,
119
+ BDRV_SECTOR_SIZE));
120
+ /*
121
+ * The contract allows us to return pnum smaller than bytes, even
122
+ * if the next query would see the same status; we truncate the
123
+ * request to avoid overflowing the driver's 32-bit interface.
124
+ */
125
+ longret = bs->drv->bdrv_co_get_block_status(
126
+ bs, aligned_offset >> BDRV_SECTOR_BITS,
127
+ MIN(INT_MAX, aligned_bytes) >> BDRV_SECTOR_BITS, &count,
128
+ &local_file);
129
+ if (longret < 0) {
130
+ assert(INT_MIN <= longret);
131
+ ret = longret;
132
+ goto out;
133
+ }
134
+ if (longret & BDRV_BLOCK_OFFSET_VALID) {
135
+ local_map = longret & BDRV_BLOCK_OFFSET_MASK;
136
+ }
137
+ ret = longret & ~BDRV_BLOCK_OFFSET_MASK;
138
+ *pnum = count * BDRV_SECTOR_SIZE;
112
+ }
139
+ }
113
+
140
+
114
+ qemu_iovec_init_external(&qiov, &iov, 1);
141
/*
115
142
- * TODO: Rather than require aligned offsets, we could instead
116
ret = qcow2_pre_write_overlap_check(bs, 0,
143
- * round to the driver's request_alignment here, then touch up
117
cluster_offset + offset_in_cluster, bytes);
144
- * count afterwards back to the caller's expectations.
118
if (ret < 0) {
145
- */
146
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
147
- /*
148
- * The contract allows us to return pnum smaller than bytes, even
149
- * if the next query would see the same status; we truncate the
150
- * request to avoid overflowing the driver's 32-bit interface.
151
+ * The driver's result must be a multiple of request_alignment.
152
+ * Clamp pnum and adjust map to original request.
153
*/
154
- bytes = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
155
- ret = bs->drv->bdrv_co_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
156
- bytes >> BDRV_SECTOR_BITS, &count,
157
- &local_file);
158
- if (ret < 0) {
119
- goto out;
159
- goto out;
120
+ return ret;
160
+ assert(QEMU_IS_ALIGNED(*pnum, align) && align > offset - aligned_offset);
161
+ *pnum -= offset - aligned_offset;
162
+ if (*pnum > bytes) {
163
+ *pnum = bytes;
121
}
164
}
122
165
if (ret & BDRV_BLOCK_OFFSET_VALID) {
123
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
166
- local_map = ret & BDRV_BLOCK_OFFSET_MASK;
124
ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
167
+ local_map += offset - aligned_offset;
125
bytes, &qiov, 0);
126
if (ret < 0) {
127
- goto out;
128
+ return ret;
129
}
168
}
130
169
- *pnum = count * BDRV_SECTOR_SIZE;
131
- ret = 0;
170
132
-out:
171
if (ret & BDRV_BLOCK_RAW) {
133
- qemu_vfree(iov.iov_base);
172
assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
134
- return ret;
173
ret = bdrv_co_block_status(local_file, want_zero, local_map,
135
+ return 0;
174
*pnum, pnum, &local_map, &local_file);
136
}
175
- assert(ret < 0 ||
137
176
- QEMU_IS_ALIGNED(*pnum | local_map, BDRV_SECTOR_SIZE));
138
177
goto out;
139
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
140
BDRVQcow2State *s = bs->opaque;
141
Qcow2COWRegion *start = &m->cow_start;
142
Qcow2COWRegion *end = &m->cow_end;
143
+ unsigned buffer_size;
144
+ uint8_t *start_buffer, *end_buffer;
145
int ret;
146
147
+ assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
148
+
149
if (start->nb_bytes == 0 && end->nb_bytes == 0) {
150
return 0;
151
}
178
}
152
179
153
+ /* Reserve a buffer large enough to store the data from both the
180
@@ -XXX,XX +XXX,XX @@ early_out:
154
+ * start and end COW regions. Add some padding in the middle if
181
if (map) {
155
+ * necessary to make sure that the end region is optimally aligned */
182
*map = local_map;
156
+ buffer_size = QEMU_ALIGN_UP(start->nb_bytes, bdrv_opt_mem_align(bs)) +
157
+ end->nb_bytes;
158
+ start_buffer = qemu_try_blockalign(bs, buffer_size);
159
+ if (start_buffer == NULL) {
160
+ return -ENOMEM;
161
+ }
162
+ /* The part of the buffer where the end region is located */
163
+ end_buffer = start_buffer + buffer_size - end->nb_bytes;
164
+
165
qemu_co_mutex_unlock(&s->lock);
166
- ret = do_perform_cow(bs, m->offset, m->alloc_offset,
167
- start->offset, start->nb_bytes);
168
+ /* First we read the existing data from both COW regions */
169
+ ret = do_perform_cow_read(bs, m->offset, start->offset,
170
+ start_buffer, start->nb_bytes);
171
if (ret < 0) {
172
goto fail;
173
}
183
}
174
184
- if (ret >= 0) {
175
- ret = do_perform_cow(bs, m->offset, m->alloc_offset,
185
- ret &= ~BDRV_BLOCK_OFFSET_MASK;
176
- end->offset, end->nb_bytes);
186
- } else {
177
+ ret = do_perform_cow_read(bs, m->offset, end->offset,
187
- assert(INT_MIN <= ret);
178
+ end_buffer, end->nb_bytes);
188
- }
179
+ if (ret < 0) {
180
+ goto fail;
181
+ }
182
+
183
+ /* Encrypt the data if necessary before writing it */
184
+ if (bs->encrypted) {
185
+ if (!do_perform_cow_encrypt(bs, m->offset, start->offset,
186
+ start_buffer, start->nb_bytes) ||
187
+ !do_perform_cow_encrypt(bs, m->offset, end->offset,
188
+ end_buffer, end->nb_bytes)) {
189
+ ret = -EIO;
190
+ goto fail;
191
+ }
192
+ }
193
+
194
+ /* And now we can write everything */
195
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset,
196
+ start_buffer, start->nb_bytes);
197
+ if (ret < 0) {
198
+ goto fail;
199
+ }
200
201
+ ret = do_perform_cow_write(bs, m->alloc_offset, end->offset,
202
+ end_buffer, end->nb_bytes);
203
fail:
204
qemu_co_mutex_lock(&s->lock);
205
206
@@ -XXX,XX +XXX,XX @@ fail:
207
qcow2_cache_depends_on_flush(s->l2_table_cache);
208
}
209
210
+ qemu_vfree(start_buffer);
211
return ret;
189
return ret;
212
}
190
}
213
191
214
--
192
--
215
1.8.3.1
193
2.13.6
216
194
217
195
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
AioContext was designed to allow nested acquire/release calls. It uses
3
Now that bdrv_is_allocated accepts non-aligned inputs, we can
4
a recursive mutex so callers don't need to worry about nesting...or so
4
remove the TODO added in commit d6a644bb.
5
we thought.
6
5
7
BDRV_POLL_WHILE() is used to wait for block I/O requests. It releases
6
Signed-off-by: Eric Blake <eblake@redhat.com>
8
the AioContext temporarily around aio_poll(). This gives IOThreads a
7
Reviewed-by: John Snow <jsnow@redhat.com>
9
chance to acquire the AioContext to process I/O completions.
10
11
It turns out that recursive locking and BDRV_POLL_WHILE() don't mix.
12
BDRV_POLL_WHILE() only releases the AioContext once, so the IOThread
13
will not be able to acquire the AioContext if it was acquired
14
multiple times.
15
16
Instead of trying to release AioContext n times in BDRV_POLL_WHILE(),
17
this patch simply avoids nested locking in save_vmstate(). It's the
18
simplest fix and we should step back to consider the big picture with
19
all the recent changes to block layer threading.
20
21
This patch is the final fix to solve 'savevm' hanging with -object
22
iothread.
23
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
Reviewed-by: Eric Blake <eblake@redhat.com>
26
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
---
9
---
29
migration/savevm.c | 12 +++++++++++-
10
block/io.c | 8 ++------
30
1 file changed, 11 insertions(+), 1 deletion(-)
11
1 file changed, 2 insertions(+), 6 deletions(-)
31
12
32
diff --git a/migration/savevm.c b/migration/savevm.c
13
diff --git a/block/io.c b/block/io.c
33
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
34
--- a/migration/savevm.c
15
--- a/block/io.c
35
+++ b/migration/savevm.c
16
+++ b/block/io.c
36
@@ -XXX,XX +XXX,XX @@ int save_snapshot(const char *name, Error **errp)
17
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
37
goto the_end;
38
}
18
}
39
19
40
+ /* The bdrv_all_create_snapshot() call that follows acquires the AioContext
20
if (flags & BDRV_REQ_COPY_ON_READ) {
41
+ * for itself. BDRV_POLL_WHILE() does not support nested locking because
21
- /* TODO: Simplify further once bdrv_is_allocated no longer
42
+ * it only releases the lock once. Therefore synchronous I/O will deadlock
22
- * requires sector alignment */
43
+ * unless we release the AioContext before bdrv_all_create_snapshot().
23
- int64_t start = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
44
+ */
24
- int64_t end = QEMU_ALIGN_UP(offset + bytes, BDRV_SECTOR_SIZE);
45
+ aio_context_release(aio_context);
25
int64_t pnum;
46
+ aio_context = NULL;
26
47
+
27
- ret = bdrv_is_allocated(bs, start, end - start, &pnum);
48
ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, &bs);
28
+ ret = bdrv_is_allocated(bs, offset, bytes, &pnum);
49
if (ret < 0) {
29
if (ret < 0) {
50
error_setg(errp, "Error while creating snapshot on '%s'",
30
goto out;
51
@@ -XXX,XX +XXX,XX @@ int save_snapshot(const char *name, Error **errp)
31
}
52
ret = 0;
32
53
33
- if (!ret || pnum != end - start) {
54
the_end:
34
+ if (!ret || pnum != bytes) {
55
- aio_context_release(aio_context);
35
ret = bdrv_co_do_copy_on_readv(child, offset, bytes, qiov);
56
+ if (aio_context) {
36
goto out;
57
+ aio_context_release(aio_context);
37
}
58
+ }
59
if (saved_vm_running) {
60
vm_start();
61
}
62
--
38
--
63
1.8.3.1
39
2.13.6
64
40
65
41
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
We already have functions for doing these calculations, so let's use
3
Now that bdrv_is_allocated accepts non-aligned inputs, we can
4
them instead of doing everything by hand. This makes the code a bit
4
remove the TODO added in earlier refactoring.
5
more readable.
6
5
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
Signed-off-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
8
---
10
block/qcow2-cluster.c | 4 ++--
9
block/qcow2.c | 12 +++---------
11
block/qcow2.c | 2 +-
10
1 file changed, 3 insertions(+), 9 deletions(-)
12
2 files changed, 3 insertions(+), 3 deletions(-)
13
11
14
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qcow2-cluster.c
17
+++ b/block/qcow2-cluster.c
18
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
19
20
/* find the cluster offset for the given disk offset */
21
22
- l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
23
+ l2_index = offset_to_l2_index(s, offset);
24
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
25
26
nb_clusters = size_to_clusters(s, bytes_needed);
27
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
28
29
/* find the cluster offset for the given disk offset */
30
31
- l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
32
+ l2_index = offset_to_l2_index(s, offset);
33
34
*new_l2_table = l2_table;
35
*new_l2_index = l2_index;
36
diff --git a/block/qcow2.c b/block/qcow2.c
12
diff --git a/block/qcow2.c b/block/qcow2.c
37
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
38
--- a/block/qcow2.c
14
--- a/block/qcow2.c
39
+++ b/block/qcow2.c
15
+++ b/block/qcow2.c
40
@@ -XXX,XX +XXX,XX @@ static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
16
@@ -XXX,XX +XXX,XX @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
17
{
18
int64_t nr;
19
int res;
20
- int64_t start;
21
-
22
- /* TODO: Widening to sector boundaries should only be needed as
23
- * long as we can't query finer granularity. */
24
- start = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
25
- bytes = QEMU_ALIGN_UP(offset + bytes, BDRV_SECTOR_SIZE) - start;
26
27
/* Clamp to image length, before checking status of underlying sectors */
28
- if (start + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) {
29
- bytes = bs->total_sectors * BDRV_SECTOR_SIZE - start;
30
+ if (offset + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) {
31
+ bytes = bs->total_sectors * BDRV_SECTOR_SIZE - offset;
41
}
32
}
42
33
43
/* Tables must be cluster aligned */
34
if (!bytes) {
44
- if (offset & (s->cluster_size - 1)) {
35
return true;
45
+ if (offset_into_cluster(s, offset) != 0) {
46
return -EINVAL;
47
}
36
}
37
- res = bdrv_block_status_above(bs, NULL, start, bytes, &nr, NULL, NULL);
38
+ res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
39
return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == bytes;
40
}
48
41
49
--
42
--
50
1.8.3.1
43
2.13.6
51
44
52
45
diff view generated by jsdifflib
1
Don't recurse into qed_aio_next_io() and qed_aio_complete() here, but
1
From: Eric Blake <eblake@redhat.com>
2
just return an error code and let the caller handle it.
3
2
4
While refactoring qed_aio_write_alloc() to accomodate the change,
3
Previously, the alloc command required that input parameters be
5
qed_aio_write_zero_cluster() ended up with a single line, so I chose to
4
sector-aligned and clamped to 32 bits, because the underlying
6
inline that line and remove the function completely.
5
bdrv_is_allocated used a 32-bit parameter and asserted aligned
6
inputs. But now that we have fixed block status to report a
7
64-bit bytes value, and to properly round requests on behalf of
8
guests, we can pass any values, and can use qemu-io to add
9
coverage that our rounding is correct regardless of the guest
10
alignment constraints.
7
11
12
Update iotest 177 to intentionally probe block status at
13
unaligned boundaries as well as with a bytes value that does not
14
map to 32-bit sectors, which also required tweaking the image
15
prep to leave an unallocated portion to the image under test.
16
17
Signed-off-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
19
---
11
block/qed.c | 58 +++++++++++++++++++++-------------------------------------
20
qemu-io-cmds.c | 13 -------------
12
1 file changed, 21 insertions(+), 37 deletions(-)
21
tests/qemu-iotests/177 | 12 ++++++++++--
22
tests/qemu-iotests/177.out | 19 ++++++++++++++-----
23
3 files changed, 24 insertions(+), 20 deletions(-)
13
24
14
diff --git a/block/qed.c b/block/qed.c
25
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
15
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qed.c
27
--- a/qemu-io-cmds.c
17
+++ b/block/qed.c
28
+++ b/qemu-io-cmds.c
18
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_main(QEDAIOCB *acb)
29
@@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv)
19
/**
30
if (offset < 0) {
20
* Populate untouched regions of new data cluster
31
print_cvtnum_err(offset, argv[1]);
21
*/
32
return 0;
22
-static void qed_aio_write_cow(void *opaque, int ret)
33
- } else if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
23
+static int qed_aio_write_cow(QEDAIOCB *acb)
34
- printf("%" PRId64 " is not a sector-aligned value for 'offset'\n",
24
{
35
- offset);
25
- QEDAIOCB *acb = opaque;
36
- return 0;
26
BDRVQEDState *s = acb_to_s(acb);
27
uint64_t start, len, offset;
28
+ int ret;
29
30
/* Populate front untouched region of new data cluster */
31
start = qed_start_of_cluster(s, acb->cur_pos);
32
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_cow(void *opaque, int ret)
33
34
trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
35
ret = qed_copy_from_backing_file(s, start, len, acb->cur_cluster);
36
- if (ret) {
37
- qed_aio_complete(acb, ret);
38
- return;
39
+ if (ret < 0) {
40
+ return ret;
41
}
37
}
42
38
43
/* Populate back untouched region of new data cluster */
39
if (argc == 3) {
44
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_cow(void *opaque, int ret)
40
@@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv)
45
41
if (count < 0) {
46
trace_qed_aio_write_postfill(s, acb, start, len, offset);
42
print_cvtnum_err(count, argv[2]);
47
ret = qed_copy_from_backing_file(s, start, len, offset);
43
return 0;
48
- if (ret) {
44
- } else if (count > INT_MAX * BDRV_SECTOR_SIZE) {
49
- qed_aio_complete(acb, ret);
45
- printf("length argument cannot exceed %llu, given %s\n",
50
- return;
46
- INT_MAX * BDRV_SECTOR_SIZE, argv[2]);
47
- return 0;
48
}
49
} else {
50
count = BDRV_SECTOR_SIZE;
51
}
52
- if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) {
53
- printf("%" PRId64 " is not a sector-aligned value for 'count'\n",
54
- count);
55
- return 0;
51
- }
56
- }
52
-
57
53
- ret = qed_aio_write_main(acb);
58
remaining = count;
54
if (ret < 0) {
59
sum_alloc = 0;
55
- qed_aio_complete(acb, ret);
60
diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177
56
- return;
61
index XXXXXXX..XXXXXXX 100755
57
+ return ret;
62
--- a/tests/qemu-iotests/177
58
}
63
+++ b/tests/qemu-iotests/177
59
- qed_aio_next_io(acb, 0);
64
@@ -XXX,XX +XXX,XX @@ echo "== setting up files =="
65
TEST_IMG="$TEST_IMG.base" _make_test_img $size
66
$QEMU_IO -c "write -P 11 0 $size" "$TEST_IMG.base" | _filter_qemu_io
67
_make_test_img -b "$TEST_IMG.base"
68
-$QEMU_IO -c "write -P 22 0 $size" "$TEST_IMG" | _filter_qemu_io
69
+$QEMU_IO -c "write -P 22 0 110M" "$TEST_IMG" | _filter_qemu_io
70
71
# Limited to 64k max-transfer
72
echo
73
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
74
-c "discard 80000001 30M" | _filter_qemu_io
75
76
echo
77
+echo "== block status smaller than alignment =="
78
+limits=align=4k
79
+$QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \
80
+     -c "alloc 1 1" -c "alloc 0x6dffff0 1000" -c "alloc 127m 5P" \
81
+     -c map | _filter_qemu_io
60
+
82
+
61
+ return qed_aio_write_main(acb);
83
+echo
84
echo "== verify image content =="
85
86
function verify_io()
87
@@ -XXX,XX +XXX,XX @@ function verify_io()
88
echo read -P 0 32M 32M
89
echo read -P 22 64M 13M
90
echo read -P $discarded 77M 29M
91
- echo read -P 22 106M 22M
92
+ echo read -P 22 106M 4M
93
+ echo read -P 11 110M 18M
62
}
94
}
63
95
64
/**
96
verify_io | $QEMU_IO -r "$TEST_IMG" | _filter_qemu_io
65
@@ -XXX,XX +XXX,XX @@ static bool qed_should_set_need_check(BDRVQEDState *s)
97
diff --git a/tests/qemu-iotests/177.out b/tests/qemu-iotests/177.out
66
return !(s->header.features & QED_F_NEED_CHECK);
98
index XXXXXXX..XXXXXXX 100644
67
}
99
--- a/tests/qemu-iotests/177.out
68
100
+++ b/tests/qemu-iotests/177.out
69
-static void qed_aio_write_zero_cluster(void *opaque, int ret)
101
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
70
-{
102
wrote 134217728/134217728 bytes at offset 0
71
- QEDAIOCB *acb = opaque;
103
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
72
-
104
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
73
- if (ret) {
105
-wrote 134217728/134217728 bytes at offset 0
74
- qed_aio_complete(acb, ret);
106
-128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
75
- return;
107
+wrote 115343360/115343360 bytes at offset 0
76
- }
108
+110 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
77
-
109
78
- ret = qed_aio_write_l2_update(acb, 1);
110
== constrained alignment and max-transfer ==
79
- if (ret < 0) {
111
wrote 131072/131072 bytes at offset 1000
80
- qed_aio_complete(acb, ret);
112
@@ -XXX,XX +XXX,XX @@ wrote 33554432/33554432 bytes at offset 33554432
81
- return;
113
discard 31457280/31457280 bytes at offset 80000001
82
- }
114
30 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
83
- qed_aio_next_io(acb, 0);
115
84
-}
116
+== block status smaller than alignment ==
85
-
117
+1/1 bytes allocated at offset 1 bytes
86
/**
118
+16/1000 bytes allocated at offset 110 MiB
87
* Write new data cluster
119
+0/1048576 bytes allocated at offset 127 MiB
88
*
120
+110 MiB (0x6e00000) bytes allocated at offset 0 bytes (0x0)
89
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_zero_cluster(void *opaque, int ret)
121
+18 MiB (0x1200000) bytes not allocated at offset 110 MiB (0x6e00000)
90
static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
91
{
92
BDRVQEDState *s = acb_to_s(acb);
93
- BlockCompletionFunc *cb;
94
int ret;
95
96
/* Cancel timer when the first allocating request comes in */
97
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
98
qed_aio_start_io(acb);
99
return;
100
}
101
-
102
- cb = qed_aio_write_zero_cluster;
103
} else {
104
- cb = qed_aio_write_cow;
105
acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
106
}
107
108
if (qed_should_set_need_check(s)) {
109
s->header.features |= QED_F_NEED_CHECK;
110
ret = qed_write_header(s);
111
- cb(acb, ret);
112
+ if (ret < 0) {
113
+ qed_aio_complete(acb, ret);
114
+ return;
115
+ }
116
+ }
117
+
122
+
118
+ if (acb->flags & QED_AIOCB_ZERO) {
123
== verify image content ==
119
+ ret = qed_aio_write_l2_update(acb, 1);
124
read 1000/1000 bytes at offset 0
120
} else {
125
1000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
121
- cb(acb, 0);
126
@@ -XXX,XX +XXX,XX @@ read 13631488/13631488 bytes at offset 67108864
122
+ ret = qed_aio_write_cow(acb);
127
13 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
123
}
128
read 30408704/30408704 bytes at offset 80740352
124
+ if (ret < 0) {
129
29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
125
+ qed_aio_complete(acb, ret);
130
-read 23068672/23068672 bytes at offset 111149056
126
+ return;
131
-22 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
127
+ }
132
+read 4194304/4194304 bytes at offset 111149056
128
+ qed_aio_next_io(acb, 0);
133
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
129
}
134
+read 18874368/18874368 bytes at offset 115343360
130
135
+18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
131
/**
136
Offset Length File
137
0 0x800000 TEST_DIR/t.IMGFMT
138
0x900000 0x2400000 TEST_DIR/t.IMGFMT
139
0x3c00000 0x1100000 TEST_DIR/t.IMGFMT
140
-0x6a00000 0x1600000 TEST_DIR/t.IMGFMT
141
+0x6a00000 0x400000 TEST_DIR/t.IMGFMT
142
No errors were found on the image.
143
*** done
132
--
144
--
133
1.8.3.1
145
2.13.6
134
146
135
147
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
Old kvm.ko versions only supported a tiny number of ioeventfds so
3
qemu-img commit invalidates all images between base and top. This
4
virtio-pci avoids ioeventfds when kvm_has_many_ioeventfds() returns 0.
4
should be mentioned in the man page.
5
5
6
Do not check kvm_has_many_ioeventfds() when KVM is disabled since it
6
Suggested-by: Ping Li <pingl@redhat.com>
7
always returns 0. Since commit 8c56c1a592b5092d91da8d8943c17777d6462a6f
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
("memory: emulate ioeventfd") it has been possible to use ioeventfds in
8
Reviewed-by: Jeff Cody <jcody@redhat.com>
9
qtest or TCG mode.
10
11
This patch makes -device virtio-blk-pci,iothread=iothread0 work even
12
when KVM is disabled.
13
14
I have tested that virtio-blk-pci works under TCG both with and without
15
iothread.
16
17
Cc: Michael S. Tsirkin <mst@redhat.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
10
---
22
hw/virtio/virtio-pci.c | 2 +-
11
qemu-img.texi | 9 ++++-----
23
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 4 insertions(+), 5 deletions(-)
24
13
25
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
14
diff --git a/qemu-img.texi b/qemu-img.texi
26
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/virtio/virtio-pci.c
16
--- a/qemu-img.texi
28
+++ b/hw/virtio/virtio-pci.c
17
+++ b/qemu-img.texi
29
@@ -XXX,XX +XXX,XX @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
18
@@ -XXX,XX +XXX,XX @@ If the backing chain of the given image file @var{filename} has more than one
30
bool pcie_port = pci_bus_is_express(pci_dev->bus) &&
19
layer, the backing file into which the changes will be committed may be
31
!pci_bus_is_root(pci_dev->bus);
20
specified as @var{base} (which has to be part of @var{filename}'s backing
32
21
chain). If @var{base} is not specified, the immediate backing file of the top
33
- if (!kvm_has_many_ioeventfds()) {
22
-image (which is @var{filename}) will be used. For reasons of consistency,
34
+ if (kvm_enabled() && !kvm_has_many_ioeventfds()) {
23
-explicitly specifying @var{base} will always imply @code{-d} (since emptying an
35
proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
24
-image after committing to an indirect backing file would lead to different data
36
}
25
-being read from the image due to content in the intermediate backing chain
26
-overruling the commit target).
27
+image (which is @var{filename}) will be used. Note that after a commit operation
28
+all images between @var{base} and the top image will be invalid and may return
29
+garbage data when read. For this reason, @code{-b} implies @code{-d} (so that
30
+the top image stays valid).
31
32
@item compare [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-s] [-q] @var{filename1} @var{filename2}
37
33
38
--
34
--
39
1.8.3.1
35
2.13.6
40
36
41
37
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
There used to be throttle_timers_{detach,attach}_aio_context() calls
3
BDRV_SECTOR_BITS is defined to be 9 in block.h (and BDRV_SECTOR_SIZE
4
in bdrv_set_aio_context(), but since 7ca7f0f6db1fedd28d490795d778cf239
4
is calculated from that), but there are still a couple of places where
5
they are now in blk_set_aio_context().
5
we are using the literal value instead of the macro.
6
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-id: 20171009153856.20387-1-berto@igalia.com
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
10
---
11
block/throttle-groups.c | 2 +-
11
block/qcow2.c | 4 ++--
12
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 2 insertions(+), 2 deletions(-)
13
13
14
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
14
diff --git a/block/qcow2.c b/block/qcow2.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/throttle-groups.c
16
--- a/block/qcow2.c
17
+++ b/block/throttle-groups.c
17
+++ b/block/qcow2.c
18
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
19
* Again, all this is handled internally and is mostly transparent to
19
20
* the outside. The 'throttle_timers' field however has an additional
20
s->cluster_bits = header.cluster_bits;
21
* constraint because it may be temporarily invalid (see for example
21
s->cluster_size = 1 << s->cluster_bits;
22
- * bdrv_set_aio_context()). Therefore in this file a thread will
22
- s->cluster_sectors = 1 << (s->cluster_bits - 9);
23
+ * blk_set_aio_context()). Therefore in this file a thread will
23
+ s->cluster_sectors = 1 << (s->cluster_bits - BDRV_SECTOR_BITS);
24
* access some other BlockBackend's timers only after verifying that
24
25
* that BlockBackend has throttled requests in the queue.
25
/* Initialise version 3 header fields */
26
*/
26
if (header.version == 2) {
27
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
28
29
bytes = MIN(INT_MAX, nb_sectors * BDRV_SECTOR_SIZE);
30
qemu_co_mutex_lock(&s->lock);
31
- ret = qcow2_get_cluster_offset(bs, sector_num << 9, &bytes,
32
+ ret = qcow2_get_cluster_offset(bs, sector_num << BDRV_SECTOR_BITS, &bytes,
33
&cluster_offset);
34
qemu_co_mutex_unlock(&s->lock);
35
if (ret < 0) {
27
--
36
--
28
1.8.3.1
37
2.13.6
29
38
30
39
diff view generated by jsdifflib
1
When qemu is exited, all running jobs should be cancelled successfully.
1
From: Max Reitz <mreitz@redhat.com>
2
This adds a test for this for all types of block jobs that currently
3
exist in qemu.
4
2
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Message-id: 20170929170843.3711-1-mreitz@redhat.com
6
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
7
---
8
tests/qemu-iotests/185 | 206 +++++++++++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/127 | 97 ++++++++++++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/185.out | 59 +++++++++++++
9
tests/qemu-iotests/127.out | 14 +++++++
10
tests/qemu-iotests/group | 1 +
10
tests/qemu-iotests/group | 1 +
11
3 files changed, 266 insertions(+)
11
3 files changed, 112 insertions(+)
12
create mode 100755 tests/qemu-iotests/185
12
create mode 100755 tests/qemu-iotests/127
13
create mode 100644 tests/qemu-iotests/185.out
13
create mode 100644 tests/qemu-iotests/127.out
14
14
15
diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185
15
diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127
16
new file mode 100755
16
new file mode 100755
17
index XXXXXXX..XXXXXXX
17
index XXXXXXX..XXXXXXX
18
--- /dev/null
18
--- /dev/null
19
+++ b/tests/qemu-iotests/185
19
+++ b/tests/qemu-iotests/127
20
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@
21
+#!/bin/bash
21
+#!/bin/bash
22
+#
22
+#
23
+# Test exiting qemu while jobs are still running
23
+# Test case for mirroring with dataplane
24
+#
24
+#
25
+# Copyright (C) 2017 Red Hat, Inc.
25
+# Copyright (C) 2017 Red Hat, Inc.
26
+#
26
+#
27
+# This program is free software; you can redistribute it and/or modify
27
+# This program is free software; you can redistribute it and/or modify
28
+# it under the terms of the GNU General Public License as published by
28
+# it under the terms of the GNU General Public License as published by
...
...
37
+# You should have received a copy of the GNU General Public License
37
+# You should have received a copy of the GNU General Public License
38
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
38
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
39
+#
39
+#
40
+
40
+
41
+# creator
41
+# creator
42
+owner=kwolf@redhat.com
42
+owner=mreitz@redhat.com
43
+
43
+
44
+seq=`basename $0`
44
+seq=$(basename $0)
45
+echo "QA output created by $seq"
45
+echo "QA output created by $seq"
46
+
46
+
47
+here=`pwd`
47
+here=$PWD
48
+status=1 # failure is the default!
48
+status=1 # failure is the default!
49
+
50
+MIG_SOCKET="${TEST_DIR}/migrate"
51
+
49
+
52
+_cleanup()
50
+_cleanup()
53
+{
51
+{
54
+ rm -f "${TEST_IMG}.mid"
52
+ _cleanup_qemu
55
+ rm -f "${TEST_IMG}.copy"
56
+ _cleanup_test_img
53
+ _cleanup_test_img
57
+ _cleanup_qemu
54
+ _rm_test_img "$TEST_IMG.overlay0"
55
+ _rm_test_img "$TEST_IMG.overlay1"
58
+}
56
+}
59
+trap "_cleanup; exit \$status" 0 1 2 3 15
57
+trap "_cleanup; exit \$status" 0 1 2 3 15
60
+
58
+
61
+# get standard environment, filters and checks
59
+# get standard environment, filters and qemu instance handling
62
+. ./common.rc
60
+. ./common.rc
63
+. ./common.filter
61
+. ./common.filter
64
+. ./common.qemu
62
+. ./common.qemu
65
+
63
+
66
+_supported_fmt qcow2
64
+_supported_fmt qcow2
67
+_supported_proto file
65
+_supported_proto file
68
+_supported_os Linux
66
+_supported_os Linux
69
+
67
+
70
+size=64M
68
+IMG_SIZE=64K
71
+TEST_IMG="${TEST_IMG}.base" _make_test_img $size
72
+
69
+
73
+echo
70
+_make_test_img $IMG_SIZE
74
+echo === Starting VM ===
71
+TEST_IMG="$TEST_IMG.overlay0" _make_test_img -b "$TEST_IMG" $IMG_SIZE
75
+echo
72
+TEST_IMG="$TEST_IMG.overlay1" _make_test_img -b "$TEST_IMG" $IMG_SIZE
76
+
73
+
77
+qemu_comm_method="qmp"
74
+# So that we actually have something to mirror and the job does not return
75
+# immediately (which may be bad because then we cannot know whether the
76
+# 'return' or the 'BLOCK_JOB_READY' comes first).
77
+$QEMU_IO -c 'write 0 42' "$TEST_IMG.overlay0" | _filter_qemu_io
78
+
78
+
79
+# We cannot use virtio-blk here because that does not actually set the attached
80
+# BB's AioContext in qtest mode
79
+_launch_qemu \
81
+_launch_qemu \
80
+ -drive file="${TEST_IMG}.base",cache=$CACHEMODE,driver=$IMGFMT,id=disk
82
+ -object iothread,id=iothr \
81
+h=$QEMU_HANDLE
83
+ -blockdev node-name=source,driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG.overlay0" \
82
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
84
+ -device virtio-scsi,id=scsi-bus,iothread=iothr \
85
+ -device scsi-hd,bus=scsi-bus.0,drive=source
83
+
86
+
84
+echo
87
+_send_qemu_cmd $QEMU_HANDLE \
85
+echo === Creating backing chain ===
88
+ "{ 'execute': 'qmp_capabilities' }" \
86
+echo
89
+ 'return'
87
+
90
+
88
+_send_qemu_cmd $h \
91
+_send_qemu_cmd $QEMU_HANDLE \
89
+ "{ 'execute': 'blockdev-snapshot-sync',
92
+ "{ 'execute': 'drive-mirror',
90
+ 'arguments': { 'device': 'disk',
93
+ 'arguments': {
91
+ 'snapshot-file': '$TEST_IMG.mid',
94
+ 'job-id': 'mirror',
92
+ 'format': '$IMGFMT',
95
+ 'device': 'source',
93
+ 'mode': 'absolute-paths' } }" \
96
+ 'target': '$TEST_IMG.overlay1',
94
+ "return"
97
+ 'mode': 'existing',
98
+ 'sync': 'top'
99
+ } }" \
100
+ 'BLOCK_JOB_READY'
95
+
101
+
96
+_send_qemu_cmd $h \
102
+# The backing BDS should be assigned the overlay's AioContext
97
+ "{ 'execute': 'human-monitor-command',
103
+_send_qemu_cmd $QEMU_HANDLE \
98
+ 'arguments': { 'command-line':
104
+ "{ 'execute': 'block-job-complete',
99
+ 'qemu-io disk \"write 0 4M\"' } }" \
105
+ 'arguments': { 'device': 'mirror' } }" \
100
+ "return"
106
+ 'BLOCK_JOB_COMPLETED'
101
+
107
+
102
+_send_qemu_cmd $h \
108
+_send_qemu_cmd $QEMU_HANDLE \
103
+ "{ 'execute': 'blockdev-snapshot-sync',
109
+ "{ 'execute': 'quit' }" \
104
+ 'arguments': { 'device': 'disk',
110
+ 'return'
105
+ 'snapshot-file': '$TEST_IMG',
106
+ 'format': '$IMGFMT',
107
+ 'mode': 'absolute-paths' } }" \
108
+ "return"
109
+
111
+
110
+echo
112
+wait=yes _cleanup_qemu
111
+echo === Start commit job and exit qemu ===
112
+echo
113
+
114
+# Note that the reference output intentionally includes the 'offset' field in
115
+# BLOCK_JOB_CANCELLED events for all of the following block jobs. They are
116
+# predictable and any change in the offsets would hint at a bug in the job
117
+# throttling code.
118
+#
119
+# In order to achieve these predictable offsets, all of the following tests
120
+# use speed=65536. Each job will perform exactly one iteration before it has
121
+# to sleep at least for a second, which is plenty of time for the 'quit' QMP
122
+# command to be received (after receiving the command, the rest runs
123
+# synchronously, so jobs can arbitrarily continue or complete).
124
+#
125
+# The buffer size for commit and streaming is 512k (waiting for 8 seconds after
126
+# the first request), for active commit and mirror it's large enough to cover
127
+# the full 4M, and for backup it's the qcow2 cluster size, which we know is
128
+# 64k. As all of these are at least as large as the speed, we are sure that the
129
+# offset doesn't advance after the first iteration before qemu exits.
130
+
131
+_send_qemu_cmd $h \
132
+ "{ 'execute': 'block-commit',
133
+ 'arguments': { 'device': 'disk',
134
+ 'base':'$TEST_IMG.base',
135
+ 'top': '$TEST_IMG.mid',
136
+ 'speed': 65536 } }" \
137
+ "return"
138
+
139
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
140
+wait=1 _cleanup_qemu
141
+
142
+echo
143
+echo === Start active commit job and exit qemu ===
144
+echo
145
+
146
+_launch_qemu \
147
+ -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk
148
+h=$QEMU_HANDLE
149
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
150
+
151
+_send_qemu_cmd $h \
152
+ "{ 'execute': 'block-commit',
153
+ 'arguments': { 'device': 'disk',
154
+ 'base':'$TEST_IMG.base',
155
+ 'speed': 65536 } }" \
156
+ "return"
157
+
158
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
159
+wait=1 _cleanup_qemu
160
+
161
+echo
162
+echo === Start mirror job and exit qemu ===
163
+echo
164
+
165
+_launch_qemu \
166
+ -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk
167
+h=$QEMU_HANDLE
168
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
169
+
170
+_send_qemu_cmd $h \
171
+ "{ 'execute': 'drive-mirror',
172
+ 'arguments': { 'device': 'disk',
173
+ 'target': '$TEST_IMG.copy',
174
+ 'format': '$IMGFMT',
175
+ 'sync': 'full',
176
+ 'speed': 65536 } }" \
177
+ "return"
178
+
179
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
180
+wait=1 _cleanup_qemu
181
+
182
+echo
183
+echo === Start backup job and exit qemu ===
184
+echo
185
+
186
+_launch_qemu \
187
+ -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk
188
+h=$QEMU_HANDLE
189
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
190
+
191
+_send_qemu_cmd $h \
192
+ "{ 'execute': 'drive-backup',
193
+ 'arguments': { 'device': 'disk',
194
+ 'target': '$TEST_IMG.copy',
195
+ 'format': '$IMGFMT',
196
+ 'sync': 'full',
197
+ 'speed': 65536 } }" \
198
+ "return"
199
+
200
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
201
+wait=1 _cleanup_qemu
202
+
203
+echo
204
+echo === Start streaming job and exit qemu ===
205
+echo
206
+
207
+_launch_qemu \
208
+ -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk
209
+h=$QEMU_HANDLE
210
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" 'return'
211
+
212
+_send_qemu_cmd $h \
213
+ "{ 'execute': 'block-stream',
214
+ 'arguments': { 'device': 'disk',
215
+ 'speed': 65536 } }" \
216
+ "return"
217
+
218
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
219
+wait=1 _cleanup_qemu
220
+
221
+_check_test_img
222
+
113
+
223
+# success, all done
114
+# success, all done
224
+echo "*** done"
115
+echo '*** done'
225
+rm -f $seq.full
116
+rm -f $seq.full
226
+status=0
117
+status=0
227
diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out
118
diff --git a/tests/qemu-iotests/127.out b/tests/qemu-iotests/127.out
228
new file mode 100644
119
new file mode 100644
229
index XXXXXXX..XXXXXXX
120
index XXXXXXX..XXXXXXX
230
--- /dev/null
121
--- /dev/null
231
+++ b/tests/qemu-iotests/185.out
122
+++ b/tests/qemu-iotests/127.out
232
@@ -XXX,XX +XXX,XX @@
123
@@ -XXX,XX +XXX,XX @@
233
+QA output created by 185
124
+QA output created by 127
234
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
125
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
235
+
126
+Formatting 'TEST_DIR/t.IMGFMT.overlay0', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT
236
+=== Starting VM ===
127
+Formatting 'TEST_DIR/t.IMGFMT.overlay1', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT
237
+
128
+wrote 42/42 bytes at offset 0
238
+{"return": {}}
129
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
239
+
240
+=== Creating backing chain ===
241
+
242
+Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
243
+{"return": {}}
244
+wrote 4194304/4194304 bytes at offset 0
245
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
246
+{"return": ""}
247
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
248
+{"return": {}}
249
+
250
+=== Start commit job and exit qemu ===
251
+
252
+{"return": {}}
130
+{"return": {}}
253
+{"return": {}}
131
+{"return": {}}
254
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
132
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "mirror", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
255
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "commit"}}
256
+
257
+=== Start active commit job and exit qemu ===
258
+
259
+{"return": {}}
133
+{"return": {}}
260
+{"return": {}}
134
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "mirror", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
261
+{"return": {}}
135
+{"return": {}}
262
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
136
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
263
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "commit"}}
264
+
265
+=== Start mirror job and exit qemu ===
266
+
267
+{"return": {}}
268
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
269
+{"return": {}}
270
+{"return": {}}
271
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
272
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}}
273
+
274
+=== Start backup job and exit qemu ===
275
+
276
+{"return": {}}
277
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
278
+{"return": {}}
279
+{"return": {}}
280
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
281
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 65536, "speed": 65536, "type": "backup"}}
282
+
283
+=== Start streaming job and exit qemu ===
284
+
285
+{"return": {}}
286
+{"return": {}}
287
+{"return": {}}
288
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
289
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "stream"}}
290
+No errors were found on the image.
291
+*** done
137
+*** done
292
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
138
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
293
index XXXXXXX..XXXXXXX 100644
139
index XXXXXXX..XXXXXXX 100644
294
--- a/tests/qemu-iotests/group
140
--- a/tests/qemu-iotests/group
295
+++ b/tests/qemu-iotests/group
141
+++ b/tests/qemu-iotests/group
296
@@ -XXX,XX +XXX,XX @@
142
@@ -XXX,XX +XXX,XX @@
297
181 rw auto migration
143
124 rw auto backing
298
182 rw auto quick
144
125 rw auto
299
183 rw auto migration
145
126 rw auto backing
300
+185 rw auto
146
+127 rw auto backing quick
147
128 rw auto quick
148
129 rw auto quick
149
130 rw auto quick
301
--
150
--
302
1.8.3.1
151
2.13.6
303
152
304
153
diff view generated by jsdifflib
Deleted patch
1
This adds documentation for the -blockdev options that apply to all
2
nodes independent of the block driver used.
3
1
4
All options that are shared by -blockdev and -drive are now explained in
5
the section for -blockdev. The documentation of -drive mentions that all
6
-blockdev options are accepted as well.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
---
12
qemu-options.hx | 108 +++++++++++++++++++++++++++++++++++++++++---------------
13
1 file changed, 79 insertions(+), 29 deletions(-)
14
15
diff --git a/qemu-options.hx b/qemu-options.hx
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qemu-options.hx
18
+++ b/qemu-options.hx
19
@@ -XXX,XX +XXX,XX @@ DEF("blockdev", HAS_ARG, QEMU_OPTION_blockdev,
20
" [,read-only=on|off][,detect-zeroes=on|off|unmap]\n"
21
" [,driver specific parameters...]\n"
22
" configure a block backend\n", QEMU_ARCH_ALL)
23
+STEXI
24
+@item -blockdev @var{option}[,@var{option}[,@var{option}[,...]]]
25
+@findex -blockdev
26
+
27
+Define a new block driver node.
28
+
29
+@table @option
30
+@item Valid options for any block driver node:
31
+
32
+@table @code
33
+@item driver
34
+Specifies the block driver to use for the given node.
35
+@item node-name
36
+This defines the name of the block driver node by which it will be referenced
37
+later. The name must be unique, i.e. it must not match the name of a different
38
+block driver node, or (if you use @option{-drive} as well) the ID of a drive.
39
+
40
+If no node name is specified, it is automatically generated. The generated node
41
+name is not intended to be predictable and changes between QEMU invocations.
42
+For the top level, an explicit node name must be specified.
43
+@item read-only
44
+Open the node read-only. Guest write attempts will fail.
45
+@item cache.direct
46
+The host page cache can be avoided with @option{cache.direct=on}. This will
47
+attempt to do disk IO directly to the guest's memory. QEMU may still perform an
48
+internal copy of the data.
49
+@item cache.no-flush
50
+In case you don't care about data integrity over host failures, you can use
51
+@option{cache.no-flush=on}. This option tells QEMU that it never needs to write
52
+any data to the disk but can instead keep things in cache. If anything goes
53
+wrong, like your host losing power, the disk storage getting disconnected
54
+accidentally, etc. your image will most probably be rendered unusable.
55
+@item discard=@var{discard}
56
+@var{discard} is one of "ignore" (or "off") or "unmap" (or "on") and controls
57
+whether @code{discard} (also known as @code{trim} or @code{unmap}) requests are
58
+ignored or passed to the filesystem. Some machine types may not support
59
+discard requests.
60
+@item detect-zeroes=@var{detect-zeroes}
61
+@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
62
+conversion of plain zero writes by the OS to driver specific optimized
63
+zero write commands. You may even choose "unmap" if @var{discard} is set
64
+to "unmap" to allow a zero write to be converted to an @code{unmap} operation.
65
+@end table
66
+
67
+@end table
68
+
69
+ETEXI
70
71
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
72
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
73
@@ -XXX,XX +XXX,XX @@ STEXI
74
@item -drive @var{option}[,@var{option}[,@var{option}[,...]]]
75
@findex -drive
76
77
-Define a new drive. Valid options are:
78
+Define a new drive. This includes creating a block driver node (the backend) as
79
+well as a guest device, and is mostly a shortcut for defining the corresponding
80
+@option{-blockdev} and @option{-device} options.
81
+
82
+@option{-drive} accepts all options that are accepted by @option{-blockdev}. In
83
+addition, it knows the following options:
84
85
@table @option
86
@item file=@var{file}
87
@@ -XXX,XX +XXX,XX @@ These options have the same definition as they have in @option{-hdachs}.
88
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
89
(see @option{-snapshot}).
90
@item cache=@var{cache}
91
-@var{cache} is "none", "writeback", "unsafe", "directsync" or "writethrough" and controls how the host cache is used to access block data.
92
+@var{cache} is "none", "writeback", "unsafe", "directsync" or "writethrough"
93
+and controls how the host cache is used to access block data. This is a
94
+shortcut that sets the @option{cache.direct} and @option{cache.no-flush}
95
+options (as in @option{-blockdev}), and additionally @option{cache.writeback},
96
+which provides a default for the @option{write-cache} option of block guest
97
+devices (as in @option{-device}). The modes correspond to the following
98
+settings:
99
+
100
+@c Our texi2pod.pl script doesn't support @multitable, so fall back to using
101
+@c plain ASCII art (well, UTF-8 art really). This looks okay both in the manpage
102
+@c and the HTML output.
103
+@example
104
+@ │ cache.writeback cache.direct cache.no-flush
105
+─────────────┼─────────────────────────────────────────────────
106
+writeback │ on off off
107
+none │ on on off
108
+writethrough │ off off off
109
+directsync │ off on off
110
+unsafe │ on off on
111
+@end example
112
+
113
+The default mode is @option{cache=writeback}.
114
+
115
@item aio=@var{aio}
116
@var{aio} is "threads", or "native" and selects between pthread based disk I/O and native Linux AIO.
117
-@item discard=@var{discard}
118
-@var{discard} is one of "ignore" (or "off") or "unmap" (or "on") and controls whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap}) requests are ignored or passed to the filesystem. Some machine types may not support discard requests.
119
@item format=@var{format}
120
Specify which disk @var{format} will be used rather than detecting
121
the format. Can be used to specify format=raw to avoid interpreting
122
@@ -XXX,XX +XXX,XX @@ Specify which @var{action} to take on write and read errors. Valid actions are:
123
"report" (report the error to the guest), "enospc" (pause QEMU only if the
124
host disk is full; report the error to the guest otherwise).
125
The default setting is @option{werror=enospc} and @option{rerror=report}.
126
-@item readonly
127
-Open drive @option{file} as read-only. Guest write attempts will fail.
128
@item copy-on-read=@var{copy-on-read}
129
@var{copy-on-read} is "on" or "off" and enables whether to copy read backing
130
file sectors into the image file.
131
-@item detect-zeroes=@var{detect-zeroes}
132
-@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
133
-conversion of plain zero writes by the OS to driver specific optimized
134
-zero write commands. You may even choose "unmap" if @var{discard} is set
135
-to "unmap" to allow a zero write to be converted to an UNMAP operation.
136
@item bps=@var{b},bps_rd=@var{r},bps_wr=@var{w}
137
Specify bandwidth throttling limits in bytes per second, either for all request
138
types or for reads or writes only. Small values can lead to timeouts or hangs
139
@@ -XXX,XX +XXX,XX @@ prevent guests from circumventing throttling limits by using many small disks
140
instead of a single larger disk.
141
@end table
142
143
-By default, the @option{cache=writeback} mode is used. It will report data
144
+By default, the @option{cache.writeback=on} mode is used. It will report data
145
writes as completed as soon as the data is present in the host page cache.
146
This is safe as long as your guest OS makes sure to correctly flush disk caches
147
where needed. If your guest OS does not handle volatile disk write caches
148
correctly and your host crashes or loses power, then the guest may experience
149
data corruption.
150
151
-For such guests, you should consider using @option{cache=writethrough}. This
152
+For such guests, you should consider using @option{cache.writeback=off}. This
153
means that the host page cache will be used to read and write data, but write
154
notification will be sent to the guest only after QEMU has made sure to flush
155
each write to the disk. Be aware that this has a major impact on performance.
156
157
-The host page cache can be avoided entirely with @option{cache=none}. This will
158
-attempt to do disk IO directly to the guest's memory. QEMU may still perform
159
-an internal copy of the data. Note that this is considered a writeback mode and
160
-the guest OS must handle the disk write cache correctly in order to avoid data
161
-corruption on host crashes.
162
-
163
-The host page cache can be avoided while only sending write notifications to
164
-the guest when the data has been flushed to the disk using
165
-@option{cache=directsync}.
166
-
167
-In case you don't care about data integrity over host failures, use
168
-@option{cache=unsafe}. This option tells QEMU that it never needs to write any
169
-data to the disk but can instead keep things in cache. If anything goes wrong,
170
-like your host losing power, the disk storage getting disconnected accidentally,
171
-etc. your image will most probably be rendered unusable. When using
172
-the @option{-snapshot} option, unsafe caching is always used.
173
+When using the @option{-snapshot} option, unsafe caching is always used.
174
175
Copy-on-read avoids accessing the same backing file sectors repeatedly and is
176
useful when the backing file is over a slow network. By default copy-on-read
177
--
178
1.8.3.1
179
180
diff view generated by jsdifflib
1
Most of the qed code is now synchronous and matches the coroutine model.
1
From: Max Reitz <mreitz@redhat.com>
2
One notable exception is the serialisation between requests which can
3
still schedule a callback. Before we can replace this with coroutine
4
locks, let's convert the driver's external interfaces to the coroutine
5
versions.
6
2
7
We need to be careful to handle both requests that call the completion
3
Tests 067 and 087 filter the actual image size because it depends on the
8
callback directly from the calling coroutine (i.e. fully synchronous
4
host filesystem (and is not part of the respective test). Since this is
9
code) and requests that involve some callback, so that we need to yield
5
generally true, we should have a common filter function for this, so
10
and wait for the completion callback coming from outside the coroutine.
6
let's pull out the sed line from both tests into such a function.
11
7
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
9
Message-id: 20171009163456.485-2-mreitz@redhat.com
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Jeff Cody <jcody@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
13
---
16
block/qed.c | 97 ++++++++++++++++++++++++++-----------------------------------
14
tests/qemu-iotests/067 | 2 +-
17
1 file changed, 42 insertions(+), 55 deletions(-)
15
tests/qemu-iotests/087 | 2 +-
16
tests/qemu-iotests/common.filter | 6 ++++++
17
3 files changed, 8 insertions(+), 2 deletions(-)
18
18
19
diff --git a/block/qed.c b/block/qed.c
19
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
20
index XXXXXXX..XXXXXXX 100755
21
--- a/tests/qemu-iotests/067
22
+++ b/tests/qemu-iotests/067
23
@@ -XXX,XX +XXX,XX @@ _filter_qmp_events()
24
function run_qemu()
25
{
26
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \
27
- | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' \
28
+ | _filter_actual_image_size \
29
| _filter_generated_node_ids | _filter_qmp_events
30
}
31
32
diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
33
index XXXXXXX..XXXXXXX 100755
34
--- a/tests/qemu-iotests/087
35
+++ b/tests/qemu-iotests/087
36
@@ -XXX,XX +XXX,XX @@ function run_qemu()
37
{
38
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
39
| _filter_qemu | _filter_imgfmt \
40
- | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
41
+ | _filter_actual_image_size
42
}
43
44
size=128M
45
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
20
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qed.c
47
--- a/tests/qemu-iotests/common.filter
22
+++ b/block/qed.c
48
+++ b/tests/qemu-iotests/common.filter
23
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb)
49
@@ -XXX,XX +XXX,XX @@ _filter_block_job_len()
24
}
50
sed -e 's/, "len": [0-9]\+,/, "len": LEN,/g'
25
}
51
}
26
52
27
-static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
53
+# replace actual image size (depends on the host filesystem)
28
- int64_t sector_num,
54
+_filter_actual_image_size()
29
- QEMUIOVector *qiov, int nb_sectors,
55
+{
30
- BlockCompletionFunc *cb,
56
+ sed -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
31
- void *opaque, int flags)
32
+typedef struct QEDRequestCo {
33
+ Coroutine *co;
34
+ bool done;
35
+ int ret;
36
+} QEDRequestCo;
37
+
38
+static void qed_co_request_cb(void *opaque, int ret)
39
{
40
- QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, cb, opaque);
41
+ QEDRequestCo *co = opaque;
42
43
- trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
44
- opaque, flags);
45
+ co->done = true;
46
+ co->ret = ret;
47
+ qemu_coroutine_enter_if_inactive(co->co);
48
+}
57
+}
49
+
58
+
50
+static int coroutine_fn qed_co_request(BlockDriverState *bs, int64_t sector_num,
59
# replace driver-specific options in the "Formatting..." line
51
+ QEMUIOVector *qiov, int nb_sectors,
60
_filter_img_create()
52
+ int flags)
53
+{
54
+ QEDRequestCo co = {
55
+ .co = qemu_coroutine_self(),
56
+ .done = false,
57
+ };
58
+ QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, qed_co_request_cb, &co);
59
+
60
+ trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors, &co, flags);
61
62
acb->flags = flags;
63
acb->qiov = qiov;
64
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
65
66
/* Start request */
67
qed_aio_start_io(acb);
68
- return &acb->common;
69
-}
70
71
-static BlockAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
72
- int64_t sector_num,
73
- QEMUIOVector *qiov, int nb_sectors,
74
- BlockCompletionFunc *cb,
75
- void *opaque)
76
-{
77
- return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
78
+ if (!co.done) {
79
+ qemu_coroutine_yield();
80
+ }
81
+
82
+ return co.ret;
83
}
84
85
-static BlockAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
86
- int64_t sector_num,
87
- QEMUIOVector *qiov, int nb_sectors,
88
- BlockCompletionFunc *cb,
89
- void *opaque)
90
+static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs,
91
+ int64_t sector_num, int nb_sectors,
92
+ QEMUIOVector *qiov)
93
{
61
{
94
- return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb,
95
- opaque, QED_AIOCB_WRITE);
96
+ return qed_co_request(bs, sector_num, qiov, nb_sectors, 0);
97
}
98
99
-typedef struct {
100
- Coroutine *co;
101
- int ret;
102
- bool done;
103
-} QEDWriteZeroesCB;
104
-
105
-static void coroutine_fn qed_co_pwrite_zeroes_cb(void *opaque, int ret)
106
+static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs,
107
+ int64_t sector_num, int nb_sectors,
108
+ QEMUIOVector *qiov)
109
{
110
- QEDWriteZeroesCB *cb = opaque;
111
-
112
- cb->done = true;
113
- cb->ret = ret;
114
- if (cb->co) {
115
- aio_co_wake(cb->co);
116
- }
117
+ return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE);
118
}
119
120
static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
121
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
122
int count,
123
BdrvRequestFlags flags)
124
{
125
- BlockAIOCB *blockacb;
126
BDRVQEDState *s = bs->opaque;
127
- QEDWriteZeroesCB cb = { .done = false };
128
QEMUIOVector qiov;
129
struct iovec iov;
130
131
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
132
iov.iov_len = count;
133
134
qemu_iovec_init_external(&qiov, &iov, 1);
135
- blockacb = qed_aio_setup(bs, offset >> BDRV_SECTOR_BITS, &qiov,
136
- count >> BDRV_SECTOR_BITS,
137
- qed_co_pwrite_zeroes_cb, &cb,
138
- QED_AIOCB_WRITE | QED_AIOCB_ZERO);
139
- if (!blockacb) {
140
- return -EIO;
141
- }
142
- if (!cb.done) {
143
- cb.co = qemu_coroutine_self();
144
- qemu_coroutine_yield();
145
- }
146
- assert(cb.done);
147
- return cb.ret;
148
+ return qed_co_request(bs, offset >> BDRV_SECTOR_BITS, &qiov,
149
+ count >> BDRV_SECTOR_BITS,
150
+ QED_AIOCB_WRITE | QED_AIOCB_ZERO);
151
}
152
153
static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
154
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
155
.bdrv_create = bdrv_qed_create,
156
.bdrv_has_zero_init = bdrv_has_zero_init_1,
157
.bdrv_co_get_block_status = bdrv_qed_co_get_block_status,
158
- .bdrv_aio_readv = bdrv_qed_aio_readv,
159
- .bdrv_aio_writev = bdrv_qed_aio_writev,
160
+ .bdrv_co_readv = bdrv_qed_co_readv,
161
+ .bdrv_co_writev = bdrv_qed_co_writev,
162
.bdrv_co_pwrite_zeroes = bdrv_qed_co_pwrite_zeroes,
163
.bdrv_truncate = bdrv_qed_truncate,
164
.bdrv_getlength = bdrv_qed_getlength,
165
--
62
--
166
1.8.3.1
63
2.13.6
167
64
168
65
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
Perform the savevm/loadvm test with both iothread on and off. This
3
Whenever the actual image size is not part of the test, it should be
4
covers the recently found savevm/loadvm hang when iothread is enabled.
4
filtered as it depends on the host filesystem.
5
5
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Message-id: 20171009163456.485-3-mreitz@redhat.com
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
11
---
9
tests/qemu-iotests/068 | 23 ++++++++++++++---------
12
tests/qemu-iotests/184 | 3 ++-
10
tests/qemu-iotests/068.out | 11 ++++++++++-
13
tests/qemu-iotests/184.out | 6 +++---
11
2 files changed, 24 insertions(+), 10 deletions(-)
14
tests/qemu-iotests/191 | 4 ++--
12
15
tests/qemu-iotests/191.out | 46 +++++++++++++++++++++++-----------------------
13
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
16
4 files changed, 30 insertions(+), 29 deletions(-)
17
18
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
14
index XXXXXXX..XXXXXXX 100755
19
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/068
20
--- a/tests/qemu-iotests/184
16
+++ b/tests/qemu-iotests/068
21
+++ b/tests/qemu-iotests/184
17
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
22
@@ -XXX,XX +XXX,XX @@ function do_run_qemu()
18
IMGOPTS="compat=1.1"
23
function run_qemu()
19
IMG_SIZE=128K
24
{
20
25
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
21
-echo
26
- | _filter_qemu_io | _filter_generated_node_ids
22
-echo "=== Saving and reloading a VM state to/from a qcow2 image ==="
27
+ | _filter_qemu_io | _filter_generated_node_ids \
23
-echo
28
+ | _filter_actual_image_size
24
-_make_test_img $IMG_SIZE
25
-
26
case "$QEMU_DEFAULT_MACHINE" in
27
s390-ccw-virtio)
28
platform_parm="-no-shutdown"
29
@@ -XXX,XX +XXX,XX @@ _qemu()
30
_filter_qemu | _filter_hmp
31
}
29
}
32
30
33
-# Give qemu some time to boot before saving the VM state
31
_make_test_img 64M
34
-bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu
32
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
35
-# Now try to continue from that VM state (this should just work)
36
-echo quit | _qemu -loadvm 0
37
+for extra_args in \
38
+ "" \
39
+ "-object iothread,id=iothread0 -set device.hba0.iothread=iothread0"; do
40
+ echo
41
+ echo "=== Saving and reloading a VM state to/from a qcow2 image ($extra_args) ==="
42
+ echo
43
+
44
+ _make_test_img $IMG_SIZE
45
+
46
+ # Give qemu some time to boot before saving the VM state
47
+ bash -c 'sleep 1; echo -e "savevm 0\nquit"' | _qemu $extra_args
48
+ # Now try to continue from that VM state (this should just work)
49
+ echo quit | _qemu $extra_args -loadvm 0
50
+done
51
52
# success, all done
53
echo "*** done"
54
diff --git a/tests/qemu-iotests/068.out b/tests/qemu-iotests/068.out
55
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
56
--- a/tests/qemu-iotests/068.out
34
--- a/tests/qemu-iotests/184.out
57
+++ b/tests/qemu-iotests/068.out
35
+++ b/tests/qemu-iotests/184.out
58
@@ -XXX,XX +XXX,XX @@
36
@@ -XXX,XX +XXX,XX @@ Testing:
59
QA output created by 068
37
"filename": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"qcow2\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/t.qcow2\"}}}",
60
38
"cluster-size": 65536,
61
-=== Saving and reloading a VM state to/from a qcow2 image ===
39
"format": "throttle",
62
+=== Saving and reloading a VM state to/from a qcow2 image () ===
40
- "actual-size": 200704,
63
+
41
+ "actual-size": SIZE,
64
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
42
"dirty-flag": false
65
+QEMU X.Y.Z monitor - type 'help' for more information
43
},
66
+(qemu) savevm 0
44
"iops_wr": 0,
67
+(qemu) quit
45
@@ -XXX,XX +XXX,XX @@ Testing:
68
+QEMU X.Y.Z monitor - type 'help' for more information
46
"filename": "TEST_DIR/t.qcow2",
69
+(qemu) quit
47
"cluster-size": 65536,
70
+
48
"format": "qcow2",
71
+=== Saving and reloading a VM state to/from a qcow2 image (-object iothread,id=iothread0 -set device.hba0.iothread=iothread0) ===
49
- "actual-size": 200704,
72
50
+ "actual-size": SIZE,
73
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
51
"format-specific": {
74
QEMU X.Y.Z monitor - type 'help' for more information
52
"type": "qcow2",
53
"data": {
54
@@ -XXX,XX +XXX,XX @@ Testing:
55
"virtual-size": 197120,
56
"filename": "TEST_DIR/t.qcow2",
57
"format": "file",
58
- "actual-size": 200704,
59
+ "actual-size": SIZE,
60
"dirty-flag": false
61
},
62
"iops_wr": 0,
63
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
64
index XXXXXXX..XXXXXXX 100755
65
--- a/tests/qemu-iotests/191
66
+++ b/tests/qemu-iotests/191
67
@@ -XXX,XX +XXX,XX @@ echo === Check that both top and top2 point to base now ===
68
echo
69
70
_send_qemu_cmd $h "{ 'execute': 'query-named-block-nodes' }" "^}" |
71
- _filter_generated_node_ids
72
+ _filter_generated_node_ids | _filter_actual_image_size
73
74
_send_qemu_cmd $h "{ 'execute': 'quit' }" "^}"
75
wait=1 _cleanup_qemu
76
@@ -XXX,XX +XXX,XX @@ echo === Check that both top and top2 point to base now ===
77
echo
78
79
_send_qemu_cmd $h "{ 'execute': 'query-named-block-nodes' }" "^}" |
80
- _filter_generated_node_ids
81
+ _filter_generated_node_ids | _filter_actual_image_size
82
83
_send_qemu_cmd $h "{ 'execute': 'quit' }" "^}"
84
wait=1 _cleanup_qemu
85
diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out
86
index XXXXXXX..XXXXXXX 100644
87
--- a/tests/qemu-iotests/191.out
88
+++ b/tests/qemu-iotests/191.out
89
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
90
"filename": "TEST_DIR/t.qcow2.base",
91
"cluster-size": 65536,
92
"format": "qcow2",
93
- "actual-size": 397312,
94
+ "actual-size": SIZE,
95
"format-specific": {
96
"type": "qcow2",
97
"data": {
98
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
99
"filename": "TEST_DIR/t.qcow2.ovl2",
100
"cluster-size": 65536,
101
"format": "qcow2",
102
- "actual-size": 200704,
103
+ "actual-size": SIZE,
104
"format-specific": {
105
"type": "qcow2",
106
"data": {
107
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
108
"virtual-size": 197120,
109
"filename": "TEST_DIR/t.qcow2.ovl2",
110
"format": "file",
111
- "actual-size": 200704,
112
+ "actual-size": SIZE,
113
"dirty-flag": false
114
},
115
"iops_wr": 0,
116
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
117
"filename": "TEST_DIR/t.qcow2.base",
118
"cluster-size": 65536,
119
"format": "qcow2",
120
- "actual-size": 397312,
121
+ "actual-size": SIZE,
122
"format-specific": {
123
"type": "qcow2",
124
"data": {
125
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
126
"filename": "TEST_DIR/t.qcow2",
127
"cluster-size": 65536,
128
"format": "qcow2",
129
- "actual-size": 200704,
130
+ "actual-size": SIZE,
131
"format-specific": {
132
"type": "qcow2",
133
"data": {
134
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
135
"virtual-size": 197120,
136
"filename": "TEST_DIR/t.qcow2",
137
"format": "file",
138
- "actual-size": 200704,
139
+ "actual-size": SIZE,
140
"dirty-flag": false
141
},
142
"iops_wr": 0,
143
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
144
"filename": "TEST_DIR/t.qcow2.base",
145
"cluster-size": 65536,
146
"format": "qcow2",
147
- "actual-size": 397312,
148
+ "actual-size": SIZE,
149
"format-specific": {
150
"type": "qcow2",
151
"data": {
152
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
153
"filename": "TEST_DIR/t.qcow2.mid",
154
"cluster-size": 65536,
155
"format": "qcow2",
156
- "actual-size": 397312,
157
+ "actual-size": SIZE,
158
"format-specific": {
159
"type": "qcow2",
160
"data": {
161
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
162
"virtual-size": 393216,
163
"filename": "TEST_DIR/t.qcow2.mid",
164
"format": "file",
165
- "actual-size": 397312,
166
+ "actual-size": SIZE,
167
"dirty-flag": false
168
},
169
"iops_wr": 0,
170
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
171
"filename": "TEST_DIR/t.qcow2.base",
172
"cluster-size": 65536,
173
"format": "qcow2",
174
- "actual-size": 397312,
175
+ "actual-size": SIZE,
176
"format-specific": {
177
"type": "qcow2",
178
"data": {
179
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
180
"virtual-size": 393216,
181
"filename": "TEST_DIR/t.qcow2.base",
182
"format": "file",
183
- "actual-size": 397312,
184
+ "actual-size": SIZE,
185
"dirty-flag": false
186
},
187
"iops_wr": 0,
188
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
189
"filename": "TEST_DIR/t.qcow2.base",
190
"cluster-size": 65536,
191
"format": "qcow2",
192
- "actual-size": 397312,
193
+ "actual-size": SIZE,
194
"format-specific": {
195
"type": "qcow2",
196
"data": {
197
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
198
"filename": "TEST_DIR/t.qcow2.ovl2",
199
"cluster-size": 65536,
200
"format": "qcow2",
201
- "actual-size": 200704,
202
+ "actual-size": SIZE,
203
"format-specific": {
204
"type": "qcow2",
205
"data": {
206
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
207
"virtual-size": 197120,
208
"filename": "TEST_DIR/t.qcow2.ovl2",
209
"format": "file",
210
- "actual-size": 200704,
211
+ "actual-size": SIZE,
212
"dirty-flag": false
213
},
214
"iops_wr": 0,
215
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
216
"filename": "TEST_DIR/t.qcow2.base",
217
"cluster-size": 65536,
218
"format": "qcow2",
219
- "actual-size": 397312,
220
+ "actual-size": SIZE,
221
"format-specific": {
222
"type": "qcow2",
223
"data": {
224
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
225
"filename": "TEST_DIR/t.qcow2.ovl2",
226
"cluster-size": 65536,
227
"format": "qcow2",
228
- "actual-size": 200704,
229
+ "actual-size": SIZE,
230
"format-specific": {
231
"type": "qcow2",
232
"data": {
233
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
234
"filename": "TEST_DIR/t.qcow2.ovl3",
235
"cluster-size": 65536,
236
"format": "qcow2",
237
- "actual-size": 200704,
238
+ "actual-size": SIZE,
239
"format-specific": {
240
"type": "qcow2",
241
"data": {
242
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
243
"virtual-size": 197120,
244
"filename": "TEST_DIR/t.qcow2.ovl3",
245
"format": "file",
246
- "actual-size": 200704,
247
+ "actual-size": SIZE,
248
"dirty-flag": false
249
},
250
"iops_wr": 0,
251
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
252
"filename": "TEST_DIR/t.qcow2.base",
253
"cluster-size": 65536,
254
"format": "qcow2",
255
- "actual-size": 397312,
256
+ "actual-size": SIZE,
257
"format-specific": {
258
"type": "qcow2",
259
"data": {
260
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
261
"virtual-size": 393216,
262
"filename": "TEST_DIR/t.qcow2.base",
263
"format": "file",
264
- "actual-size": 397312,
265
+ "actual-size": SIZE,
266
"dirty-flag": false
267
},
268
"iops_wr": 0,
269
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
270
"filename": "TEST_DIR/t.qcow2.base",
271
"cluster-size": 65536,
272
"format": "qcow2",
273
- "actual-size": 397312,
274
+ "actual-size": SIZE,
275
"format-specific": {
276
"type": "qcow2",
277
"data": {
278
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
279
"filename": "TEST_DIR/t.qcow2",
280
"cluster-size": 65536,
281
"format": "qcow2",
282
- "actual-size": 200704,
283
+ "actual-size": SIZE,
284
"format-specific": {
285
"type": "qcow2",
286
"data": {
287
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
288
"virtual-size": 197120,
289
"filename": "TEST_DIR/t.qcow2",
290
"format": "file",
291
- "actual-size": 200704,
292
+ "actual-size": SIZE,
293
"dirty-flag": false
294
},
295
"iops_wr": 0,
75
--
296
--
76
1.8.3.1
297
2.13.6
77
298
78
299
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
---
4
block/qed-cluster.c | 39 ++++++++++++++++++++++-----------------
5
block/qed.c | 24 +++++++++++-------------
6
block/qed.h | 4 ++--
7
3 files changed, 35 insertions(+), 32 deletions(-)
8
1
9
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/block/qed-cluster.c
12
+++ b/block/qed-cluster.c
13
@@ -XXX,XX +XXX,XX @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
14
* @s: QED state
15
* @request: L2 cache entry
16
* @pos: Byte position in device
17
- * @len: Number of bytes
18
- * @cb: Completion function
19
- * @opaque: User data for completion function
20
+ * @len: Number of bytes (may be shortened on return)
21
+ * @img_offset: Contains offset in the image file on success
22
*
23
* This function translates a position in the block device to an offset in the
24
- * image file. It invokes the cb completion callback to report back the
25
- * translated offset or unallocated range in the image file.
26
+ * image file. The translated offset or unallocated range in the image file is
27
+ * reported back in *img_offset and *len.
28
*
29
* If the L2 table exists, request->l2_table points to the L2 table cache entry
30
* and the caller must free the reference when they are finished. The cache
31
* entry is exposed in this way to avoid callers having to read the L2 table
32
* again later during request processing. If request->l2_table is non-NULL it
33
* will be unreferenced before taking on the new cache entry.
34
+ *
35
+ * On success QED_CLUSTER_FOUND is returned and img_offset/len are a contiguous
36
+ * range in the image file.
37
+ *
38
+ * On failure QED_CLUSTER_L2 or QED_CLUSTER_L1 is returned for missing L2 or L1
39
+ * table offset, respectively. len is number of contiguous unallocated bytes.
40
*/
41
-void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
42
- size_t len, QEDFindClusterFunc *cb, void *opaque)
43
+int qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
44
+ size_t *len, uint64_t *img_offset)
45
{
46
uint64_t l2_offset;
47
uint64_t offset = 0;
48
@@ -XXX,XX +XXX,XX @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
49
/* Limit length to L2 boundary. Requests are broken up at the L2 boundary
50
* so that a request acts on one L2 table at a time.
51
*/
52
- len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
53
+ *len = MIN(*len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
54
55
l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
56
if (qed_offset_is_unalloc_cluster(l2_offset)) {
57
- cb(opaque, QED_CLUSTER_L1, 0, len);
58
- return;
59
+ *img_offset = 0;
60
+ return QED_CLUSTER_L1;
61
}
62
if (!qed_check_table_offset(s, l2_offset)) {
63
- cb(opaque, -EINVAL, 0, 0);
64
- return;
65
+ *img_offset = *len = 0;
66
+ return -EINVAL;
67
}
68
69
ret = qed_read_l2_table(s, request, l2_offset);
70
@@ -XXX,XX +XXX,XX @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
71
}
72
73
index = qed_l2_index(s, pos);
74
- n = qed_bytes_to_clusters(s,
75
- qed_offset_into_cluster(s, pos) + len);
76
+ n = qed_bytes_to_clusters(s, qed_offset_into_cluster(s, pos) + *len);
77
n = qed_count_contiguous_clusters(s, request->l2_table->table,
78
index, n, &offset);
79
80
@@ -XXX,XX +XXX,XX @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
81
ret = -EINVAL;
82
}
83
84
- len = MIN(len,
85
- n * s->header.cluster_size - qed_offset_into_cluster(s, pos));
86
+ *len = MIN(*len,
87
+ n * s->header.cluster_size - qed_offset_into_cluster(s, pos));
88
89
out:
90
- cb(opaque, ret, offset, len);
91
+ *img_offset = offset;
92
qed_release(s);
93
+ return ret;
94
}
95
diff --git a/block/qed.c b/block/qed.c
96
index XXXXXXX..XXXXXXX 100644
97
--- a/block/qed.c
98
+++ b/block/qed.c
99
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
100
.file = file,
101
};
102
QEDRequest request = { .l2_table = NULL };
103
+ uint64_t offset;
104
+ int ret;
105
106
- qed_find_cluster(s, &request, cb.pos, len, qed_is_allocated_cb, &cb);
107
+ ret = qed_find_cluster(s, &request, cb.pos, &len, &offset);
108
+ qed_is_allocated_cb(&cb, ret, offset, len);
109
110
- /* Now sleep if the callback wasn't invoked immediately */
111
- while (cb.status == BDRV_BLOCK_OFFSET_MASK) {
112
- cb.co = qemu_coroutine_self();
113
- qemu_coroutine_yield();
114
- }
115
+ /* The callback was invoked immediately */
116
+ assert(cb.status != BDRV_BLOCK_OFFSET_MASK);
117
118
qed_unref_l2_cache_entry(request.l2_table);
119
120
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
121
* or -errno
122
* @offset: Cluster offset in bytes
123
* @len: Length in bytes
124
- *
125
- * Callback from qed_find_cluster().
126
*/
127
static void qed_aio_write_data(void *opaque, int ret,
128
uint64_t offset, size_t len)
129
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_data(void *opaque, int ret,
130
* or -errno
131
* @offset: Cluster offset in bytes
132
* @len: Length in bytes
133
- *
134
- * Callback from qed_find_cluster().
135
*/
136
static void qed_aio_read_data(void *opaque, int ret,
137
uint64_t offset, size_t len)
138
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb, int ret)
139
BDRVQEDState *s = acb_to_s(acb);
140
QEDFindClusterFunc *io_fn = (acb->flags & QED_AIOCB_WRITE) ?
141
qed_aio_write_data : qed_aio_read_data;
142
+ uint64_t offset;
143
+ size_t len;
144
145
trace_qed_aio_next_io(s, acb, ret, acb->cur_pos + acb->cur_qiov.size);
146
147
@@ -XXX,XX +XXX,XX @@ static void qed_aio_next_io(QEDAIOCB *acb, int ret)
148
}
149
150
/* Find next cluster and start I/O */
151
- qed_find_cluster(s, &acb->request,
152
- acb->cur_pos, acb->end_pos - acb->cur_pos,
153
- io_fn, acb);
154
+ len = acb->end_pos - acb->cur_pos;
155
+ ret = qed_find_cluster(s, &acb->request, acb->cur_pos, &len, &offset);
156
+ io_fn(acb, ret, offset, len);
157
}
158
159
static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
160
diff --git a/block/qed.h b/block/qed.h
161
index XXXXXXX..XXXXXXX 100644
162
--- a/block/qed.h
163
+++ b/block/qed.h
164
@@ -XXX,XX +XXX,XX @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
165
/**
166
* Cluster functions
167
*/
168
-void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
169
- size_t len, QEDFindClusterFunc *cb, void *opaque);
170
+int qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
171
+ size_t *len, uint64_t *img_offset);
172
173
/**
174
* Consistency check
175
--
176
1.8.3.1
177
178
diff view generated by jsdifflib
Deleted patch
1
qed_commit_l2_update() is unconditionally called at the end of
2
qed_aio_write_l1_update(). Inline it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/qed.c | 36 ++++++++++++++----------------------
8
1 file changed, 14 insertions(+), 22 deletions(-)
9
10
diff --git a/block/qed.c b/block/qed.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed.c
13
+++ b/block/qed.c
14
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
15
}
16
17
/**
18
- * Commit the current L2 table to the cache
19
+ * Update L1 table with new L2 table offset and write it out
20
*/
21
-static void qed_commit_l2_update(void *opaque, int ret)
22
+static void qed_aio_write_l1_update(void *opaque, int ret)
23
{
24
QEDAIOCB *acb = opaque;
25
BDRVQEDState *s = acb_to_s(acb);
26
CachedL2Table *l2_table = acb->request.l2_table;
27
uint64_t l2_offset = l2_table->offset;
28
+ int index;
29
+
30
+ if (ret) {
31
+ qed_aio_complete(acb, ret);
32
+ return;
33
+ }
34
35
+ index = qed_l1_index(s, acb->cur_pos);
36
+ s->l1_table->offsets[index] = l2_table->offset;
37
+
38
+ ret = qed_write_l1_table(s, index, 1);
39
+
40
+ /* Commit the current L2 table to the cache */
41
qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
42
43
/* This is guaranteed to succeed because we just committed the entry to the
44
@@ -XXX,XX +XXX,XX @@ static void qed_commit_l2_update(void *opaque, int ret)
45
qed_aio_next_io(acb, ret);
46
}
47
48
-/**
49
- * Update L1 table with new L2 table offset and write it out
50
- */
51
-static void qed_aio_write_l1_update(void *opaque, int ret)
52
-{
53
- QEDAIOCB *acb = opaque;
54
- BDRVQEDState *s = acb_to_s(acb);
55
- int index;
56
-
57
- if (ret) {
58
- qed_aio_complete(acb, ret);
59
- return;
60
- }
61
-
62
- index = qed_l1_index(s, acb->cur_pos);
63
- s->l1_table->offsets[index] = acb->request.l2_table->offset;
64
-
65
- ret = qed_write_l1_table(s, index, 1);
66
- qed_commit_l2_update(acb, ret);
67
-}
68
69
/**
70
* Update L2 table with new cluster offsets and write them out
71
--
72
1.8.3.1
73
74
diff view generated by jsdifflib
Deleted patch
1
Don't recurse into qed_aio_next_io() and qed_aio_complete() here, but
2
just return an error code and let the caller handle it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/qed.c | 19 +++++++++----------
8
1 file changed, 9 insertions(+), 10 deletions(-)
9
10
diff --git a/block/qed.c b/block/qed.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed.c
13
+++ b/block/qed.c
14
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
15
/**
16
* Update L1 table with new L2 table offset and write it out
17
*/
18
-static void qed_aio_write_l1_update(void *opaque, int ret)
19
+static int qed_aio_write_l1_update(QEDAIOCB *acb)
20
{
21
- QEDAIOCB *acb = opaque;
22
BDRVQEDState *s = acb_to_s(acb);
23
CachedL2Table *l2_table = acb->request.l2_table;
24
uint64_t l2_offset = l2_table->offset;
25
- int index;
26
-
27
- if (ret) {
28
- qed_aio_complete(acb, ret);
29
- return;
30
- }
31
+ int index, ret;
32
33
index = qed_l1_index(s, acb->cur_pos);
34
s->l1_table->offsets[index] = l2_table->offset;
35
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l1_update(void *opaque, int ret)
36
acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
37
assert(acb->request.l2_table != NULL);
38
39
- qed_aio_next_io(acb, ret);
40
+ return ret;
41
}
42
43
44
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
45
if (need_alloc) {
46
/* Write out the whole new L2 table */
47
ret = qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true);
48
- qed_aio_write_l1_update(acb, ret);
49
+ if (ret) {
50
+ goto err;
51
+ }
52
+ ret = qed_aio_write_l1_update(acb);
53
+ qed_aio_next_io(acb, ret);
54
+
55
} else {
56
/* Write out only the updated part of the L2 table */
57
ret = qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters,
58
--
59
1.8.3.1
60
61
diff view generated by jsdifflib
Deleted patch
1
Don't recurse into qed_aio_next_io() and qed_aio_complete() here, but
2
just return an error code and let the caller handle it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
block/qed.c | 43 ++++++++++++++++++++++++++-----------------
8
1 file changed, 26 insertions(+), 17 deletions(-)
9
10
diff --git a/block/qed.c b/block/qed.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed.c
13
+++ b/block/qed.c
14
@@ -XXX,XX +XXX,XX @@ static int qed_aio_write_l1_update(QEDAIOCB *acb)
15
/**
16
* Update L2 table with new cluster offsets and write them out
17
*/
18
-static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
19
+static int qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
20
{
21
BDRVQEDState *s = acb_to_s(acb);
22
bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
23
- int index;
24
-
25
- if (ret) {
26
- goto err;
27
- }
28
+ int index, ret;
29
30
if (need_alloc) {
31
qed_unref_l2_cache_entry(acb->request.l2_table);
32
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
33
/* Write out the whole new L2 table */
34
ret = qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true);
35
if (ret) {
36
- goto err;
37
+ return ret;
38
}
39
- ret = qed_aio_write_l1_update(acb);
40
- qed_aio_next_io(acb, ret);
41
-
42
+ return qed_aio_write_l1_update(acb);
43
} else {
44
/* Write out only the updated part of the L2 table */
45
ret = qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters,
46
false);
47
- qed_aio_next_io(acb, ret);
48
+ if (ret) {
49
+ return ret;
50
+ }
51
}
52
- return;
53
-
54
-err:
55
- qed_aio_complete(acb, ret);
56
+ return 0;
57
}
58
59
/**
60
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
61
*/
62
ret = bdrv_flush(s->bs->file->bs);
63
}
64
- qed_aio_write_l2_update(acb, ret, acb->cur_cluster);
65
+ if (ret) {
66
+ goto err;
67
+ }
68
+ ret = qed_aio_write_l2_update(acb, acb->cur_cluster);
69
+ if (ret) {
70
+ goto err;
71
+ }
72
+ qed_aio_next_io(acb, 0);
73
}
74
+ return;
75
+
76
+err:
77
+ qed_aio_complete(acb, ret);
78
}
79
80
/**
81
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_zero_cluster(void *opaque, int ret)
82
return;
83
}
84
85
- qed_aio_write_l2_update(acb, 0, 1);
86
+ ret = qed_aio_write_l2_update(acb, 1);
87
+ if (ret < 0) {
88
+ qed_aio_complete(acb, ret);
89
+ return;
90
+ }
91
+ qed_aio_next_io(acb, 0);
92
}
93
94
/**
95
--
96
1.8.3.1
97
98
diff view generated by jsdifflib
1
Don't recurse into qed_aio_next_io() and qed_aio_complete() here, but
1
From: Max Reitz <mreitz@redhat.com>
2
just return an error code and let the caller handle it.
3
2
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
bdrv_truncate() has an errp parameter which is always set when an error
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
occurs. Let's use that instead of a plain strerror().
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Message-id: 20171009155431.14093-1-mreitz@redhat.com
8
Reviewed-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
11
---
7
block/qed.c | 43 ++++++++++++++++++++-----------------------
12
block/qcow2.c | 13 +++++++------
8
1 file changed, 20 insertions(+), 23 deletions(-)
13
1 file changed, 7 insertions(+), 6 deletions(-)
9
14
10
diff --git a/block/qed.c b/block/qed.c
15
diff --git a/block/qcow2.c b/block/qcow2.c
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/block/qed.c
17
--- a/block/qcow2.c
13
+++ b/block/qed.c
18
+++ b/block/qcow2.c
14
@@ -XXX,XX +XXX,XX @@ static bool qed_should_set_need_check(BDRVQEDState *s)
19
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
15
*
20
return last_cluster;
16
* This path is taken when writing to previously unallocated clusters.
21
}
17
*/
22
if ((last_cluster + 1) * s->cluster_size < old_file_size) {
18
-static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
23
- ret = bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
19
+static int qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
24
- PREALLOC_MODE_OFF, NULL);
20
{
25
- if (ret < 0) {
21
BDRVQEDState *s = acb_to_s(acb);
26
- warn_report("Failed to truncate the tail of the image: %s",
22
int ret;
27
- strerror(-ret));
23
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
28
- ret = 0;
24
}
29
+ Error *local_err = NULL;
25
if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs) ||
30
+
26
s->allocating_write_reqs_plugged) {
31
+ bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
27
- return; /* wait for existing request to finish */
32
+ PREALLOC_MODE_OFF, &local_err);
28
+ return -EINPROGRESS; /* wait for existing request to finish */
33
+ if (local_err) {
29
}
34
+ warn_reportf_err(local_err,
30
35
+ "Failed to truncate the tail of the image: ");
31
acb->cur_nclusters = qed_bytes_to_clusters(s,
36
}
32
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
33
if (acb->flags & QED_AIOCB_ZERO) {
34
/* Skip ahead if the clusters are already zero */
35
if (acb->find_cluster_ret == QED_CLUSTER_ZERO) {
36
- qed_aio_start_io(acb);
37
- return;
38
+ return 0;
39
}
37
}
40
} else {
38
} else {
41
acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
42
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
43
s->header.features |= QED_F_NEED_CHECK;
44
ret = qed_write_header(s);
45
if (ret < 0) {
46
- qed_aio_complete(acb, ret);
47
- return;
48
+ return ret;
49
}
50
}
51
52
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
53
ret = qed_aio_write_cow(acb);
54
}
55
if (ret < 0) {
56
- qed_aio_complete(acb, ret);
57
- return;
58
+ return ret;
59
}
60
- qed_aio_next_io(acb, 0);
61
+ return 0;
62
}
63
64
/**
65
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
66
*
67
* This path is taken when writing to already allocated clusters.
68
*/
69
-static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
70
+static int qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
71
{
72
- int ret;
73
-
74
/* Allocate buffer for zero writes */
75
if (acb->flags & QED_AIOCB_ZERO) {
76
struct iovec *iov = acb->qiov->iov;
77
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
78
if (!iov->iov_base) {
79
iov->iov_base = qemu_try_blockalign(acb->common.bs, iov->iov_len);
80
if (iov->iov_base == NULL) {
81
- qed_aio_complete(acb, -ENOMEM);
82
- return;
83
+ return -ENOMEM;
84
}
85
memset(iov->iov_base, 0, iov->iov_len);
86
}
87
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
88
qemu_iovec_concat(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
89
90
/* Do the actual write */
91
- ret = qed_aio_write_main(acb);
92
- if (ret < 0) {
93
- qed_aio_complete(acb, ret);
94
- return;
95
- }
96
- qed_aio_next_io(acb, 0);
97
+ return qed_aio_write_main(acb);
98
}
99
100
/**
101
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_data(void *opaque, int ret,
102
103
switch (ret) {
104
case QED_CLUSTER_FOUND:
105
- qed_aio_write_inplace(acb, offset, len);
106
+ ret = qed_aio_write_inplace(acb, offset, len);
107
break;
108
109
case QED_CLUSTER_L2:
110
case QED_CLUSTER_L1:
111
case QED_CLUSTER_ZERO:
112
- qed_aio_write_alloc(acb, len);
113
+ ret = qed_aio_write_alloc(acb, len);
114
break;
115
116
default:
117
- qed_aio_complete(acb, ret);
118
+ assert(ret < 0);
119
break;
120
}
121
+
122
+ if (ret < 0) {
123
+ if (ret != -EINPROGRESS) {
124
+ qed_aio_complete(acb, ret);
125
+ }
126
+ return;
127
+ }
128
+ qed_aio_next_io(acb, 0);
129
}
130
131
/**
132
--
39
--
133
1.8.3.1
40
2.13.6
134
41
135
42
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
uri_parse(...)->scheme may be NULL. In fact, probably every field may be
3
A qcow2 image file's length is not required to have a length that is a
4
NULL, and the callers do test this for all of the other fields but not
4
multiple of the cluster size. However, qcow2_refcount_area() expects an
5
for scheme (except for block/gluster.c; block/vxhs.c does not access
5
aligned value for its @start_offset parameter, so we need to round
6
that field at all).
6
@old_file_size up to the next cluster boundary.
7
7
8
We can easily fix this by using g_strcmp0() instead of strcmp().
8
Reported-by: Ping Li <pingl@redhat.com>
9
9
Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1414049
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Message-id: 20171009215533.12530-2-mreitz@redhat.com
10
Cc: qemu-stable@nongnu.org
12
Cc: qemu-stable@nongnu.org
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Message-id: 20170613205726.13544-1-mreitz@redhat.com
14
Reviewed-by: Jeff Cody <jcody@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
17
---
16
block/nbd.c | 6 +++---
18
block/qcow2.c | 1 +
17
block/nfs.c | 2 +-
19
1 file changed, 1 insertion(+)
18
block/sheepdog.c | 6 +++---
19
block/ssh.c | 2 +-
20
4 files changed, 8 insertions(+), 8 deletions(-)
21
20
22
diff --git a/block/nbd.c b/block/nbd.c
21
diff --git a/block/qcow2.c b/block/qcow2.c
23
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
24
--- a/block/nbd.c
23
--- a/block/qcow2.c
25
+++ b/block/nbd.c
24
+++ b/block/qcow2.c
26
@@ -XXX,XX +XXX,XX @@ static int nbd_parse_uri(const char *filename, QDict *options)
25
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
27
}
26
"Failed to inquire current file length");
28
27
return old_file_size;
29
/* transport */
28
}
30
- if (!strcmp(uri->scheme, "nbd")) {
29
+ old_file_size = ROUND_UP(old_file_size, s->cluster_size);
31
+ if (!g_strcmp0(uri->scheme, "nbd")) {
30
32
is_unix = false;
31
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
33
- } else if (!strcmp(uri->scheme, "nbd+tcp")) {
32
s->cluster_size);
34
+ } else if (!g_strcmp0(uri->scheme, "nbd+tcp")) {
35
is_unix = false;
36
- } else if (!strcmp(uri->scheme, "nbd+unix")) {
37
+ } else if (!g_strcmp0(uri->scheme, "nbd+unix")) {
38
is_unix = true;
39
} else {
40
ret = -EINVAL;
41
diff --git a/block/nfs.c b/block/nfs.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block/nfs.c
44
+++ b/block/nfs.c
45
@@ -XXX,XX +XXX,XX @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
46
error_setg(errp, "Invalid URI specified");
47
goto out;
48
}
49
- if (strcmp(uri->scheme, "nfs") != 0) {
50
+ if (g_strcmp0(uri->scheme, "nfs") != 0) {
51
error_setg(errp, "URI scheme must be 'nfs'");
52
goto out;
53
}
54
diff --git a/block/sheepdog.c b/block/sheepdog.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/block/sheepdog.c
57
+++ b/block/sheepdog.c
58
@@ -XXX,XX +XXX,XX @@ static void sd_parse_uri(SheepdogConfig *cfg, const char *filename,
59
}
60
61
/* transport */
62
- if (!strcmp(uri->scheme, "sheepdog")) {
63
+ if (!g_strcmp0(uri->scheme, "sheepdog")) {
64
is_unix = false;
65
- } else if (!strcmp(uri->scheme, "sheepdog+tcp")) {
66
+ } else if (!g_strcmp0(uri->scheme, "sheepdog+tcp")) {
67
is_unix = false;
68
- } else if (!strcmp(uri->scheme, "sheepdog+unix")) {
69
+ } else if (!g_strcmp0(uri->scheme, "sheepdog+unix")) {
70
is_unix = true;
71
} else {
72
error_setg(&err, "URI scheme must be 'sheepdog', 'sheepdog+tcp',"
73
diff --git a/block/ssh.c b/block/ssh.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/ssh.c
76
+++ b/block/ssh.c
77
@@ -XXX,XX +XXX,XX @@ static int parse_uri(const char *filename, QDict *options, Error **errp)
78
return -EINVAL;
79
}
80
81
- if (strcmp(uri->scheme, "ssh") != 0) {
82
+ if (g_strcmp0(uri->scheme, "ssh") != 0) {
83
error_setg(errp, "URI scheme must be 'ssh'");
84
goto err;
85
}
86
--
33
--
87
1.8.3.1
34
2.13.6
88
35
89
36
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
The bs->exact_filename field may not be sufficient to store the full
3
Some qcow2 functions (at least perform_cow()) expect s->lock to be
4
blkverify node filename. In this case, we should not generate a filename
4
taken. Therefore, if we want to make use of them, we should execute
5
at all instead of an unusable one.
5
preallocate() (as "preallocate_co") in a coroutine so that we can use
6
the qemu_co_mutex_* functions.
6
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20171009215533.12530-3-mreitz@redhat.com
7
Cc: qemu-stable@nongnu.org
10
Cc: qemu-stable@nongnu.org
8
Reported-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
Message-id: 20170613172006.19685-3-mreitz@redhat.com
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
---
15
block/blkverify.c | 12 ++++++++----
16
block/qcow2.c | 41 ++++++++++++++++++++++++++++++++++-------
16
1 file changed, 8 insertions(+), 4 deletions(-)
17
1 file changed, 34 insertions(+), 7 deletions(-)
17
18
18
diff --git a/block/blkverify.c b/block/blkverify.c
19
diff --git a/block/qcow2.c b/block/qcow2.c
19
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
20
--- a/block/blkverify.c
21
--- a/block/qcow2.c
21
+++ b/block/blkverify.c
22
+++ b/block/qcow2.c
22
@@ -XXX,XX +XXX,XX @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
23
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
23
if (bs->file->bs->exact_filename[0]
24
}
24
&& s->test_file->bs->exact_filename[0])
25
25
{
26
26
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
27
+typedef struct PreallocCo {
27
- "blkverify:%s:%s",
28
+ BlockDriverState *bs;
28
- bs->file->bs->exact_filename,
29
+ uint64_t offset;
29
- s->test_file->bs->exact_filename);
30
+ uint64_t new_length;
30
+ int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
31
+
31
+ "blkverify:%s:%s",
32
+ int ret;
32
+ bs->file->bs->exact_filename,
33
+} PreallocCo;
33
+ s->test_file->bs->exact_filename);
34
+
34
+ if (ret >= sizeof(bs->exact_filename)) {
35
/**
35
+ /* An overflow makes the filename unusable, so do not report any */
36
* Preallocates metadata structures for data clusters between @offset (in the
36
+ bs->exact_filename[0] = 0;
37
* guest disk) and @new_length (which is thus generally the new guest disk
37
+ }
38
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
39
*
40
* Returns: 0 on success, -errno on failure.
41
*/
42
-static int preallocate(BlockDriverState *bs,
43
- uint64_t offset, uint64_t new_length)
44
+static void coroutine_fn preallocate_co(void *opaque)
45
{
46
+ PreallocCo *params = opaque;
47
+ BlockDriverState *bs = params->bs;
48
+ uint64_t offset = params->offset;
49
+ uint64_t new_length = params->new_length;
50
BDRVQcow2State *s = bs->opaque;
51
uint64_t bytes;
52
uint64_t host_offset = 0;
53
@@ -XXX,XX +XXX,XX @@ static int preallocate(BlockDriverState *bs,
54
int ret;
55
QCowL2Meta *meta;
56
57
- if (qemu_in_coroutine()) {
58
- qemu_co_mutex_lock(&s->lock);
59
- }
60
+ qemu_co_mutex_lock(&s->lock);
61
62
assert(offset <= new_length);
63
bytes = new_length - offset;
64
@@ -XXX,XX +XXX,XX @@ static int preallocate(BlockDriverState *bs,
65
ret = 0;
66
67
done:
68
+ qemu_co_mutex_unlock(&s->lock);
69
+ params->ret = ret;
70
+}
71
+
72
+static int preallocate(BlockDriverState *bs,
73
+ uint64_t offset, uint64_t new_length)
74
+{
75
+ PreallocCo params = {
76
+ .bs = bs,
77
+ .offset = offset,
78
+ .new_length = new_length,
79
+ .ret = -EINPROGRESS,
80
+ };
81
+
82
if (qemu_in_coroutine()) {
83
- qemu_co_mutex_unlock(&s->lock);
84
+ preallocate_co(&params);
85
+ } else {
86
+ Coroutine *co = qemu_coroutine_create(preallocate_co, &params);
87
+ bdrv_coroutine_enter(bs, co);
88
+ BDRV_POLL_WHILE(bs, params.ret == -EINPROGRESS);
38
}
89
}
90
- return ret;
91
+ return params.ret;
39
}
92
}
40
93
94
/* qcow2_refcount_metadata_size:
41
--
95
--
42
1.8.3.1
96
2.13.6
43
97
44
98
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
The bs->exact_filename field may not be sufficient to store the full
3
Apparently it would be a good idea to test that, too.
4
blkdebug node filename. In this case, we should not generate a filename
5
at all instead of an unusable one.
6
4
7
Cc: qemu-stable@nongnu.org
8
Reported-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20170613172006.19685-2-mreitz@redhat.com
6
Message-id: 20171009215533.12530-4-mreitz@redhat.com
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Jeff Cody <jcody@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
11
---
15
block/blkdebug.c | 10 +++++++---
12
tests/qemu-iotests/125 | 7 +-
16
1 file changed, 7 insertions(+), 3 deletions(-)
13
tests/qemu-iotests/125.out | 480 ++++++++++++++++++++++++++++++++++++++++-----
14
2 files changed, 437 insertions(+), 50 deletions(-)
17
15
18
diff --git a/block/blkdebug.c b/block/blkdebug.c
16
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/125
19
+++ b/tests/qemu-iotests/125
20
@@ -XXX,XX +XXX,XX @@ fi
21
# in B
22
CREATION_SIZE=$((2 * 1024 * 1024 - 48 * 1024))
23
24
+# 512 is the actual test -- but it's good to test 64k as well, just to be sure.
25
+for cluster_size in 512 64k; do
26
# in kB
27
for GROWTH_SIZE in 16 48 80; do
28
for create_mode in off metadata falloc full; do
29
for growth_mode in off metadata falloc full; do
30
- echo "--- growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---"
31
+ echo "--- cluster_size=$cluster_size growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---"
32
33
- IMGOPTS="preallocation=$create_mode,cluster_size=512" _make_test_img ${CREATION_SIZE}
34
+ IMGOPTS="preallocation=$create_mode,cluster_size=$cluster_size" _make_test_img ${CREATION_SIZE}
35
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
36
37
host_size_0=$(get_image_size_on_host)
38
@@ -XXX,XX +XXX,XX @@ for GROWTH_SIZE in 16 48 80; do
39
done
40
done
41
done
42
+done
43
44
# success, all done
45
echo '*** done'
46
diff --git a/tests/qemu-iotests/125.out b/tests/qemu-iotests/125.out
19
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
20
--- a/block/blkdebug.c
48
--- a/tests/qemu-iotests/125.out
21
+++ b/block/blkdebug.c
49
+++ b/tests/qemu-iotests/125.out
22
@@ -XXX,XX +XXX,XX @@ static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
50
@@ -XXX,XX +XXX,XX @@
23
}
51
QA output created by 125
24
52
---- growth_size=16 create_mode=off growth_mode=off ---
25
if (!force_json && bs->file->bs->exact_filename[0]) {
53
+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=off ---
26
- snprintf(bs->exact_filename, sizeof(bs->exact_filename),
54
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
27
- "blkdebug:%s:%s", s->config_file ?: "",
55
Image resized.
28
- bs->file->bs->exact_filename);
56
wrote 2048000/2048000 bytes at offset 0
29
+ int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
57
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
30
+ "blkdebug:%s:%s", s->config_file ?: "",
58
wrote 16384/16384 bytes at offset 2048000
31
+ bs->file->bs->exact_filename);
59
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
32
+ if (ret >= sizeof(bs->exact_filename)) {
60
33
+ /* An overflow makes the filename unusable, so do not report any */
61
---- growth_size=16 create_mode=off growth_mode=metadata ---
34
+ bs->exact_filename[0] = 0;
62
+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=metadata ---
35
+ }
63
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
36
}
64
Image resized.
37
65
wrote 2048000/2048000 bytes at offset 0
38
opts = qdict_new();
66
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
67
wrote 16384/16384 bytes at offset 2048000
68
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
69
70
---- growth_size=16 create_mode=off growth_mode=falloc ---
71
+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=falloc ---
72
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
73
Image resized.
74
wrote 2048000/2048000 bytes at offset 0
75
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
76
wrote 16384/16384 bytes at offset 2048000
77
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
78
79
---- growth_size=16 create_mode=off growth_mode=full ---
80
+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=full ---
81
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
82
Image resized.
83
wrote 2048000/2048000 bytes at offset 0
84
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
85
wrote 16384/16384 bytes at offset 2048000
86
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
87
88
---- growth_size=16 create_mode=metadata growth_mode=off ---
89
+--- cluster_size=512 growth_size=16 create_mode=metadata growth_mode=off ---
90
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
91
Image resized.
92
wrote 2048000/2048000 bytes at offset 0
93
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
94
wrote 16384/16384 bytes at offset 2048000
95
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
96
97
---- growth_size=16 create_mode=metadata growth_mode=metadata ---
98
+--- cluster_size=512 growth_size=16 create_mode=metadata growth_mode=metadata ---
99
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
100
Image resized.
101
wrote 2048000/2048000 bytes at offset 0
102
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
103
wrote 16384/16384 bytes at offset 2048000
104
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
105
106
---- growth_size=16 create_mode=metadata growth_mode=falloc ---
107
+--- cluster_size=512 growth_size=16 create_mode=metadata growth_mode=falloc ---
108
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
109
Image resized.
110
wrote 2048000/2048000 bytes at offset 0
111
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
112
wrote 16384/16384 bytes at offset 2048000
113
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
114
115
---- growth_size=16 create_mode=metadata growth_mode=full ---
116
+--- cluster_size=512 growth_size=16 create_mode=metadata growth_mode=full ---
117
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
118
Image resized.
119
wrote 2048000/2048000 bytes at offset 0
120
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
121
wrote 16384/16384 bytes at offset 2048000
122
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
123
124
---- growth_size=16 create_mode=falloc growth_mode=off ---
125
+--- cluster_size=512 growth_size=16 create_mode=falloc growth_mode=off ---
126
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
127
Image resized.
128
wrote 2048000/2048000 bytes at offset 0
129
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
130
wrote 16384/16384 bytes at offset 2048000
131
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
132
133
---- growth_size=16 create_mode=falloc growth_mode=metadata ---
134
+--- cluster_size=512 growth_size=16 create_mode=falloc growth_mode=metadata ---
135
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
136
Image resized.
137
wrote 2048000/2048000 bytes at offset 0
138
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
139
wrote 16384/16384 bytes at offset 2048000
140
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
141
142
---- growth_size=16 create_mode=falloc growth_mode=falloc ---
143
+--- cluster_size=512 growth_size=16 create_mode=falloc growth_mode=falloc ---
144
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
145
Image resized.
146
wrote 2048000/2048000 bytes at offset 0
147
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
148
wrote 16384/16384 bytes at offset 2048000
149
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
150
151
---- growth_size=16 create_mode=falloc growth_mode=full ---
152
+--- cluster_size=512 growth_size=16 create_mode=falloc growth_mode=full ---
153
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
154
Image resized.
155
wrote 2048000/2048000 bytes at offset 0
156
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
157
wrote 16384/16384 bytes at offset 2048000
158
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
159
160
---- growth_size=16 create_mode=full growth_mode=off ---
161
+--- cluster_size=512 growth_size=16 create_mode=full growth_mode=off ---
162
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
163
Image resized.
164
wrote 2048000/2048000 bytes at offset 0
165
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
166
wrote 16384/16384 bytes at offset 2048000
167
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
168
169
---- growth_size=16 create_mode=full growth_mode=metadata ---
170
+--- cluster_size=512 growth_size=16 create_mode=full growth_mode=metadata ---
171
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
172
Image resized.
173
wrote 2048000/2048000 bytes at offset 0
174
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
175
wrote 16384/16384 bytes at offset 2048000
176
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
177
178
---- growth_size=16 create_mode=full growth_mode=falloc ---
179
+--- cluster_size=512 growth_size=16 create_mode=full growth_mode=falloc ---
180
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
181
Image resized.
182
wrote 2048000/2048000 bytes at offset 0
183
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
184
wrote 16384/16384 bytes at offset 2048000
185
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
186
187
---- growth_size=16 create_mode=full growth_mode=full ---
188
+--- cluster_size=512 growth_size=16 create_mode=full growth_mode=full ---
189
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
190
Image resized.
191
wrote 2048000/2048000 bytes at offset 0
192
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
193
wrote 16384/16384 bytes at offset 2048000
194
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
195
196
---- growth_size=48 create_mode=off growth_mode=off ---
197
+--- cluster_size=512 growth_size=48 create_mode=off growth_mode=off ---
198
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
199
Image resized.
200
wrote 2048000/2048000 bytes at offset 0
201
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
202
wrote 49152/49152 bytes at offset 2048000
203
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
204
205
---- growth_size=48 create_mode=off growth_mode=metadata ---
206
+--- cluster_size=512 growth_size=48 create_mode=off growth_mode=metadata ---
207
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
208
Image resized.
209
wrote 2048000/2048000 bytes at offset 0
210
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
211
wrote 49152/49152 bytes at offset 2048000
212
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
213
214
---- growth_size=48 create_mode=off growth_mode=falloc ---
215
+--- cluster_size=512 growth_size=48 create_mode=off growth_mode=falloc ---
216
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
217
Image resized.
218
wrote 2048000/2048000 bytes at offset 0
219
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
220
wrote 49152/49152 bytes at offset 2048000
221
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
222
223
---- growth_size=48 create_mode=off growth_mode=full ---
224
+--- cluster_size=512 growth_size=48 create_mode=off growth_mode=full ---
225
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
226
Image resized.
227
wrote 2048000/2048000 bytes at offset 0
228
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
229
wrote 49152/49152 bytes at offset 2048000
230
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
231
232
---- growth_size=48 create_mode=metadata growth_mode=off ---
233
+--- cluster_size=512 growth_size=48 create_mode=metadata growth_mode=off ---
234
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
235
Image resized.
236
wrote 2048000/2048000 bytes at offset 0
237
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
238
wrote 49152/49152 bytes at offset 2048000
239
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
240
241
---- growth_size=48 create_mode=metadata growth_mode=metadata ---
242
+--- cluster_size=512 growth_size=48 create_mode=metadata growth_mode=metadata ---
243
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
244
Image resized.
245
wrote 2048000/2048000 bytes at offset 0
246
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
247
wrote 49152/49152 bytes at offset 2048000
248
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
249
250
---- growth_size=48 create_mode=metadata growth_mode=falloc ---
251
+--- cluster_size=512 growth_size=48 create_mode=metadata growth_mode=falloc ---
252
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
253
Image resized.
254
wrote 2048000/2048000 bytes at offset 0
255
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
256
wrote 49152/49152 bytes at offset 2048000
257
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
258
259
---- growth_size=48 create_mode=metadata growth_mode=full ---
260
+--- cluster_size=512 growth_size=48 create_mode=metadata growth_mode=full ---
261
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
262
Image resized.
263
wrote 2048000/2048000 bytes at offset 0
264
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
265
wrote 49152/49152 bytes at offset 2048000
266
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
267
268
---- growth_size=48 create_mode=falloc growth_mode=off ---
269
+--- cluster_size=512 growth_size=48 create_mode=falloc growth_mode=off ---
270
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
271
Image resized.
272
wrote 2048000/2048000 bytes at offset 0
273
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
274
wrote 49152/49152 bytes at offset 2048000
275
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
276
277
---- growth_size=48 create_mode=falloc growth_mode=metadata ---
278
+--- cluster_size=512 growth_size=48 create_mode=falloc growth_mode=metadata ---
279
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
280
Image resized.
281
wrote 2048000/2048000 bytes at offset 0
282
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
283
wrote 49152/49152 bytes at offset 2048000
284
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
285
286
---- growth_size=48 create_mode=falloc growth_mode=falloc ---
287
+--- cluster_size=512 growth_size=48 create_mode=falloc growth_mode=falloc ---
288
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
289
Image resized.
290
wrote 2048000/2048000 bytes at offset 0
291
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
292
wrote 49152/49152 bytes at offset 2048000
293
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
294
295
---- growth_size=48 create_mode=falloc growth_mode=full ---
296
+--- cluster_size=512 growth_size=48 create_mode=falloc growth_mode=full ---
297
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
298
Image resized.
299
wrote 2048000/2048000 bytes at offset 0
300
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
301
wrote 49152/49152 bytes at offset 2048000
302
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
303
304
---- growth_size=48 create_mode=full growth_mode=off ---
305
+--- cluster_size=512 growth_size=48 create_mode=full growth_mode=off ---
306
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
307
Image resized.
308
wrote 2048000/2048000 bytes at offset 0
309
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
310
wrote 49152/49152 bytes at offset 2048000
311
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
312
313
---- growth_size=48 create_mode=full growth_mode=metadata ---
314
+--- cluster_size=512 growth_size=48 create_mode=full growth_mode=metadata ---
315
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
316
Image resized.
317
wrote 2048000/2048000 bytes at offset 0
318
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
319
wrote 49152/49152 bytes at offset 2048000
320
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
321
322
---- growth_size=48 create_mode=full growth_mode=falloc ---
323
+--- cluster_size=512 growth_size=48 create_mode=full growth_mode=falloc ---
324
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
325
Image resized.
326
wrote 2048000/2048000 bytes at offset 0
327
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
328
wrote 49152/49152 bytes at offset 2048000
329
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
330
331
---- growth_size=48 create_mode=full growth_mode=full ---
332
+--- cluster_size=512 growth_size=48 create_mode=full growth_mode=full ---
333
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
334
Image resized.
335
wrote 2048000/2048000 bytes at offset 0
336
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
337
wrote 49152/49152 bytes at offset 2048000
338
48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
339
340
---- growth_size=80 create_mode=off growth_mode=off ---
341
+--- cluster_size=512 growth_size=80 create_mode=off growth_mode=off ---
342
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
343
Image resized.
344
wrote 2048000/2048000 bytes at offset 0
345
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
346
wrote 81920/81920 bytes at offset 2048000
347
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
348
349
---- growth_size=80 create_mode=off growth_mode=metadata ---
350
+--- cluster_size=512 growth_size=80 create_mode=off growth_mode=metadata ---
351
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
352
Image resized.
353
wrote 2048000/2048000 bytes at offset 0
354
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
355
wrote 81920/81920 bytes at offset 2048000
356
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
357
358
---- growth_size=80 create_mode=off growth_mode=falloc ---
359
+--- cluster_size=512 growth_size=80 create_mode=off growth_mode=falloc ---
360
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
361
Image resized.
362
wrote 2048000/2048000 bytes at offset 0
363
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
364
wrote 81920/81920 bytes at offset 2048000
365
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
366
367
---- growth_size=80 create_mode=off growth_mode=full ---
368
+--- cluster_size=512 growth_size=80 create_mode=off growth_mode=full ---
369
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
370
Image resized.
371
wrote 2048000/2048000 bytes at offset 0
372
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
373
wrote 81920/81920 bytes at offset 2048000
374
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
375
376
---- growth_size=80 create_mode=metadata growth_mode=off ---
377
+--- cluster_size=512 growth_size=80 create_mode=metadata growth_mode=off ---
378
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
379
Image resized.
380
wrote 2048000/2048000 bytes at offset 0
381
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
382
wrote 81920/81920 bytes at offset 2048000
383
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
384
385
---- growth_size=80 create_mode=metadata growth_mode=metadata ---
386
+--- cluster_size=512 growth_size=80 create_mode=metadata growth_mode=metadata ---
387
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
388
Image resized.
389
wrote 2048000/2048000 bytes at offset 0
390
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
391
wrote 81920/81920 bytes at offset 2048000
392
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
393
394
---- growth_size=80 create_mode=metadata growth_mode=falloc ---
395
+--- cluster_size=512 growth_size=80 create_mode=metadata growth_mode=falloc ---
396
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
397
Image resized.
398
wrote 2048000/2048000 bytes at offset 0
399
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
400
wrote 81920/81920 bytes at offset 2048000
401
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
402
403
---- growth_size=80 create_mode=metadata growth_mode=full ---
404
+--- cluster_size=512 growth_size=80 create_mode=metadata growth_mode=full ---
405
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
406
Image resized.
407
wrote 2048000/2048000 bytes at offset 0
408
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
409
wrote 81920/81920 bytes at offset 2048000
410
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
411
412
---- growth_size=80 create_mode=falloc growth_mode=off ---
413
+--- cluster_size=512 growth_size=80 create_mode=falloc growth_mode=off ---
414
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
415
Image resized.
416
wrote 2048000/2048000 bytes at offset 0
417
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
418
wrote 81920/81920 bytes at offset 2048000
419
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
420
421
---- growth_size=80 create_mode=falloc growth_mode=metadata ---
422
+--- cluster_size=512 growth_size=80 create_mode=falloc growth_mode=metadata ---
423
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
424
Image resized.
425
wrote 2048000/2048000 bytes at offset 0
426
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
427
wrote 81920/81920 bytes at offset 2048000
428
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
429
430
---- growth_size=80 create_mode=falloc growth_mode=falloc ---
431
+--- cluster_size=512 growth_size=80 create_mode=falloc growth_mode=falloc ---
432
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
433
Image resized.
434
wrote 2048000/2048000 bytes at offset 0
435
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
436
wrote 81920/81920 bytes at offset 2048000
437
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
438
439
---- growth_size=80 create_mode=falloc growth_mode=full ---
440
+--- cluster_size=512 growth_size=80 create_mode=falloc growth_mode=full ---
441
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
442
Image resized.
443
wrote 2048000/2048000 bytes at offset 0
444
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
445
wrote 81920/81920 bytes at offset 2048000
446
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
447
448
---- growth_size=80 create_mode=full growth_mode=off ---
449
+--- cluster_size=512 growth_size=80 create_mode=full growth_mode=off ---
450
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
451
Image resized.
452
wrote 2048000/2048000 bytes at offset 0
453
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
454
wrote 81920/81920 bytes at offset 2048000
455
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
456
457
---- growth_size=80 create_mode=full growth_mode=metadata ---
458
+--- cluster_size=512 growth_size=80 create_mode=full growth_mode=metadata ---
459
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
460
Image resized.
461
wrote 2048000/2048000 bytes at offset 0
462
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
463
wrote 81920/81920 bytes at offset 2048000
464
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
465
466
---- growth_size=80 create_mode=full growth_mode=falloc ---
467
+--- cluster_size=512 growth_size=80 create_mode=full growth_mode=falloc ---
468
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
469
Image resized.
470
wrote 2048000/2048000 bytes at offset 0
471
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
472
wrote 81920/81920 bytes at offset 2048000
473
80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
474
475
---- growth_size=80 create_mode=full growth_mode=full ---
476
+--- cluster_size=512 growth_size=80 create_mode=full growth_mode=full ---
477
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
478
+Image resized.
479
+wrote 2048000/2048000 bytes at offset 0
480
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
481
+wrote 81920/81920 bytes at offset 2048000
482
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
483
+
484
+--- cluster_size=64k growth_size=16 create_mode=off growth_mode=off ---
485
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
486
+Image resized.
487
+wrote 2048000/2048000 bytes at offset 0
488
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
489
+wrote 16384/16384 bytes at offset 2048000
490
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
491
+
492
+--- cluster_size=64k growth_size=16 create_mode=off growth_mode=metadata ---
493
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
494
+Image resized.
495
+wrote 2048000/2048000 bytes at offset 0
496
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
497
+wrote 16384/16384 bytes at offset 2048000
498
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
499
+
500
+--- cluster_size=64k growth_size=16 create_mode=off growth_mode=falloc ---
501
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
502
+Image resized.
503
+wrote 2048000/2048000 bytes at offset 0
504
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
505
+wrote 16384/16384 bytes at offset 2048000
506
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
507
+
508
+--- cluster_size=64k growth_size=16 create_mode=off growth_mode=full ---
509
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
510
+Image resized.
511
+wrote 2048000/2048000 bytes at offset 0
512
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
513
+wrote 16384/16384 bytes at offset 2048000
514
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
515
+
516
+--- cluster_size=64k growth_size=16 create_mode=metadata growth_mode=off ---
517
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
518
+Image resized.
519
+wrote 2048000/2048000 bytes at offset 0
520
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
521
+wrote 16384/16384 bytes at offset 2048000
522
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
523
+
524
+--- cluster_size=64k growth_size=16 create_mode=metadata growth_mode=metadata ---
525
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
526
+Image resized.
527
+wrote 2048000/2048000 bytes at offset 0
528
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
529
+wrote 16384/16384 bytes at offset 2048000
530
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
531
+
532
+--- cluster_size=64k growth_size=16 create_mode=metadata growth_mode=falloc ---
533
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
534
+Image resized.
535
+wrote 2048000/2048000 bytes at offset 0
536
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
537
+wrote 16384/16384 bytes at offset 2048000
538
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
539
+
540
+--- cluster_size=64k growth_size=16 create_mode=metadata growth_mode=full ---
541
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
542
+Image resized.
543
+wrote 2048000/2048000 bytes at offset 0
544
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
545
+wrote 16384/16384 bytes at offset 2048000
546
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
547
+
548
+--- cluster_size=64k growth_size=16 create_mode=falloc growth_mode=off ---
549
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
550
+Image resized.
551
+wrote 2048000/2048000 bytes at offset 0
552
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
553
+wrote 16384/16384 bytes at offset 2048000
554
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
555
+
556
+--- cluster_size=64k growth_size=16 create_mode=falloc growth_mode=metadata ---
557
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
558
+Image resized.
559
+wrote 2048000/2048000 bytes at offset 0
560
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
561
+wrote 16384/16384 bytes at offset 2048000
562
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
563
+
564
+--- cluster_size=64k growth_size=16 create_mode=falloc growth_mode=falloc ---
565
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
566
+Image resized.
567
+wrote 2048000/2048000 bytes at offset 0
568
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
569
+wrote 16384/16384 bytes at offset 2048000
570
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
571
+
572
+--- cluster_size=64k growth_size=16 create_mode=falloc growth_mode=full ---
573
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
574
+Image resized.
575
+wrote 2048000/2048000 bytes at offset 0
576
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
577
+wrote 16384/16384 bytes at offset 2048000
578
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
579
+
580
+--- cluster_size=64k growth_size=16 create_mode=full growth_mode=off ---
581
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
582
+Image resized.
583
+wrote 2048000/2048000 bytes at offset 0
584
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
585
+wrote 16384/16384 bytes at offset 2048000
586
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
587
+
588
+--- cluster_size=64k growth_size=16 create_mode=full growth_mode=metadata ---
589
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
590
+Image resized.
591
+wrote 2048000/2048000 bytes at offset 0
592
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
593
+wrote 16384/16384 bytes at offset 2048000
594
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
595
+
596
+--- cluster_size=64k growth_size=16 create_mode=full growth_mode=falloc ---
597
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
598
+Image resized.
599
+wrote 2048000/2048000 bytes at offset 0
600
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
601
+wrote 16384/16384 bytes at offset 2048000
602
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
603
+
604
+--- cluster_size=64k growth_size=16 create_mode=full growth_mode=full ---
605
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
606
+Image resized.
607
+wrote 2048000/2048000 bytes at offset 0
608
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
609
+wrote 16384/16384 bytes at offset 2048000
610
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
611
+
612
+--- cluster_size=64k growth_size=48 create_mode=off growth_mode=off ---
613
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
614
+Image resized.
615
+wrote 2048000/2048000 bytes at offset 0
616
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
617
+wrote 49152/49152 bytes at offset 2048000
618
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
619
+
620
+--- cluster_size=64k growth_size=48 create_mode=off growth_mode=metadata ---
621
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
622
+Image resized.
623
+wrote 2048000/2048000 bytes at offset 0
624
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
625
+wrote 49152/49152 bytes at offset 2048000
626
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
627
+
628
+--- cluster_size=64k growth_size=48 create_mode=off growth_mode=falloc ---
629
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
630
+Image resized.
631
+wrote 2048000/2048000 bytes at offset 0
632
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
633
+wrote 49152/49152 bytes at offset 2048000
634
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
635
+
636
+--- cluster_size=64k growth_size=48 create_mode=off growth_mode=full ---
637
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
638
+Image resized.
639
+wrote 2048000/2048000 bytes at offset 0
640
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
641
+wrote 49152/49152 bytes at offset 2048000
642
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
643
+
644
+--- cluster_size=64k growth_size=48 create_mode=metadata growth_mode=off ---
645
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
646
+Image resized.
647
+wrote 2048000/2048000 bytes at offset 0
648
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
649
+wrote 49152/49152 bytes at offset 2048000
650
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
651
+
652
+--- cluster_size=64k growth_size=48 create_mode=metadata growth_mode=metadata ---
653
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
654
+Image resized.
655
+wrote 2048000/2048000 bytes at offset 0
656
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
657
+wrote 49152/49152 bytes at offset 2048000
658
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
659
+
660
+--- cluster_size=64k growth_size=48 create_mode=metadata growth_mode=falloc ---
661
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
662
+Image resized.
663
+wrote 2048000/2048000 bytes at offset 0
664
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
665
+wrote 49152/49152 bytes at offset 2048000
666
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
667
+
668
+--- cluster_size=64k growth_size=48 create_mode=metadata growth_mode=full ---
669
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
670
+Image resized.
671
+wrote 2048000/2048000 bytes at offset 0
672
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
673
+wrote 49152/49152 bytes at offset 2048000
674
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
675
+
676
+--- cluster_size=64k growth_size=48 create_mode=falloc growth_mode=off ---
677
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
678
+Image resized.
679
+wrote 2048000/2048000 bytes at offset 0
680
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
681
+wrote 49152/49152 bytes at offset 2048000
682
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
683
+
684
+--- cluster_size=64k growth_size=48 create_mode=falloc growth_mode=metadata ---
685
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
686
+Image resized.
687
+wrote 2048000/2048000 bytes at offset 0
688
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
689
+wrote 49152/49152 bytes at offset 2048000
690
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
691
+
692
+--- cluster_size=64k growth_size=48 create_mode=falloc growth_mode=falloc ---
693
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
694
+Image resized.
695
+wrote 2048000/2048000 bytes at offset 0
696
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
697
+wrote 49152/49152 bytes at offset 2048000
698
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
699
+
700
+--- cluster_size=64k growth_size=48 create_mode=falloc growth_mode=full ---
701
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
702
+Image resized.
703
+wrote 2048000/2048000 bytes at offset 0
704
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
705
+wrote 49152/49152 bytes at offset 2048000
706
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
707
+
708
+--- cluster_size=64k growth_size=48 create_mode=full growth_mode=off ---
709
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
710
+Image resized.
711
+wrote 2048000/2048000 bytes at offset 0
712
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
713
+wrote 49152/49152 bytes at offset 2048000
714
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
715
+
716
+--- cluster_size=64k growth_size=48 create_mode=full growth_mode=metadata ---
717
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
718
+Image resized.
719
+wrote 2048000/2048000 bytes at offset 0
720
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
721
+wrote 49152/49152 bytes at offset 2048000
722
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
723
+
724
+--- cluster_size=64k growth_size=48 create_mode=full growth_mode=falloc ---
725
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
726
+Image resized.
727
+wrote 2048000/2048000 bytes at offset 0
728
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
729
+wrote 49152/49152 bytes at offset 2048000
730
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
731
+
732
+--- cluster_size=64k growth_size=48 create_mode=full growth_mode=full ---
733
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
734
+Image resized.
735
+wrote 2048000/2048000 bytes at offset 0
736
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
737
+wrote 49152/49152 bytes at offset 2048000
738
+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
739
+
740
+--- cluster_size=64k growth_size=80 create_mode=off growth_mode=off ---
741
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
742
+Image resized.
743
+wrote 2048000/2048000 bytes at offset 0
744
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
745
+wrote 81920/81920 bytes at offset 2048000
746
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
747
+
748
+--- cluster_size=64k growth_size=80 create_mode=off growth_mode=metadata ---
749
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
750
+Image resized.
751
+wrote 2048000/2048000 bytes at offset 0
752
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
753
+wrote 81920/81920 bytes at offset 2048000
754
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
755
+
756
+--- cluster_size=64k growth_size=80 create_mode=off growth_mode=falloc ---
757
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
758
+Image resized.
759
+wrote 2048000/2048000 bytes at offset 0
760
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
761
+wrote 81920/81920 bytes at offset 2048000
762
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
763
+
764
+--- cluster_size=64k growth_size=80 create_mode=off growth_mode=full ---
765
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
766
+Image resized.
767
+wrote 2048000/2048000 bytes at offset 0
768
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
769
+wrote 81920/81920 bytes at offset 2048000
770
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
771
+
772
+--- cluster_size=64k growth_size=80 create_mode=metadata growth_mode=off ---
773
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
774
+Image resized.
775
+wrote 2048000/2048000 bytes at offset 0
776
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
777
+wrote 81920/81920 bytes at offset 2048000
778
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
779
+
780
+--- cluster_size=64k growth_size=80 create_mode=metadata growth_mode=metadata ---
781
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
782
+Image resized.
783
+wrote 2048000/2048000 bytes at offset 0
784
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
785
+wrote 81920/81920 bytes at offset 2048000
786
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
787
+
788
+--- cluster_size=64k growth_size=80 create_mode=metadata growth_mode=falloc ---
789
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
790
+Image resized.
791
+wrote 2048000/2048000 bytes at offset 0
792
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
793
+wrote 81920/81920 bytes at offset 2048000
794
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
795
+
796
+--- cluster_size=64k growth_size=80 create_mode=metadata growth_mode=full ---
797
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata
798
+Image resized.
799
+wrote 2048000/2048000 bytes at offset 0
800
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
801
+wrote 81920/81920 bytes at offset 2048000
802
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
803
+
804
+--- cluster_size=64k growth_size=80 create_mode=falloc growth_mode=off ---
805
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
806
+Image resized.
807
+wrote 2048000/2048000 bytes at offset 0
808
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
809
+wrote 81920/81920 bytes at offset 2048000
810
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
811
+
812
+--- cluster_size=64k growth_size=80 create_mode=falloc growth_mode=metadata ---
813
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
814
+Image resized.
815
+wrote 2048000/2048000 bytes at offset 0
816
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
817
+wrote 81920/81920 bytes at offset 2048000
818
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
819
+
820
+--- cluster_size=64k growth_size=80 create_mode=falloc growth_mode=falloc ---
821
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
822
+Image resized.
823
+wrote 2048000/2048000 bytes at offset 0
824
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
825
+wrote 81920/81920 bytes at offset 2048000
826
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
827
+
828
+--- cluster_size=64k growth_size=80 create_mode=falloc growth_mode=full ---
829
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc
830
+Image resized.
831
+wrote 2048000/2048000 bytes at offset 0
832
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
833
+wrote 81920/81920 bytes at offset 2048000
834
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
835
+
836
+--- cluster_size=64k growth_size=80 create_mode=full growth_mode=off ---
837
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
838
+Image resized.
839
+wrote 2048000/2048000 bytes at offset 0
840
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
841
+wrote 81920/81920 bytes at offset 2048000
842
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
843
+
844
+--- cluster_size=64k growth_size=80 create_mode=full growth_mode=metadata ---
845
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
846
+Image resized.
847
+wrote 2048000/2048000 bytes at offset 0
848
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
849
+wrote 81920/81920 bytes at offset 2048000
850
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
851
+
852
+--- cluster_size=64k growth_size=80 create_mode=full growth_mode=falloc ---
853
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
854
+Image resized.
855
+wrote 2048000/2048000 bytes at offset 0
856
+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
857
+wrote 81920/81920 bytes at offset 2048000
858
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
859
+
860
+--- cluster_size=64k growth_size=80 create_mode=full growth_mode=full ---
861
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full
862
Image resized.
863
wrote 2048000/2048000 bytes at offset 0
39
--
864
--
40
1.8.3.1
865
2.13.6
41
866
42
867
diff view generated by jsdifflib