1
The following changes since commit ae49fbbcd8e4e9d8bf7131add34773f579e1aff7:
1
The following changes since commit d9bbfea646e86426d549bd612cd9f91e49aa50c2:
2
2
3
Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20171025' into staging (2017-10-25 16:38:57 +0100)
3
Merge remote-tracking branch 'remotes/riscv/tags/riscv-qemu-upstream-v8.2' into staging (2018-03-09 10:58:57 +0000)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 4254d01ce4eec9a3ccf320d14e2da132b8ad4a51:
9
for you to fetch changes up to a1be5921e35dcf84ce9e3c9a5c3029cea530a60b:
10
10
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-10-26' into queue-block (2017-10-26 15:02:40 +0200)
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-03-09' into queue-block (2018-03-09 16:09:06 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches
15
15
16
----------------------------------------------------------------
16
----------------------------------------------------------------
17
Alberto Garcia (1):
17
Alberto Garcia (8):
18
qcow2: Use BDRV_SECTOR_BITS instead of its literal value
18
qcow2: Generalize validate_table_offset() into qcow2_validate_table()
19
qcow2: Check L1 table offset in qcow2_snapshot_load_tmp()
20
qcow2: Check L1 table parameters in qcow2_expand_zero_clusters()
21
qcow2: Check snapshot L1 tables in qcow2_check_metadata_overlap()
22
qcow2: Check snapshot L1 table in qcow2_snapshot_goto()
23
qcow2: Check snapshot L1 table in qcow2_snapshot_delete()
24
qcow2: Make qemu-img check detect corrupted L1 tables in snapshots
25
iotests: Tweak 030 in order to trigger a race condition with parallel jobs
19
26
20
Eric Blake (24):
27
Daniel P. Berrangé (1):
21
block: Allow NULL file for bdrv_get_block_status()
28
block: implement the bdrv_reopen_prepare helper for LUKS driver
22
block: Add flag to avoid wasted work in bdrv_is_allocated()
23
block: Make bdrv_round_to_clusters() signature more useful
24
qcow2: Switch is_zero_sectors() to byte-based
25
block: Switch bdrv_make_zero() to byte-based
26
qemu-img: Switch get_block_status() to byte-based
27
block: Convert bdrv_get_block_status() to bytes
28
block: Switch bdrv_co_get_block_status() to byte-based
29
block: Switch BdrvCoGetBlockStatusData to byte-based
30
block: Switch bdrv_common_block_status_above() to byte-based
31
block: Switch bdrv_co_get_block_status_above() to byte-based
32
block: Convert bdrv_get_block_status_above() to bytes
33
qemu-img: Simplify logic in img_compare()
34
qemu-img: Speed up compare on pre-allocated larger file
35
qemu-img: Add find_nonzero()
36
qemu-img: Drop redundant error message in compare
37
qemu-img: Change check_empty_sectors() to byte-based
38
qemu-img: Change compare_sectors() to be byte-based
39
qemu-img: Change img_rebase() to be byte-based
40
qemu-img: Change img_compare() to be byte-based
41
block: Align block status requests
42
block: Reduce bdrv_aligned_preadv() rounding
43
qcow2: Reduce is_zero() rounding
44
qemu-io: Relax 'alloc' now that block-status doesn't assert
45
29
46
Kevin Wolf (2):
30
Eric Blake (1):
47
qemu-iotests: Test backing_fmt with backing node reference
31
iotests: Mark all tests executable
48
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-10-26' into queue-block
49
32
50
Max Reitz (8):
33
Fam Zheng (2):
51
qemu-img.1: Image invalidation on qemu-img commit
34
iotests: Test creating overlay when guest running
52
iotests: Add test for dataplane mirroring
35
iotests: Skip test for ENOMEM error
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
59
36
60
Peter Krempa (1):
37
Kevin Wolf (38):
61
block: don't add 'driver' to options when referring to backing via node name
38
block/qapi: Introduce BlockdevCreateOptions
39
block/qapi: Add qcow2 create options to schema
40
qcow2: Rename qcow2_co_create2() to qcow2_co_create()
41
qcow2: Let qcow2_create() handle protocol layer
42
qcow2: Pass BlockdevCreateOptions to qcow2_co_create()
43
qcow2: Use BlockdevRef in qcow2_co_create()
44
qcow2: Use QCryptoBlockCreateOptions in qcow2_co_create()
45
qcow2: Handle full/falloc preallocation in qcow2_co_create()
46
util: Add qemu_opts_to_qdict_filtered()
47
test-qemu-opts: Test qemu_opts_append()
48
test-qemu-opts: Test qemu_opts_to_qdict_filtered()
49
qdict: Introduce qdict_rename_keys()
50
qcow2: Use visitor for options in qcow2_create()
51
block: Make bdrv_is_whitelisted() public
52
block: x-blockdev-create QMP command
53
file-posix: Support .bdrv_co_create
54
file-win32: Support .bdrv_co_create
55
gluster: Support .bdrv_co_create
56
rbd: Fix use after free in qemu_rbd_set_keypairs() error path
57
rbd: Factor out qemu_rbd_connect()
58
rbd: Remove non-schema options from runtime_opts
59
rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
60
rbd: Support .bdrv_co_create
61
rbd: Assign s->snap/image_name in qemu_rbd_open()
62
rbd: Use qemu_rbd_connect() in qemu_rbd_do_create()
63
nfs: Use QAPI options in nfs_client_open()
64
nfs: Support .bdrv_co_create
65
sheepdog: QAPIfy "redundancy" create option
66
sheepdog: Support .bdrv_co_create
67
ssh: Use QAPI BlockdevOptionsSsh object
68
ssh: QAPIfy host-key-check option
69
ssh: Pass BlockdevOptionsSsh to connect_to_ssh()
70
ssh: Support .bdrv_co_create
71
file-posix: Fix no-op bdrv_truncate() with falloc preallocation
72
block: Fail bdrv_truncate() with negative size
73
qemu-iotests: Test qcow2 over file image creation with QMP
74
qemu-iotests: Test ssh image creation over QMP
75
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-03-09' into queue-block
62
76
63
include/block/block.h | 29 ++-
77
Paolo Bonzini (6):
64
include/block/block_int.h | 11 +-
78
qcow2: introduce qcow2_write_caches and qcow2_flush_caches
65
block.c | 3 +-
79
qcow2: fix flushing after dirty bitmap metadata writes
66
block/blkdebug.c | 13 +-
80
qcow2: make qcow2_do_open a coroutine_fn
67
block/io.c | 334 ++++++++++++++++-----------
81
qed: make bdrv_qed_do_open a coroutine_fn
68
block/mirror.c | 26 +--
82
block: convert bdrv_invalidate_cache callback to coroutine_fn
69
block/qcow2-cluster.c | 2 +-
83
block: convert bdrv_check callback to coroutine_fn
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
93
84
85
Stefan Hajnoczi (1):
86
qemu-iotests: fix 203 migration completion race
87
88
qapi/block-core.json | 326 +++++++++++++++++++++++++-
89
block/qcow2.h | 12 +-
90
include/block/block.h | 2 +
91
include/block/block_int.h | 13 +-
92
include/qapi/qmp/qdict.h | 6 +
93
include/qemu/option.h | 2 +
94
block.c | 138 +++++++++++-
95
block/create.c | 76 +++++++
96
block/crypto.c | 7 +
97
block/file-posix.c | 93 +++++---
98
block/file-win32.c | 47 +++-
99
block/gluster.c | 135 +++++++----
100
block/iscsi.c | 6 +-
101
block/nfs.c | 244 +++++++++-----------
102
block/parallels.c | 17 +-
103
block/qcow2-bitmap.c | 4 +-
104
block/qcow2-cluster.c | 24 +-
105
block/qcow2-refcount.c | 52 ++++-
106
block/qcow2-snapshot.c | 24 +-
107
block/qcow2.c | 552 ++++++++++++++++++++++++++++-----------------
108
block/qed-check.c | 1 +
109
block/qed-table.c | 26 +--
110
block/qed.c | 66 ++++--
111
block/rbd.c | 403 +++++++++++++++++----------------
112
block/sheepdog.c | 321 ++++++++++++++++++--------
113
block/ssh.c | 290 +++++++++++++-----------
114
block/vdi.c | 6 +-
115
block/vhdx.c | 7 +-
116
block/vmdk.c | 7 +-
117
qobject/qdict.c | 34 +++
118
tests/check-qdict.c | 129 +++++++++++
119
tests/test-qemu-opts.c | 253 +++++++++++++++++++++
120
util/qemu-option.c | 42 +++-
121
block/Makefile.objs | 2 +-
122
tests/qemu-iotests/030 | 52 ++++-
123
tests/qemu-iotests/030.out | 4 +-
124
tests/qemu-iotests/049.out | 8 +-
125
tests/qemu-iotests/059 | 5 +-
126
tests/qemu-iotests/080 | 22 +-
127
tests/qemu-iotests/080.out | 58 ++++-
128
tests/qemu-iotests/096 | 0
129
tests/qemu-iotests/112.out | 4 +-
130
tests/qemu-iotests/124 | 0
131
tests/qemu-iotests/129 | 0
132
tests/qemu-iotests/132 | 0
133
tests/qemu-iotests/136 | 0
134
tests/qemu-iotests/139 | 0
135
tests/qemu-iotests/148 | 0
136
tests/qemu-iotests/152 | 0
137
tests/qemu-iotests/153 | 8 +-
138
tests/qemu-iotests/153.out | 7 +-
139
tests/qemu-iotests/163 | 0
140
tests/qemu-iotests/203 | 15 +-
141
tests/qemu-iotests/203.out | 5 +
142
tests/qemu-iotests/205 | 0
143
tests/qemu-iotests/206 | 436 +++++++++++++++++++++++++++++++++++
144
tests/qemu-iotests/206.out | 209 +++++++++++++++++
145
tests/qemu-iotests/207 | 261 +++++++++++++++++++++
146
tests/qemu-iotests/207.out | 75 ++++++
147
tests/qemu-iotests/group | 2 +
148
60 files changed, 3574 insertions(+), 964 deletions(-)
149
create mode 100644 block/create.c
150
mode change 100644 => 100755 tests/qemu-iotests/096
151
mode change 100644 => 100755 tests/qemu-iotests/124
152
mode change 100644 => 100755 tests/qemu-iotests/129
153
mode change 100644 => 100755 tests/qemu-iotests/132
154
mode change 100644 => 100755 tests/qemu-iotests/136
155
mode change 100644 => 100755 tests/qemu-iotests/139
156
mode change 100644 => 100755 tests/qemu-iotests/148
157
mode change 100644 => 100755 tests/qemu-iotests/152
158
mode change 100644 => 100755 tests/qemu-iotests/163
159
mode change 100644 => 100755 tests/qemu-iotests/205
160
create mode 100755 tests/qemu-iotests/206
161
create mode 100644 tests/qemu-iotests/206.out
162
create mode 100755 tests/qemu-iotests/207
163
create mode 100644 tests/qemu-iotests/207.out
164
diff view generated by jsdifflib
New patch
1
From: "Daniel P. Berrange" <berrange@redhat.com>
1
2
3
If the bdrv_reopen_prepare helper isn't provided, the qemu-img commit
4
command fails to re-open the base layer after committing changes into
5
it. Provide a no-op implementation for the LUKS driver, since there
6
is not any custom work that needs doing to re-open it.
7
8
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block/crypto.c | 7 +++++++
12
1 file changed, 7 insertions(+)
13
14
diff --git a/block/crypto.c b/block/crypto.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/crypto.c
17
+++ b/block/crypto.c
18
@@ -XXX,XX +XXX,XX @@ static void block_crypto_close(BlockDriverState *bs)
19
qcrypto_block_free(crypto->block);
20
}
21
22
+static int block_crypto_reopen_prepare(BDRVReopenState *state,
23
+ BlockReopenQueue *queue, Error **errp)
24
+{
25
+ /* nothing needs checking */
26
+ return 0;
27
+}
28
29
/*
30
* 1 MB bounce buffer gives good performance / memory tradeoff
31
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
32
.bdrv_truncate = block_crypto_truncate,
33
.create_opts = &block_crypto_create_opts_luks,
34
35
+ .bdrv_reopen_prepare = block_crypto_reopen_prepare,
36
.bdrv_refresh_limits = block_crypto_refresh_limits,
37
.bdrv_co_preadv = block_crypto_co_preadv,
38
.bdrv_co_pwritev = block_crypto_co_pwritev,
39
--
40
2.13.6
41
42
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We are gradually converting to byte-based interfaces, as they are
3
They will be used to avoid recursively taking s->lock during
4
easier to reason about than sector-based. Continue by converting
4
bdrv_open or bdrv_check.
5
an internal function (no semantic change), and simplifying its
6
caller accordingly.
7
5
8
Signed-off-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Reviewed-by: Fam Zheng <famz@redhat.com>
7
Message-Id: <1516279431-30424-7-git-send-email-pbonzini@redhat.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
10
---
13
qemu-img.c | 24 +++++++++++-------------
11
block/qcow2.h | 2 ++
14
1 file changed, 11 insertions(+), 13 deletions(-)
12
block/qcow2-refcount.c | 28 ++++++++++++++++++++++++++++
13
block/qcow2.c | 20 ++++----------------
14
3 files changed, 34 insertions(+), 16 deletions(-)
15
15
16
diff --git a/qemu-img.c b/qemu-img.c
16
diff --git a/block/qcow2.h b/block/qcow2.h
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-img.c
18
--- a/block/qcow2.h
19
+++ b/qemu-img.c
19
+++ b/block/qcow2.h
20
@@ -XXX,XX +XXX,XX @@ static void dump_map_entry(OutputFormat output_format, MapEntry *e,
20
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
21
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
22
int64_t l1_table_offset, int l1_size, int addend);
23
24
+int coroutine_fn qcow2_flush_caches(BlockDriverState *bs);
25
+int coroutine_fn qcow2_write_caches(BlockDriverState *bs);
26
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
27
BdrvCheckMode fix);
28
29
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2-refcount.c
32
+++ b/block/qcow2-refcount.c
33
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
21
}
34
}
22
}
35
}
23
36
24
-static int get_block_status(BlockDriverState *bs, int64_t sector_num,
37
+int coroutine_fn qcow2_write_caches(BlockDriverState *bs)
25
- int nb_sectors, MapEntry *e)
38
+{
26
+static int get_block_status(BlockDriverState *bs, int64_t offset,
39
+ BDRVQcow2State *s = bs->opaque;
27
+ int64_t bytes, MapEntry *e)
40
+ int ret;
28
{
41
29
int64_t ret;
42
+ ret = qcow2_cache_write(bs, s->l2_table_cache);
30
int depth;
43
+ if (ret < 0) {
31
BlockDriverState *file;
44
+ return ret;
32
bool has_offset;
45
+ }
33
+ int nb_sectors = bytes >> BDRV_SECTOR_BITS;
46
+
34
47
+ if (qcow2_need_accurate_refcounts(s)) {
35
+ assert(bytes < INT_MAX);
48
+ ret = qcow2_cache_write(bs, s->refcount_block_cache);
36
/* As an optimization, we could cache the current range of unallocated
49
+ if (ret < 0) {
37
* clusters in each file of the chain, and avoid querying the same
50
+ return ret;
38
* range repeatedly.
51
+ }
39
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num,
52
+ }
40
53
+
41
depth = 0;
54
+ return 0;
42
for (;;) {
55
+}
43
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors,
56
+
44
- &file);
57
+int coroutine_fn qcow2_flush_caches(BlockDriverState *bs)
45
+ ret = bdrv_get_block_status(bs, offset >> BDRV_SECTOR_BITS, nb_sectors,
58
+{
46
+ &nb_sectors, &file);
59
+ int ret = qcow2_write_caches(bs);
60
+ if (ret < 0) {
61
+ return ret;
62
+ }
63
+
64
+ return bdrv_flush(bs->file->bs);
65
+}
66
67
/*********************************************************/
68
/* snapshots and image creation */
69
diff --git a/block/qcow2.c b/block/qcow2.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/qcow2.c
72
+++ b/block/qcow2.c
73
@@ -XXX,XX +XXX,XX @@ static int qcow2_mark_clean(BlockDriverState *bs)
74
75
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
76
77
- ret = bdrv_flush(bs);
78
+ ret = qcow2_flush_caches(bs);
47
if (ret < 0) {
79
if (ret < 0) {
48
return ret;
80
return ret;
49
}
81
}
50
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num,
82
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_consistent(BlockDriverState *bs)
51
has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
83
BDRVQcow2State *s = bs->opaque;
52
84
53
*e = (MapEntry) {
85
if (s->incompatible_features & QCOW2_INCOMPAT_CORRUPT) {
54
- .start = sector_num * BDRV_SECTOR_SIZE,
86
- int ret = bdrv_flush(bs);
55
+ .start = offset,
87
+ int ret = qcow2_flush_caches(bs);
56
.length = nb_sectors * BDRV_SECTOR_SIZE,
88
if (ret < 0) {
57
.data = !!(ret & BDRV_BLOCK_DATA),
89
return ret;
58
.zero = !!(ret & BDRV_BLOCK_ZERO),
90
}
59
@@ -XXX,XX +XXX,XX @@ static int img_map(int argc, char **argv)
91
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
60
92
int ret;
61
length = blk_getlength(blk);
93
62
while (curr.start + curr.length < length) {
94
qemu_co_mutex_lock(&s->lock);
63
- int64_t nsectors_left;
95
- ret = qcow2_cache_write(bs, s->l2_table_cache);
64
- int64_t sector_num;
96
- if (ret < 0) {
65
- int n;
97
- qemu_co_mutex_unlock(&s->lock);
98
- return ret;
99
- }
66
-
100
-
67
- sector_num = (curr.start + curr.length) >> BDRV_SECTOR_BITS;
101
- if (qcow2_need_accurate_refcounts(s)) {
68
+ int64_t offset = curr.start + curr.length;
102
- ret = qcow2_cache_write(bs, s->refcount_block_cache);
69
+ int64_t n;
103
- if (ret < 0) {
70
104
- qemu_co_mutex_unlock(&s->lock);
71
/* Probe up to 1 GiB at a time. */
105
- return ret;
72
- nsectors_left = DIV_ROUND_UP(length, BDRV_SECTOR_SIZE) - sector_num;
106
- }
73
- n = MIN(1 << (30 - BDRV_SECTOR_BITS), nsectors_left);
107
- }
74
- ret = get_block_status(bs, sector_num, n, &next);
108
+ ret = qcow2_write_caches(bs);
75
+ n = QEMU_ALIGN_DOWN(MIN(1 << 30, length - offset), BDRV_SECTOR_SIZE);
109
qemu_co_mutex_unlock(&s->lock);
76
+ ret = get_block_status(bs, offset, n, &next);
110
77
111
- return 0;
78
if (ret < 0) {
112
+ return ret;
79
error_report("Could not read file metadata: %s", strerror(-ret));
113
}
114
115
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
80
--
116
--
81
2.13.6
117
2.13.6
82
118
83
119
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Now that bdrv_is_allocated accepts non-aligned inputs, we can
3
update_header_sync itself does not need to flush the caches to disk.
4
remove the TODO added in commit d6a644bb.
4
The only paths that allocate clusters are:
5
5
6
Signed-off-by: Eric Blake <eblake@redhat.com>
6
- bitmap_list_store with in_place=false, called by update_ext_header_and_dir
7
Reviewed-by: John Snow <jsnow@redhat.com>
7
8
- store_bitmap_data, called by store_bitmap
9
10
- store_bitmap, called by qcow2_store_persistent_dirty_bitmaps and
11
followed by update_ext_header_and_dir
12
13
So in the end the central place where we need to flush the caches
14
is update_ext_header_and_dir.
15
16
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
18
---
10
block/io.c | 8 ++------
19
block/qcow2-bitmap.c | 4 ++--
11
1 file changed, 2 insertions(+), 6 deletions(-)
20
1 file changed, 2 insertions(+), 2 deletions(-)
12
21
13
diff --git a/block/io.c b/block/io.c
22
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
14
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
15
--- a/block/io.c
24
--- a/block/qcow2-bitmap.c
16
+++ b/block/io.c
25
+++ b/block/qcow2-bitmap.c
17
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
26
@@ -XXX,XX +XXX,XX @@ static int update_header_sync(BlockDriverState *bs)
27
return ret;
18
}
28
}
19
29
20
if (flags & BDRV_REQ_COPY_ON_READ) {
30
- return bdrv_flush(bs);
21
- /* TODO: Simplify further once bdrv_is_allocated no longer
31
+ return bdrv_flush(bs->file->bs);
22
- * requires sector alignment */
32
}
23
- int64_t start = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
33
24
- int64_t end = QEMU_ALIGN_UP(offset + bytes, BDRV_SECTOR_SIZE);
34
static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
25
int64_t pnum;
35
@@ -XXX,XX +XXX,XX @@ static int update_ext_header_and_dir(BlockDriverState *bs,
26
36
return ret;
27
- ret = bdrv_is_allocated(bs, start, end - start, &pnum);
37
}
28
+ ret = bdrv_is_allocated(bs, offset, bytes, &pnum);
38
39
- ret = bdrv_flush(bs->file->bs);
40
+ ret = qcow2_flush_caches(bs);
29
if (ret < 0) {
41
if (ret < 0) {
30
goto out;
42
goto fail;
31
}
32
33
- if (!ret || pnum != end - start) {
34
+ if (!ret || pnum != bytes) {
35
ret = bdrv_co_do_copy_on_readv(child, offset, bytes, qiov);
36
goto out;
37
}
43
}
38
--
44
--
39
2.13.6
45
2.13.6
40
46
41
47
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Now that bdrv_is_allocated accepts non-aligned inputs, we can
3
It is called from qcow2_invalidate_cache in coroutine context (incoming
4
remove the TODO added in earlier refactoring.
4
migration runs in a coroutine), so it's cleaner if metadata is always
5
loaded from a coroutine.
5
6
6
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <1516279431-30424-4-git-send-email-pbonzini@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
11
---
9
block/qcow2.c | 12 +++---------
12
block/qcow2.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
10
1 file changed, 3 insertions(+), 9 deletions(-)
13
1 file changed, 41 insertions(+), 5 deletions(-)
11
14
12
diff --git a/block/qcow2.c b/block/qcow2.c
15
diff --git a/block/qcow2.c b/block/qcow2.c
13
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
14
--- a/block/qcow2.c
17
--- a/block/qcow2.c
15
+++ b/block/qcow2.c
18
+++ b/block/qcow2.c
16
@@ -XXX,XX +XXX,XX @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
19
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
20
return ret;
21
}
22
23
-static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
24
- Error **errp)
25
+/* Called with s->lock held. */
26
+static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
27
+ int flags, Error **errp)
17
{
28
{
18
int64_t nr;
29
BDRVQcow2State *s = bs->opaque;
19
int res;
30
unsigned int len, i;
20
- int64_t start;
31
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
21
-
32
}
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;
32
}
33
}
33
34
34
if (!bytes) {
35
- /* Initialise locks */
35
return true;
36
- qemu_co_mutex_init(&s->lock);
37
bs->supported_zero_flags = header.version >= 3 ? BDRV_REQ_MAY_UNMAP : 0;
38
39
/* Repair image if dirty */
40
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
41
return ret;
42
}
43
44
+typedef struct QCow2OpenCo {
45
+ BlockDriverState *bs;
46
+ QDict *options;
47
+ int flags;
48
+ Error **errp;
49
+ int ret;
50
+} QCow2OpenCo;
51
+
52
+static void coroutine_fn qcow2_open_entry(void *opaque)
53
+{
54
+ QCow2OpenCo *qoc = opaque;
55
+ BDRVQcow2State *s = qoc->bs->opaque;
56
+
57
+ qemu_co_mutex_lock(&s->lock);
58
+ qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, qoc->errp);
59
+ qemu_co_mutex_unlock(&s->lock);
60
+}
61
+
62
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
63
Error **errp)
64
{
65
+ BDRVQcow2State *s = bs->opaque;
66
+ QCow2OpenCo qoc = {
67
+ .bs = bs,
68
+ .options = options,
69
+ .flags = flags,
70
+ .errp = errp,
71
+ .ret = -EINPROGRESS
72
+ };
73
+
74
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
75
false, errp);
76
if (!bs->file) {
77
return -EINVAL;
36
}
78
}
37
- res = bdrv_block_status_above(bs, NULL, start, bytes, &nr, NULL, NULL);
79
38
+ res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
80
- return qcow2_do_open(bs, options, flags, errp);
39
return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == bytes;
81
+ /* Initialise locks */
82
+ qemu_co_mutex_init(&s->lock);
83
+
84
+ if (qemu_in_coroutine()) {
85
+ /* From bdrv_co_create. */
86
+ qcow2_open_entry(&qoc);
87
+ } else {
88
+ qemu_coroutine_enter(qemu_coroutine_create(qcow2_open_entry, &qoc));
89
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
90
+ }
91
+ return qoc.ret;
40
}
92
}
41
93
94
static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
42
--
95
--
43
2.13.6
96
2.13.6
44
97
45
98
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Previously, the alloc command required that input parameters be
3
It is called from qed_invalidate_cache in coroutine context (incoming
4
sector-aligned and clamped to 32 bits, because the underlying
4
migration runs in a coroutine), so it's cleaner if metadata is always
5
bdrv_is_allocated used a 32-bit parameter and asserted aligned
5
loaded from a coroutine.
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.
11
6
12
Update iotest 177 to intentionally probe block status at
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
13
unaligned boundaries as well as with a bytes value that does not
8
Message-Id: <1516279431-30424-5-git-send-email-pbonzini@redhat.com>
14
map to 32-bit sectors, which also required tweaking the image
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
prep to leave an unallocated portion to the image under test.
16
17
Signed-off-by: Eric Blake <eblake@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
11
---
20
qemu-io-cmds.c | 13 -------------
12
block/qed.c | 40 +++++++++++++++++++++++++++++++++++++---
21
tests/qemu-iotests/177 | 12 ++++++++++--
13
1 file changed, 37 insertions(+), 3 deletions(-)
22
tests/qemu-iotests/177.out | 19 ++++++++++++++-----
23
3 files changed, 24 insertions(+), 20 deletions(-)
24
14
25
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
15
diff --git a/block/qed.c b/block/qed.c
26
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
27
--- a/qemu-io-cmds.c
17
--- a/block/qed.c
28
+++ b/qemu-io-cmds.c
18
+++ b/block/qed.c
29
@@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv)
19
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_init_state(BlockDriverState *bs)
30
if (offset < 0) {
20
qemu_co_queue_init(&s->allocating_write_reqs);
31
print_cvtnum_err(offset, argv[1]);
21
}
32
return 0;
22
33
- } else if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
23
-static int bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags,
34
- printf("%" PRId64 " is not a sector-aligned value for 'offset'\n",
24
- Error **errp)
35
- offset);
25
+/* Called with table_lock held. */
36
- return 0;
26
+static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
27
+ int flags, Error **errp)
28
{
29
BDRVQEDState *s = bs->opaque;
30
QEDHeader le_header;
31
@@ -XXX,XX +XXX,XX @@ out:
32
return ret;
33
}
34
35
+typedef struct QEDOpenCo {
36
+ BlockDriverState *bs;
37
+ QDict *options;
38
+ int flags;
39
+ Error **errp;
40
+ int ret;
41
+} QEDOpenCo;
42
+
43
+static void coroutine_fn bdrv_qed_open_entry(void *opaque)
44
+{
45
+ QEDOpenCo *qoc = opaque;
46
+ BDRVQEDState *s = qoc->bs->opaque;
47
+
48
+ qemu_co_mutex_lock(&s->table_lock);
49
+ qoc->ret = bdrv_qed_do_open(qoc->bs, qoc->options, qoc->flags, qoc->errp);
50
+ qemu_co_mutex_unlock(&s->table_lock);
51
+}
52
+
53
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
54
Error **errp)
55
{
56
+ QEDOpenCo qoc = {
57
+ .bs = bs,
58
+ .options = options,
59
+ .flags = flags,
60
+ .errp = errp,
61
+ .ret = -EINPROGRESS
62
+ };
63
+
64
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
65
false, errp);
66
if (!bs->file) {
67
@@ -XXX,XX +XXX,XX @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
37
}
68
}
38
69
39
if (argc == 3) {
70
bdrv_qed_init_state(bs);
40
@@ -XXX,XX +XXX,XX @@ static int alloc_f(BlockBackend *blk, int argc, char **argv)
71
- return bdrv_qed_do_open(bs, options, flags, errp);
41
if (count < 0) {
72
+ if (qemu_in_coroutine()) {
42
print_cvtnum_err(count, argv[2]);
73
+ bdrv_qed_open_entry(&qoc);
43
return 0;
74
+ } else {
44
- } else if (count > INT_MAX * BDRV_SECTOR_SIZE) {
75
+ qemu_coroutine_enter(qemu_coroutine_create(bdrv_qed_open_entry, &qoc));
45
- printf("length argument cannot exceed %llu, given %s\n",
76
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
46
- INT_MAX * BDRV_SECTOR_SIZE, argv[2]);
77
+ }
47
- return 0;
78
+ BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
48
}
79
+ return qoc.ret;
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;
56
- }
57
58
remaining = count;
59
sum_alloc = 0;
60
diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177
61
index XXXXXXX..XXXXXXX 100755
62
--- a/tests/qemu-iotests/177
63
+++ b/tests/qemu-iotests/177
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
82
+
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
94
}
80
}
95
81
96
verify_io | $QEMU_IO -r "$TEST_IMG" | _filter_qemu_io
82
static void bdrv_qed_refresh_limits(BlockDriverState *bs, Error **errp)
97
diff --git a/tests/qemu-iotests/177.out b/tests/qemu-iotests/177.out
98
index XXXXXXX..XXXXXXX 100644
99
--- a/tests/qemu-iotests/177.out
100
+++ b/tests/qemu-iotests/177.out
101
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
102
wrote 134217728/134217728 bytes at offset 0
103
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
104
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
105
-wrote 134217728/134217728 bytes at offset 0
106
-128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
107
+wrote 115343360/115343360 bytes at offset 0
108
+110 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
109
110
== constrained alignment and max-transfer ==
111
wrote 131072/131072 bytes at offset 1000
112
@@ -XXX,XX +XXX,XX @@ wrote 33554432/33554432 bytes at offset 33554432
113
discard 31457280/31457280 bytes at offset 80000001
114
30 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
115
116
+== block status smaller than alignment ==
117
+1/1 bytes allocated at offset 1 bytes
118
+16/1000 bytes allocated at offset 110 MiB
119
+0/1048576 bytes allocated at offset 127 MiB
120
+110 MiB (0x6e00000) bytes allocated at offset 0 bytes (0x0)
121
+18 MiB (0x1200000) bytes not allocated at offset 110 MiB (0x6e00000)
122
+
123
== verify image content ==
124
read 1000/1000 bytes at offset 0
125
1000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
126
@@ -XXX,XX +XXX,XX @@ read 13631488/13631488 bytes at offset 67108864
127
13 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
128
read 30408704/30408704 bytes at offset 80740352
129
29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
130
-read 23068672/23068672 bytes at offset 111149056
131
-22 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
132
+read 4194304/4194304 bytes at offset 111149056
133
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
134
+read 18874368/18874368 bytes at offset 115343360
135
+18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
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
144
--
83
--
145
2.13.6
84
2.13.6
146
85
147
86
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Not all callers care about which BDS owns the mapping for a given
3
QED's bdrv_invalidate_cache implementation would like to reuse functions
4
range of the file. This patch merely simplifies the callers by
4
that acquire/release the metadata locks. Call it from coroutine context
5
consolidating the logic in the common call point, while guaranteeing
5
to simplify the logic.
6
a non-NULL file to all the driver callbacks, for no semantic change.
6
7
The only caller that does not care about pnum is bdrv_is_allocated,
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
as invoked by vvfat; we can likewise add assertions that the rest
8
Message-Id: <1516279431-30424-6-git-send-email-pbonzini@redhat.com>
9
of the stack does not have to worry about a NULL pnum.
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
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>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
11
---
25
include/block/block_int.h | 10 ++++++----
12
include/block/block_int.h | 3 ++-
26
block/io.c | 49 ++++++++++++++++++++++++++---------------------
13
block.c | 41 +++++++++++++++++++++++++++++++++++++----
27
block/mirror.c | 3 +--
14
block/iscsi.c | 6 +++---
28
block/qcow2.c | 8 ++------
15
block/nfs.c | 6 +++---
29
qemu-img.c | 10 ++++------
16
block/qcow2.c | 7 +++++--
30
5 files changed, 40 insertions(+), 40 deletions(-)
17
block/qed.c | 13 +++++--------
18
block/rbd.c | 6 +++---
19
7 files changed, 58 insertions(+), 24 deletions(-)
31
20
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
33
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int.h
23
--- a/include/block/block_int.h
35
+++ b/include/block/block_int.h
24
+++ b/include/block/block_int.h
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
25
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
37
int64_t offset, int bytes);
38
39
/*
26
/*
40
- * Building block for bdrv_block_status[_above]. The driver should
27
* Invalidate any cached meta-data.
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
*/
28
*/
51
int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs,
29
- void (*bdrv_invalidate_cache)(BlockDriverState *bs, Error **errp);
52
int64_t sector_num, int nb_sectors, int *pnum,
30
+ void coroutine_fn (*bdrv_co_invalidate_cache)(BlockDriverState *bs,
53
diff --git a/block/io.c b/block/io.c
31
+ Error **errp);
54
index XXXXXXX..XXXXXXX 100644
32
int (*bdrv_inactivate)(BlockDriverState *bs);
55
--- a/block/io.c
33
56
+++ b/block/io.c
34
/*
57
@@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
35
diff --git a/block.c b/block.c
58
{
36
index XXXXXXX..XXXXXXX 100644
59
int64_t target_sectors, ret, nb_sectors, sector_num = 0;
37
--- a/block.c
60
BlockDriverState *bs = child->bs;
38
+++ b/block.c
61
- BlockDriverState *file;
39
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
62
int n;
40
bdrv_init();
63
41
}
64
target_sectors = bdrv_nb_sectors(bs);
42
65
@@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
43
-void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
66
if (nb_sectors <= 0) {
44
+static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
67
return 0;
45
+ Error **errp)
68
}
46
{
69
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, &file);
47
BdrvChild *child, *parent;
70
+ ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, NULL);
48
uint64_t perm, shared_perm;
71
if (ret < 0) {
49
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
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
}
50
}
101
51
102
if (sector_num >= total_sectors) {
52
QLIST_FOREACH(child, &bs->children, next) {
103
- *pnum = 0;
53
- bdrv_invalidate_cache(child->bs, &local_err);
104
- return BDRV_BLOCK_EOF;
54
+ bdrv_co_invalidate_cache(child->bs, &local_err);
105
+ ret = BDRV_BLOCK_EOF;
55
if (local_err) {
106
+ goto early_out;
56
error_propagate(errp, local_err);
57
return;
58
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
107
}
59
}
108
if (!nb_sectors) {
60
bdrv_set_perm(bs, perm, shared_perm);
109
- *pnum = 0;
61
110
- return 0;
62
- if (bs->drv->bdrv_invalidate_cache) {
111
+ ret = 0;
63
- bs->drv->bdrv_invalidate_cache(bs, &local_err);
112
+ goto early_out;
64
+ if (bs->drv->bdrv_co_invalidate_cache) {
65
+ bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
66
if (local_err) {
67
bs->open_flags |= BDRV_O_INACTIVE;
68
error_propagate(errp, local_err);
69
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
113
}
70
}
114
71
}
115
n = total_sectors - sector_num;
72
116
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
73
+typedef struct InvalidateCacheCo {
117
}
74
+ BlockDriverState *bs;
118
if (bs->drv->protocol_name) {
75
+ Error **errp;
119
ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
76
+ bool done;
120
- *file = bs;
77
+} InvalidateCacheCo;
121
+ local_file = bs;
78
+
122
}
79
+static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque)
123
- return ret;
80
+{
124
+ goto early_out;
81
+ InvalidateCacheCo *ico = opaque;
125
}
82
+ bdrv_co_invalidate_cache(ico->bs, ico->errp);
126
83
+ ico->done = true;
127
bdrv_inc_in_flight(bs);
84
+}
128
ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
85
+
129
- file);
86
+void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
130
+ &local_file);
87
+{
131
if (ret < 0) {
88
+ Coroutine *co;
132
*pnum = 0;
89
+ InvalidateCacheCo ico = {
133
goto out;
90
+ .bs = bs,
134
}
91
+ .done = false,
135
92
+ .errp = errp
136
if (ret & BDRV_BLOCK_RAW) {
93
+ };
137
- assert(ret & BDRV_BLOCK_OFFSET_VALID && *file);
94
+
138
- ret = bdrv_co_get_block_status(*file, ret >> BDRV_SECTOR_BITS,
95
+ if (qemu_in_coroutine()) {
139
- *pnum, pnum, file);
96
+ /* Fast-path if already in coroutine context */
140
+ assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
97
+ bdrv_invalidate_cache_co_entry(&ico);
141
+ ret = bdrv_co_get_block_status(local_file, ret >> BDRV_SECTOR_BITS,
98
+ } else {
142
+ *pnum, pnum, &local_file);
99
+ co = qemu_coroutine_create(bdrv_invalidate_cache_co_entry, &ico);
143
goto out;
100
+ qemu_coroutine_enter(co);
144
}
101
+ BDRV_POLL_WHILE(bs, !ico.done);
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
+ }
102
+ }
172
return ret;
103
+}
173
}
104
+
174
105
void bdrv_invalidate_cache_all(Error **errp)
175
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status(BlockDriverState *bs,
106
{
176
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
107
BlockDriverState *bs;
177
int64_t bytes, int64_t *pnum)
108
diff --git a/block/iscsi.c b/block/iscsi.c
178
{
109
index XXXXXXX..XXXXXXX 100644
179
- BlockDriverState *file;
110
--- a/block/iscsi.c
180
int64_t sector_num = offset >> BDRV_SECTOR_BITS;
111
+++ b/block/iscsi.c
181
int nb_sectors = bytes >> BDRV_SECTOR_BITS;
112
@@ -XXX,XX +XXX,XX @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
182
int64_t ret;
113
return 0;
183
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
114
}
184
assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
115
185
assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE) && bytes < INT_MAX);
116
-static void iscsi_invalidate_cache(BlockDriverState *bs,
186
ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &psectors,
117
- Error **errp)
187
- &file);
118
+static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs,
188
+ NULL);
119
+ Error **errp)
189
if (ret < 0) {
120
{
190
return ret;
121
IscsiLun *iscsilun = bs->opaque;
191
}
122
iscsi_allocmap_invalidate(iscsilun);
192
diff --git a/block/mirror.c b/block/mirror.c
123
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = {
193
index XXXXXXX..XXXXXXX 100644
124
.create_opts = &iscsi_create_opts,
194
--- a/block/mirror.c
125
.bdrv_reopen_prepare = iscsi_reopen_prepare,
195
+++ b/block/mirror.c
126
.bdrv_reopen_commit = iscsi_reopen_commit,
196
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
127
- .bdrv_invalidate_cache = iscsi_invalidate_cache,
197
int io_sectors;
128
+ .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache,
198
unsigned int io_bytes;
129
199
int64_t io_bytes_acct;
130
.bdrv_getlength = iscsi_getlength,
200
- BlockDriverState *file;
131
.bdrv_get_info = iscsi_get_info,
201
enum MirrorMethod {
132
diff --git a/block/nfs.c b/block/nfs.c
202
MIRROR_METHOD_COPY,
133
index XXXXXXX..XXXXXXX 100644
203
MIRROR_METHOD_ZERO,
134
--- a/block/nfs.c
204
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
135
+++ b/block/nfs.c
205
ret = bdrv_get_block_status_above(source, NULL,
136
@@ -XXX,XX +XXX,XX @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
206
offset >> BDRV_SECTOR_BITS,
137
}
207
nb_chunks * sectors_per_chunk,
138
208
- &io_sectors, &file);
139
#ifdef LIBNFS_FEATURE_PAGECACHE
209
+ &io_sectors, NULL);
140
-static void nfs_invalidate_cache(BlockDriverState *bs,
210
io_bytes = io_sectors * BDRV_SECTOR_SIZE;
141
- Error **errp)
211
if (ret < 0) {
142
+static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs,
212
io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes);
143
+ Error **errp)
144
{
145
NFSClient *client = bs->opaque;
146
nfs_pagecache_invalidate(client->context, client->fh);
147
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
148
.bdrv_refresh_filename = nfs_refresh_filename,
149
150
#ifdef LIBNFS_FEATURE_PAGECACHE
151
- .bdrv_invalidate_cache = nfs_invalidate_cache,
152
+ .bdrv_co_invalidate_cache = nfs_co_invalidate_cache,
153
#endif
154
};
155
213
diff --git a/block/qcow2.c b/block/qcow2.c
156
diff --git a/block/qcow2.c b/block/qcow2.c
214
index XXXXXXX..XXXXXXX 100644
157
index XXXXXXX..XXXXXXX 100644
215
--- a/block/qcow2.c
158
--- a/block/qcow2.c
216
+++ b/block/qcow2.c
159
+++ b/block/qcow2.c
217
@@ -XXX,XX +XXX,XX @@ static bool is_zero_sectors(BlockDriverState *bs, int64_t start,
160
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
218
uint32_t count)
161
qcow2_free_snapshots(bs);
219
{
162
}
220
int nr;
163
221
- BlockDriverState *file;
164
-static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
222
int64_t res;
165
+static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs,
223
166
+ Error **errp)
224
if (start + count > bs->total_sectors) {
167
{
225
@@ -XXX,XX +XXX,XX @@ static bool is_zero_sectors(BlockDriverState *bs, int64_t start,
168
BDRVQcow2State *s = bs->opaque;
226
if (!count) {
169
int flags = s->flags;
227
return true;
170
@@ -XXX,XX +XXX,XX @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
228
}
171
options = qdict_clone_shallow(bs->options);
229
- res = bdrv_get_block_status_above(bs, NULL, start, count,
172
230
- &nr, &file);
173
flags &= ~BDRV_O_INACTIVE;
231
+ res = bdrv_get_block_status_above(bs, NULL, start, count, &nr, NULL);
174
+ qemu_co_mutex_lock(&s->lock);
232
return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == count;
175
ret = qcow2_do_open(bs, options, flags, &local_err);
233
}
176
+ qemu_co_mutex_unlock(&s->lock);
234
177
QDECREF(options);
235
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
178
if (local_err) {
236
offset += pnum * BDRV_SECTOR_SIZE) {
179
error_propagate(errp, local_err);
237
int nb_sectors = MIN(ssize - offset,
180
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
238
BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;
181
.bdrv_change_backing_file = qcow2_change_backing_file,
239
- BlockDriverState *file;
182
240
int64_t ret;
183
.bdrv_refresh_limits = qcow2_refresh_limits,
241
184
- .bdrv_invalidate_cache = qcow2_invalidate_cache,
242
ret = bdrv_get_block_status_above(in_bs, NULL,
185
+ .bdrv_co_invalidate_cache = qcow2_co_invalidate_cache,
243
offset >> BDRV_SECTOR_BITS,
186
.bdrv_inactivate = qcow2_inactivate,
244
- nb_sectors,
187
245
- &pnum, &file);
188
.create_opts = &qcow2_create_opts,
246
+ nb_sectors, &pnum, NULL);
189
diff --git a/block/qed.c b/block/qed.c
247
if (ret < 0) {
190
index XXXXXXX..XXXXXXX 100644
248
error_setg_errno(&local_err, -ret,
191
--- a/block/qed.c
249
"Unable to get block status");
192
+++ b/block/qed.c
250
diff --git a/qemu-img.c b/qemu-img.c
193
@@ -XXX,XX +XXX,XX @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
251
index XXXXXXX..XXXXXXX 100644
194
return ret;
252
--- a/qemu-img.c
195
}
253
+++ b/qemu-img.c
196
254
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
197
-static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
255
198
+static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs,
256
for (;;) {
199
+ Error **errp)
257
int64_t status1, status2;
200
{
258
- BlockDriverState *file;
201
BDRVQEDState *s = bs->opaque;
259
202
Error *local_err = NULL;
260
nb_sectors = sectors_to_process(total_sectors, sector_num);
203
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
261
if (nb_sectors <= 0) {
204
bdrv_qed_close(bs);
262
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
205
263
}
206
bdrv_qed_init_state(bs);
264
status1 = bdrv_get_block_status_above(bs1, NULL, sector_num,
207
- if (qemu_in_coroutine()) {
265
total_sectors1 - sector_num,
208
- qemu_co_mutex_lock(&s->table_lock);
266
- &pnum1, &file);
209
- }
267
+ &pnum1, NULL);
210
+ qemu_co_mutex_lock(&s->table_lock);
268
if (status1 < 0) {
211
ret = bdrv_qed_do_open(bs, NULL, bs->open_flags, &local_err);
269
ret = 3;
212
- if (qemu_in_coroutine()) {
270
error_report("Sector allocation test failed for %s", filename1);
213
- qemu_co_mutex_unlock(&s->table_lock);
271
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
214
- }
272
215
+ qemu_co_mutex_unlock(&s->table_lock);
273
status2 = bdrv_get_block_status_above(bs2, NULL, sector_num,
216
if (local_err) {
274
total_sectors2 - sector_num,
217
error_propagate(errp, local_err);
275
- &pnum2, &file);
218
error_prepend(errp, "Could not reopen qed layer: ");
276
+ &pnum2, NULL);
219
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
277
if (status2 < 0) {
220
.bdrv_get_info = bdrv_qed_get_info,
278
ret = 3;
221
.bdrv_refresh_limits = bdrv_qed_refresh_limits,
279
error_report("Sector allocation test failed for %s", filename2);
222
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
280
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
223
- .bdrv_invalidate_cache = bdrv_qed_invalidate_cache,
281
n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
224
+ .bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache,
282
225
.bdrv_check = bdrv_qed_check,
283
if (s->sector_next_status <= sector_num) {
226
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
284
- BlockDriverState *file;
227
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
285
if (s->target_has_backing) {
228
diff --git a/block/rbd.c b/block/rbd.c
286
ret = bdrv_get_block_status(blk_bs(s->src[src_cur]),
229
index XXXXXXX..XXXXXXX 100644
287
sector_num - src_cur_offset,
230
--- a/block/rbd.c
288
- n, &n, &file);
231
+++ b/block/rbd.c
289
+ n, &n, NULL);
232
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qemu_rbd_aio_pdiscard(BlockDriverState *bs,
290
} else {
233
#endif
291
ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL,
234
292
sector_num - src_cur_offset,
235
#ifdef LIBRBD_SUPPORTS_INVALIDATE
293
- n, &n, &file);
236
-static void qemu_rbd_invalidate_cache(BlockDriverState *bs,
294
+ n, &n, NULL);
237
- Error **errp)
295
}
238
+static void coroutine_fn qemu_rbd_co_invalidate_cache(BlockDriverState *bs,
296
if (ret < 0) {
239
+ Error **errp)
297
return ret;
240
{
241
BDRVRBDState *s = bs->opaque;
242
int r = rbd_invalidate_cache(s->image);
243
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
244
.bdrv_snapshot_list = qemu_rbd_snap_list,
245
.bdrv_snapshot_goto = qemu_rbd_snap_rollback,
246
#ifdef LIBRBD_SUPPORTS_INVALIDATE
247
- .bdrv_invalidate_cache = qemu_rbd_invalidate_cache,
248
+ .bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache,
249
#endif
250
};
251
298
--
252
--
299
2.13.6
253
2.13.6
300
254
301
255
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Any device that has request_alignment greater than 512 should be
3
Suggested-by: Kevin Wolf <kwolf@redhat.com>
4
unable to report status at a finer granularity; it may also be
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
simpler for such devices to be guaranteed that the block layer
5
Message-Id: <1516279431-30424-8-git-send-email-pbonzini@redhat.com>
6
has rounded things out to the granularity boundary (the way the
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
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.
11
12
Add an assertion in blkdebug that proves that the block layer
13
never requests status of unaligned sections, similar to what it
14
does on other requests (while still keeping the generic helper
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.
20
21
There is a mid-function scope added for 'count' and 'longret',
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>
32
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
33
---
8
---
34
include/block/block_int.h | 3 +-
9
include/block/block_int.h | 5 +++--
35
block/blkdebug.c | 13 ++++++++-
10
block.c | 43 ++++++++++++++++++++++++++++++++++++++++---
36
block/io.c | 71 ++++++++++++++++++++++++++++++-----------------
11
block/parallels.c | 17 +++++++++++------
37
3 files changed, 59 insertions(+), 28 deletions(-)
12
block/qcow2.c | 23 +++++++++++++++++++----
13
block/qed-check.c | 1 +
14
block/qed-table.c | 26 +++++++++-----------------
15
block/qed.c | 13 +++++++++----
16
block/vdi.c | 6 +++---
17
block/vhdx.c | 7 ++++---
18
block/vmdk.c | 7 ++++---
19
10 files changed, 103 insertions(+), 45 deletions(-)
38
20
39
diff --git a/include/block/block_int.h b/include/block/block_int.h
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
40
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
41
--- a/include/block/block_int.h
23
--- a/include/block/block_int.h
42
+++ b/include/block/block_int.h
24
+++ b/include/block/block_int.h
43
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
25
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
44
* according to the current layer, and should not set
26
* Returns 0 for completed check, -errno for internal errors.
45
* BDRV_BLOCK_ALLOCATED, but may set BDRV_BLOCK_RAW. See block.h
27
* The check results are stored in result.
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
*/
28
*/
51
int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs,
29
- int (*bdrv_check)(BlockDriverState *bs, BdrvCheckResult *result,
52
int64_t sector_num, int nb_sectors, int *pnum,
30
- BdrvCheckMode fix);
53
diff --git a/block/blkdebug.c b/block/blkdebug.c
31
+ int coroutine_fn (*bdrv_co_check)(BlockDriverState *bs,
54
index XXXXXXX..XXXXXXX 100644
32
+ BdrvCheckResult *result,
55
--- a/block/blkdebug.c
33
+ BdrvCheckMode fix);
56
+++ b/block/blkdebug.c
34
57
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
35
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
58
return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
36
BlockDriverAmendStatusCB *status_cb,
59
}
37
diff --git a/block.c b/block.c
60
38
index XXXXXXX..XXXXXXX 100644
61
+static int64_t coroutine_fn blkdebug_co_get_block_status(
39
--- a/block.c
62
+ BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
40
+++ b/block.c
63
+ BlockDriverState **file)
41
@@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs)
42
* free of errors) or -errno when an internal error occurred. The results of the
43
* check are stored in res.
44
*/
45
-int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
46
+static int coroutine_fn bdrv_co_check(BlockDriverState *bs,
47
+ BdrvCheckResult *res, BdrvCheckMode fix)
48
{
49
if (bs->drv == NULL) {
50
return -ENOMEDIUM;
51
}
52
- if (bs->drv->bdrv_check == NULL) {
53
+ if (bs->drv->bdrv_co_check == NULL) {
54
return -ENOTSUP;
55
}
56
57
memset(res, 0, sizeof(*res));
58
- return bs->drv->bdrv_check(bs, res, fix);
59
+ return bs->drv->bdrv_co_check(bs, res, fix);
60
+}
61
+
62
+typedef struct CheckCo {
63
+ BlockDriverState *bs;
64
+ BdrvCheckResult *res;
65
+ BdrvCheckMode fix;
66
+ int ret;
67
+} CheckCo;
68
+
69
+static void bdrv_check_co_entry(void *opaque)
64
+{
70
+{
65
+ assert(QEMU_IS_ALIGNED(sector_num | nb_sectors,
71
+ CheckCo *cco = opaque;
66
+ DIV_ROUND_UP(bs->bl.request_alignment,
72
+ cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix);
67
+ BDRV_SECTOR_SIZE)));
68
+ return bdrv_co_get_block_status_from_file(bs, sector_num, nb_sectors,
69
+ pnum, file);
70
+}
73
+}
71
+
74
+
72
static void blkdebug_close(BlockDriverState *bs)
75
+int bdrv_check(BlockDriverState *bs,
73
{
76
+ BdrvCheckResult *res, BdrvCheckMode fix)
74
BDRVBlkdebugState *s = bs->opaque;
77
+{
75
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
78
+ Coroutine *co;
76
.bdrv_co_flush_to_disk = blkdebug_co_flush,
79
+ CheckCo cco = {
77
.bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes,
80
+ .bs = bs,
78
.bdrv_co_pdiscard = blkdebug_co_pdiscard,
81
+ .res = res,
79
- .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
82
+ .ret = -EINPROGRESS,
80
+ .bdrv_co_get_block_status = blkdebug_co_get_block_status,
83
+ .fix = fix,
81
84
+ };
82
.bdrv_debug_event = blkdebug_debug_event,
85
+
83
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
86
+ if (qemu_in_coroutine()) {
84
diff --git a/block/io.c b/block/io.c
87
+ /* Fast-path if already in coroutine context */
85
index XXXXXXX..XXXXXXX 100644
88
+ bdrv_check_co_entry(&cco);
86
--- a/block/io.c
89
+ } else {
87
+++ b/block/io.c
90
+ co = qemu_coroutine_create(bdrv_check_co_entry, &cco);
88
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
91
+ qemu_coroutine_enter(co);
89
{
92
+ BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS);
90
int64_t total_size;
93
+ }
91
int64_t n; /* bytes */
94
+
92
- int64_t ret;
95
+ return cco.ret;
96
}
97
98
/*
99
diff --git a/block/parallels.c b/block/parallels.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/parallels.c
102
+++ b/block/parallels.c
103
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
104
}
105
106
107
-static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
108
- BdrvCheckMode fix)
109
+static int coroutine_fn parallels_co_check(BlockDriverState *bs,
110
+ BdrvCheckResult *res,
111
+ BdrvCheckMode fix)
112
{
113
BDRVParallelsState *s = bs->opaque;
114
int64_t size, prev_off, high_off;
115
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
116
return size;
117
}
118
119
+ qemu_co_mutex_lock(&s->lock);
120
if (s->header_unclean) {
121
fprintf(stderr, "%s image was not closed correctly\n",
122
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
123
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
124
prev_off = off;
125
}
126
127
+ ret = 0;
128
if (flush_bat) {
129
ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
130
if (ret < 0) {
131
res->check_errors++;
132
- return ret;
133
+ goto out;
134
}
135
}
136
137
@@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
138
if (ret < 0) {
139
error_report_err(local_err);
140
res->check_errors++;
141
- return ret;
142
+ goto out;
143
}
144
res->leaks_fixed += count;
145
}
146
}
147
148
- return 0;
149
+out:
150
+ qemu_co_mutex_unlock(&s->lock);
151
+ return ret;
152
}
153
154
155
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_parallels = {
156
.bdrv_co_writev = parallels_co_writev,
157
.supports_backing = true,
158
.bdrv_co_create_opts = parallels_co_create_opts,
159
- .bdrv_check = parallels_check,
160
+ .bdrv_co_check = parallels_co_check,
161
.create_opts = &parallels_create_opts,
162
};
163
164
diff --git a/block/qcow2.c b/block/qcow2.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/block/qcow2.c
167
+++ b/block/qcow2.c
168
@@ -XXX,XX +XXX,XX @@ int qcow2_mark_consistent(BlockDriverState *bs)
169
return 0;
170
}
171
172
-static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
173
- BdrvCheckMode fix)
174
+static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs,
175
+ BdrvCheckResult *result,
176
+ BdrvCheckMode fix)
177
{
178
int ret = qcow2_check_refcounts(bs, result, fix);
179
if (ret < 0) {
180
@@ -XXX,XX +XXX,XX @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
181
return ret;
182
}
183
184
+static int coroutine_fn qcow2_co_check(BlockDriverState *bs,
185
+ BdrvCheckResult *result,
186
+ BdrvCheckMode fix)
187
+{
188
+ BDRVQcow2State *s = bs->opaque;
93
+ int ret;
189
+ int ret;
94
int64_t local_map = 0;
190
+
95
BlockDriverState *local_file = NULL;
191
+ qemu_co_mutex_lock(&s->lock);
96
- int count; /* sectors */
192
+ ret = qcow2_co_check_locked(bs, result, fix);
97
+ int64_t aligned_offset, aligned_bytes;
193
+ qemu_co_mutex_unlock(&s->lock);
98
+ uint32_t align;
194
+ return ret;
99
195
+}
100
assert(pnum);
196
+
101
*pnum = 0;
197
static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
198
uint64_t entries, size_t entry_len)
103
}
199
{
104
200
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
105
bdrv_inc_in_flight(bs);
201
(s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
106
+
202
BdrvCheckResult result = {0};
107
+ /* Round out to request_alignment boundaries */
203
108
+ /* TODO: until we have a byte-based driver callback, we also have to
204
- ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
109
+ * round out to sectors, even if that is bigger than request_alignment */
205
+ ret = qcow2_co_check_locked(bs, &result,
110
+ align = MAX(bs->bl.request_alignment, BDRV_SECTOR_SIZE);
206
+ BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
111
+ aligned_offset = QEMU_ALIGN_DOWN(offset, align);
207
if (ret < 0 || result.check_errors) {
112
+ aligned_bytes = ROUND_UP(offset + bytes, align) - aligned_offset;
208
if (ret >= 0) {
113
+
209
ret = -EIO;
114
+ {
210
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
115
+ int count; /* sectors */
211
.bdrv_inactivate = qcow2_inactivate,
116
+ int64_t longret;
212
117
+
213
.create_opts = &qcow2_create_opts,
118
+ assert(QEMU_IS_ALIGNED(aligned_offset | aligned_bytes,
214
- .bdrv_check = qcow2_check,
119
+ BDRV_SECTOR_SIZE));
215
+ .bdrv_co_check = qcow2_co_check,
120
+ /*
216
.bdrv_amend_options = qcow2_amend_options,
121
+ * The contract allows us to return pnum smaller than bytes, even
217
122
+ * if the next query would see the same status; we truncate the
218
.bdrv_detach_aio_context = qcow2_detach_aio_context,
123
+ * request to avoid overflowing the driver's 32-bit interface.
219
diff --git a/block/qed-check.c b/block/qed-check.c
124
+ */
220
index XXXXXXX..XXXXXXX 100644
125
+ longret = bs->drv->bdrv_co_get_block_status(
221
--- a/block/qed-check.c
126
+ bs, aligned_offset >> BDRV_SECTOR_BITS,
222
+++ b/block/qed-check.c
127
+ MIN(INT_MAX, aligned_bytes) >> BDRV_SECTOR_BITS, &count,
223
@@ -XXX,XX +XXX,XX @@ static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
128
+ &local_file);
224
qed_write_header_sync(s);
129
+ if (longret < 0) {
225
}
130
+ assert(INT_MIN <= longret);
226
131
+ ret = longret;
227
+/* Called with table_lock held. */
132
+ goto out;
228
int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
133
+ }
229
{
134
+ if (longret & BDRV_BLOCK_OFFSET_VALID) {
230
QEDCheck check = {
135
+ local_map = longret & BDRV_BLOCK_OFFSET_MASK;
231
diff --git a/block/qed-table.c b/block/qed-table.c
136
+ }
232
index XXXXXXX..XXXXXXX 100644
137
+ ret = longret & ~BDRV_BLOCK_OFFSET_MASK;
233
--- a/block/qed-table.c
138
+ *pnum = count * BDRV_SECTOR_SIZE;
234
+++ b/block/qed-table.c
139
+ }
235
@@ -XXX,XX +XXX,XX @@
140
+
236
#include "qed.h"
141
/*
237
#include "qemu/bswap.h"
142
- * TODO: Rather than require aligned offsets, we could instead
238
143
- * round to the driver's request_alignment here, then touch up
239
-/* Called either from qed_check or with table_lock held. */
144
- * count afterwards back to the caller's expectations.
240
+/* Called with table_lock held. */
145
- */
241
static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
146
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
242
{
147
- /*
243
QEMUIOVector qiov;
148
- * The contract allows us to return pnum smaller than bytes, even
244
@@ -XXX,XX +XXX,XX @@ static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
149
- * if the next query would see the same status; we truncate the
245
150
- * request to avoid overflowing the driver's 32-bit interface.
246
trace_qed_read_table(s, offset, table);
151
+ * The driver's result must be a multiple of request_alignment.
247
152
+ * Clamp pnum and adjust map to original request.
248
- if (qemu_in_coroutine()) {
153
*/
249
- qemu_co_mutex_unlock(&s->table_lock);
154
- bytes = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
250
- }
155
- ret = bs->drv->bdrv_co_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
251
+ qemu_co_mutex_unlock(&s->table_lock);
156
- bytes >> BDRV_SECTOR_BITS, &count,
252
ret = bdrv_preadv(s->bs->file, offset, &qiov);
157
- &local_file);
253
- if (qemu_in_coroutine()) {
158
- if (ret < 0) {
254
- qemu_co_mutex_lock(&s->table_lock);
159
- goto out;
255
- }
160
+ assert(QEMU_IS_ALIGNED(*pnum, align) && align > offset - aligned_offset);
256
+ qemu_co_mutex_lock(&s->table_lock);
161
+ *pnum -= offset - aligned_offset;
257
if (ret < 0) {
162
+ if (*pnum > bytes) {
163
+ *pnum = bytes;
164
}
165
if (ret & BDRV_BLOCK_OFFSET_VALID) {
166
- local_map = ret & BDRV_BLOCK_OFFSET_MASK;
167
+ local_map += offset - aligned_offset;
168
}
169
- *pnum = count * BDRV_SECTOR_SIZE;
170
171
if (ret & BDRV_BLOCK_RAW) {
172
assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
173
ret = bdrv_co_block_status(local_file, want_zero, local_map,
174
*pnum, pnum, &local_map, &local_file);
175
- assert(ret < 0 ||
176
- QEMU_IS_ALIGNED(*pnum | local_map, BDRV_SECTOR_SIZE));
177
goto out;
258
goto out;
178
}
259
}
179
260
@@ -XXX,XX +XXX,XX @@ out:
180
@@ -XXX,XX +XXX,XX @@ early_out:
261
* @n: Number of elements
181
if (map) {
262
* @flush: Whether or not to sync to disk
182
*map = local_map;
263
*
183
}
264
- * Called either from qed_check or with table_lock held.
184
- if (ret >= 0) {
265
+ * Called with table_lock held.
185
- ret &= ~BDRV_BLOCK_OFFSET_MASK;
266
*/
186
- } else {
267
static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
187
- assert(INT_MIN <= ret);
268
unsigned int index, unsigned int n, bool flush)
269
@@ -XXX,XX +XXX,XX @@ static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
270
/* Adjust for offset into table */
271
offset += start * sizeof(uint64_t);
272
273
- if (qemu_in_coroutine()) {
274
- qemu_co_mutex_unlock(&s->table_lock);
188
- }
275
- }
189
return ret;
276
+ qemu_co_mutex_unlock(&s->table_lock);
190
}
277
ret = bdrv_pwritev(s->bs->file, offset, &qiov);
191
278
- if (qemu_in_coroutine()) {
279
- qemu_co_mutex_lock(&s->table_lock);
280
- }
281
+ qemu_co_mutex_lock(&s->table_lock);
282
trace_qed_write_table_cb(s, table, flush, ret);
283
if (ret < 0) {
284
goto out;
285
@@ -XXX,XX +XXX,XX @@ int qed_read_l1_table_sync(BDRVQEDState *s)
286
return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
287
}
288
289
-/* Called either from qed_check or with table_lock held. */
290
+/* Called with table_lock held. */
291
int qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n)
292
{
293
BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
294
@@ -XXX,XX +XXX,XX @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
295
return qed_write_l1_table(s, index, n);
296
}
297
298
-/* Called either from qed_check or with table_lock held. */
299
+/* Called with table_lock held. */
300
int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
301
{
302
int ret;
303
@@ -XXX,XX +XXX,XX @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
304
return qed_read_l2_table(s, request, offset);
305
}
306
307
-/* Called either from qed_check or with table_lock held. */
308
+/* Called with table_lock held. */
309
int qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
310
unsigned int index, unsigned int n, bool flush)
311
{
312
diff --git a/block/qed.c b/block/qed.c
313
index XXXXXXX..XXXXXXX 100644
314
--- a/block/qed.c
315
+++ b/block/qed.c
316
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs,
317
}
318
}
319
320
-static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
321
- BdrvCheckMode fix)
322
+static int bdrv_qed_co_check(BlockDriverState *bs, BdrvCheckResult *result,
323
+ BdrvCheckMode fix)
324
{
325
BDRVQEDState *s = bs->opaque;
326
+ int ret;
327
328
- return qed_check(s, result, !!fix);
329
+ qemu_co_mutex_lock(&s->table_lock);
330
+ ret = qed_check(s, result, !!fix);
331
+ qemu_co_mutex_unlock(&s->table_lock);
332
+
333
+ return ret;
334
}
335
336
static QemuOptsList qed_create_opts = {
337
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
338
.bdrv_refresh_limits = bdrv_qed_refresh_limits,
339
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
340
.bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache,
341
- .bdrv_check = bdrv_qed_check,
342
+ .bdrv_co_check = bdrv_qed_co_check,
343
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
344
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
345
.bdrv_co_drain_begin = bdrv_qed_co_drain_begin,
346
diff --git a/block/vdi.c b/block/vdi.c
347
index XXXXXXX..XXXXXXX 100644
348
--- a/block/vdi.c
349
+++ b/block/vdi.c
350
@@ -XXX,XX +XXX,XX @@ static void vdi_header_print(VdiHeader *header)
351
}
352
#endif
353
354
-static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res,
355
- BdrvCheckMode fix)
356
+static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res,
357
+ BdrvCheckMode fix)
358
{
359
/* TODO: additional checks possible. */
360
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
361
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = {
362
.bdrv_get_info = vdi_get_info,
363
364
.create_opts = &vdi_create_opts,
365
- .bdrv_check = vdi_check,
366
+ .bdrv_co_check = vdi_co_check,
367
};
368
369
static void bdrv_vdi_init(void)
370
diff --git a/block/vhdx.c b/block/vhdx.c
371
index XXXXXXX..XXXXXXX 100644
372
--- a/block/vhdx.c
373
+++ b/block/vhdx.c
374
@@ -XXX,XX +XXX,XX @@ exit:
375
* r/w and any log has already been replayed, so there is nothing (currently)
376
* for us to do here
377
*/
378
-static int vhdx_check(BlockDriverState *bs, BdrvCheckResult *result,
379
- BdrvCheckMode fix)
380
+static int coroutine_fn vhdx_co_check(BlockDriverState *bs,
381
+ BdrvCheckResult *result,
382
+ BdrvCheckMode fix)
383
{
384
BDRVVHDXState *s = bs->opaque;
385
386
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vhdx = {
387
.bdrv_co_writev = vhdx_co_writev,
388
.bdrv_co_create_opts = vhdx_co_create_opts,
389
.bdrv_get_info = vhdx_get_info,
390
- .bdrv_check = vhdx_check,
391
+ .bdrv_co_check = vhdx_co_check,
392
.bdrv_has_zero_init = bdrv_has_zero_init_1,
393
394
.create_opts = &vhdx_create_opts,
395
diff --git a/block/vmdk.c b/block/vmdk.c
396
index XXXXXXX..XXXXXXX 100644
397
--- a/block/vmdk.c
398
+++ b/block/vmdk.c
399
@@ -XXX,XX +XXX,XX @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
400
return info;
401
}
402
403
-static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result,
404
- BdrvCheckMode fix)
405
+static int coroutine_fn vmdk_co_check(BlockDriverState *bs,
406
+ BdrvCheckResult *result,
407
+ BdrvCheckMode fix)
408
{
409
BDRVVmdkState *s = bs->opaque;
410
VmdkExtent *extent = NULL;
411
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = {
412
.instance_size = sizeof(BDRVVmdkState),
413
.bdrv_probe = vmdk_probe,
414
.bdrv_open = vmdk_open,
415
- .bdrv_check = vmdk_check,
416
+ .bdrv_co_check = vmdk_co_check,
417
.bdrv_reopen_prepare = vmdk_reopen_prepare,
418
.bdrv_child_perm = bdrv_format_default_perms,
419
.bdrv_co_preadv = vmdk_co_preadv,
192
--
420
--
193
2.13.6
421
2.13.6
194
422
195
423
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
BDRV_SECTOR_BITS is defined to be 9 in block.h (and BDRV_SECTOR_SIZE
3
This function checks that the offset and size of a table are valid.
4
is calculated from that), but there are still a couple of places where
4
5
we are using the literal value instead of the macro.
5
While the offset checks are fine, the size check is too generic, since
6
it only verifies that the total size in bytes fits in a 64-bit
7
integer. In practice all tables used in qcow2 have much smaller size
8
limits, so the size needs to be checked again for each table using its
9
actual limit.
10
11
This patch generalizes this function by allowing the caller to specify
12
the maximum size for that table. In addition to that it allows passing
13
an Error variable.
14
15
The function is also renamed and made public since we're going to use
16
it in other parts of the code.
6
17
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
18
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Message-id: 20171009153856.20387-1-berto@igalia.com
19
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
21
---
11
block/qcow2.c | 4 ++--
22
block/qcow2.h | 10 +++---
12
1 file changed, 2 insertions(+), 2 deletions(-)
23
block/qcow2.c | 77 ++++++++++++++++++----------------------------
13
24
tests/qemu-iotests/080.out | 16 +++++-----
25
3 files changed, 43 insertions(+), 60 deletions(-)
26
27
diff --git a/block/qcow2.h b/block/qcow2.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/block/qcow2.h
30
+++ b/block/qcow2.h
31
@@ -XXX,XX +XXX,XX @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
32
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
33
}
34
35
-static inline uint64_t qcow2_max_refcount_clusters(BDRVQcow2State *s)
36
-{
37
- return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits;
38
-}
39
-
40
static inline QCow2ClusterType qcow2_get_cluster_type(uint64_t l2_entry)
41
{
42
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
43
@@ -XXX,XX +XXX,XX @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
44
int64_t size, const char *message_format, ...)
45
GCC_FMT_ATTR(5, 6);
46
47
+int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
48
+ uint64_t entries, size_t entry_len,
49
+ int64_t max_size_bytes, const char *table_name,
50
+ Error **errp);
51
+
52
/* qcow2-refcount.c functions */
53
int qcow2_refcount_init(BlockDriverState *bs);
54
void qcow2_refcount_close(BlockDriverState *bs);
14
diff --git a/block/qcow2.c b/block/qcow2.c
55
diff --git a/block/qcow2.c b/block/qcow2.c
15
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qcow2.c
57
--- a/block/qcow2.c
17
+++ b/block/qcow2.c
58
+++ b/block/qcow2.c
18
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
59
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_check(BlockDriverState *bs,
19
60
return ret;
20
s->cluster_bits = header.cluster_bits;
61
}
21
s->cluster_size = 1 << s->cluster_bits;
62
22
- s->cluster_sectors = 1 << (s->cluster_bits - 9);
63
-static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
23
+ s->cluster_sectors = 1 << (s->cluster_bits - BDRV_SECTOR_BITS);
64
- uint64_t entries, size_t entry_len)
24
65
+int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
25
/* Initialise version 3 header fields */
66
+ uint64_t entries, size_t entry_len,
26
if (header.version == 2) {
67
+ int64_t max_size_bytes, const char *table_name,
27
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
68
+ Error **errp)
28
69
{
29
bytes = MIN(INT_MAX, nb_sectors * BDRV_SECTOR_SIZE);
70
BDRVQcow2State *s = bs->opaque;
30
qemu_co_mutex_lock(&s->lock);
71
- uint64_t size;
31
- ret = qcow2_get_cluster_offset(bs, sector_num << 9, &bytes,
72
32
+ ret = qcow2_get_cluster_offset(bs, sector_num << BDRV_SECTOR_BITS, &bytes,
73
- /* Use signed INT64_MAX as the maximum even for uint64_t header fields,
33
&cluster_offset);
74
- * because values will be passed to qemu functions taking int64_t. */
34
qemu_co_mutex_unlock(&s->lock);
75
- if (entries > INT64_MAX / entry_len) {
76
- return -EINVAL;
77
- }
78
-
79
- size = entries * entry_len;
80
-
81
- if (INT64_MAX - size < offset) {
82
- return -EINVAL;
83
+ if (entries > max_size_bytes / entry_len) {
84
+ error_setg(errp, "%s too large", table_name);
85
+ return -EFBIG;
86
}
87
88
- /* Tables must be cluster aligned */
89
- if (offset_into_cluster(s, offset) != 0) {
90
+ /* Use signed INT64_MAX as the maximum even for uint64_t header fields,
91
+ * because values will be passed to qemu functions taking int64_t. */
92
+ if ((INT64_MAX - entries * entry_len < offset) ||
93
+ (offset_into_cluster(s, offset) != 0)) {
94
+ error_setg(errp, "%s offset invalid", table_name);
95
return -EINVAL;
96
}
97
98
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
99
s->refcount_table_size =
100
header.refcount_table_clusters << (s->cluster_bits - 3);
101
102
- if (header.refcount_table_clusters > qcow2_max_refcount_clusters(s)) {
103
- error_setg(errp, "Reference count table too large");
104
- ret = -EINVAL;
105
- goto fail;
106
- }
107
-
108
if (header.refcount_table_clusters == 0 && !(flags & BDRV_O_CHECK)) {
109
error_setg(errp, "Image does not contain a reference count table");
110
ret = -EINVAL;
111
goto fail;
112
}
113
114
- ret = validate_table_offset(bs, s->refcount_table_offset,
115
- s->refcount_table_size, sizeof(uint64_t));
116
+ ret = qcow2_validate_table(bs, s->refcount_table_offset,
117
+ header.refcount_table_clusters,
118
+ s->cluster_size, QCOW_MAX_REFTABLE_SIZE,
119
+ "Reference count table", errp);
35
if (ret < 0) {
120
if (ret < 0) {
121
- error_setg(errp, "Invalid reference count table offset");
122
goto fail;
123
}
124
125
- /* Snapshot table offset/length */
126
- if (header.nb_snapshots > QCOW_MAX_SNAPSHOTS) {
127
- error_setg(errp, "Too many snapshots");
128
- ret = -EINVAL;
129
- goto fail;
130
- }
131
-
132
- ret = validate_table_offset(bs, header.snapshots_offset,
133
- header.nb_snapshots,
134
- sizeof(QCowSnapshotHeader));
135
+ /* The total size in bytes of the snapshot table is checked in
136
+ * qcow2_read_snapshots() because the size of each snapshot is
137
+ * variable and we don't know it yet.
138
+ * Here we only check the offset and number of snapshots. */
139
+ ret = qcow2_validate_table(bs, header.snapshots_offset,
140
+ header.nb_snapshots,
141
+ sizeof(QCowSnapshotHeader),
142
+ sizeof(QCowSnapshotHeader) * QCOW_MAX_SNAPSHOTS,
143
+ "Snapshot table", errp);
144
if (ret < 0) {
145
- error_setg(errp, "Invalid snapshot table offset");
146
goto fail;
147
}
148
149
/* read the level 1 table */
150
- if (header.l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
151
- error_setg(errp, "Active L1 table too large");
152
- ret = -EFBIG;
153
+ ret = qcow2_validate_table(bs, header.l1_table_offset,
154
+ header.l1_size, sizeof(uint64_t),
155
+ QCOW_MAX_L1_SIZE, "Active L1 table", errp);
156
+ if (ret < 0) {
157
goto fail;
158
}
159
s->l1_size = header.l1_size;
160
+ s->l1_table_offset = header.l1_table_offset;
161
162
l1_vm_state_index = size_to_l1(s, header.size);
163
if (l1_vm_state_index > INT_MAX) {
164
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
165
goto fail;
166
}
167
168
- ret = validate_table_offset(bs, header.l1_table_offset,
169
- header.l1_size, sizeof(uint64_t));
170
- if (ret < 0) {
171
- error_setg(errp, "Invalid L1 table offset");
172
- goto fail;
173
- }
174
- s->l1_table_offset = header.l1_table_offset;
175
-
176
-
177
if (s->l1_size > 0) {
178
s->l1_table = qemu_try_blockalign(bs->file->bs,
179
ROUND_UP(s->l1_size * sizeof(uint64_t), 512));
180
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
181
index XXXXXXX..XXXXXXX 100644
182
--- a/tests/qemu-iotests/080.out
183
+++ b/tests/qemu-iotests/080.out
184
@@ -XXX,XX +XXX,XX @@ can't open device TEST_DIR/t.qcow2: Reference count table too large
185
186
== Misaligned refcount table ==
187
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
188
-can't open device TEST_DIR/t.qcow2: Invalid reference count table offset
189
+can't open device TEST_DIR/t.qcow2: Reference count table offset invalid
190
191
== Huge refcount offset ==
192
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
193
-can't open device TEST_DIR/t.qcow2: Invalid reference count table offset
194
+can't open device TEST_DIR/t.qcow2: Reference count table offset invalid
195
196
== Invalid snapshot table ==
197
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
198
-can't open device TEST_DIR/t.qcow2: Too many snapshots
199
-can't open device TEST_DIR/t.qcow2: Too many snapshots
200
-can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset
201
-can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset
202
+can't open device TEST_DIR/t.qcow2: Snapshot table too large
203
+can't open device TEST_DIR/t.qcow2: Snapshot table too large
204
+can't open device TEST_DIR/t.qcow2: Snapshot table offset invalid
205
+can't open device TEST_DIR/t.qcow2: Snapshot table offset invalid
206
207
== Hitting snapshot table size limit ==
208
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
209
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0
210
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
211
can't open device TEST_DIR/t.qcow2: Active L1 table too large
212
can't open device TEST_DIR/t.qcow2: Active L1 table too large
213
-can't open device TEST_DIR/t.qcow2: Invalid L1 table offset
214
-can't open device TEST_DIR/t.qcow2: Invalid L1 table offset
215
+can't open device TEST_DIR/t.qcow2: Active L1 table offset invalid
216
+can't open device TEST_DIR/t.qcow2: Active L1 table offset invalid
217
218
== Invalid L1 table (with internal snapshot in the image) ==
219
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
36
--
220
--
37
2.13.6
221
2.13.6
38
222
39
223
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This function checks that the size of a snapshot's L1 table is not too
4
large, but it doesn't validate the offset.
5
6
We now have a function to take care of this, so let's use it.
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block/qcow2-snapshot.c | 8 +++++---
13
tests/qemu-iotests/080 | 10 +++++++++-
14
tests/qemu-iotests/080.out | 8 +++++++-
15
3 files changed, 21 insertions(+), 5 deletions(-)
16
17
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-snapshot.c
20
+++ b/block/qcow2-snapshot.c
21
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
22
sn = &s->snapshots[snapshot_index];
23
24
/* Allocate and read in the snapshot's L1 table */
25
- if (sn->l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
26
- error_setg(errp, "Snapshot L1 table too large");
27
- return -EFBIG;
28
+ ret = qcow2_validate_table(bs, sn->l1_table_offset, sn->l1_size,
29
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
30
+ "Snapshot L1 table", errp);
31
+ if (ret < 0) {
32
+ return ret;
33
}
34
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
35
new_l1_table = qemu_try_blockalign(bs->file->bs,
36
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
37
index XXXXXXX..XXXXXXX 100755
38
--- a/tests/qemu-iotests/080
39
+++ b/tests/qemu-iotests/080
40
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_l2_table_0" "\x80\x00\x00\xff\xff\xff\x00\x00"
41
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
42
43
echo
44
-echo "== Invalid snapshot L1 table =="
45
+echo "== Invalid snapshot L1 table offset =="
46
+_make_test_img 64M
47
+{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
48
+{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
49
+poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x00"
50
+{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
51
+
52
+echo
53
+echo "== Invalid snapshot L1 table size =="
54
_make_test_img 64M
55
{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
56
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
57
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
58
index XXXXXXX..XXXXXXX 100644
59
--- a/tests/qemu-iotests/080.out
60
+++ b/tests/qemu-iotests/080.out
61
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0
62
qemu-img: Could not create snapshot 'test': -27 (File too large)
63
qemu-img: Could not create snapshot 'test': -11 (Resource temporarily unavailable)
64
65
-== Invalid snapshot L1 table ==
66
+== Invalid snapshot L1 table offset ==
67
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
68
+wrote 512/512 bytes at offset 0
69
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
70
+qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid
71
+
72
+== Invalid snapshot L1 table size ==
73
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
74
wrote 512/512 bytes at offset 0
75
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76
--
77
2.13.6
78
79
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
We are gradually moving away from sector-based interfaces, towards
3
This function iterates over all snapshots of a qcow2 file in order to
4
byte-based. In the common case, allocation is unlikely to ever use
4
expand all zero clusters, but it does not validate the snapshots' L1
5
values that are not naturally sector-aligned, but it is possible
5
tables first.
6
that byte-based values will let us be more precise about allocation
7
at the end of an unaligned file that can do byte-based access.
8
6
9
Changing the name of the function from bdrv_get_block_status() to
7
We now have a function to take care of this, so let's use it.
10
bdrv_block_status() ensures that the compiler enforces that all
11
callers are updated. For now, the io.c layer still assert()s that
12
all callers are sector-aligned, but that can be relaxed when a later
13
patch implements byte-based block status in the drivers.
14
8
15
There was an inherent limitation in returning the offset via the
9
We can also take the opportunity to replace the sector-based
16
return value: we only have room for BDRV_BLOCK_OFFSET_MASK bits, which
10
bdrv_read() with bdrv_pread().
17
means an offset can only be mapped for sector-aligned queries (or,
18
if we declare that non-aligned input is at the same relative position
19
modulo 512 of the answer), so the new interface also changes things to
20
return the offset via output through a parameter by reference rather
21
than mashed into the return value. We'll have some glue code that
22
munges between the two styles until we finish converting all uses.
23
11
24
For the most part this patch is just the addition of scaling at the
12
Cc: Eric Blake <eblake@redhat.com>
25
callers followed by inverse scaling at bdrv_block_status(), coupled
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
26
with the tweak in calling convention. But some code, particularly
14
Reviewed-by: Eric Blake <eblake@redhat.com>
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>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
---
16
---
36
include/block/block.h | 17 +++++++++--------
17
block/qcow2-cluster.c | 24 +++++++++++++++++-------
37
block/io.c | 47 ++++++++++++++++++++++++++++++++++-------------
18
tests/qemu-iotests/080 | 2 ++
38
block/qcow2-cluster.c | 2 +-
19
tests/qemu-iotests/080.out | 4 ++++
39
qemu-img.c | 25 ++++++++++++++-----------
20
3 files changed, 23 insertions(+), 7 deletions(-)
40
4 files changed, 58 insertions(+), 33 deletions(-)
41
21
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,
171
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
22
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
172
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
173
--- a/block/qcow2-cluster.c
24
--- a/block/qcow2-cluster.c
174
+++ b/block/qcow2-cluster.c
25
+++ b/block/qcow2-cluster.c
175
@@ -XXX,XX +XXX,XX @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
26
@@ -XXX,XX +XXX,XX @@
176
* cluster is already marked as zero, or if it's unallocated and we
27
#include "qemu/osdep.h"
177
* don't have a backing file.
28
#include <zlib.h>
178
*
29
179
- * TODO We might want to use bdrv_get_block_status(bs) here, but we're
30
+#include "qapi/error.h"
180
+ * TODO We might want to use bdrv_block_status(bs) here, but we're
31
#include "qemu-common.h"
181
* holding s->lock, so that doesn't work today.
32
#include "block/block_int.h"
182
*
33
#include "block/qcow2.h"
183
* If full_discard is true, the sector should not read back as zeroes,
34
@@ -XXX,XX +XXX,XX @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
184
diff --git a/qemu-img.c b/qemu-img.c
35
}
36
37
for (i = 0; i < s->nb_snapshots; i++) {
38
- int l1_sectors = DIV_ROUND_UP(s->snapshots[i].l1_size *
39
- sizeof(uint64_t), BDRV_SECTOR_SIZE);
40
+ int l1_size2;
41
+ uint64_t *new_l1_table;
42
+ Error *local_err = NULL;
43
+
44
+ ret = qcow2_validate_table(bs, s->snapshots[i].l1_table_offset,
45
+ s->snapshots[i].l1_size, sizeof(uint64_t),
46
+ QCOW_MAX_L1_SIZE, "Snapshot L1 table",
47
+ &local_err);
48
+ if (ret < 0) {
49
+ error_report_err(local_err);
50
+ goto fail;
51
+ }
52
53
- uint64_t *new_l1_table =
54
- g_try_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
55
+ l1_size2 = s->snapshots[i].l1_size * sizeof(uint64_t);
56
+ new_l1_table = g_try_realloc(l1_table, l1_size2);
57
58
if (!new_l1_table) {
59
ret = -ENOMEM;
60
@@ -XXX,XX +XXX,XX @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
61
62
l1_table = new_l1_table;
63
64
- ret = bdrv_read(bs->file,
65
- s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,
66
- (void *)l1_table, l1_sectors);
67
+ ret = bdrv_pread(bs->file, s->snapshots[i].l1_table_offset,
68
+ l1_table, l1_size2);
69
if (ret < 0) {
70
goto fail;
71
}
72
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
73
index XXXXXXX..XXXXXXX 100755
74
--- a/tests/qemu-iotests/080
75
+++ b/tests/qemu-iotests/080
76
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
77
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
78
poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x00"
79
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
80
+{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
81
82
echo
83
echo "== Invalid snapshot L1 table size =="
84
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
85
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
86
poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
87
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
88
+{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
89
90
# success, all done
91
echo "*** done"
92
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
185
index XXXXXXX..XXXXXXX 100644
93
index XXXXXXX..XXXXXXX 100644
186
--- a/qemu-img.c
94
--- a/tests/qemu-iotests/080.out
187
+++ b/qemu-img.c
95
+++ b/tests/qemu-iotests/080.out
188
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
96
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
189
97
wrote 512/512 bytes at offset 0
190
if (s->sector_next_status <= sector_num) {
98
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
191
if (s->target_has_backing) {
99
qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid
192
- ret = bdrv_get_block_status(blk_bs(s->src[src_cur]),
100
+qemu-img: Snapshot L1 table offset invalid
193
- sector_num - src_cur_offset,
101
+qemu-img: Error while amending options: Invalid argument
194
- n, &n, NULL);
102
195
+ int64_t count = n * BDRV_SECTOR_SIZE;
103
== Invalid snapshot L1 table size ==
196
+
104
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
197
+ ret = bdrv_block_status(blk_bs(s->src[src_cur]),
105
wrote 512/512 bytes at offset 0
198
+ (sector_num - src_cur_offset) *
106
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
199
+ BDRV_SECTOR_SIZE,
107
qemu-img: Failed to load snapshot: Snapshot L1 table too large
200
+ count, &count, NULL, NULL);
108
+qemu-img: Snapshot L1 table too large
201
+ assert(ret < 0 || QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
109
+qemu-img: Error while amending options: File too large
202
+ n = count >> BDRV_SECTOR_BITS;
110
*** done
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)
209
{
210
- int64_t ret;
211
+ int ret;
212
int depth;
213
BlockDriverState *file;
214
bool has_offset;
215
- int nb_sectors = bytes >> BDRV_SECTOR_BITS;
216
+ int64_t map;
217
218
- assert(bytes < INT_MAX);
219
/* As an optimization, we could cache the current range of unallocated
220
* clusters in each file of the chain, and avoid querying the same
221
* range repeatedly.
222
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
223
224
depth = 0;
225
for (;;) {
226
- ret = bdrv_get_block_status(bs, offset >> BDRV_SECTOR_BITS, nb_sectors,
227
- &nb_sectors, &file);
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,
250
--
111
--
251
2.13.6
112
2.13.6
252
113
253
114
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
The inactive-l2 overlap check iterates uses the L1 tables from all
4
snapshots, but it does not validate them first.
5
6
We now have a function to take care of this, so let's use it.
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
block/qcow2-refcount.c | 10 +++++++++-
13
tests/qemu-iotests/080 | 4 ++++
14
tests/qemu-iotests/080.out | 4 ++++
15
3 files changed, 17 insertions(+), 1 deletion(-)
16
17
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-refcount.c
20
+++ b/block/qcow2-refcount.c
21
@@ -XXX,XX +XXX,XX @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
22
uint64_t l1_ofs = s->snapshots[i].l1_table_offset;
23
uint32_t l1_sz = s->snapshots[i].l1_size;
24
uint64_t l1_sz2 = l1_sz * sizeof(uint64_t);
25
- uint64_t *l1 = g_try_malloc(l1_sz2);
26
+ uint64_t *l1;
27
int ret;
28
29
+ ret = qcow2_validate_table(bs, l1_ofs, l1_sz, sizeof(uint64_t),
30
+ QCOW_MAX_L1_SIZE, "", NULL);
31
+ if (ret < 0) {
32
+ return ret;
33
+ }
34
+
35
+ l1 = g_try_malloc(l1_sz2);
36
+
37
if (l1_sz2 && l1 == NULL) {
38
return -ENOMEM;
39
}
40
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
41
index XXXXXXX..XXXXXXX 100755
42
--- a/tests/qemu-iotests/080
43
+++ b/tests/qemu-iotests/080
44
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
45
poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x00"
46
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
47
{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
48
+{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
49
+ -c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
50
51
echo
52
echo "== Invalid snapshot L1 table size =="
53
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
54
poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
55
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
56
{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
57
+{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
58
+ -c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
59
60
# success, all done
61
echo "*** done"
62
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
63
index XXXXXXX..XXXXXXX 100644
64
--- a/tests/qemu-iotests/080.out
65
+++ b/tests/qemu-iotests/080.out
66
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0
67
qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid
68
qemu-img: Snapshot L1 table offset invalid
69
qemu-img: Error while amending options: Invalid argument
70
+Failed to flush the refcount block cache: Invalid argument
71
+write failed: Invalid argument
72
73
== Invalid snapshot L1 table size ==
74
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
75
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 0
76
qemu-img: Failed to load snapshot: Snapshot L1 table too large
77
qemu-img: Snapshot L1 table too large
78
qemu-img: Error while amending options: File too large
79
+Failed to flush the refcount block cache: File too large
80
+write failed: File too large
81
*** done
82
--
83
2.13.6
84
85
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This function copies a snapshot's L1 table into the active one without
4
validating it first.
5
6
We now have a function to take care of this, so let's use it.
7
8
Cc: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block/qcow2-snapshot.c | 9 +++++++++
14
tests/qemu-iotests/080 | 2 ++
15
tests/qemu-iotests/080.out | 4 ++++
16
3 files changed, 15 insertions(+)
17
18
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2-snapshot.c
21
+++ b/block/qcow2-snapshot.c
22
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
23
{
24
BDRVQcow2State *s = bs->opaque;
25
QCowSnapshot *sn;
26
+ Error *local_err = NULL;
27
int i, snapshot_index;
28
int cur_l1_bytes, sn_l1_bytes;
29
int ret;
30
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
31
}
32
sn = &s->snapshots[snapshot_index];
33
34
+ ret = qcow2_validate_table(bs, sn->l1_table_offset, sn->l1_size,
35
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
36
+ "Snapshot L1 table", &local_err);
37
+ if (ret < 0) {
38
+ error_report_err(local_err);
39
+ goto fail;
40
+ }
41
+
42
if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
43
error_report("qcow2: Loading snapshots with different disk "
44
"size is not implemented");
45
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
46
index XXXXXXX..XXXXXXX 100755
47
--- a/tests/qemu-iotests/080
48
+++ b/tests/qemu-iotests/080
49
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x0
50
{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
51
{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
52
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
53
+{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
54
55
echo
56
echo "== Invalid snapshot L1 table size =="
57
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
58
{ $QEMU_IMG amend -o compat=0.10 $TEST_IMG; } 2>&1 | _filter_testdir
59
{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
60
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
61
+{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
62
63
# success, all done
64
echo "*** done"
65
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
66
index XXXXXXX..XXXXXXX 100644
67
--- a/tests/qemu-iotests/080.out
68
+++ b/tests/qemu-iotests/080.out
69
@@ -XXX,XX +XXX,XX @@ qemu-img: Snapshot L1 table offset invalid
70
qemu-img: Error while amending options: Invalid argument
71
Failed to flush the refcount block cache: Invalid argument
72
write failed: Invalid argument
73
+qemu-img: Snapshot L1 table offset invalid
74
+qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument
75
76
== Invalid snapshot L1 table size ==
77
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
78
@@ -XXX,XX +XXX,XX @@ qemu-img: Snapshot L1 table too large
79
qemu-img: Error while amending options: File too large
80
Failed to flush the refcount block cache: File too large
81
write failed: File too large
82
+qemu-img: Snapshot L1 table too large
83
+qemu-img: Could not apply snapshot 'test': Failed to load snapshot: File too large
84
*** done
85
--
86
2.13.6
87
88
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
If a read error is encountered during 'qemu-img compare', we
3
This function deletes a snapshot from disk, removing its entry from
4
were printing the "Error while reading offset ..." message twice;
4
the snapshot table, freeing its L1 table and decreasing the refcounts
5
this was because our helper function was awkward, printing output
5
of all clusters.
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.
9
6
10
Further simplify the code by hoisting the conversion from an error
7
The L1 table offset and size are however not validated. If we use
11
message to an exit code into the helper function, rather than
8
invalid values in this function we'll probably corrupt the image even
12
repeating that logic at all callers (yes, the helper function is
9
more, so we should return an error instead.
13
now less generic, but it's a net win in lines of code).
14
10
15
Signed-off-by: Eric Blake <eblake@redhat.com>
11
We now have a function to take care of this, so let's use it.
16
Reviewed-by: John Snow <jsnow@redhat.com>
12
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
16
---
19
qemu-img.c | 19 +++++--------------
17
block/qcow2-snapshot.c | 7 +++++++
20
tests/qemu-iotests/074.out | 2 --
18
tests/qemu-iotests/080 | 2 ++
21
2 files changed, 5 insertions(+), 16 deletions(-)
19
tests/qemu-iotests/080.out | 2 ++
20
3 files changed, 11 insertions(+)
22
21
23
diff --git a/qemu-img.c b/qemu-img.c
22
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
24
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
25
--- a/qemu-img.c
24
--- a/block/qcow2-snapshot.c
26
+++ b/qemu-img.c
25
+++ b/block/qcow2-snapshot.c
27
@@ -XXX,XX +XXX,XX @@ static int64_t sectors_to_bytes(int64_t sectors)
26
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_delete(BlockDriverState *bs,
28
/*
29
* Check if passed sectors are empty (not allocated or contain only 0 bytes)
30
*
31
- * Returns 0 in case sectors are filled with 0, 1 if sectors contain non-zero
32
- * data and negative value on error.
33
+ * Intended for use by 'qemu-img compare': Returns 0 in case sectors are
34
+ * filled with 0, 1 if sectors contain non-zero data (this is a comparison
35
+ * failure), and 4 on error (the exit status for read errors), after emitting
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,
41
if (ret < 0) {
42
error_report("Error while reading offset %" PRId64 " of %s: %s",
43
sectors_to_bytes(sect_num), filename, strerror(-ret));
44
- return ret;
45
+ return 4;
46
}
27
}
47
idx = find_nonzero(buffer, sect_count * BDRV_SECTOR_SIZE);
28
sn = s->snapshots[snapshot_index];
48
if (idx >= 0) {
29
49
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
30
+ ret = qcow2_validate_table(bs, sn.l1_table_offset, sn.l1_size,
50
filename2, buf1, quiet);
31
+ sizeof(uint64_t), QCOW_MAX_L1_SIZE,
51
}
32
+ "Snapshot L1 table", errp);
52
if (ret) {
33
+ if (ret < 0) {
53
- if (ret < 0) {
34
+ return ret;
54
- error_report("Error while reading offset %" PRId64 ": %s",
35
+ }
55
- sectors_to_bytes(sector_num), strerror(-ret));
36
+
56
- ret = 4;
37
/* Remove it from the snapshot list */
57
- }
38
memmove(s->snapshots + snapshot_index,
58
goto out;
39
s->snapshots + snapshot_index + 1,
59
}
40
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
60
}
41
index XXXXXXX..XXXXXXX 100755
61
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
42
--- a/tests/qemu-iotests/080
62
ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
43
+++ b/tests/qemu-iotests/080
63
filename_over, buf1, quiet);
44
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x0
64
if (ret) {
45
{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
65
- if (ret < 0) {
46
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
66
- error_report("Error while reading offset %" PRId64
47
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
67
- " of %s: %s", sectors_to_bytes(sector_num),
48
+{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
68
- filename_over, strerror(-ret));
49
69
- ret = 4;
50
echo
70
- }
51
echo "== Invalid snapshot L1 table size =="
71
goto out;
52
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
72
}
53
{ $QEMU_IO -c "open -o overlap-check.inactive-l2=on $TEST_IMG" \
73
}
54
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
74
diff --git a/tests/qemu-iotests/074.out b/tests/qemu-iotests/074.out
55
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
56
+{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
57
58
# success, all done
59
echo "*** done"
60
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
75
index XXXXXXX..XXXXXXX 100644
61
index XXXXXXX..XXXXXXX 100644
76
--- a/tests/qemu-iotests/074.out
62
--- a/tests/qemu-iotests/080.out
77
+++ b/tests/qemu-iotests/074.out
63
+++ b/tests/qemu-iotests/080.out
78
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
64
@@ -XXX,XX +XXX,XX @@ Failed to flush the refcount block cache: Invalid argument
79
wrote 512/512 bytes at offset 512
65
write failed: Invalid argument
80
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
66
qemu-img: Snapshot L1 table offset invalid
81
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
67
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument
82
-qemu-img: Error while reading offset 0: Input/output error
68
+qemu-img: Could not delete snapshot 'test': Snapshot L1 table offset invalid
83
4
69
84
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
70
== Invalid snapshot L1 table size ==
85
Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=0
71
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
86
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=0
72
@@ -XXX,XX +XXX,XX @@ Failed to flush the refcount block cache: File too large
87
wrote 512/512 bytes at offset 512
73
write failed: File too large
88
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
74
qemu-img: Snapshot L1 table too large
89
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
75
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: File too large
90
-qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
76
+qemu-img: Could not delete snapshot 'test': Snapshot L1 table too large
91
Warning: Image size mismatch!
77
*** done
92
4
93
Cleanup
94
--
78
--
95
2.13.6
79
2.13.6
96
80
97
81
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Compare the following images with all-zero contents:
3
'qemu-img check' cannot detect if a snapshot's L1 table is corrupted.
4
$ truncate --size 1M A
4
This patch checks the table's offset and size and reports corruption
5
$ qemu-img create -f qcow2 -o preallocation=off B 1G
5
if the values are not valid.
6
$ qemu-img create -f qcow2 -o preallocation=metadata C 1G
7
6
8
On my machine, the difference is noticeable for pre-patch speeds,
7
This patch doesn't add code to fix that corruption yet, only to detect
9
with more than an order of magnitude in difference caused by the
8
and report it.
10
choice of preallocation in the qcow2 file:
11
9
12
$ time ./qemu-img compare -f raw -F qcow2 A B
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
Warning: Image size mismatch!
11
Reviewed-by: Eric Blake <eblake@redhat.com>
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>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
49
---
13
---
50
qemu-img.c | 8 ++++----
14
block/qcow2-refcount.c | 14 ++++++++++++++
51
1 file changed, 4 insertions(+), 4 deletions(-)
15
tests/qemu-iotests/080 | 2 ++
16
tests/qemu-iotests/080.out | 20 ++++++++++++++++++++
17
3 files changed, 36 insertions(+)
52
18
53
diff --git a/qemu-img.c b/qemu-img.c
19
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
54
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
55
--- a/qemu-img.c
21
--- a/block/qcow2-refcount.c
56
+++ b/qemu-img.c
22
+++ b/block/qcow2-refcount.c
57
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
23
@@ -XXX,XX +XXX,XX @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
58
while (sector_num < progress_base) {
24
/* snapshots */
59
int64_t count;
25
for (i = 0; i < s->nb_snapshots; i++) {
60
26
sn = s->snapshots + i;
61
- ret = bdrv_is_allocated_above(blk_bs(blk_over), NULL,
27
+ if (offset_into_cluster(s, sn->l1_table_offset)) {
62
+ ret = bdrv_block_status_above(blk_bs(blk_over), NULL,
28
+ fprintf(stderr, "ERROR snapshot %s (%s) l1_offset=%#" PRIx64 ": "
63
sector_num * BDRV_SECTOR_SIZE,
29
+ "L1 table is not cluster aligned; snapshot table entry "
64
(progress_base - sector_num) *
30
+ "corrupted\n", sn->id_str, sn->name, sn->l1_table_offset);
65
BDRV_SECTOR_SIZE,
31
+ res->corruptions++;
66
- &count);
32
+ continue;
67
+ &count, NULL, NULL);
33
+ }
68
if (ret < 0) {
34
+ if (sn->l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
69
ret = 3;
35
+ fprintf(stderr, "ERROR snapshot %s (%s) l1_size=%#" PRIx32 ": "
70
error_report("Sector allocation test failed for %s",
36
+ "L1 table is too large; snapshot table entry corrupted\n",
71
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
37
+ sn->id_str, sn->name, sn->l1_size);
72
goto out;
38
+ res->corruptions++;
73
39
+ continue;
74
}
40
+ }
75
- /* TODO relax this once bdrv_is_allocated_above does not enforce
41
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
76
+ /* TODO relax this once bdrv_block_status_above does not enforce
42
sn->l1_table_offset, sn->l1_size, 0, fix);
77
* sector alignment */
43
if (ret < 0) {
78
assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
44
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
79
nb_sectors = count >> BDRV_SECTOR_BITS;
45
index XXXXXXX..XXXXXXX 100755
80
- if (ret) {
46
--- a/tests/qemu-iotests/080
81
+ if (ret & BDRV_BLOCK_ALLOCATED && !(ret & BDRV_BLOCK_ZERO)) {
47
+++ b/tests/qemu-iotests/080
82
nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
48
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_offset" "\x00\x00\x00\x00\x00\x40\x02\x0
83
ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
49
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
84
filename_over, buf1, quiet);
50
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
51
{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
52
+_check_test_img
53
54
echo
55
echo "== Invalid snapshot L1 table size =="
56
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
57
-c 'write 0 4k'; } 2>&1 | _filter_qemu_io | _filter_testdir
58
{ $QEMU_IMG snapshot -a test $TEST_IMG; } 2>&1 | _filter_testdir
59
{ $QEMU_IMG snapshot -d test $TEST_IMG; } 2>&1 | _filter_testdir
60
+_check_test_img
61
62
# success, all done
63
echo "*** done"
64
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
65
index XXXXXXX..XXXXXXX 100644
66
--- a/tests/qemu-iotests/080.out
67
+++ b/tests/qemu-iotests/080.out
68
@@ -XXX,XX +XXX,XX @@ write failed: Invalid argument
69
qemu-img: Snapshot L1 table offset invalid
70
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: Invalid argument
71
qemu-img: Could not delete snapshot 'test': Snapshot L1 table offset invalid
72
+ERROR snapshot 1 (test) l1_offset=0x400200: L1 table is not cluster aligned; snapshot table entry corrupted
73
+Leaked cluster 4 refcount=2 reference=1
74
+Leaked cluster 5 refcount=2 reference=1
75
+Leaked cluster 6 refcount=1 reference=0
76
+
77
+1 errors were found on the image.
78
+Data may be corrupted, or further writes to the image may corrupt it.
79
+
80
+3 leaked clusters were found on the image.
81
+This means waste of disk space, but no harm to data.
82
83
== Invalid snapshot L1 table size ==
84
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
85
@@ -XXX,XX +XXX,XX @@ write failed: File too large
86
qemu-img: Snapshot L1 table too large
87
qemu-img: Could not apply snapshot 'test': Failed to load snapshot: File too large
88
qemu-img: Could not delete snapshot 'test': Snapshot L1 table too large
89
+ERROR snapshot 1 (test) l1_size=0x10000000: L1 table is too large; snapshot table entry corrupted
90
+Leaked cluster 4 refcount=2 reference=1
91
+Leaked cluster 5 refcount=2 reference=1
92
+Leaked cluster 6 refcount=1 reference=0
93
+
94
+1 errors were found on the image.
95
+Data may be corrupted, or further writes to the image may corrupt it.
96
+
97
+3 leaked clusters were found on the image.
98
+This means waste of disk space, but no harm to data.
99
*** done
85
--
100
--
86
2.13.6
101
2.13.6
87
102
88
103
diff view generated by jsdifflib
New patch
1
This creates a BlockdevCreateOptions union type that will contain all of
2
the options for image creation. We'll start out with an empty struct
3
type BlockdevCreateNotSupported for all drivers.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
---
9
qapi/block-core.json | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
10
1 file changed, 62 insertions(+)
11
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/block-core.json
15
+++ b/qapi/block-core.json
16
@@ -XXX,XX +XXX,XX @@
17
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
18
19
##
20
+# @BlockdevCreateNotSupported:
21
+#
22
+# This is used for all drivers that don't support creating images.
23
+#
24
+# Since: 2.12
25
+##
26
+{ 'struct': 'BlockdevCreateNotSupported', 'data': {}}
27
+
28
+##
29
+# @BlockdevCreateOptions:
30
+#
31
+# Options for creating an image format on a given node.
32
+#
33
+# @driver block driver to create the image format
34
+#
35
+# Since: 2.12
36
+##
37
+{ 'union': 'BlockdevCreateOptions',
38
+ 'base': {
39
+ 'driver': 'BlockdevDriver' },
40
+ 'discriminator': 'driver',
41
+ 'data': {
42
+ 'blkdebug': 'BlockdevCreateNotSupported',
43
+ 'blkverify': 'BlockdevCreateNotSupported',
44
+ 'bochs': 'BlockdevCreateNotSupported',
45
+ 'cloop': 'BlockdevCreateNotSupported',
46
+ 'dmg': 'BlockdevCreateNotSupported',
47
+ 'file': 'BlockdevCreateNotSupported',
48
+ 'ftp': 'BlockdevCreateNotSupported',
49
+ 'ftps': 'BlockdevCreateNotSupported',
50
+ 'gluster': 'BlockdevCreateNotSupported',
51
+ 'host_cdrom': 'BlockdevCreateNotSupported',
52
+ 'host_device': 'BlockdevCreateNotSupported',
53
+ 'http': 'BlockdevCreateNotSupported',
54
+ 'https': 'BlockdevCreateNotSupported',
55
+ 'iscsi': 'BlockdevCreateNotSupported',
56
+ 'luks': 'BlockdevCreateNotSupported',
57
+ 'nbd': 'BlockdevCreateNotSupported',
58
+ 'nfs': 'BlockdevCreateNotSupported',
59
+ 'null-aio': 'BlockdevCreateNotSupported',
60
+ 'null-co': 'BlockdevCreateNotSupported',
61
+ 'nvme': 'BlockdevCreateNotSupported',
62
+ 'parallels': 'BlockdevCreateNotSupported',
63
+ 'qcow2': 'BlockdevCreateNotSupported',
64
+ 'qcow': 'BlockdevCreateNotSupported',
65
+ 'qed': 'BlockdevCreateNotSupported',
66
+ 'quorum': 'BlockdevCreateNotSupported',
67
+ 'raw': 'BlockdevCreateNotSupported',
68
+ 'rbd': 'BlockdevCreateNotSupported',
69
+ 'replication': 'BlockdevCreateNotSupported',
70
+ 'sheepdog': 'BlockdevCreateNotSupported',
71
+ 'ssh': 'BlockdevCreateNotSupported',
72
+ 'throttle': 'BlockdevCreateNotSupported',
73
+ 'vdi': 'BlockdevCreateNotSupported',
74
+ 'vhdx': 'BlockdevCreateNotSupported',
75
+ 'vmdk': 'BlockdevCreateNotSupported',
76
+ 'vpc': 'BlockdevCreateNotSupported',
77
+ 'vvfat': 'BlockdevCreateNotSupported',
78
+ 'vxhs': 'BlockdevCreateNotSupported'
79
+ } }
80
+
81
+##
82
# @blockdev-open-tray:
83
#
84
# Opens a block device's tray. If there is a block driver state tree inserted as
85
--
86
2.13.6
87
88
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
---
5
qapi/block-core.json | 45 ++++++++++++++++++++++++++++++++++++++++++++-
6
1 file changed, 44 insertions(+), 1 deletion(-)
1
7
8
diff --git a/qapi/block-core.json b/qapi/block-core.json
9
index XXXXXXX..XXXXXXX 100644
10
--- a/qapi/block-core.json
11
+++ b/qapi/block-core.json
12
@@ -XXX,XX +XXX,XX @@
13
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
14
15
##
16
+# @BlockdevQcow2Version:
17
+#
18
+# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
19
+# @v3: The extended QCOW2 format as introduced in qemu 1.1 (version 3)
20
+#
21
+# Since: 2.12
22
+##
23
+{ 'enum': 'BlockdevQcow2Version',
24
+ 'data': [ 'v2', 'v3' ] }
25
+
26
+
27
+##
28
+# @BlockdevCreateOptionsQcow2:
29
+#
30
+# Driver specific image creation options for qcow2.
31
+#
32
+# @file Node to create the image format on
33
+# @size Size of the virtual disk in bytes
34
+# @version Compatibility level (default: v3)
35
+# @backing-file File name of the backing file if a backing file
36
+# should be used
37
+# @backing-fmt Name of the block driver to use for the backing file
38
+# @encrypt Encryption options if the image should be encrypted
39
+# @cluster-size qcow2 cluster size in bytes (default: 65536)
40
+# @preallocation Preallocation mode for the new image (default: off)
41
+# @lazy-refcounts True if refcounts may be updated lazily (default: off)
42
+# @refcount-bits Width of reference counts in bits (default: 16)
43
+#
44
+# Since: 2.12
45
+##
46
+{ 'struct': 'BlockdevCreateOptionsQcow2',
47
+ 'data': { 'file': 'BlockdevRef',
48
+ 'size': 'size',
49
+ '*version': 'BlockdevQcow2Version',
50
+ '*backing-file': 'str',
51
+ '*backing-fmt': 'BlockdevDriver',
52
+ '*encrypt': 'QCryptoBlockCreateOptions',
53
+ '*cluster-size': 'size',
54
+ '*preallocation': 'PreallocMode',
55
+ '*lazy-refcounts': 'bool',
56
+ '*refcount-bits': 'int' } }
57
+
58
+##
59
# @BlockdevCreateNotSupported:
60
#
61
# This is used for all drivers that don't support creating images.
62
@@ -XXX,XX +XXX,XX @@
63
'null-co': 'BlockdevCreateNotSupported',
64
'nvme': 'BlockdevCreateNotSupported',
65
'parallels': 'BlockdevCreateNotSupported',
66
- 'qcow2': 'BlockdevCreateNotSupported',
67
+ 'qcow2': 'BlockdevCreateOptionsQcow2',
68
'qcow': 'BlockdevCreateNotSupported',
69
'qed': 'BlockdevCreateNotSupported',
70
'quorum': 'BlockdevCreateNotSupported',
71
--
72
2.13.6
73
74
diff view generated by jsdifflib
New patch
1
The functions originally known as qcow2_create() and qcow2_create2()
2
are now called qcow2_co_create_opts() and qcow2_co_create(), which
3
matches the names of the BlockDriver callbacks that they will implement
4
at the end of this patch series.
1
5
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
10
block/qcow2.c | 16 ++++++++--------
11
1 file changed, 8 insertions(+), 8 deletions(-)
12
13
diff --git a/block/qcow2.c b/block/qcow2.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qcow2.c
16
+++ b/block/qcow2.c
17
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
18
}
19
20
static int coroutine_fn
21
-qcow2_co_create2(const char *filename, int64_t total_size,
22
- const char *backing_file, const char *backing_format,
23
- int flags, size_t cluster_size, PreallocMode prealloc,
24
- QemuOpts *opts, int version, int refcount_order,
25
- const char *encryptfmt, Error **errp)
26
+qcow2_co_create(const char *filename, int64_t total_size,
27
+ const char *backing_file, const char *backing_format,
28
+ int flags, size_t cluster_size, PreallocMode prealloc,
29
+ QemuOpts *opts, int version, int refcount_order,
30
+ const char *encryptfmt, Error **errp)
31
{
32
QDict *options;
33
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
35
36
refcount_order = ctz32(refcount_bits);
37
38
- ret = qcow2_co_create2(filename, size, backing_file, backing_fmt, flags,
39
- cluster_size, prealloc, opts, version, refcount_order,
40
- encryptfmt, &local_err);
41
+ ret = qcow2_co_create(filename, size, backing_file, backing_fmt, flags,
42
+ cluster_size, prealloc, opts, version, refcount_order,
43
+ encryptfmt, &local_err);
44
error_propagate(errp, local_err);
45
46
finish:
47
--
48
2.13.6
49
50
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Currently, qcow2_create() only parses the QemuOpts and then calls
2
qcow2_co_create() for the actual image creation, which includes both the
3
creation of the actual file on the file system and writing a valid empty
4
qcow2 image into that file.
2
5
3
A qcow2 image file's length is not required to have a length that is a
6
The plan is that qcow2_co_create() becomes the function that implements
4
multiple of the cluster size. However, qcow2_refcount_area() expects an
7
the functionality for a future 'blockdev-create' QMP command, which only
5
aligned value for its @start_offset parameter, so we need to round
8
creates the qcow2 layer on an already opened file node.
6
@old_file_size up to the next cluster boundary.
7
9
8
Reported-by: Ping Li <pingl@redhat.com>
10
This is a first step towards that goal: Let's move out anything that
9
Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1414049
11
deals with the protocol layer from qcow2_co_create() into
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
qcow2_create(). This means that qcow2_co_create() doesn't need a file
11
Message-id: 20171009215533.12530-2-mreitz@redhat.com
13
name any more.
12
Cc: qemu-stable@nongnu.org
14
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: Jeff Cody <jcody@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
---
18
block/qcow2.c | 1 +
19
block/qcow2.c | 64 +++++++++++++++++++++++++++++++++++------------------------
19
1 file changed, 1 insertion(+)
20
1 file changed, 38 insertions(+), 26 deletions(-)
20
21
21
diff --git a/block/qcow2.c b/block/qcow2.c
22
diff --git a/block/qcow2.c b/block/qcow2.c
22
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow2.c
24
--- a/block/qcow2.c
24
+++ b/block/qcow2.c
25
+++ b/block/qcow2.c
25
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
26
"Failed to inquire current file length");
27
}
27
return old_file_size;
28
28
}
29
static int coroutine_fn
29
+ old_file_size = ROUND_UP(old_file_size, s->cluster_size);
30
-qcow2_co_create(const char *filename, int64_t total_size,
30
31
+qcow2_co_create(BlockDriverState *bs, int64_t total_size,
31
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
32
const char *backing_file, const char *backing_format,
32
s->cluster_size);
33
int flags, size_t cluster_size, PreallocMode prealloc,
34
QemuOpts *opts, int version, int refcount_order,
35
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(const char *filename, int64_t total_size,
36
Error *local_err = NULL;
37
int ret;
38
39
- if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
40
- int64_t prealloc_size =
41
- qcow2_calc_prealloc_size(total_size, cluster_size, refcount_order);
42
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
43
- qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
44
- &error_abort);
45
- }
46
-
47
- ret = bdrv_create_file(filename, opts, &local_err);
48
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
49
+ ret = blk_insert_bs(blk, bs, errp);
50
if (ret < 0) {
51
- error_propagate(errp, local_err);
52
- return ret;
53
- }
54
-
55
- blk = blk_new_open(filename, NULL, NULL,
56
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
57
- &local_err);
58
- if (blk == NULL) {
59
- error_propagate(errp, local_err);
60
- return -EIO;
61
+ goto out;
62
}
63
-
64
blk_set_allow_write_beyond_eof(blk, true);
65
66
/* Write the header */
67
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(const char *filename, int64_t total_size,
68
*/
69
options = qdict_new();
70
qdict_put_str(options, "driver", "qcow2");
71
- blk = blk_new_open(filename, NULL, options,
72
+ qdict_put_str(options, "file", bs->node_name);
73
+ blk = blk_new_open(NULL, NULL, options,
74
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH,
75
&local_err);
76
if (blk == NULL) {
77
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(const char *filename, int64_t total_size,
78
*/
79
options = qdict_new();
80
qdict_put_str(options, "driver", "qcow2");
81
- blk = blk_new_open(filename, NULL, options,
82
+ qdict_put_str(options, "file", bs->node_name);
83
+ blk = blk_new_open(NULL, NULL, options,
84
BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO,
85
&local_err);
86
if (blk == NULL) {
87
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
88
uint64_t refcount_bits;
89
int refcount_order;
90
char *encryptfmt = NULL;
91
+ BlockDriverState *bs = NULL;
92
Error *local_err = NULL;
93
int ret;
94
95
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
96
97
refcount_order = ctz32(refcount_bits);
98
99
- ret = qcow2_co_create(filename, size, backing_file, backing_fmt, flags,
100
+ /* Create and open the file (protocol layer) */
101
+ if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
102
+ int64_t prealloc_size =
103
+ qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
104
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
105
+ qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
106
+ &error_abort);
107
+ }
108
+
109
+ ret = bdrv_create_file(filename, opts, errp);
110
+ if (ret < 0) {
111
+ goto finish;
112
+ }
113
+
114
+ bs = bdrv_open(filename, NULL, NULL,
115
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
116
+ if (bs == NULL) {
117
+ ret = -EIO;
118
+ goto finish;
119
+ }
120
+
121
+ /* Create the qcow2 image (format layer) */
122
+ ret = qcow2_co_create(bs, size, backing_file, backing_fmt, flags,
123
cluster_size, prealloc, opts, version, refcount_order,
124
- encryptfmt, &local_err);
125
- error_propagate(errp, local_err);
126
+ encryptfmt, errp);
127
+ if (ret < 0) {
128
+ goto finish;
129
+ }
130
131
finish:
132
+ bdrv_unref(bs);
133
+
134
g_free(backing_file);
135
g_free(backing_fmt);
136
g_free(encryptfmt);
33
--
137
--
34
2.13.6
138
2.13.6
35
139
36
140
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
All of the simple options are now passed to qcow2_co_create() in a
2
BlockdevCreateOptions object. Still missing: node-name and the
3
encryption options.
2
4
3
In the continuing quest to make more things byte-based, change
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
the internal iteration of img_rebase(). We can finally drop the
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
TODO assertion added earlier, now that the entire algorithm is
7
Reviewed-by: Eric Blake <eblake@redhat.com>
6
byte-based and no longer has to shift from bytes to sectors.
8
---
9
block/qcow2.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++------------
10
1 file changed, 151 insertions(+), 38 deletions(-)
7
11
8
Most of the change is mechanical ('num_sectors' becomes 'size',
12
diff --git a/block/qcow2.c b/block/qcow2.c
9
'sector' becomes 'offset', 'n' goes from sectors to bytes); some
10
of it is also a cleanup (use of MIN() instead of open-coding,
11
loss of variable 'count' added earlier in commit d6a644bb).
12
13
Signed-off-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: John Snow <jsnow@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
qemu-img.c | 84 +++++++++++++++++++++++++-------------------------------------
18
1 file changed, 34 insertions(+), 50 deletions(-)
19
20
diff --git a/qemu-img.c b/qemu-img.c
21
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
22
--- a/qemu-img.c
14
--- a/block/qcow2.c
23
+++ b/qemu-img.c
15
+++ b/block/qcow2.c
24
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
16
@@ -XXX,XX +XXX,XX @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size,
25
* the image is the same as the original one at any time.
17
return meta_size + aligned_total_size;
18
}
19
20
-static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
21
+static bool validate_cluster_size(size_t cluster_size, Error **errp)
22
{
23
- size_t cluster_size;
24
- int cluster_bits;
25
-
26
- cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
27
- DEFAULT_CLUSTER_SIZE);
28
- cluster_bits = ctz32(cluster_size);
29
+ int cluster_bits = ctz32(cluster_size);
30
if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS ||
31
(1 << cluster_bits) != cluster_size)
32
{
33
error_setg(errp, "Cluster size must be a power of two between %d and "
34
"%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10));
35
+ return false;
36
+ }
37
+ return true;
38
+}
39
+
40
+static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
41
+{
42
+ size_t cluster_size;
43
+
44
+ cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
45
+ DEFAULT_CLUSTER_SIZE);
46
+ if (!validate_cluster_size(cluster_size, errp)) {
47
return 0;
48
}
49
return cluster_size;
50
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
51
}
52
53
static int coroutine_fn
54
-qcow2_co_create(BlockDriverState *bs, int64_t total_size,
55
- const char *backing_file, const char *backing_format,
56
- int flags, size_t cluster_size, PreallocMode prealloc,
57
- QemuOpts *opts, int version, int refcount_order,
58
- const char *encryptfmt, Error **errp)
59
+qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
60
+ QemuOpts *opts, const char *encryptfmt, Error **errp)
61
{
62
+ BlockdevCreateOptionsQcow2 *qcow2_opts;
63
QDict *options;
64
65
/*
66
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
26
*/
67
*/
27
if (!unsafe) {
68
BlockBackend *blk;
28
- int64_t num_sectors;
69
QCowHeader *header;
29
- int64_t old_backing_num_sectors;
70
+ size_t cluster_size;
30
- int64_t new_backing_num_sectors = 0;
71
+ int version;
31
- uint64_t sector;
72
+ int refcount_order;
32
- int n;
73
uint64_t* refcount_table;
33
- int64_t count;
74
Error *local_err = NULL;
34
+ int64_t size;
75
int ret;
35
+ int64_t old_backing_size;
76
36
+ int64_t new_backing_size = 0;
77
+ /* Validate options and set default values */
37
+ uint64_t offset;
78
+ assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2);
38
+ int64_t n;
79
+ qcow2_opts = &create_options->u.qcow2;
39
float local_progress = 0;
80
+
40
81
+ if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
41
buf_old = blk_blockalign(blk, IO_BUF_SIZE);
82
+ error_setg(errp, "Image size must be a multiple of 512 bytes");
42
buf_new = blk_blockalign(blk, IO_BUF_SIZE);
83
+ ret = -EINVAL;
43
84
+ goto out;
44
- num_sectors = blk_nb_sectors(blk);
85
+ }
45
- if (num_sectors < 0) {
86
+
46
+ size = blk_getlength(blk);
87
+ if (qcow2_opts->has_version) {
47
+ if (size < 0) {
88
+ switch (qcow2_opts->version) {
48
error_report("Could not get size of '%s': %s",
89
+ case BLOCKDEV_QCOW2_VERSION_V2:
49
- filename, strerror(-num_sectors));
90
+ version = 2;
50
+ filename, strerror(-size));
91
+ break;
51
ret = -1;
92
+ case BLOCKDEV_QCOW2_VERSION_V3:
93
+ version = 3;
94
+ break;
95
+ default:
96
+ g_assert_not_reached();
97
+ }
98
+ } else {
99
+ version = 3;
100
+ }
101
+
102
+ if (qcow2_opts->has_cluster_size) {
103
+ cluster_size = qcow2_opts->cluster_size;
104
+ } else {
105
+ cluster_size = DEFAULT_CLUSTER_SIZE;
106
+ }
107
+
108
+ if (!validate_cluster_size(cluster_size, errp)) {
109
+ return -EINVAL;
110
+ }
111
+
112
+ if (!qcow2_opts->has_preallocation) {
113
+ qcow2_opts->preallocation = PREALLOC_MODE_OFF;
114
+ }
115
+ if (qcow2_opts->has_backing_file &&
116
+ qcow2_opts->preallocation != PREALLOC_MODE_OFF)
117
+ {
118
+ error_setg(errp, "Backing file and preallocation cannot be used at "
119
+ "the same time");
120
+ return -EINVAL;
121
+ }
122
+ if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) {
123
+ error_setg(errp, "Backing format cannot be used without backing file");
124
+ return -EINVAL;
125
+ }
126
+
127
+ if (!qcow2_opts->has_lazy_refcounts) {
128
+ qcow2_opts->lazy_refcounts = false;
129
+ }
130
+ if (version < 3 && qcow2_opts->lazy_refcounts) {
131
+ error_setg(errp, "Lazy refcounts only supported with compatibility "
132
+ "level 1.1 and above (use compat=1.1 or greater)");
133
+ return -EINVAL;
134
+ }
135
+
136
+ if (!qcow2_opts->has_refcount_bits) {
137
+ qcow2_opts->refcount_bits = 16;
138
+ }
139
+ if (qcow2_opts->refcount_bits > 64 ||
140
+ !is_power_of_2(qcow2_opts->refcount_bits))
141
+ {
142
+ error_setg(errp, "Refcount width must be a power of two and may not "
143
+ "exceed 64 bits");
144
+ return -EINVAL;
145
+ }
146
+ if (version < 3 && qcow2_opts->refcount_bits != 16) {
147
+ error_setg(errp, "Different refcount widths than 16 bits require "
148
+ "compatibility level 1.1 or above (use compat=1.1 or "
149
+ "greater)");
150
+ return -EINVAL;
151
+ }
152
+ refcount_order = ctz32(qcow2_opts->refcount_bits);
153
+
154
+
155
+ /* Create BlockBackend to write to the image */
156
blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
157
ret = blk_insert_bs(blk, bs, errp);
158
if (ret < 0) {
159
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
160
/* We'll update this to correct value later */
161
header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
162
163
- if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
164
+ if (qcow2_opts->lazy_refcounts) {
165
header->compatible_features |=
166
cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
167
}
168
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
169
}
170
171
/* Okay, now that we have a valid image, let's give it the right size */
172
- ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
173
+ ret = blk_truncate(blk, qcow2_opts->size, PREALLOC_MODE_OFF, errp);
174
if (ret < 0) {
175
error_prepend(errp, "Could not resize image: ");
176
goto out;
177
}
178
179
/* Want a backing file? There you go.*/
180
- if (backing_file) {
181
- ret = bdrv_change_backing_file(blk_bs(blk), backing_file, backing_format);
182
+ if (qcow2_opts->has_backing_file) {
183
+ const char *backing_format = NULL;
184
+
185
+ if (qcow2_opts->has_backing_fmt) {
186
+ backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt);
187
+ }
188
+
189
+ ret = bdrv_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
190
+ backing_format);
191
if (ret < 0) {
192
error_setg_errno(errp, -ret, "Could not assign backing file '%s' "
193
- "with format '%s'", backing_file, backing_format);
194
+ "with format '%s'", qcow2_opts->backing_file,
195
+ backing_format);
52
goto out;
196
goto out;
53
}
197
}
54
- old_backing_num_sectors = blk_nb_sectors(blk_old_backing);
198
}
55
- if (old_backing_num_sectors < 0) {
199
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, int64_t total_size,
56
+ old_backing_size = blk_getlength(blk_old_backing);
200
}
57
+ if (old_backing_size < 0) {
201
58
char backing_name[PATH_MAX];
202
/* And if we're supposed to preallocate metadata, do that now */
59
203
- if (prealloc != PREALLOC_MODE_OFF) {
60
bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
204
- ret = preallocate(blk_bs(blk), 0, total_size);
61
error_report("Could not get size of '%s': %s",
205
+ if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) {
62
- backing_name, strerror(-old_backing_num_sectors));
206
+ ret = preallocate(blk_bs(blk), 0, qcow2_opts->size);
63
+ backing_name, strerror(-old_backing_size));
207
if (ret < 0) {
64
ret = -1;
208
error_setg_errno(errp, -ret, "Could not preallocate metadata");
65
goto out;
209
goto out;
66
}
210
@@ -XXX,XX +XXX,XX @@ out:
67
if (blk_new_backing) {
211
static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opts,
68
- new_backing_num_sectors = blk_nb_sectors(blk_new_backing);
212
Error **errp)
69
- if (new_backing_num_sectors < 0) {
213
{
70
+ new_backing_size = blk_getlength(blk_new_backing);
214
+ BlockdevCreateOptions create_options;
71
+ if (new_backing_size < 0) {
215
char *backing_file = NULL;
72
error_report("Could not get size of '%s': %s",
216
char *backing_fmt = NULL;
73
- out_baseimg, strerror(-new_backing_num_sectors));
217
+ BlockdevDriver backing_drv;
74
+ out_baseimg, strerror(-new_backing_size));
218
char *buf = NULL;
75
ret = -1;
219
uint64_t size = 0;
76
goto out;
220
int flags = 0;
77
}
221
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
78
}
222
PreallocMode prealloc;
79
223
int version;
80
- if (num_sectors != 0) {
224
uint64_t refcount_bits;
81
- local_progress = (float)100 /
225
- int refcount_order;
82
- (num_sectors / MIN(num_sectors, IO_BUF_SIZE / 512));
226
char *encryptfmt = NULL;
83
+ if (size != 0) {
227
BlockDriverState *bs = NULL;
84
+ local_progress = (float)100 / (size / MIN(size, IO_BUF_SIZE));
228
Error *local_err = NULL;
85
}
229
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
86
230
BDRV_SECTOR_SIZE);
87
- for (sector = 0; sector < num_sectors; sector += n) {
231
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
232
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
233
+ backing_drv = qapi_enum_parse(&BlockdevDriver_lookup, backing_fmt,
234
+ 0, &local_err);
235
+ if (local_err) {
236
+ error_propagate(errp, local_err);
237
+ ret = -EINVAL;
238
+ goto finish;
239
+ }
240
encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
241
if (encryptfmt) {
242
if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
243
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
244
flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
245
}
246
247
- if (backing_file && prealloc != PREALLOC_MODE_OFF) {
248
- error_setg(errp, "Backing file and preallocation cannot be used at "
249
- "the same time");
250
- ret = -EINVAL;
251
- goto finish;
252
- }
88
-
253
-
89
- /* How many sectors can we handle with the next read? */
254
- if (version < 3 && (flags & BLOCK_FLAG_LAZY_REFCOUNTS)) {
90
- if (sector + (IO_BUF_SIZE / 512) <= num_sectors) {
255
- error_setg(errp, "Lazy refcounts only supported with compatibility "
91
- n = (IO_BUF_SIZE / 512);
256
- "level 1.1 and above (use compat=1.1 or greater)");
92
- } else {
257
- ret = -EINVAL;
93
- n = num_sectors - sector;
258
- goto finish;
94
- }
259
- }
95
+ for (offset = 0; offset < size; offset += n) {
260
-
96
+ /* How many bytes can we handle with the next read? */
261
refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);
97
+ n = MIN(IO_BUF_SIZE, size - offset);
262
if (local_err) {
98
263
error_propagate(errp, local_err);
99
/* If the cluster is allocated, we don't need to take action */
264
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
100
- ret = bdrv_is_allocated(bs, sector << BDRV_SECTOR_BITS,
265
goto finish;
101
- n << BDRV_SECTOR_BITS, &count);
266
}
102
+ ret = bdrv_is_allocated(bs, offset, n, &n);
267
103
if (ret < 0) {
268
- refcount_order = ctz32(refcount_bits);
104
error_report("error while reading image metadata: %s",
269
105
strerror(-ret));
270
/* Create and open the file (protocol layer) */
106
goto out;
271
if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
107
}
272
+ int refcount_order = ctz32(refcount_bits);
108
- /* TODO relax this once bdrv_is_allocated does not enforce
273
int64_t prealloc_size =
109
- * sector alignment */
274
qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
110
- assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
275
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
111
- n = count >> BDRV_SECTOR_BITS;
276
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
112
if (ret) {
277
}
113
continue;
278
114
}
279
/* Create the qcow2 image (format layer) */
115
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
280
- ret = qcow2_co_create(bs, size, backing_file, backing_fmt, flags,
116
* Read old and new backing file and take into consideration that
281
- cluster_size, prealloc, opts, version, refcount_order,
117
* backing files may be smaller than the COW image.
282
- encryptfmt, errp);
118
*/
283
+ create_options = (BlockdevCreateOptions) {
119
- if (sector >= old_backing_num_sectors) {
284
+ .driver = BLOCKDEV_DRIVER_QCOW2,
120
- memset(buf_old, 0, n * BDRV_SECTOR_SIZE);
285
+ .u.qcow2 = {
121
+ if (offset >= old_backing_size) {
286
+ .file = &(BlockdevRef) {
122
+ memset(buf_old, 0, n);
287
+ .type = QTYPE_QSTRING,
123
} else {
288
+ .u.reference = bs->node_name,
124
- if (sector + n > old_backing_num_sectors) {
289
+ },
125
- n = old_backing_num_sectors - sector;
290
+ .size = size,
126
+ if (offset + n > old_backing_size) {
291
+ .has_version = true,
127
+ n = old_backing_size - offset;
292
+ .version = version == 2
128
}
293
+ ? BLOCKDEV_QCOW2_VERSION_V2
129
294
+ : BLOCKDEV_QCOW2_VERSION_V3,
130
- ret = blk_pread(blk_old_backing, sector << BDRV_SECTOR_BITS,
295
+ .has_backing_file = (backing_file != NULL),
131
- buf_old, n << BDRV_SECTOR_BITS);
296
+ .backing_file = backing_file,
132
+ ret = blk_pread(blk_old_backing, offset, buf_old, n);
297
+ .has_backing_fmt = (backing_fmt != NULL),
133
if (ret < 0) {
298
+ .backing_fmt = backing_drv,
134
error_report("error while reading from old backing file");
299
+ .has_cluster_size = true,
135
goto out;
300
+ .cluster_size = cluster_size,
136
}
301
+ .has_preallocation = true,
137
}
302
+ .preallocation = prealloc,
138
303
+ .has_lazy_refcounts = true,
139
- if (sector >= new_backing_num_sectors || !blk_new_backing) {
304
+ .lazy_refcounts = (flags & BLOCK_FLAG_LAZY_REFCOUNTS),
140
- memset(buf_new, 0, n * BDRV_SECTOR_SIZE);
305
+ .has_refcount_bits = true,
141
+ if (offset >= new_backing_size || !blk_new_backing) {
306
+ .refcount_bits = refcount_bits,
142
+ memset(buf_new, 0, n);
307
+ },
143
} else {
308
+ };
144
- if (sector + n > new_backing_num_sectors) {
309
+ ret = qcow2_co_create(bs, &create_options, opts, encryptfmt, errp);
145
- n = new_backing_num_sectors - sector;
310
if (ret < 0) {
146
+ if (offset + n > new_backing_size) {
311
goto finish;
147
+ n = new_backing_size - offset;
312
}
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",
176
--
313
--
177
2.13.6
314
2.13.6
178
315
179
316
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
Instead of passing a separate BlockDriverState* into qcow2_co_create(),
2
2
make use of the BlockdevRef that is included in BlockdevCreateOptions.
3
We are gradually moving away from sector-based interfaces, towards
3
4
byte-based. In the common case, allocation is unlikely to ever use
5
values that are not naturally sector-aligned, but it is possible
6
that byte-based values will let us be more precise about allocation
7
at the end of an unaligned file that can do byte-based access.
8
9
Changing the name of the function from bdrv_get_block_status_above()
10
to bdrv_block_status_above() ensures that the compiler enforces that
11
all callers are updated. Likewise, since it a byte interface allows
12
an offset mapping that might not be sector aligned, split the mapping
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>
33
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
34
---
7
---
35
include/block/block.h | 8 +++-----
8
include/block/block.h | 1 +
36
block/io.c | 55 ++++++++-------------------------------------------
9
block.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
37
block/mirror.c | 18 ++++++-----------
10
block/qcow2.c | 39 +++++++++++++++++++++++++--------------
38
block/qcow2.c | 30 +++++++++++-----------------
11
3 files changed, 73 insertions(+), 14 deletions(-)
39
qemu-img.c | 49 +++++++++++++++++++++++++--------------------
40
5 files changed, 57 insertions(+), 103 deletions(-)
41
12
42
diff --git a/include/block/block.h b/include/block/block.h
13
diff --git a/include/block/block.h b/include/block/block.h
43
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
44
--- a/include/block/block.h
15
--- a/include/block/block.h
45
+++ b/include/block/block.h
16
+++ b/include/block/block.h
46
@@ -XXX,XX +XXX,XX @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
17
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
47
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
18
BlockDriverState* parent,
48
int64_t bytes, int64_t *pnum, int64_t *map,
19
const BdrvChildRole *child_role,
49
BlockDriverState **file);
20
bool allow_none, Error **errp);
50
-int64_t bdrv_get_block_status_above(BlockDriverState *bs,
21
+BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
51
- BlockDriverState *base,
22
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
52
- int64_t sector_num,
23
Error **errp);
53
- int nb_sectors, int *pnum,
24
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
54
- BlockDriverState **file);
25
diff --git a/block.c b/block.c
55
+int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
56
+ int64_t offset, int64_t bytes, int64_t *pnum,
57
+ int64_t *map, BlockDriverState **file);
58
int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
59
int64_t *pnum);
60
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
61
diff --git a/block/io.c b/block/io.c
62
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
63
--- a/block/io.c
27
--- a/block.c
64
+++ b/block/io.c
28
+++ b/block.c
65
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
29
@@ -XXX,XX +XXX,XX @@
66
return ret;
30
#include "qapi/qmp/qdict.h"
31
#include "qapi/qmp/qjson.h"
32
#include "qapi/qmp/qstring.h"
33
+#include "qapi/qobject-output-visitor.h"
34
+#include "qapi/qapi-visit-block-core.h"
35
#include "sysemu/block-backend.h"
36
#include "sysemu/sysemu.h"
37
#include "qemu/notify.h"
38
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
39
return c;
67
}
40
}
68
41
69
-/* Coroutine wrapper for bdrv_get_block_status_above() */
42
+/* TODO Future callers may need to specify parent/child_role in order for
70
+/* Coroutine wrapper for bdrv_block_status_above() */
43
+ * option inheritance to work. Existing callers use it for the root node. */
71
static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
44
+BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
72
{
45
+{
73
BdrvCoBlockStatusData *data = opaque;
46
+ BlockDriverState *bs = NULL;
74
@@ -XXX,XX +XXX,XX @@ static int bdrv_common_block_status_above(BlockDriverState *bs,
47
+ Error *local_err = NULL;
75
return data.ret;
48
+ QObject *obj = NULL;
76
}
49
+ QDict *qdict = NULL;
77
50
+ const char *reference = NULL;
78
-int64_t bdrv_get_block_status_above(BlockDriverState *bs,
51
+ Visitor *v = NULL;
79
- BlockDriverState *base,
52
+
80
- int64_t sector_num,
53
+ if (ref->type == QTYPE_QSTRING) {
81
- int nb_sectors, int *pnum,
54
+ reference = ref->u.reference;
82
- BlockDriverState **file)
55
+ } else {
83
+int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
56
+ BlockdevOptions *options = &ref->u.definition;
84
+ int64_t offset, int64_t bytes, int64_t *pnum,
57
+ assert(ref->type == QTYPE_QDICT);
85
+ int64_t *map, BlockDriverState **file)
58
+
86
{
59
+ v = qobject_output_visitor_new(&obj);
87
- int64_t ret;
60
+ visit_type_BlockdevOptions(v, NULL, &options, &local_err);
88
- int64_t n;
61
+ if (local_err) {
89
- int64_t map;
62
+ error_propagate(errp, local_err);
90
-
63
+ goto fail;
91
- ret = bdrv_common_block_status_above(bs, base, true,
64
+ }
92
- sector_num * BDRV_SECTOR_SIZE,
65
+ visit_complete(v, &obj);
93
- nb_sectors * BDRV_SECTOR_SIZE,
66
+
94
- &n, &map, file);
67
+ qdict = qobject_to_qdict(obj);
95
- if (ret < 0) {
68
+ qdict_flatten(qdict);
96
- *pnum = 0;
69
+
97
- return ret;
70
+ /* bdrv_open_inherit() defaults to the values in bdrv_flags (for
98
- }
71
+ * compatibility with other callers) rather than what we want as the
99
- assert(QEMU_IS_ALIGNED(n | map, BDRV_SECTOR_SIZE));
72
+ * real defaults. Apply the defaults here instead. */
100
- *pnum = n >> BDRV_SECTOR_BITS;
73
+ qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
101
- return ret | map;
74
+ qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
102
+ return bdrv_common_block_status_above(bs, base, true, offset, bytes,
75
+ qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
103
+ pnum, map, file);
76
+ }
104
}
77
+
105
78
+ bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
106
int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
79
+ obj = NULL;
107
int64_t *pnum, int64_t *map, BlockDriverState **file)
80
+
108
{
81
+fail:
109
- int64_t ret;
82
+ qobject_decref(obj);
110
- int n;
83
+ visit_free(v);
111
-
84
+ return bs;
112
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
85
+}
113
- assert(pnum);
86
+
114
- /*
87
static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
115
- * The contract allows us to return pnum smaller than bytes, even
88
int flags,
116
- * if the next query would see the same status; we truncate the
89
QDict *snapshot_options,
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)
153
}
154
155
/* Clear dirty bits before querying the block status, because
156
- * calling bdrv_get_block_status_above could yield - if some blocks are
157
+ * calling bdrv_block_status_above could yield - if some blocks are
158
* marked dirty in this window, we need to know.
159
*/
160
bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset,
161
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
162
163
bitmap_set(s->in_flight_bitmap, offset / s->granularity, nb_chunks);
164
while (nb_chunks > 0 && offset < s->bdev_length) {
165
- int64_t ret;
166
- int io_sectors;
167
+ int ret;
168
int64_t io_bytes;
169
int64_t io_bytes_acct;
170
enum MirrorMethod {
171
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
172
} mirror_method = MIRROR_METHOD_COPY;
173
174
assert(!(offset % s->granularity));
175
- ret = bdrv_get_block_status_above(source, NULL,
176
- offset >> BDRV_SECTOR_BITS,
177
- nb_chunks * sectors_per_chunk,
178
- &io_sectors, NULL);
179
- io_bytes = io_sectors * BDRV_SECTOR_SIZE;
180
+ ret = bdrv_block_status_above(source, NULL, offset,
181
+ nb_chunks * s->granularity,
182
+ &io_bytes, NULL, NULL);
183
if (ret < 0) {
184
io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes);
185
} else if (ret & BDRV_BLOCK_DATA) {
186
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
187
granularity = bdrv_get_default_bitmap_granularity(target);
188
}
189
190
- assert ((granularity & (granularity - 1)) == 0);
191
- /* Granularity must be large enough for sector-based dirty bitmap */
192
- assert(granularity >= BDRV_SECTOR_SIZE);
193
+ assert(is_power_of_2(granularity));
194
195
if (buf_size < 0) {
196
error_setg(errp, "Invalid parameter 'buf-size'");
197
diff --git a/block/qcow2.c b/block/qcow2.c
90
diff --git a/block/qcow2.c b/block/qcow2.c
198
index XXXXXXX..XXXXXXX 100644
91
index XXXXXXX..XXXXXXX 100644
199
--- a/block/qcow2.c
92
--- a/block/qcow2.c
200
+++ b/block/qcow2.c
93
+++ b/block/qcow2.c
201
@@ -XXX,XX +XXX,XX @@ finish:
94
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
202
95
}
203
static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
96
97
static int coroutine_fn
98
-qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
99
- QemuOpts *opts, const char *encryptfmt, Error **errp)
100
+qcow2_co_create(BlockdevCreateOptions *create_options, QemuOpts *opts,
101
+ const char *encryptfmt, Error **errp)
204
{
102
{
205
- int nr;
103
BlockdevCreateOptionsQcow2 *qcow2_opts;
206
- int64_t res;
104
QDict *options;
207
+ int64_t nr;
105
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
208
+ int res;
106
* 2 GB for 64k clusters, and we don't want to have a 2 GB initial file
209
int64_t start;
107
* size for any qcow2 image.
210
108
*/
211
/* TODO: Widening to sector boundaries should only be needed as
109
- BlockBackend *blk;
212
@@ -XXX,XX +XXX,XX @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
110
+ BlockBackend *blk = NULL;
213
if (!bytes) {
111
+ BlockDriverState *bs = NULL;
214
return true;
112
QCowHeader *header;
215
}
113
size_t cluster_size;
216
- res = bdrv_get_block_status_above(bs, NULL, start >> BDRV_SECTOR_BITS,
114
int version;
217
- bytes >> BDRV_SECTOR_BITS, &nr, NULL);
115
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
218
- return res >= 0 && (res & BDRV_BLOCK_ZERO) &&
116
Error *local_err = NULL;
219
- nr * BDRV_SECTOR_SIZE == bytes;
117
int ret;
220
+ res = bdrv_block_status_above(bs, NULL, start, bytes, &nr, NULL, NULL);
118
221
+ return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == bytes;
119
- /* Validate options and set default values */
120
assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2);
121
qcow2_opts = &create_options->u.qcow2;
122
123
+ bs = bdrv_open_blockdev_ref(qcow2_opts->file, errp);
124
+ if (bs == NULL) {
125
+ return -EIO;
126
+ }
127
+
128
+ /* Validate options and set default values */
129
if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
130
error_setg(errp, "Image size must be a multiple of 512 bytes");
131
ret = -EINVAL;
132
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
133
}
134
135
if (!validate_cluster_size(cluster_size, errp)) {
136
- return -EINVAL;
137
+ ret = -EINVAL;
138
+ goto out;
139
}
140
141
if (!qcow2_opts->has_preallocation) {
142
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
143
{
144
error_setg(errp, "Backing file and preallocation cannot be used at "
145
"the same time");
146
- return -EINVAL;
147
+ ret = -EINVAL;
148
+ goto out;
149
}
150
if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) {
151
error_setg(errp, "Backing format cannot be used without backing file");
152
- return -EINVAL;
153
+ ret = -EINVAL;
154
+ goto out;
155
}
156
157
if (!qcow2_opts->has_lazy_refcounts) {
158
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
159
if (version < 3 && qcow2_opts->lazy_refcounts) {
160
error_setg(errp, "Lazy refcounts only supported with compatibility "
161
"level 1.1 and above (use compat=1.1 or greater)");
162
- return -EINVAL;
163
+ ret = -EINVAL;
164
+ goto out;
165
}
166
167
if (!qcow2_opts->has_refcount_bits) {
168
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
169
{
170
error_setg(errp, "Refcount width must be a power of two and may not "
171
"exceed 64 bits");
172
- return -EINVAL;
173
+ ret = -EINVAL;
174
+ goto out;
175
}
176
if (version < 3 && qcow2_opts->refcount_bits != 16) {
177
error_setg(errp, "Different refcount widths than 16 bits require "
178
"compatibility level 1.1 or above (use compat=1.1 or "
179
"greater)");
180
- return -EINVAL;
181
+ ret = -EINVAL;
182
+ goto out;
183
}
184
refcount_order = ctz32(qcow2_opts->refcount_bits);
185
186
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockDriverState *bs, BlockdevCreateOptions *create_options,
187
188
ret = 0;
189
out:
190
- if (blk) {
191
- blk_unref(blk);
192
- }
193
+ blk_unref(blk);
194
+ bdrv_unref(bs);
195
return ret;
222
}
196
}
223
197
224
static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
198
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
225
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
199
.refcount_bits = refcount_bits,
226
required = virtual_size;
200
},
227
} else {
201
};
228
int64_t offset;
202
- ret = qcow2_co_create(bs, &create_options, opts, encryptfmt, errp);
229
- int pnum = 0;
203
+ ret = qcow2_co_create(&create_options, opts, encryptfmt, errp);
230
+ int64_t pnum = 0;
204
if (ret < 0) {
231
205
goto finish;
232
- for (offset = 0; offset < ssize;
206
}
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;
360
+
361
if (s->target_has_backing) {
362
- int64_t count = n * BDRV_SECTOR_SIZE;
363
364
ret = bdrv_block_status(blk_bs(s->src[src_cur]),
365
(sector_num - src_cur_offset) *
366
BDRV_SECTOR_SIZE,
367
count, &count, NULL, NULL);
368
- assert(ret < 0 || QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
369
- n = count >> BDRV_SECTOR_BITS;
370
} else {
371
- ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL,
372
- sector_num - src_cur_offset,
373
- n, &n, NULL);
374
+ ret = bdrv_block_status_above(blk_bs(s->src[src_cur]), NULL,
375
+ (sector_num - src_cur_offset) *
376
+ BDRV_SECTOR_SIZE,
377
+ count, &count, NULL, NULL);
378
}
379
if (ret < 0) {
380
return ret;
381
}
382
+ n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE);
383
384
if (ret & BDRV_BLOCK_ZERO) {
385
s->status = BLK_ZERO;
386
--
207
--
387
2.13.6
208
2.13.6
388
209
389
210
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
Instead of passing the encryption format name and the QemuOpts down, use
2
the QCryptoBlockCreateOptions contained in BlockdevCreateOptions.
2
3
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>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
---
7
---
13
block/qcow2.c | 33 +++++++++++++++++++--------------
8
block/qcow2.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------------
14
1 file changed, 19 insertions(+), 14 deletions(-)
9
1 file changed, 45 insertions(+), 17 deletions(-)
15
10
16
diff --git a/block/qcow2.c b/block/qcow2.c
11
diff --git a/block/qcow2.c b/block/qcow2.c
17
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.c
13
--- a/block/qcow2.c
19
+++ b/block/qcow2.c
14
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ finish:
15
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypt_method_from_format(const char *encryptfmt)
16
}
21
}
17
}
22
18
23
19
-static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
24
-static bool is_zero_sectors(BlockDriverState *bs, int64_t start,
20
- QemuOpts *opts, Error **errp)
25
- uint32_t count)
21
+static QCryptoBlockCreateOptions *
26
+static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
22
+qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **errp)
27
{
23
{
28
int nr;
24
- BDRVQcow2State *s = bs->opaque;
29
int64_t res;
25
QCryptoBlockCreateOptions *cryptoopts = NULL;
30
+ int64_t start;
26
- QCryptoBlock *crypto = NULL;
31
27
- int ret = -EINVAL;
32
- if (start + count > bs->total_sectors) {
28
QDict *options, *encryptopts;
33
- count = bs->total_sectors - start;
29
int fmt;
34
+ /* TODO: Widening to sector boundaries should only be needed as
30
35
+ * long as we can't query finer granularity. */
31
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
36
+ start = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
32
error_setg(errp, "Unknown encryption format '%s'", encryptfmt);
37
+ bytes = QEMU_ALIGN_UP(offset + bytes, BDRV_SECTOR_SIZE) - start;
33
break;
34
}
35
- if (!cryptoopts) {
36
- ret = -EINVAL;
37
- goto out;
38
+
38
+
39
+ /* Clamp to image length, before checking status of underlying sectors */
39
+ QDECREF(encryptopts);
40
+ if (start + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) {
40
+ return cryptoopts;
41
+ bytes = bs->total_sectors * BDRV_SECTOR_SIZE - start;
41
+}
42
+
43
+static int qcow2_set_up_encryption(BlockDriverState *bs,
44
+ QCryptoBlockCreateOptions *cryptoopts,
45
+ Error **errp)
46
+{
47
+ BDRVQcow2State *s = bs->opaque;
48
+ QCryptoBlock *crypto = NULL;
49
+ int fmt, ret;
50
+
51
+ switch (cryptoopts->format) {
52
+ case Q_CRYPTO_BLOCK_FORMAT_LUKS:
53
+ fmt = QCOW_CRYPT_LUKS;
54
+ break;
55
+ case Q_CRYPTO_BLOCK_FORMAT_QCOW:
56
+ fmt = QCOW_CRYPT_AES;
57
+ break;
58
+ default:
59
+ error_setg(errp, "Crypto format not supported in qcow2");
60
+ return -EINVAL;
42
}
61
}
43
62
+
44
- if (!count) {
63
s->crypt_method_header = fmt;
45
+ if (!bytes) {
64
46
return true;
65
crypto = qcrypto_block_create(cryptoopts, "encrypt.",
66
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
67
qcow2_crypto_hdr_write_func,
68
bs, errp);
69
if (!crypto) {
70
- ret = -EINVAL;
71
- goto out;
72
+ return -EINVAL;
47
}
73
}
48
- res = bdrv_get_block_status_above(bs, NULL, start, count, &nr, NULL);
74
49
- return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == count;
75
ret = qcow2_update_header(bs);
50
+ res = bdrv_get_block_status_above(bs, NULL, start >> BDRV_SECTOR_BITS,
76
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
51
+ bytes >> BDRV_SECTOR_BITS, &nr, NULL);
77
goto out;
52
+ return res >= 0 && (res & BDRV_BLOCK_ZERO) &&
78
}
53
+ nr * BDRV_SECTOR_SIZE == bytes;
79
80
+ ret = 0;
81
out:
82
- QDECREF(encryptopts);
83
qcrypto_block_free(crypto);
84
- qapi_free_QCryptoBlockCreateOptions(cryptoopts);
85
return ret;
54
}
86
}
55
87
56
static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
88
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
57
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
89
}
90
91
static int coroutine_fn
92
-qcow2_co_create(BlockdevCreateOptions *create_options, QemuOpts *opts,
93
- const char *encryptfmt, Error **errp)
94
+qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
95
{
96
BlockdevCreateOptionsQcow2 *qcow2_opts;
97
QDict *options;
98
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, QemuOpts *opts,
58
}
99
}
59
100
60
if (head || tail) {
101
/* Want encryption? There you go. */
61
- int64_t cl_start = (offset - head) >> BDRV_SECTOR_BITS;
102
- if (encryptfmt) {
62
uint64_t off;
103
- ret = qcow2_set_up_encryption(blk_bs(blk), encryptfmt, opts, errp);
63
unsigned int nr;
104
+ if (qcow2_opts->has_encrypt) {
64
105
+ ret = qcow2_set_up_encryption(blk_bs(blk), qcow2_opts->encrypt, errp);
65
assert(head + bytes <= s->cluster_size);
106
if (ret < 0) {
66
107
goto out;
67
/* check whether remainder of cluster already reads as zero */
68
- if (!(is_zero_sectors(bs, cl_start,
69
- DIV_ROUND_UP(head, BDRV_SECTOR_SIZE)) &&
70
- is_zero_sectors(bs, (offset + bytes) >> BDRV_SECTOR_BITS,
71
- DIV_ROUND_UP(-tail & (s->cluster_size - 1),
72
- BDRV_SECTOR_SIZE)))) {
73
+ if (!(is_zero(bs, offset - head, head) &&
74
+ is_zero(bs, offset + bytes,
75
+ tail ? s->cluster_size - tail : 0))) {
76
return -ENOTSUP;
77
}
108
}
78
109
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
79
qemu_co_mutex_lock(&s->lock);
110
int version;
80
/* We can have new write after previous check */
111
uint64_t refcount_bits;
81
- offset = cl_start << BDRV_SECTOR_BITS;
112
char *encryptfmt = NULL;
82
+ offset = QEMU_ALIGN_DOWN(offset, s->cluster_size);
113
+ QCryptoBlockCreateOptions *cryptoopts = NULL;
83
bytes = s->cluster_size;
114
BlockDriverState *bs = NULL;
84
nr = s->cluster_size;
115
Error *local_err = NULL;
85
ret = qcow2_get_cluster_offset(bs, offset, &nr, &off);
116
int ret;
117
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
118
ret = -EINVAL;
119
goto finish;
120
}
121
+
122
encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
123
if (encryptfmt) {
124
if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
125
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
126
} else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
127
encryptfmt = g_strdup("aes");
128
}
129
+ if (encryptfmt) {
130
+ cryptoopts = qcow2_parse_encryption(encryptfmt, opts, errp);
131
+ if (cryptoopts == NULL) {
132
+ ret = -EINVAL;
133
+ goto finish;
134
+ }
135
+ }
136
+
137
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
138
if (local_err) {
139
error_propagate(errp, local_err);
140
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
141
.backing_file = backing_file,
142
.has_backing_fmt = (backing_fmt != NULL),
143
.backing_fmt = backing_drv,
144
+ .has_encrypt = (encryptfmt != NULL),
145
+ .encrypt = cryptoopts,
146
.has_cluster_size = true,
147
.cluster_size = cluster_size,
148
.has_preallocation = true,
149
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
150
.refcount_bits = refcount_bits,
151
},
152
};
153
- ret = qcow2_co_create(&create_options, opts, encryptfmt, errp);
154
+ ret = qcow2_co_create(&create_options, errp);
155
if (ret < 0) {
156
goto finish;
157
}
158
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
159
finish:
160
bdrv_unref(bs);
161
162
+ qapi_free_QCryptoBlockCreateOptions(cryptoopts);
163
g_free(backing_file);
164
g_free(backing_fmt);
165
g_free(encryptfmt);
86
--
166
--
87
2.13.6
167
2.13.6
88
168
89
169
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Once qcow2_co_create() can be called directly on an already existing
2
node, we must provide the 'full' and 'falloc' preallocation modes
3
outside of creating the image on the protocol layer. Fortunately, we
4
have preallocated truncate now which can provide this functionality.
2
5
3
bdrv_truncate() has an errp parameter which is always set when an error
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
occurs. Let's use that instead of a plain strerror().
7
Reviewed-by: Eric Blake <eblake@redhat.com>
5
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
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>
11
---
9
---
12
block/qcow2.c | 13 +++++++------
10
block/qcow2.c | 28 +++++++++++++++++++---------
13
1 file changed, 7 insertions(+), 6 deletions(-)
11
1 file changed, 19 insertions(+), 9 deletions(-)
14
12
15
diff --git a/block/qcow2.c b/block/qcow2.c
13
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2.c
15
--- a/block/qcow2.c
18
+++ b/block/qcow2.c
16
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
17
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
20
return last_cluster;
18
}
21
}
19
blk_set_allow_write_beyond_eof(blk, true);
22
if ((last_cluster + 1) * s->cluster_size < old_file_size) {
20
23
- ret = bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
21
+ /* Clear the protocol layer and preallocate it if necessary */
24
- PREALLOC_MODE_OFF, NULL);
22
+ ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
25
- if (ret < 0) {
23
+ if (ret < 0) {
26
- warn_report("Failed to truncate the tail of the image: %s",
24
+ goto out;
27
- strerror(-ret));
25
+ }
28
- ret = 0;
29
+ Error *local_err = NULL;
30
+
26
+
31
+ bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
27
+ if (qcow2_opts->preallocation == PREALLOC_MODE_FULL ||
32
+ PREALLOC_MODE_OFF, &local_err);
28
+ qcow2_opts->preallocation == PREALLOC_MODE_FALLOC)
33
+ if (local_err) {
29
+ {
34
+ warn_reportf_err(local_err,
30
+ int64_t prealloc_size =
35
+ "Failed to truncate the tail of the image: ");
31
+ qcow2_calc_prealloc_size(qcow2_opts->size, cluster_size,
36
}
32
+ refcount_order);
37
}
33
+
38
} else {
34
+ ret = blk_truncate(blk, prealloc_size, qcow2_opts->preallocation, errp);
35
+ if (ret < 0) {
36
+ goto out;
37
+ }
38
+ }
39
+
40
/* Write the header */
41
QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header));
42
header = g_malloc0(cluster_size);
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt
44
45
46
/* Create and open the file (protocol layer) */
47
- if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
48
- int refcount_order = ctz32(refcount_bits);
49
- int64_t prealloc_size =
50
- qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
51
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
52
- qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
53
- &error_abort);
54
- }
55
-
56
ret = bdrv_create_file(filename, opts, errp);
57
if (ret < 0) {
58
goto finish;
39
--
59
--
40
2.13.6
60
2.13.6
41
61
42
62
diff view generated by jsdifflib
New patch
1
This allows, given a QemuOpts for a QemuOptsList that was merged from
2
multiple QemuOptsList, to only consider those options that exist in one
3
specific list. Block drivers need this to separate format-layer create
4
options from protocol-level options.
1
5
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
10
include/qemu/option.h | 2 ++
11
util/qemu-option.c | 42 +++++++++++++++++++++++++++++++++++++-----
12
2 files changed, 39 insertions(+), 5 deletions(-)
13
14
diff --git a/include/qemu/option.h b/include/qemu/option.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/qemu/option.h
17
+++ b/include/qemu/option.h
18
@@ -XXX,XX +XXX,XX @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
19
int permit_abbrev);
20
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
21
Error **errp);
22
+QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
23
+ QemuOptsList *list, bool del);
24
QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
25
void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp);
26
27
diff --git a/util/qemu-option.c b/util/qemu-option.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/util/qemu-option.c
30
+++ b/util/qemu-option.c
31
@@ -XXX,XX +XXX,XX @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
32
}
33
34
/*
35
- * Convert from QemuOpts to QDict.
36
- * The QDict values are of type QString.
37
+ * Convert from QemuOpts to QDict. The QDict values are of type QString.
38
+ *
39
+ * If @list is given, only add those options to the QDict that are contained in
40
+ * the list. If @del is true, any options added to the QDict are removed from
41
+ * the QemuOpts, otherwise they remain there.
42
+ *
43
+ * If two options in @opts have the same name, they are processed in order
44
+ * so that the last one wins (consistent with the reverse iteration in
45
+ * qemu_opt_find()), but all of them are deleted if @del is true.
46
+ *
47
* TODO We'll want to use types appropriate for opt->desc->type, but
48
* this is enough for now.
49
*/
50
-QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
51
+QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
52
+ QemuOptsList *list, bool del)
53
{
54
- QemuOpt *opt;
55
+ QemuOpt *opt, *next;
56
57
if (!qdict) {
58
qdict = qdict_new();
59
@@ -XXX,XX +XXX,XX @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
60
if (opts->id) {
61
qdict_put_str(qdict, "id", opts->id);
62
}
63
- QTAILQ_FOREACH(opt, &opts->head, next) {
64
+ QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next) {
65
+ if (list) {
66
+ QemuOptDesc *desc;
67
+ bool found = false;
68
+ for (desc = list->desc; desc->name; desc++) {
69
+ if (!strcmp(desc->name, opt->name)) {
70
+ found = true;
71
+ break;
72
+ }
73
+ }
74
+ if (!found) {
75
+ continue;
76
+ }
77
+ }
78
qdict_put_str(qdict, opt->name, opt->str);
79
+ if (del) {
80
+ qemu_opt_del(opt);
81
+ }
82
}
83
return qdict;
84
}
85
86
+/* Copy all options in a QemuOpts to the given QDict. See
87
+ * qemu_opts_to_qdict_filtered() for details. */
88
+QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
89
+{
90
+ return qemu_opts_to_qdict_filtered(opts, qdict, NULL, false);
91
+}
92
+
93
/* Validate parsed opts against descriptions where no
94
* descriptions were provided in the QemuOptsList.
95
*/
96
--
97
2.13.6
98
99
diff view generated by jsdifflib
New patch
1
Basic test for merging two QemuOptsLists.
1
2
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
7
tests/test-qemu-opts.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 128 insertions(+)
9
10
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-qemu-opts.c
13
+++ b/tests/test-qemu-opts.c
14
@@ -XXX,XX +XXX,XX @@ static QemuOptsList opts_list_01 = {
15
{
16
.name = "str1",
17
.type = QEMU_OPT_STRING,
18
+ .help = "Help texts are preserved in qemu_opts_append",
19
+ .def_value_str = "default",
20
},{
21
.name = "str2",
22
.type = QEMU_OPT_STRING,
23
@@ -XXX,XX +XXX,XX @@ static QemuOptsList opts_list_01 = {
24
},{
25
.name = "number1",
26
.type = QEMU_OPT_NUMBER,
27
+ .help = "Having help texts only for some options is okay",
28
},{
29
.name = "number2",
30
.type = QEMU_OPT_NUMBER,
31
@@ -XXX,XX +XXX,XX @@ static void test_opts_parse_size(void)
32
qemu_opts_reset(&opts_list_02);
33
}
34
35
+static void append_verify_list_01(QemuOptDesc *desc, bool with_overlapping)
36
+{
37
+ int i = 0;
38
+
39
+ if (with_overlapping) {
40
+ g_assert_cmpstr(desc[i].name, ==, "str1");
41
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
42
+ g_assert_cmpstr(desc[i].help, ==,
43
+ "Help texts are preserved in qemu_opts_append");
44
+ g_assert_cmpstr(desc[i].def_value_str, ==, "default");
45
+ i++;
46
+
47
+ g_assert_cmpstr(desc[i].name, ==, "str2");
48
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
49
+ g_assert_cmpstr(desc[i].help, ==, NULL);
50
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
51
+ i++;
52
+ }
53
+
54
+ g_assert_cmpstr(desc[i].name, ==, "str3");
55
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
56
+ g_assert_cmpstr(desc[i].help, ==, NULL);
57
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
58
+ i++;
59
+
60
+ g_assert_cmpstr(desc[i].name, ==, "number1");
61
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
62
+ g_assert_cmpstr(desc[i].help, ==,
63
+ "Having help texts only for some options is okay");
64
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
65
+ i++;
66
+
67
+ g_assert_cmpstr(desc[i].name, ==, "number2");
68
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
69
+ g_assert_cmpstr(desc[i].help, ==, NULL);
70
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
71
+ i++;
72
+
73
+ g_assert_cmpstr(desc[i].name, ==, NULL);
74
+}
75
+
76
+static void append_verify_list_02(QemuOptDesc *desc)
77
+{
78
+ int i = 0;
79
+
80
+ g_assert_cmpstr(desc[i].name, ==, "str1");
81
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
82
+ g_assert_cmpstr(desc[i].help, ==, NULL);
83
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
84
+ i++;
85
+
86
+ g_assert_cmpstr(desc[i].name, ==, "str2");
87
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
88
+ g_assert_cmpstr(desc[i].help, ==, NULL);
89
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
90
+ i++;
91
+
92
+ g_assert_cmpstr(desc[i].name, ==, "bool1");
93
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
94
+ g_assert_cmpstr(desc[i].help, ==, NULL);
95
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
96
+ i++;
97
+
98
+ g_assert_cmpstr(desc[i].name, ==, "bool2");
99
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
100
+ g_assert_cmpstr(desc[i].help, ==, NULL);
101
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
102
+ i++;
103
+
104
+ g_assert_cmpstr(desc[i].name, ==, "size1");
105
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
106
+ g_assert_cmpstr(desc[i].help, ==, NULL);
107
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
108
+ i++;
109
+
110
+ g_assert_cmpstr(desc[i].name, ==, "size2");
111
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
112
+ g_assert_cmpstr(desc[i].help, ==, NULL);
113
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
114
+ i++;
115
+
116
+ g_assert_cmpstr(desc[i].name, ==, "size3");
117
+ g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
118
+ g_assert_cmpstr(desc[i].help, ==, NULL);
119
+ g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
120
+}
121
+
122
+static void test_opts_append_to_null(void)
123
+{
124
+ QemuOptsList *merged;
125
+
126
+ merged = qemu_opts_append(NULL, &opts_list_01);
127
+ g_assert(merged != &opts_list_01);
128
+
129
+ g_assert_cmpstr(merged->name, ==, NULL);
130
+ g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
131
+ g_assert_false(merged->merge_lists);
132
+
133
+ append_verify_list_01(merged->desc, true);
134
+
135
+ qemu_opts_free(merged);
136
+}
137
+
138
+static void test_opts_append(void)
139
+{
140
+ QemuOptsList *first, *merged;
141
+
142
+ first = qemu_opts_append(NULL, &opts_list_02);
143
+ merged = qemu_opts_append(first, &opts_list_01);
144
+ g_assert(first != &opts_list_02);
145
+ g_assert(merged != &opts_list_01);
146
+
147
+ g_assert_cmpstr(merged->name, ==, NULL);
148
+ g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
149
+ g_assert_false(merged->merge_lists);
150
+
151
+ append_verify_list_02(&merged->desc[0]);
152
+ append_verify_list_01(&merged->desc[7], false);
153
+
154
+ qemu_opts_free(merged);
155
+}
156
+
157
+
158
int main(int argc, char *argv[])
159
{
160
register_opts();
161
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
162
g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool);
163
g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);
164
g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
165
+ g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null);
166
+ g_test_add_func("/qemu-opts/append", test_opts_append);
167
g_test_run();
168
return 0;
169
}
170
--
171
2.13.6
172
173
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
---
5
tests/test-qemu-opts.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
6
1 file changed, 125 insertions(+)
1
7
8
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
9
index XXXXXXX..XXXXXXX 100644
10
--- a/tests/test-qemu-opts.c
11
+++ b/tests/test-qemu-opts.c
12
@@ -XXX,XX +XXX,XX @@
13
#include "qemu/osdep.h"
14
#include "qemu/cutils.h"
15
#include "qemu/option.h"
16
+#include "qemu/option_int.h"
17
#include "qapi/error.h"
18
#include "qapi/qmp/qdict.h"
19
#include "qapi/qmp/qstring.h"
20
@@ -XXX,XX +XXX,XX @@ static void test_opts_append(void)
21
qemu_opts_free(merged);
22
}
23
24
+static void test_opts_to_qdict_basic(void)
25
+{
26
+ QemuOpts *opts;
27
+ QDict *dict;
28
+
29
+ opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
30
+ false, &error_abort);
31
+ g_assert(opts != NULL);
32
+
33
+ dict = qemu_opts_to_qdict(opts, NULL);
34
+ g_assert(dict != NULL);
35
+
36
+ g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
37
+ g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
38
+ g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
39
+ g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
40
+ g_assert_false(qdict_haskey(dict, "number2"));
41
+
42
+ QDECREF(dict);
43
+ qemu_opts_del(opts);
44
+}
45
+
46
+static void test_opts_to_qdict_filtered(void)
47
+{
48
+ QemuOptsList *first, *merged;
49
+ QemuOpts *opts;
50
+ QDict *dict;
51
+
52
+ first = qemu_opts_append(NULL, &opts_list_02);
53
+ merged = qemu_opts_append(first, &opts_list_01);
54
+
55
+ opts = qemu_opts_parse(merged,
56
+ "str1=foo,str2=,str3=bar,bool1=off,number1=42",
57
+ false, &error_abort);
58
+ g_assert(opts != NULL);
59
+
60
+ /* Convert to QDict without deleting from opts */
61
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, false);
62
+ g_assert(dict != NULL);
63
+ g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
64
+ g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
65
+ g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
66
+ g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
67
+ g_assert_false(qdict_haskey(dict, "number2"));
68
+ g_assert_false(qdict_haskey(dict, "bool1"));
69
+ QDECREF(dict);
70
+
71
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, false);
72
+ g_assert(dict != NULL);
73
+ g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
74
+ g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
75
+ g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
76
+ g_assert_false(qdict_haskey(dict, "str3"));
77
+ g_assert_false(qdict_haskey(dict, "number1"));
78
+ g_assert_false(qdict_haskey(dict, "number2"));
79
+ QDECREF(dict);
80
+
81
+ /* Now delete converted options from opts */
82
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, true);
83
+ g_assert(dict != NULL);
84
+ g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
85
+ g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
86
+ g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
87
+ g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
88
+ g_assert_false(qdict_haskey(dict, "number2"));
89
+ g_assert_false(qdict_haskey(dict, "bool1"));
90
+ QDECREF(dict);
91
+
92
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, true);
93
+ g_assert(dict != NULL);
94
+ g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
95
+ g_assert_false(qdict_haskey(dict, "str1"));
96
+ g_assert_false(qdict_haskey(dict, "str2"));
97
+ g_assert_false(qdict_haskey(dict, "str3"));
98
+ g_assert_false(qdict_haskey(dict, "number1"));
99
+ g_assert_false(qdict_haskey(dict, "number2"));
100
+ QDECREF(dict);
101
+
102
+ g_assert_true(QTAILQ_EMPTY(&opts->head));
103
+
104
+ qemu_opts_del(opts);
105
+ qemu_opts_free(merged);
106
+}
107
+
108
+static void test_opts_to_qdict_duplicates(void)
109
+{
110
+ QemuOpts *opts;
111
+ QemuOpt *opt;
112
+ QDict *dict;
113
+
114
+ opts = qemu_opts_parse(&opts_list_03, "foo=a,foo=b", false, &error_abort);
115
+ g_assert(opts != NULL);
116
+
117
+ /* Verify that opts has two options with the same name */
118
+ opt = QTAILQ_FIRST(&opts->head);
119
+ g_assert_cmpstr(opt->name, ==, "foo");
120
+ g_assert_cmpstr(opt->str , ==, "a");
121
+
122
+ opt = QTAILQ_NEXT(opt, next);
123
+ g_assert_cmpstr(opt->name, ==, "foo");
124
+ g_assert_cmpstr(opt->str , ==, "b");
125
+
126
+ opt = QTAILQ_NEXT(opt, next);
127
+ g_assert(opt == NULL);
128
+
129
+ /* In the conversion to QDict, the last one wins */
130
+ dict = qemu_opts_to_qdict(opts, NULL);
131
+ g_assert(dict != NULL);
132
+ g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
133
+ QDECREF(dict);
134
+
135
+ /* The last one still wins if entries are deleted, and both are deleted */
136
+ dict = qemu_opts_to_qdict_filtered(opts, NULL, NULL, true);
137
+ g_assert(dict != NULL);
138
+ g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
139
+ QDECREF(dict);
140
+
141
+ g_assert_true(QTAILQ_EMPTY(&opts->head));
142
+
143
+ qemu_opts_del(opts);
144
+}
145
146
int main(int argc, char *argv[])
147
{
148
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
149
g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
150
g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null);
151
g_test_add_func("/qemu-opts/append", test_opts_append);
152
+ g_test_add_func("/qemu-opts/to_qdict/basic", test_opts_to_qdict_basic);
153
+ g_test_add_func("/qemu-opts/to_qdict/filtered", test_opts_to_qdict_filtered);
154
+ g_test_add_func("/qemu-opts/to_qdict/duplicates", test_opts_to_qdict_duplicates);
155
g_test_run();
156
return 0;
157
}
158
--
159
2.13.6
160
161
diff view generated by jsdifflib
New patch
1
1
A few block drivers will need to rename .bdrv_create options for their
2
QAPIfication, so let's have a helper function for that.
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
include/qapi/qmp/qdict.h | 6 +++
9
qobject/qdict.c | 34 +++++++++++++
10
tests/check-qdict.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++
11
3 files changed, 169 insertions(+)
12
13
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/qapi/qmp/qdict.h
16
+++ b/include/qapi/qmp/qdict.h
17
@@ -XXX,XX +XXX,XX @@ QObject *qdict_crumple(const QDict *src, Error **errp);
18
19
void qdict_join(QDict *dest, QDict *src, bool overwrite);
20
21
+typedef struct QDictRenames {
22
+ const char *from;
23
+ const char *to;
24
+} QDictRenames;
25
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
26
+
27
#endif /* QDICT_H */
28
diff --git a/qobject/qdict.c b/qobject/qdict.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/qobject/qdict.c
31
+++ b/qobject/qdict.c
32
@@ -XXX,XX +XXX,XX @@ void qdict_join(QDict *dest, QDict *src, bool overwrite)
33
entry = next;
34
}
35
}
36
+
37
+/**
38
+ * qdict_rename_keys(): Rename keys in qdict according to the replacements
39
+ * specified in the array renames. The array must be terminated by an entry
40
+ * with from = NULL.
41
+ *
42
+ * The renames are performed individually in the order of the array, so entries
43
+ * may be renamed multiple times and may or may not conflict depending on the
44
+ * order of the renames array.
45
+ *
46
+ * Returns true for success, false in error cases.
47
+ */
48
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
49
+{
50
+ QObject *qobj;
51
+
52
+ while (renames->from) {
53
+ if (qdict_haskey(qdict, renames->from)) {
54
+ if (qdict_haskey(qdict, renames->to)) {
55
+ error_setg(errp, "'%s' and its alias '%s' can't be used at the "
56
+ "same time", renames->to, renames->from);
57
+ return false;
58
+ }
59
+
60
+ qobj = qdict_get(qdict, renames->from);
61
+ qobject_incref(qobj);
62
+ qdict_put_obj(qdict, renames->to, qobj);
63
+ qdict_del(qdict, renames->from);
64
+ }
65
+
66
+ renames++;
67
+ }
68
+ return true;
69
+}
70
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/tests/check-qdict.c
73
+++ b/tests/check-qdict.c
74
@@ -XXX,XX +XXX,XX @@ static void qdict_crumple_test_empty(void)
75
QDECREF(dst);
76
}
77
78
+static int qdict_count_entries(QDict *dict)
79
+{
80
+ const QDictEntry *e;
81
+ int count = 0;
82
+
83
+ for (e = qdict_first(dict); e; e = qdict_next(dict, e)) {
84
+ count++;
85
+ }
86
+
87
+ return count;
88
+}
89
+
90
+static void qdict_rename_keys_test(void)
91
+{
92
+ QDict *dict = qdict_new();
93
+ QDict *copy;
94
+ QDictRenames *renames;
95
+ Error *local_err = NULL;
96
+
97
+ qdict_put_str(dict, "abc", "foo");
98
+ qdict_put_str(dict, "abcdef", "bar");
99
+ qdict_put_int(dict, "number", 42);
100
+ qdict_put_bool(dict, "flag", true);
101
+ qdict_put_null(dict, "nothing");
102
+
103
+ /* Empty rename list */
104
+ renames = (QDictRenames[]) {
105
+ { NULL, "this can be anything" }
106
+ };
107
+ copy = qdict_clone_shallow(dict);
108
+ qdict_rename_keys(copy, renames, &error_abort);
109
+
110
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
111
+ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
112
+ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
113
+ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
114
+ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
115
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
116
+
117
+ QDECREF(copy);
118
+
119
+ /* Simple rename of all entries */
120
+ renames = (QDictRenames[]) {
121
+ { "abc", "str1" },
122
+ { "abcdef", "str2" },
123
+ { "number", "int" },
124
+ { "flag", "bool" },
125
+ { "nothing", "null" },
126
+ { NULL , NULL }
127
+ };
128
+ copy = qdict_clone_shallow(dict);
129
+ qdict_rename_keys(copy, renames, &error_abort);
130
+
131
+ g_assert(!qdict_haskey(copy, "abc"));
132
+ g_assert(!qdict_haskey(copy, "abcdef"));
133
+ g_assert(!qdict_haskey(copy, "number"));
134
+ g_assert(!qdict_haskey(copy, "flag"));
135
+ g_assert(!qdict_haskey(copy, "nothing"));
136
+
137
+ g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
138
+ g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
139
+ g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
140
+ g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
141
+ g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
142
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
143
+
144
+ QDECREF(copy);
145
+
146
+ /* Renames are processed top to bottom */
147
+ renames = (QDictRenames[]) {
148
+ { "abc", "tmp" },
149
+ { "abcdef", "abc" },
150
+ { "number", "abcdef" },
151
+ { "flag", "number" },
152
+ { "nothing", "flag" },
153
+ { "tmp", "nothing" },
154
+ { NULL , NULL }
155
+ };
156
+ copy = qdict_clone_shallow(dict);
157
+ qdict_rename_keys(copy, renames, &error_abort);
158
+
159
+ g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
160
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
161
+ g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
162
+ g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
163
+ g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
164
+ g_assert(!qdict_haskey(copy, "tmp"));
165
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
166
+
167
+ QDECREF(copy);
168
+
169
+ /* Conflicting rename */
170
+ renames = (QDictRenames[]) {
171
+ { "abcdef", "abc" },
172
+ { NULL , NULL }
173
+ };
174
+ copy = qdict_clone_shallow(dict);
175
+ qdict_rename_keys(copy, renames, &local_err);
176
+
177
+ g_assert(local_err != NULL);
178
+ error_free(local_err);
179
+ local_err = NULL;
180
+
181
+ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
182
+ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
183
+ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
184
+ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
185
+ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
186
+ g_assert_cmpint(qdict_count_entries(copy), ==, 5);
187
+
188
+ QDECREF(copy);
189
+
190
+ /* Renames in an empty dict */
191
+ renames = (QDictRenames[]) {
192
+ { "abcdef", "abc" },
193
+ { NULL , NULL }
194
+ };
195
+
196
+ QDECREF(dict);
197
+ dict = qdict_new();
198
+
199
+ qdict_rename_keys(dict, renames, &error_abort);
200
+ g_assert(qdict_first(dict) == NULL);
201
+
202
+ QDECREF(dict);
203
+}
204
+
205
static void qdict_crumple_test_bad_inputs(void)
206
{
207
QDict *src;
208
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
209
g_test_add_func("/public/crumple/bad_inputs",
210
qdict_crumple_test_bad_inputs);
211
212
+ g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
213
+
214
/* The Big one */
215
if (g_test_slow()) {
216
g_test_add_func("/stress/test", qdict_stress_test);
217
--
218
2.13.6
219
220
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Instead of manually creating the BlockdevCreateOptions object, use a
2
2
visitor to parse the given options into the QAPI object.
3
Some qcow2 functions (at least perform_cow()) expect s->lock to be
3
4
taken. Therefore, if we want to make use of them, we should execute
4
This involves translation from the old command line syntax to the syntax
5
preallocate() (as "preallocate_co") in a coroutine so that we can use
5
mandated by the QAPI schema. Option names are still checked against
6
the qemu_co_mutex_* functions.
6
qcow2_create_opts, so only the old option names are allowed on the
7
7
command line, even if they are translated in qcow2_create().
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
9
Message-id: 20171009215533.12530-3-mreitz@redhat.com
9
In contrast, new option values are optionally recognised besides the old
10
Cc: qemu-stable@nongnu.org
10
values: 'compat' accepts 'v2'/'v3' as an alias for '0.10'/'1.1', and
11
'encrypt.format' accepts 'qcow' as an alias for 'aes' now.
12
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Jeff Cody <jcody@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
---
16
block/qcow2.c | 41 ++++++++++++++++++++++++++++++++++-------
17
block/qcow2.c | 218 ++++++++++++++++-----------------------------
17
1 file changed, 34 insertions(+), 7 deletions(-)
18
tests/qemu-iotests/049.out | 8 +-
19
tests/qemu-iotests/112.out | 4 +-
20
3 files changed, 84 insertions(+), 146 deletions(-)
18
21
19
diff --git a/block/qcow2.c b/block/qcow2.c
22
diff --git a/block/qcow2.c b/block/qcow2.c
20
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.c
24
--- a/block/qcow2.c
22
+++ b/block/qcow2.c
25
+++ b/block/qcow2.c
23
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
26
@@ -XXX,XX +XXX,XX @@
27
#include "qemu/option_int.h"
28
#include "qemu/cutils.h"
29
#include "qemu/bswap.h"
30
-#include "qapi/opts-visitor.h"
31
+#include "qapi/qobject-input-visitor.h"
32
+#include "qapi/qapi-visit-block-core.h"
33
#include "block/crypto.h"
34
35
/*
36
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypt_method_from_format(const char *encryptfmt)
37
}
24
}
38
}
25
39
26
40
-static QCryptoBlockCreateOptions *
27
+typedef struct PreallocCo {
41
-qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **errp)
28
+ BlockDriverState *bs;
42
-{
29
+ uint64_t offset;
43
- QCryptoBlockCreateOptions *cryptoopts = NULL;
30
+ uint64_t new_length;
44
- QDict *options, *encryptopts;
31
+
45
- int fmt;
32
+ int ret;
46
-
33
+} PreallocCo;
47
- options = qemu_opts_to_qdict(opts, NULL);
34
+
48
- qdict_extract_subqdict(options, &encryptopts, "encrypt.");
35
/**
49
- QDECREF(options);
36
* Preallocates metadata structures for data clusters between @offset (in the
50
-
37
* guest disk) and @new_length (which is thus generally the new guest disk
51
- fmt = qcow2_crypt_method_from_format(encryptfmt);
38
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
52
-
39
*
53
- switch (fmt) {
40
* Returns: 0 on success, -errno on failure.
54
- case QCOW_CRYPT_LUKS:
41
*/
55
- cryptoopts = block_crypto_create_opts_init(
42
-static int preallocate(BlockDriverState *bs,
56
- Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp);
43
- uint64_t offset, uint64_t new_length)
57
- break;
44
+static void coroutine_fn preallocate_co(void *opaque)
58
- case QCOW_CRYPT_AES:
59
- cryptoopts = block_crypto_create_opts_init(
60
- Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
61
- break;
62
- default:
63
- error_setg(errp, "Unknown encryption format '%s'", encryptfmt);
64
- break;
65
- }
66
-
67
- QDECREF(encryptopts);
68
- return cryptoopts;
69
-}
70
-
71
static int qcow2_set_up_encryption(BlockDriverState *bs,
72
QCryptoBlockCreateOptions *cryptoopts,
73
Error **errp)
74
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
75
}
76
if (version < 3 && qcow2_opts->lazy_refcounts) {
77
error_setg(errp, "Lazy refcounts only supported with compatibility "
78
- "level 1.1 and above (use compat=1.1 or greater)");
79
+ "level 1.1 and above (use version=v3 or greater)");
80
ret = -EINVAL;
81
goto out;
82
}
83
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
84
}
85
if (version < 3 && qcow2_opts->refcount_bits != 16) {
86
error_setg(errp, "Different refcount widths than 16 bits require "
87
- "compatibility level 1.1 or above (use compat=1.1 or "
88
+ "compatibility level 1.1 or above (use version=v3 or "
89
"greater)");
90
ret = -EINVAL;
91
goto out;
92
@@ -XXX,XX +XXX,XX @@ out:
93
static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opts,
94
Error **errp)
45
{
95
{
46
+ PreallocCo *params = opaque;
96
- BlockdevCreateOptions create_options;
47
+ BlockDriverState *bs = params->bs;
97
- char *backing_file = NULL;
48
+ uint64_t offset = params->offset;
98
- char *backing_fmt = NULL;
49
+ uint64_t new_length = params->new_length;
99
- BlockdevDriver backing_drv;
50
BDRVQcow2State *s = bs->opaque;
100
- char *buf = NULL;
51
uint64_t bytes;
101
- uint64_t size = 0;
52
uint64_t host_offset = 0;
102
- int flags = 0;
53
@@ -XXX,XX +XXX,XX @@ static int preallocate(BlockDriverState *bs,
103
- size_t cluster_size = DEFAULT_CLUSTER_SIZE;
104
- PreallocMode prealloc;
105
- int version;
106
- uint64_t refcount_bits;
107
- char *encryptfmt = NULL;
108
- QCryptoBlockCreateOptions *cryptoopts = NULL;
109
+ BlockdevCreateOptions *create_options = NULL;
110
+ QDict *qdict = NULL;
111
+ QObject *qobj;
112
+ Visitor *v;
113
BlockDriverState *bs = NULL;
114
Error *local_err = NULL;
115
+ const char *val;
54
int ret;
116
int ret;
55
QCowL2Meta *meta;
117
56
118
- /* Read out options */
57
- if (qemu_in_coroutine()) {
119
- size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
58
- qemu_co_mutex_lock(&s->lock);
120
- BDRV_SECTOR_SIZE);
59
- }
121
- backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
60
+ qemu_co_mutex_lock(&s->lock);
122
- backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
61
123
- backing_drv = qapi_enum_parse(&BlockdevDriver_lookup, backing_fmt,
62
assert(offset <= new_length);
124
- 0, &local_err);
63
bytes = new_length - offset;
125
- if (local_err) {
64
@@ -XXX,XX +XXX,XX @@ static int preallocate(BlockDriverState *bs,
126
- error_propagate(errp, local_err);
65
ret = 0;
127
+ /* Only the keyval visitor supports the dotted syntax needed for
66
128
+ * encryption, so go through a QDict before getting a QAPI type. Ignore
67
done:
129
+ * options meant for the protocol layer so that the visitor doesn't
68
+ qemu_co_mutex_unlock(&s->lock);
130
+ * complain. */
69
+ params->ret = ret;
131
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, bdrv_qcow2.create_opts,
70
+}
132
+ true);
71
+
133
+
72
+static int preallocate(BlockDriverState *bs,
134
+ /* Handle encryption options */
73
+ uint64_t offset, uint64_t new_length)
135
+ val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT);
74
+{
136
+ if (val && !strcmp(val, "on")) {
75
+ PreallocCo params = {
137
+ qdict_put_str(qdict, BLOCK_OPT_ENCRYPT, "qcow");
76
+ .bs = bs,
138
+ } else if (val && !strcmp(val, "off")) {
77
+ .offset = offset,
139
+ qdict_del(qdict, BLOCK_OPT_ENCRYPT);
78
+ .new_length = new_length,
140
+ }
79
+ .ret = -EINPROGRESS,
141
+
142
+ val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT);
143
+ if (val && !strcmp(val, "aes")) {
144
+ qdict_put_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT, "qcow");
145
+ }
146
+
147
+ /* Convert compat=0.10/1.1 into compat=v2/v3, to be renamed into
148
+ * version=v2/v3 below. */
149
+ val = qdict_get_try_str(qdict, BLOCK_OPT_COMPAT_LEVEL);
150
+ if (val && !strcmp(val, "0.10")) {
151
+ qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v2");
152
+ } else if (val && !strcmp(val, "1.1")) {
153
+ qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v3");
154
+ }
155
+
156
+ /* Change legacy command line options into QMP ones */
157
+ static const QDictRenames opt_renames[] = {
158
+ { BLOCK_OPT_BACKING_FILE, "backing-file" },
159
+ { BLOCK_OPT_BACKING_FMT, "backing-fmt" },
160
+ { BLOCK_OPT_CLUSTER_SIZE, "cluster-size" },
161
+ { BLOCK_OPT_LAZY_REFCOUNTS, "lazy-refcounts" },
162
+ { BLOCK_OPT_REFCOUNT_BITS, "refcount-bits" },
163
+ { BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
164
+ { BLOCK_OPT_COMPAT_LEVEL, "version" },
165
+ { NULL, NULL },
80
+ };
166
+ };
81
+
167
+
82
if (qemu_in_coroutine()) {
168
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
83
- qemu_co_mutex_unlock(&s->lock);
169
ret = -EINVAL;
84
+ preallocate_co(&params);
170
goto finish;
85
+ } else {
171
}
86
+ Coroutine *co = qemu_coroutine_create(preallocate_co, &params);
172
87
+ bdrv_coroutine_enter(bs, co);
173
- encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
88
+ BDRV_POLL_WHILE(bs, params.ret == -EINPROGRESS);
174
- if (encryptfmt) {
89
}
175
- if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
90
- return ret;
176
- error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and "
91
+ return params.ret;
177
- BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive");
178
- ret = -EINVAL;
179
- goto finish;
180
- }
181
- } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
182
- encryptfmt = g_strdup("aes");
183
- }
184
- if (encryptfmt) {
185
- cryptoopts = qcow2_parse_encryption(encryptfmt, opts, errp);
186
- if (cryptoopts == NULL) {
187
- ret = -EINVAL;
188
- goto finish;
189
- }
190
- }
191
-
192
- cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
193
- if (local_err) {
194
- error_propagate(errp, local_err);
195
- ret = -EINVAL;
196
+ /* Create and open the file (protocol layer) */
197
+ ret = bdrv_create_file(filename, opts, errp);
198
+ if (ret < 0) {
199
goto finish;
200
}
201
- buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
202
- prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
203
- PREALLOC_MODE_OFF, &local_err);
204
- if (local_err) {
205
- error_propagate(errp, local_err);
206
- ret = -EINVAL;
207
+
208
+ bs = bdrv_open(filename, NULL, NULL,
209
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
210
+ if (bs == NULL) {
211
+ ret = -EIO;
212
goto finish;
213
}
214
215
- version = qcow2_opt_get_version_del(opts, &local_err);
216
- if (local_err) {
217
- error_propagate(errp, local_err);
218
+ /* Set 'driver' and 'node' options */
219
+ qdict_put_str(qdict, "driver", "qcow2");
220
+ qdict_put_str(qdict, "file", bs->node_name);
221
+
222
+ /* Now get the QAPI type BlockdevCreateOptions */
223
+ qobj = qdict_crumple(qdict, errp);
224
+ QDECREF(qdict);
225
+ qdict = qobject_to_qdict(qobj);
226
+ if (qdict == NULL) {
227
ret = -EINVAL;
228
goto finish;
229
}
230
231
- if (qemu_opt_get_bool_del(opts, BLOCK_OPT_LAZY_REFCOUNTS, false)) {
232
- flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
233
- }
234
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
235
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
236
+ visit_free(v);
237
238
- refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);
239
if (local_err) {
240
error_propagate(errp, local_err);
241
ret = -EINVAL;
242
goto finish;
243
}
244
245
-
246
- /* Create and open the file (protocol layer) */
247
- ret = bdrv_create_file(filename, opts, errp);
248
- if (ret < 0) {
249
- goto finish;
250
- }
251
-
252
- bs = bdrv_open(filename, NULL, NULL,
253
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
254
- if (bs == NULL) {
255
- ret = -EIO;
256
- goto finish;
257
- }
258
+ /* Silently round up size */
259
+ create_options->u.qcow2.size = ROUND_UP(create_options->u.qcow2.size,
260
+ BDRV_SECTOR_SIZE);
261
262
/* Create the qcow2 image (format layer) */
263
- create_options = (BlockdevCreateOptions) {
264
- .driver = BLOCKDEV_DRIVER_QCOW2,
265
- .u.qcow2 = {
266
- .file = &(BlockdevRef) {
267
- .type = QTYPE_QSTRING,
268
- .u.reference = bs->node_name,
269
- },
270
- .size = size,
271
- .has_version = true,
272
- .version = version == 2
273
- ? BLOCKDEV_QCOW2_VERSION_V2
274
- : BLOCKDEV_QCOW2_VERSION_V3,
275
- .has_backing_file = (backing_file != NULL),
276
- .backing_file = backing_file,
277
- .has_backing_fmt = (backing_fmt != NULL),
278
- .backing_fmt = backing_drv,
279
- .has_encrypt = (encryptfmt != NULL),
280
- .encrypt = cryptoopts,
281
- .has_cluster_size = true,
282
- .cluster_size = cluster_size,
283
- .has_preallocation = true,
284
- .preallocation = prealloc,
285
- .has_lazy_refcounts = true,
286
- .lazy_refcounts = (flags & BLOCK_FLAG_LAZY_REFCOUNTS),
287
- .has_refcount_bits = true,
288
- .refcount_bits = refcount_bits,
289
- },
290
- };
291
- ret = qcow2_co_create(&create_options, errp);
292
+ ret = qcow2_co_create(create_options, errp);
293
if (ret < 0) {
294
goto finish;
295
}
296
297
+ ret = 0;
298
finish:
299
+ QDECREF(qdict);
300
bdrv_unref(bs);
301
-
302
- qapi_free_QCryptoBlockCreateOptions(cryptoopts);
303
- g_free(backing_file);
304
- g_free(backing_fmt);
305
- g_free(encryptfmt);
306
- g_free(buf);
307
+ qapi_free_BlockdevCreateOptions(create_options);
308
return ret;
92
}
309
}
93
310
94
/* qcow2_refcount_metadata_size:
311
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
312
index XXXXXXX..XXXXXXX 100644
313
--- a/tests/qemu-iotests/049.out
314
+++ b/tests/qemu-iotests/049.out
315
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
316
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16
317
318
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
319
-qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42'
320
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42'
321
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16
322
323
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
324
-qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar'
325
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar'
326
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16
327
328
== Check preallocation option ==
329
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
330
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16
331
332
qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
333
-qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234
334
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234'
335
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16
336
337
== Check encryption option ==
338
@@ -XXX,XX +XXX,XX @@ qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
339
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16
340
341
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
342
-qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
343
+qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
344
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16
345
346
*** done
347
diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
348
index XXXXXXX..XXXXXXX 100644
349
--- a/tests/qemu-iotests/112.out
350
+++ b/tests/qemu-iotests/112.out
351
@@ -XXX,XX +XXX,XX @@ refcount bits: 16
352
353
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
354
refcount bits: 16
355
-qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use or greater)
356
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
357
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
358
-qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use or greater)
359
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
360
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
361
362
=== Snapshot limit on refcount_bits=1 ===
95
--
363
--
96
2.13.6
364
2.13.6
97
365
98
366
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
We'll use a separate source file for image creation, and we need to
2
check there whether the requested driver is whitelisted.
2
3
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>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
18
---
7
---
19
include/block/block.h | 4 ++--
8
include/block/block.h | 1 +
20
block/io.c | 6 +++---
9
block.c | 2 +-
21
block/mirror.c | 7 +++----
10
2 files changed, 2 insertions(+), 1 deletion(-)
22
block/trace-events | 2 +-
23
4 files changed, 9 insertions(+), 10 deletions(-)
24
11
25
diff --git a/include/block/block.h b/include/block/block.h
12
diff --git a/include/block/block.h b/include/block/block.h
26
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
27
--- a/include/block/block.h
14
--- a/include/block/block.h
28
+++ b/include/block/block.h
15
+++ b/include/block/block.h
29
@@ -XXX,XX +XXX,XX @@ int bdrv_get_flags(BlockDriverState *bs);
16
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm);
30
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
17
void bdrv_init(void);
31
ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs);
18
void bdrv_init_with_whitelist(void);
32
void bdrv_round_to_clusters(BlockDriverState *bs,
19
bool bdrv_uses_whitelist(void);
33
- int64_t offset, unsigned int bytes,
20
+int bdrv_is_whitelisted(BlockDriver *drv, bool read_only);
34
+ int64_t offset, int64_t bytes,
21
BlockDriver *bdrv_find_protocol(const char *filename,
35
int64_t *cluster_offset,
22
bool allow_protocol_prefix,
36
- unsigned int *cluster_bytes);
23
Error **errp);
37
+ int64_t *cluster_bytes);
24
diff --git a/block.c b/block.c
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
25
index XXXXXXX..XXXXXXX 100644
43
--- a/block/io.c
26
--- a/block.c
44
+++ b/block/io.c
27
+++ b/block.c
45
@@ -XXX,XX +XXX,XX @@ static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
28
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_format(const char *format_name)
46
* Round a region to cluster boundaries
29
return bdrv_do_find_format(format_name);
47
*/
30
}
48
void bdrv_round_to_clusters(BlockDriverState *bs,
31
49
- int64_t offset, unsigned int bytes,
32
-static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
50
+ int64_t offset, int64_t bytes,
33
+int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
51
int64_t *cluster_offset,
52
- unsigned int *cluster_bytes)
53
+ int64_t *cluster_bytes)
54
{
34
{
55
BlockDriverInfo bdi;
35
static const char *whitelist_rw[] = {
56
36
CONFIG_BDRV_RW_WHITELIST
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
67
index XXXXXXX..XXXXXXX 100644
68
--- a/block/mirror.c
69
+++ b/block/mirror.c
70
@@ -XXX,XX +XXX,XX @@ static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset,
71
bool need_cow;
72
int ret = 0;
73
int64_t align_offset = *offset;
74
- unsigned int align_bytes = *bytes;
75
+ int64_t align_bytes = *bytes;
76
int max_bytes = s->granularity * s->max_iov;
77
78
- assert(*bytes < INT_MAX);
79
need_cow = !test_bit(*offset / s->granularity, s->cow_bitmap);
80
need_cow |= !test_bit((*offset + *bytes - 1) / s->granularity,
81
s->cow_bitmap);
82
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
83
while (nb_chunks > 0 && offset < s->bdev_length) {
84
int64_t ret;
85
int io_sectors;
86
- unsigned int io_bytes;
87
+ int64_t io_bytes;
88
int64_t io_bytes_acct;
89
enum MirrorMethod {
90
MIRROR_METHOD_COPY,
91
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
92
io_bytes = s->granularity;
93
} else if (ret >= 0 && !(ret & BDRV_BLOCK_DATA)) {
94
int64_t target_offset;
95
- unsigned int target_bytes;
96
+ int64_t target_bytes;
97
bdrv_round_to_clusters(blk_bs(s->target), offset, io_bytes,
98
&target_offset, &target_bytes);
99
if (target_offset == offset &&
100
diff --git a/block/trace-events b/block/trace-events
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/trace-events
103
+++ b/block/trace-events
104
@@ -XXX,XX +XXX,XX @@ blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flag
105
bdrv_co_preadv(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x"
106
bdrv_co_pwritev(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x"
107
bdrv_co_pwrite_zeroes(void *bs, int64_t offset, int count, int flags) "bs %p offset %"PRId64" count %d flags 0x%x"
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"
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
110
111
# block/stream.c
112
stream_one_iteration(void *s, int64_t offset, uint64_t bytes, int is_allocated) "s %p offset %" PRId64 " bytes %" PRIu64 " is_allocated %d"
113
--
37
--
114
2.13.6
38
2.13.6
115
39
116
40
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
This adds a synchronous x-blockdev-create QMP command that can create
2
qcow2 images on a given node name.
2
3
3
qemu-img commit invalidates all images between base and top. This
4
We don't want to block while creating an image, so this is not the final
4
should be mentioned in the man page.
5
interface in all aspects, but BlockdevCreateOptionsQcow2 and
6
.bdrv_co_create() are what they actually might look like in the end. In
7
any case, this should be good enough to test whether we interpret
8
BlockdevCreateOptions as we should.
5
9
6
Suggested-by: Ping Li <pingl@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Jeff Cody <jcody@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
10
---
13
---
11
qemu-img.texi | 9 ++++-----
14
qapi/block-core.json | 12 ++++++++
12
1 file changed, 4 insertions(+), 5 deletions(-)
15
include/block/block_int.h | 5 +++-
16
block/create.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++
17
block/qcow2.c | 1 +
18
block/Makefile.objs | 2 +-
19
5 files changed, 94 insertions(+), 2 deletions(-)
20
create mode 100644 block/create.c
13
21
14
diff --git a/qemu-img.texi b/qemu-img.texi
22
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
16
--- a/qemu-img.texi
24
--- a/qapi/block-core.json
17
+++ b/qemu-img.texi
25
+++ b/qapi/block-core.json
18
@@ -XXX,XX +XXX,XX @@ If the backing chain of the given image file @var{filename} has more than one
26
@@ -XXX,XX +XXX,XX @@
19
layer, the backing file into which the changes will be committed may be
27
} }
20
specified as @var{base} (which has to be part of @var{filename}'s backing
28
21
chain). If @var{base} is not specified, the immediate backing file of the top
29
##
22
-image (which is @var{filename}) will be used. For reasons of consistency,
30
+# @x-blockdev-create:
23
-explicitly specifying @var{base} will always imply @code{-d} (since emptying an
31
+#
24
-image after committing to an indirect backing file would lead to different data
32
+# Create an image format on a given node.
25
-being read from the image due to content in the intermediate backing chain
33
+# TODO Replace with something asynchronous (block job?)
26
-overruling the commit target).
34
+#
27
+image (which is @var{filename}) will be used. Note that after a commit operation
35
+# Since: 2.12
28
+all images between @var{base} and the top image will be invalid and may return
36
+##
29
+garbage data when read. For this reason, @code{-b} implies @code{-d} (so that
37
+{ 'command': 'x-blockdev-create',
30
+the top image stays valid).
38
+ 'data': 'BlockdevCreateOptions',
31
39
+ 'boxed': true }
32
@item compare [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-s] [-q] @var{filename1} @var{filename2}
40
+
41
+##
42
# @blockdev-open-tray:
43
#
44
# Opens a block device's tray. If there is a block driver state tree inserted as
45
diff --git a/include/block/block_int.h b/include/block/block_int.h
46
index XXXXXXX..XXXXXXX 100644
47
--- a/include/block/block_int.h
48
+++ b/include/block/block_int.h
49
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
50
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
51
Error **errp);
52
void (*bdrv_close)(BlockDriverState *bs);
53
- int coroutine_fn (*bdrv_co_create_opts)(const char *filename, QemuOpts *opts,
54
+ int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts,
55
Error **errp);
56
+ int coroutine_fn (*bdrv_co_create_opts)(const char *filename,
57
+ QemuOpts *opts,
58
+ Error **errp);
59
int (*bdrv_make_empty)(BlockDriverState *bs);
60
61
void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
62
diff --git a/block/create.c b/block/create.c
63
new file mode 100644
64
index XXXXXXX..XXXXXXX
65
--- /dev/null
66
+++ b/block/create.c
67
@@ -XXX,XX +XXX,XX @@
68
+/*
69
+ * Block layer code related to image creation
70
+ *
71
+ * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
72
+ *
73
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
74
+ * of this software and associated documentation files (the "Software"), to deal
75
+ * in the Software without restriction, including without limitation the rights
76
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
77
+ * copies of the Software, and to permit persons to whom the Software is
78
+ * furnished to do so, subject to the following conditions:
79
+ *
80
+ * The above copyright notice and this permission notice shall be included in
81
+ * all copies or substantial portions of the Software.
82
+ *
83
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
84
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
85
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
86
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
87
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
88
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
89
+ * THE SOFTWARE.
90
+ */
91
+
92
+#include "qemu/osdep.h"
93
+#include "block/block_int.h"
94
+#include "qapi/qapi-commands-block-core.h"
95
+#include "qapi/error.h"
96
+
97
+typedef struct BlockdevCreateCo {
98
+ BlockDriver *drv;
99
+ BlockdevCreateOptions *opts;
100
+ int ret;
101
+ Error **errp;
102
+} BlockdevCreateCo;
103
+
104
+static void coroutine_fn bdrv_co_create_co_entry(void *opaque)
105
+{
106
+ BlockdevCreateCo *cco = opaque;
107
+ cco->ret = cco->drv->bdrv_co_create(cco->opts, cco->errp);
108
+}
109
+
110
+void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp)
111
+{
112
+ const char *fmt = BlockdevDriver_str(options->driver);
113
+ BlockDriver *drv = bdrv_find_format(fmt);
114
+ Coroutine *co;
115
+ BlockdevCreateCo cco;
116
+
117
+ /* If the driver is in the schema, we know that it exists. But it may not
118
+ * be whitelisted. */
119
+ assert(drv);
120
+ if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
121
+ error_setg(errp, "Driver is not whitelisted");
122
+ return;
123
+ }
124
+
125
+ /* Call callback if it exists */
126
+ if (!drv->bdrv_co_create) {
127
+ error_setg(errp, "Driver does not support blockdev-create");
128
+ return;
129
+ }
130
+
131
+ cco = (BlockdevCreateCo) {
132
+ .drv = drv,
133
+ .opts = options,
134
+ .ret = -EINPROGRESS,
135
+ .errp = errp,
136
+ };
137
+
138
+ co = qemu_coroutine_create(bdrv_co_create_co_entry, &cco);
139
+ qemu_coroutine_enter(co);
140
+ while (cco.ret == -EINPROGRESS) {
141
+ aio_poll(qemu_get_aio_context(), true);
142
+ }
143
+}
144
diff --git a/block/qcow2.c b/block/qcow2.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/block/qcow2.c
147
+++ b/block/qcow2.c
148
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
149
.bdrv_join_options = qcow2_join_options,
150
.bdrv_child_perm = bdrv_format_default_perms,
151
.bdrv_co_create_opts = qcow2_co_create_opts,
152
+ .bdrv_co_create = qcow2_co_create,
153
.bdrv_has_zero_init = bdrv_has_zero_init_1,
154
.bdrv_co_block_status = qcow2_co_block_status,
155
156
diff --git a/block/Makefile.objs b/block/Makefile.objs
157
index XXXXXXX..XXXXXXX 100644
158
--- a/block/Makefile.objs
159
+++ b/block/Makefile.objs
160
@@ -XXX,XX +XXX,XX @@ block-obj-y += block-backend.o snapshot.o qapi.o
161
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
162
block-obj-$(CONFIG_POSIX) += file-posix.o
163
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
164
-block-obj-y += null.o mirror.o commit.o io.o
165
+block-obj-y += null.o mirror.o commit.o io.o create.o
166
block-obj-y += throttle-groups.o
167
block-obj-$(CONFIG_LINUX) += nvme.o
33
168
34
--
169
--
35
2.13.6
170
2.13.6
36
171
37
172
diff view generated by jsdifflib
New patch
1
This adds the .bdrv_co_create driver callback to file, which enables
2
image creation over QMP.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
qapi/block-core.json | 20 ++++++++++++-
9
block/file-posix.c | 79 +++++++++++++++++++++++++++++++++++++---------------
10
2 files changed, 75 insertions(+), 24 deletions(-)
11
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/block-core.json
15
+++ b/qapi/block-core.json
16
@@ -XXX,XX +XXX,XX @@
17
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
18
19
##
20
+# @BlockdevCreateOptionsFile:
21
+#
22
+# Driver specific image creation options for file.
23
+#
24
+# @filename Filename for the new image file
25
+# @size Size of the virtual disk in bytes
26
+# @preallocation Preallocation mode for the new image (default: off)
27
+# @nocow Turn off copy-on-write (valid only on btrfs; default: off)
28
+#
29
+# Since: 2.12
30
+##
31
+{ 'struct': 'BlockdevCreateOptionsFile',
32
+ 'data': { 'filename': 'str',
33
+ 'size': 'size',
34
+ '*preallocation': 'PreallocMode',
35
+ '*nocow': 'bool' } }
36
+
37
+##
38
# @BlockdevQcow2Version:
39
#
40
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
41
@@ -XXX,XX +XXX,XX @@
42
'bochs': 'BlockdevCreateNotSupported',
43
'cloop': 'BlockdevCreateNotSupported',
44
'dmg': 'BlockdevCreateNotSupported',
45
- 'file': 'BlockdevCreateNotSupported',
46
+ 'file': 'BlockdevCreateOptionsFile',
47
'ftp': 'BlockdevCreateNotSupported',
48
'ftps': 'BlockdevCreateNotSupported',
49
'gluster': 'BlockdevCreateNotSupported',
50
diff --git a/block/file-posix.c b/block/file-posix.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/file-posix.c
53
+++ b/block/file-posix.c
54
@@ -XXX,XX +XXX,XX @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
55
return (int64_t)st.st_blocks * 512;
56
}
57
58
-static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
59
- Error **errp)
60
+static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
61
{
62
+ BlockdevCreateOptionsFile *file_opts;
63
int fd;
64
int result = 0;
65
- int64_t total_size = 0;
66
- bool nocow = false;
67
- PreallocMode prealloc;
68
- char *buf = NULL;
69
- Error *local_err = NULL;
70
71
- strstart(filename, "file:", &filename);
72
+ /* Validate options and set default values */
73
+ assert(options->driver == BLOCKDEV_DRIVER_FILE);
74
+ file_opts = &options->u.file;
75
76
- /* Read out options */
77
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
78
- BDRV_SECTOR_SIZE);
79
- nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
80
- buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
81
- prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
82
- PREALLOC_MODE_OFF, &local_err);
83
- g_free(buf);
84
- if (local_err) {
85
- error_propagate(errp, local_err);
86
- result = -EINVAL;
87
- goto out;
88
+ if (!file_opts->has_nocow) {
89
+ file_opts->nocow = false;
90
+ }
91
+ if (!file_opts->has_preallocation) {
92
+ file_opts->preallocation = PREALLOC_MODE_OFF;
93
}
94
95
- fd = qemu_open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
96
+ /* Create file */
97
+ fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
98
0644);
99
if (fd < 0) {
100
result = -errno;
101
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
102
goto out;
103
}
104
105
- if (nocow) {
106
+ if (file_opts->nocow) {
107
#ifdef __linux__
108
/* Set NOCOW flag to solve performance issue on fs like btrfs.
109
* This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
111
#endif
112
}
113
114
- result = raw_regular_truncate(fd, total_size, prealloc, errp);
115
+ result = raw_regular_truncate(fd, file_opts->size, file_opts->preallocation,
116
+ errp);
117
if (result < 0) {
118
goto out_close;
119
}
120
@@ -XXX,XX +XXX,XX @@ out:
121
return result;
122
}
123
124
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
125
+ Error **errp)
126
+{
127
+ BlockdevCreateOptions options;
128
+ int64_t total_size = 0;
129
+ bool nocow = false;
130
+ PreallocMode prealloc;
131
+ char *buf = NULL;
132
+ Error *local_err = NULL;
133
+
134
+ /* Skip file: protocol prefix */
135
+ strstart(filename, "file:", &filename);
136
+
137
+ /* Read out options */
138
+ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
139
+ BDRV_SECTOR_SIZE);
140
+ nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
141
+ buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
142
+ prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
143
+ PREALLOC_MODE_OFF, &local_err);
144
+ g_free(buf);
145
+ if (local_err) {
146
+ error_propagate(errp, local_err);
147
+ return -EINVAL;
148
+ }
149
+
150
+ options = (BlockdevCreateOptions) {
151
+ .driver = BLOCKDEV_DRIVER_FILE,
152
+ .u.file = {
153
+ .filename = (char *) filename,
154
+ .size = total_size,
155
+ .has_preallocation = true,
156
+ .preallocation = prealloc,
157
+ .has_nocow = true,
158
+ .nocow = nocow,
159
+ },
160
+ };
161
+ return raw_co_create(&options, errp);
162
+}
163
+
164
/*
165
* Find allocation range in @bs around offset @start.
166
* May change underlying file descriptor's file offset.
167
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
168
.bdrv_reopen_commit = raw_reopen_commit,
169
.bdrv_reopen_abort = raw_reopen_abort,
170
.bdrv_close = raw_close,
171
+ .bdrv_co_create = raw_co_create,
172
.bdrv_co_create_opts = raw_co_create_opts,
173
.bdrv_has_zero_init = bdrv_has_zero_init_1,
174
.bdrv_co_block_status = raw_co_block_status,
175
--
176
2.13.6
177
178
diff view generated by jsdifflib
New patch
1
This adds the .bdrv_co_create driver callback to file-win32, which
2
enables image creation over QMP.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
block/file-win32.c | 47 ++++++++++++++++++++++++++++++++++++++---------
9
1 file changed, 38 insertions(+), 9 deletions(-)
10
11
diff --git a/block/file-win32.c b/block/file-win32.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/file-win32.c
14
+++ b/block/file-win32.c
15
@@ -XXX,XX +XXX,XX @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
16
return st.st_size;
17
}
18
19
-static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
20
- Error **errp)
21
+static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
22
{
23
+ BlockdevCreateOptionsFile *file_opts;
24
int fd;
25
- int64_t total_size = 0;
26
27
- strstart(filename, "file:", &filename);
28
+ assert(options->driver == BLOCKDEV_DRIVER_FILE);
29
+ file_opts = &options->u.file;
30
31
- /* Read out options */
32
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
33
- BDRV_SECTOR_SIZE);
34
+ if (file_opts->has_preallocation) {
35
+ error_setg(errp, "Preallocation is not supported on Windows");
36
+ return -EINVAL;
37
+ }
38
+ if (file_opts->has_nocow) {
39
+ error_setg(errp, "nocow is not supported on Windows");
40
+ return -EINVAL;
41
+ }
42
43
- fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
44
+ fd = qemu_open(file_opts->filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
45
0644);
46
if (fd < 0) {
47
error_setg_errno(errp, errno, "Could not create file");
48
return -EIO;
49
}
50
set_sparse(fd);
51
- ftruncate(fd, total_size);
52
+ ftruncate(fd, file_opts->size);
53
qemu_close(fd);
54
+
55
return 0;
56
}
57
58
+static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
59
+ Error **errp)
60
+{
61
+ BlockdevCreateOptions options;
62
+ int64_t total_size = 0;
63
+
64
+ strstart(filename, "file:", &filename);
65
+
66
+ /* Read out options */
67
+ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
68
+ BDRV_SECTOR_SIZE);
69
+
70
+ options = (BlockdevCreateOptions) {
71
+ .driver = BLOCKDEV_DRIVER_FILE,
72
+ .u.file = {
73
+ .filename = (char *) filename,
74
+ .size = total_size,
75
+ .has_preallocation = false,
76
+ .has_nocow = false,
77
+ },
78
+ };
79
+ return raw_co_create(&options, errp);
80
+}
81
82
static QemuOptsList raw_create_opts = {
83
.name = "raw-create-opts",
84
--
85
2.13.6
86
87
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
This adds the .bdrv_co_create driver callback to gluster, which enables
2
2
image creation over QMP.
3
During 'qemu-img compare', when we are checking that an allocated
3
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.
9
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>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
17
---
7
---
18
qemu-img.c | 32 ++++++++++++++++++++++++++++----
8
qapi/block-core.json | 18 ++++++-
19
1 file changed, 28 insertions(+), 4 deletions(-)
9
block/gluster.c | 135 ++++++++++++++++++++++++++++++++++-----------------
20
10
2 files changed, 108 insertions(+), 45 deletions(-)
21
diff --git a/qemu-img.c b/qemu-img.c
11
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
22
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
23
--- a/qemu-img.c
14
--- a/qapi/block-core.json
24
+++ b/qemu-img.c
15
+++ b/qapi/block-core.json
25
@@ -XXX,XX +XXX,XX @@ done:
16
@@ -XXX,XX +XXX,XX @@
17
'*nocow': 'bool' } }
18
19
##
20
+# @BlockdevCreateOptionsGluster:
21
+#
22
+# Driver specific image creation options for gluster.
23
+#
24
+# @location Where to store the new image file
25
+# @size Size of the virtual disk in bytes
26
+# @preallocation Preallocation mode for the new image (default: off)
27
+#
28
+# Since: 2.12
29
+##
30
+{ 'struct': 'BlockdevCreateOptionsGluster',
31
+ 'data': { 'location': 'BlockdevOptionsGluster',
32
+ 'size': 'size',
33
+ '*preallocation': 'PreallocMode' } }
34
+
35
+##
36
# @BlockdevQcow2Version:
37
#
38
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
39
@@ -XXX,XX +XXX,XX @@
40
'file': 'BlockdevCreateOptionsFile',
41
'ftp': 'BlockdevCreateNotSupported',
42
'ftps': 'BlockdevCreateNotSupported',
43
- 'gluster': 'BlockdevCreateNotSupported',
44
+ 'gluster': 'BlockdevCreateOptionsGluster',
45
'host_cdrom': 'BlockdevCreateNotSupported',
46
'host_device': 'BlockdevCreateNotSupported',
47
'http': 'BlockdevCreateNotSupported',
48
diff --git a/block/gluster.c b/block/gluster.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/gluster.c
51
+++ b/block/gluster.c
52
@@ -XXX,XX +XXX,XX @@ out:
53
return -errno;
26
}
54
}
27
55
28
/*
56
-static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
29
+ * Returns -1 if 'buf' contains only zeroes, otherwise the byte index
57
- const char *filename,
30
+ * of the first sector boundary within buf where the sector contains a
58
- QDict *options, Error **errp)
31
+ * non-zero byte. This function is robust to a buffer that is not
59
+/* Converts options given in @filename and the @options QDict into the QAPI
32
+ * sector-aligned.
60
+ * object @gconf. */
33
+ */
61
+static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
34
+static int64_t find_nonzero(const uint8_t *buf, int64_t n)
62
+ const char *filename,
63
+ QDict *options, Error **errp)
64
{
65
int ret;
66
if (filename) {
67
@@ -XXX,XX +XXX,XX @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
68
"[host[:port]]volume/path[?socket=...]"
69
"[,file.debug=N]"
70
"[,file.logfile=/path/filename.log]\n");
71
- errno = -ret;
72
- return NULL;
73
+ return ret;
74
}
75
} else {
76
ret = qemu_gluster_parse_json(gconf, options, errp);
77
@@ -XXX,XX +XXX,XX @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
78
"file.server.1.transport=unix,"
79
"file.server.1.socket=/var/run/glusterd.socket ..."
80
"\n");
81
- errno = -ret;
82
- return NULL;
83
+ return ret;
84
}
85
+ }
86
87
+ return 0;
88
+}
89
+
90
+static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
91
+ const char *filename,
92
+ QDict *options, Error **errp)
35
+{
93
+{
36
+ int64_t i;
94
+ int ret;
37
+ int64_t end = QEMU_ALIGN_DOWN(n, BDRV_SECTOR_SIZE);
95
+
38
+
96
+ ret = qemu_gluster_parse(gconf, filename, options, errp);
39
+ for (i = 0; i < end; i += BDRV_SECTOR_SIZE) {
97
+ if (ret < 0) {
40
+ if (!buffer_is_zero(buf + i, BDRV_SECTOR_SIZE)) {
98
+ errno = -ret;
41
+ return i;
99
+ return NULL;
100
}
101
102
return qemu_gluster_glfs_init(gconf, errp);
103
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
104
return 0;
105
}
106
107
+static int qemu_gluster_co_create(BlockdevCreateOptions *options,
108
+ Error **errp)
109
+{
110
+ BlockdevCreateOptionsGluster *opts = &options->u.gluster;
111
+ struct glfs *glfs;
112
+ struct glfs_fd *fd = NULL;
113
+ int ret = 0;
114
+
115
+ assert(options->driver == BLOCKDEV_DRIVER_GLUSTER);
116
+
117
+ glfs = qemu_gluster_glfs_init(opts->location, errp);
118
+ if (!glfs) {
119
+ ret = -errno;
120
+ goto out;
121
+ }
122
+
123
+ fd = glfs_creat(glfs, opts->location->path,
124
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
125
+ if (!fd) {
126
+ ret = -errno;
127
+ goto out;
128
+ }
129
+
130
+ ret = qemu_gluster_do_truncate(fd, opts->size, opts->preallocation, errp);
131
+
132
+out:
133
+ if (fd) {
134
+ if (glfs_close(fd) != 0 && ret == 0) {
135
+ ret = -errno;
42
+ }
136
+ }
43
+ }
137
+ }
44
+ if (i < n && !buffer_is_zero(buf + i, n - end)) {
138
+ glfs_clear_preopened(glfs);
45
+ return i;
139
+ return ret;
46
+ }
47
+ return -1;
48
+}
140
+}
49
+
141
+
50
+/*
142
static int coroutine_fn qemu_gluster_co_create_opts(const char *filename,
51
* Returns true iff the first sector pointed to by 'buf' contains at least
143
QemuOpts *opts,
52
* a non-NUL byte.
144
Error **errp)
53
*
54
@@ -XXX,XX +XXX,XX @@ static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
55
int sect_count, const char *filename,
56
uint8_t *buffer, bool quiet)
57
{
145
{
58
- int pnum, ret = 0;
146
+ BlockdevCreateOptions *options;
59
+ int ret = 0;
147
+ BlockdevCreateOptionsGluster *gopts;
60
+ int64_t idx;
148
BlockdevOptionsGluster *gconf;
61
+
149
- struct glfs *glfs;
62
ret = blk_pread(blk, sect_num << BDRV_SECTOR_BITS, buffer,
150
- struct glfs_fd *fd = NULL;
63
sect_count << BDRV_SECTOR_BITS);
151
- int ret = 0;
64
if (ret < 0) {
152
- PreallocMode prealloc;
65
@@ -XXX,XX +XXX,XX @@ static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
153
- int64_t total_size = 0;
66
sectors_to_bytes(sect_num), filename, strerror(-ret));
154
char *tmp = NULL;
67
return ret;
155
Error *local_err = NULL;
68
}
156
+ int ret;
69
- ret = is_allocated_sectors(buffer, sect_count, &pnum);
157
+
70
- if (ret || pnum != sect_count) {
158
+ options = g_new0(BlockdevCreateOptions, 1);
71
+ idx = find_nonzero(buffer, sect_count * BDRV_SECTOR_SIZE);
159
+ options->driver = BLOCKDEV_DRIVER_GLUSTER;
72
+ if (idx >= 0) {
160
+ gopts = &options->u.gluster;
73
qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
161
74
- sectors_to_bytes(ret ? sect_num : sect_num + pnum));
162
gconf = g_new0(BlockdevOptionsGluster, 1);
75
+ sectors_to_bytes(sect_num) + idx);
163
+ gopts->location = gconf;
76
return 1;
164
+
77
}
165
+ gopts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
78
166
+ BDRV_SECTOR_SIZE);
167
+
168
+ tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
169
+ gopts->preallocation = qapi_enum_parse(&PreallocMode_lookup, tmp,
170
+ PREALLOC_MODE_OFF, &local_err);
171
+ g_free(tmp);
172
+ if (local_err) {
173
+ error_propagate(errp, local_err);
174
+ ret = -EINVAL;
175
+ goto fail;
176
+ }
177
+
178
gconf->debug = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
179
GLUSTER_DEBUG_DEFAULT);
180
if (gconf->debug < 0) {
181
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_gluster_co_create_opts(const char *filename,
182
}
183
gconf->has_logfile = true;
184
185
- glfs = qemu_gluster_init(gconf, filename, NULL, errp);
186
- if (!glfs) {
187
- ret = -errno;
188
- goto out;
189
- }
190
-
191
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
192
- BDRV_SECTOR_SIZE);
193
-
194
- tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
195
- prealloc = qapi_enum_parse(&PreallocMode_lookup, tmp, PREALLOC_MODE_OFF,
196
- &local_err);
197
- g_free(tmp);
198
- if (local_err) {
199
- error_propagate(errp, local_err);
200
- ret = -EINVAL;
201
- goto out;
202
+ ret = qemu_gluster_parse(gconf, filename, NULL, errp);
203
+ if (ret < 0) {
204
+ goto fail;
205
}
206
207
- fd = glfs_creat(glfs, gconf->path,
208
- O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
209
- if (!fd) {
210
- ret = -errno;
211
- goto out;
212
+ ret = qemu_gluster_co_create(options, errp);
213
+ if (ret < 0) {
214
+ goto fail;
215
}
216
217
- ret = qemu_gluster_do_truncate(fd, total_size, prealloc, errp);
218
-
219
-out:
220
- if (fd) {
221
- if (glfs_close(fd) != 0 && ret == 0) {
222
- ret = -errno;
223
- }
224
- }
225
- qapi_free_BlockdevOptionsGluster(gconf);
226
- glfs_clear_preopened(glfs);
227
+ ret = 0;
228
+fail:
229
+ qapi_free_BlockdevCreateOptions(options);
230
return ret;
231
}
232
233
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster = {
234
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
235
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
236
.bdrv_close = qemu_gluster_close,
237
+ .bdrv_co_create = qemu_gluster_co_create,
238
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
239
.bdrv_getlength = qemu_gluster_getlength,
240
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
241
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_tcp = {
242
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
243
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
244
.bdrv_close = qemu_gluster_close,
245
+ .bdrv_co_create = qemu_gluster_co_create,
246
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
247
.bdrv_getlength = qemu_gluster_getlength,
248
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
249
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_unix = {
250
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
251
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
252
.bdrv_close = qemu_gluster_close,
253
+ .bdrv_co_create = qemu_gluster_co_create,
254
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
255
.bdrv_getlength = qemu_gluster_getlength,
256
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
257
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_rdma = {
258
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
259
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
260
.bdrv_close = qemu_gluster_close,
261
+ .bdrv_co_create = qemu_gluster_co_create,
262
.bdrv_co_create_opts = qemu_gluster_co_create_opts,
263
.bdrv_getlength = qemu_gluster_getlength,
264
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
79
--
265
--
80
2.13.6
266
2.13.6
81
267
82
268
diff view generated by jsdifflib
New patch
1
If we want to include the invalid option name in the error message, we
2
can't free the string earlier than that.
1
3
4
Cc: qemu-stable@nongnu.org
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
9
block/rbd.c | 3 ++-
10
1 file changed, 2 insertions(+), 1 deletion(-)
11
12
diff --git a/block/rbd.c b/block/rbd.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/rbd.c
15
+++ b/block/rbd.c
16
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
17
key = qstring_get_str(name);
18
19
ret = rados_conf_set(cluster, key, qstring_get_str(value));
20
- QDECREF(name);
21
QDECREF(value);
22
if (ret < 0) {
23
error_setg_errno(errp, -ret, "invalid conf option %s", key);
24
+ QDECREF(name);
25
ret = -EINVAL;
26
break;
27
}
28
+ QDECREF(name);
29
}
30
31
QDECREF(keypairs);
32
--
33
2.13.6
34
35
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
The code to establish an RBD connection is duplicated between open and
2
create. In order to be able to share the code, factor out the code from
3
qemu_rbd_open() as a first step.
2
4
3
In the continuing quest to make more things byte-based, change
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
the internal iteration of img_compare(). We can finally drop the
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
TODO assertions added earlier, now that the entire algorithm is
7
---
6
byte-based and no longer has to shift from bytes to sectors.
8
block/rbd.c | 100 ++++++++++++++++++++++++++++++++++++------------------------
9
1 file changed, 60 insertions(+), 40 deletions(-)
7
10
8
Most of the change is mechanical ('total_sectors' becomes
11
diff --git a/block/rbd.c b/block/rbd.c
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>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
qemu-img.c | 124 ++++++++++++++++++++++++-------------------------------------
19
1 file changed, 48 insertions(+), 76 deletions(-)
20
21
diff --git a/qemu-img.c b/qemu-img.c
22
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
23
--- a/qemu-img.c
13
--- a/block/rbd.c
24
+++ b/qemu-img.c
14
+++ b/block/rbd.c
25
@@ -XXX,XX +XXX,XX @@ static int compare_buffers(const uint8_t *buf1, const uint8_t *buf2,
15
@@ -XXX,XX +XXX,XX @@ out:
26
16
return rados_str;
27
#define IO_BUF_SIZE (2 * 1024 * 1024)
17
}
28
18
29
-static int64_t sectors_to_bytes(int64_t sectors)
19
-static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
30
-{
20
- Error **errp)
31
- return sectors << BDRV_SECTOR_BITS;
21
+static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
32
-}
22
+ char **s_snap, char **s_image_name,
23
+ QDict *options, bool cache, Error **errp)
24
{
25
- BDRVRBDState *s = bs->opaque;
26
- const char *pool, *snap, *conf, *user, *image_name, *keypairs;
27
- const char *secretid, *filename;
28
QemuOpts *opts;
29
- Error *local_err = NULL;
30
char *mon_host = NULL;
31
+ const char *pool, *snap, *conf, *user, *image_name, *keypairs;
32
+ const char *secretid;
33
+ Error *local_err = NULL;
34
int r;
35
36
- /* If we are given a filename, parse the filename, with precedence given to
37
- * filename encoded options */
38
- filename = qdict_get_try_str(options, "filename");
39
- if (filename) {
40
- warn_report("'filename' option specified. "
41
- "This is an unsupported option, and may be deprecated "
42
- "in the future");
43
- qemu_rbd_parse_filename(filename, options, &local_err);
44
- if (local_err) {
45
- r = -EINVAL;
46
- error_propagate(errp, local_err);
47
- goto exit;
48
- }
49
- }
33
-
50
-
34
/*
51
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
35
* Check if passed sectors are empty (not allocated or contain only 0 bytes)
52
qemu_opts_absorb_qdict(opts, options, &local_err);
36
*
53
if (local_err) {
37
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
54
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
38
const char *fmt1 = NULL, *fmt2 = NULL, *cache, *filename1, *filename2;
55
goto failed_opts;
39
BlockBackend *blk1, *blk2;
40
BlockDriverState *bs1, *bs2;
41
- int64_t total_sectors1, total_sectors2;
42
+ int64_t total_size1, total_size2;
43
uint8_t *buf1 = NULL, *buf2 = NULL;
44
int64_t pnum1, pnum2;
45
int allocated1, allocated2;
46
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
47
bool progress = false, quiet = false, strict = false;
48
int flags;
49
bool writethrough;
50
- int64_t total_sectors;
51
- int64_t sector_num = 0;
52
- int64_t nb_sectors;
53
+ int64_t total_size;
54
+ int64_t offset = 0;
55
+ int64_t chunk;
56
int c;
57
uint64_t progress_base;
58
bool image_opts = false;
59
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
60
61
buf1 = blk_blockalign(blk1, IO_BUF_SIZE);
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
}
56
}
73
- total_sectors2 = blk_nb_sectors(blk2);
57
74
- if (total_sectors2 < 0) {
58
- r = rados_create(&s->cluster, user);
75
+ total_size2 = blk_getlength(blk2);
59
+ r = rados_create(cluster, user);
76
+ if (total_size2 < 0) {
60
if (r < 0) {
77
error_report("Can't get size of %s: %s",
61
error_setg_errno(errp, -r, "error initializing");
78
- filename2, strerror(-total_sectors2));
62
goto failed_opts;
79
+ filename2, strerror(-total_size2));
80
ret = 4;
81
goto out;
82
}
63
}
83
- total_sectors = MIN(total_sectors1, total_sectors2);
64
84
- progress_base = MAX(total_sectors1, total_sectors2);
65
- s->snap = g_strdup(snap);
85
+ total_size = MIN(total_size1, total_size2);
66
- s->image_name = g_strdup(image_name);
86
+ progress_base = MAX(total_size1, total_size2);
67
+ *s_snap = g_strdup(snap);
87
68
+ *s_image_name = g_strdup(image_name);
88
qemu_progress_print(0, 100);
69
89
70
/* try default location when conf=NULL, but ignore failure */
90
- if (strict && total_sectors1 != total_sectors2) {
71
- r = rados_conf_read_file(s->cluster, conf);
91
+ if (strict && total_size1 != total_size2) {
72
+ r = rados_conf_read_file(*cluster, conf);
92
ret = 1;
73
if (conf && r < 0) {
93
qprintf(quiet, "Strict mode: Image size mismatch!\n");
74
error_setg_errno(errp, -r, "error reading conf file %s", conf);
94
goto out;
75
goto failed_shutdown;
95
}
76
}
96
77
97
- while (sector_num < total_sectors) {
78
- r = qemu_rbd_set_keypairs(s->cluster, keypairs, errp);
98
+ while (offset < total_size) {
79
+ r = qemu_rbd_set_keypairs(*cluster, keypairs, errp);
99
int status1, status2;
80
if (r < 0) {
100
81
goto failed_shutdown;
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
}
82
}
214
83
215
- if (total_sectors1 != total_sectors2) {
84
if (mon_host) {
216
+ if (total_size1 != total_size2) {
85
- r = rados_conf_set(s->cluster, "mon_host", mon_host);
217
BlockBackend *blk_over;
86
+ r = rados_conf_set(*cluster, "mon_host", mon_host);
218
const char *filename_over;
87
if (r < 0) {
219
88
goto failed_shutdown;
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;
232
-
233
- ret = bdrv_block_status_above(blk_bs(blk_over), NULL,
234
- sector_num * BDRV_SECTOR_SIZE,
235
- (progress_base - sector_num) *
236
- BDRV_SECTOR_SIZE,
237
- &count, NULL, NULL);
238
+ while (offset < progress_base) {
239
+ ret = bdrv_block_status_above(blk_bs(blk_over), NULL, offset,
240
+ progress_base - offset, &chunk,
241
+ NULL, NULL);
242
if (ret < 0) {
243
ret = 3;
244
error_report("Sector allocation test failed for %s",
245
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
246
goto out;
247
248
}
249
- /* TODO relax this once bdrv_block_status_above does not enforce
250
- * sector alignment */
251
- assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
252
- nb_sectors = count >> BDRV_SECTOR_BITS;
253
if (ret & BDRV_BLOCK_ALLOCATED && !(ret & BDRV_BLOCK_ZERO)) {
254
- nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
255
- ret = check_empty_sectors(blk_over,
256
- sector_num * BDRV_SECTOR_SIZE,
257
- nb_sectors * BDRV_SECTOR_SIZE,
258
+ chunk = MIN(chunk, IO_BUF_SIZE);
259
+ ret = check_empty_sectors(blk_over, offset, chunk,
260
filename_over, buf1, quiet);
261
if (ret) {
262
goto out;
263
}
264
}
265
- sector_num += nb_sectors;
266
- qemu_progress_print(((float) nb_sectors / progress_base)*100, 100);
267
+ offset += chunk;
268
+ qemu_progress_print(((float) chunk / progress_base) * 100, 100);
269
}
89
}
270
}
90
}
91
92
- if (qemu_rbd_set_auth(s->cluster, secretid, errp) < 0) {
93
+ if (qemu_rbd_set_auth(*cluster, secretid, errp) < 0) {
94
r = -EIO;
95
goto failed_shutdown;
96
}
97
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
98
* librbd defaults to no caching. If write through caching cannot
99
* be set up, fall back to no caching.
100
*/
101
- if (flags & BDRV_O_NOCACHE) {
102
- rados_conf_set(s->cluster, "rbd_cache", "false");
103
+ if (cache) {
104
+ rados_conf_set(*cluster, "rbd_cache", "true");
105
} else {
106
- rados_conf_set(s->cluster, "rbd_cache", "true");
107
+ rados_conf_set(*cluster, "rbd_cache", "false");
108
}
109
110
- r = rados_connect(s->cluster);
111
+ r = rados_connect(*cluster);
112
if (r < 0) {
113
error_setg_errno(errp, -r, "error connecting");
114
goto failed_shutdown;
115
}
116
117
- r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
118
+ r = rados_ioctx_create(*cluster, pool, io_ctx);
119
if (r < 0) {
120
error_setg_errno(errp, -r, "error opening pool %s", pool);
121
goto failed_shutdown;
122
}
123
124
+ qemu_opts_del(opts);
125
+ return 0;
126
+
127
+failed_shutdown:
128
+ rados_shutdown(*cluster);
129
+ g_free(*s_snap);
130
+ g_free(*s_image_name);
131
+failed_opts:
132
+ qemu_opts_del(opts);
133
+ g_free(mon_host);
134
+ return r;
135
+}
136
+
137
+static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
138
+ Error **errp)
139
+{
140
+ BDRVRBDState *s = bs->opaque;
141
+ Error *local_err = NULL;
142
+ const char *filename;
143
+ int r;
144
+
145
+ /* If we are given a filename, parse the filename, with precedence given to
146
+ * filename encoded options */
147
+ filename = qdict_get_try_str(options, "filename");
148
+ if (filename) {
149
+ warn_report("'filename' option specified. "
150
+ "This is an unsupported option, and may be deprecated "
151
+ "in the future");
152
+ qemu_rbd_parse_filename(filename, options, &local_err);
153
+ if (local_err) {
154
+ error_propagate(errp, local_err);
155
+ return -EINVAL;
156
+ }
157
+ }
158
+
159
+ r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
160
+ options, !(flags & BDRV_O_NOCACHE), errp);
161
+ if (r < 0) {
162
+ return r;
163
+ }
164
+
165
/* rbd_open is always r/w */
166
r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
167
if (r < 0) {
168
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
169
}
170
}
171
172
- qemu_opts_del(opts);
173
return 0;
174
175
failed_open:
176
rados_ioctx_destroy(s->io_ctx);
177
-failed_shutdown:
178
- rados_shutdown(s->cluster);
179
g_free(s->snap);
180
g_free(s->image_name);
181
-failed_opts:
182
- qemu_opts_del(opts);
183
- g_free(mon_host);
184
-exit:
185
+ rados_shutdown(s->cluster);
186
return r;
187
}
271
188
272
--
189
--
273
2.13.6
190
2.13.6
274
191
275
192
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
Instead of the QemuOpts in qemu_rbd_connect(), we want to use QAPI
2
objects. As a preparation, fetch those options directly from the QDict
3
that .bdrv_open() supports in the rbd driver and that are not in the
4
schema.
2
5
3
We are gradually converting to byte-based interfaces, as they are
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
easier to reason about than sector-based. Change the internal
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
loop iteration of zeroing a device to track by bytes instead of
8
---
6
sectors (although we are still guaranteed that we iterate by steps
9
block/rbd.c | 55 ++++++++++++++++++++++++-------------------------------
7
that are sector-aligned).
10
1 file changed, 24 insertions(+), 31 deletions(-)
8
11
9
Signed-off-by: Eric Blake <eblake@redhat.com>
12
diff --git a/block/rbd.c b/block/rbd.c
10
Reviewed-by: Fam Zheng <famz@redhat.com>
11
Reviewed-by: John Snow <jsnow@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
block/io.c | 32 ++++++++++++++++----------------
15
1 file changed, 16 insertions(+), 16 deletions(-)
16
17
diff --git a/block/io.c b/block/io.c
18
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
19
--- a/block/io.c
14
--- a/block/rbd.c
20
+++ b/block/io.c
15
+++ b/block/rbd.c
21
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
16
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
22
*/
17
/*
23
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
18
* server.* extracted manually, see qemu_rbd_mon_host()
19
*/
20
- {
21
- .name = "password-secret",
22
- .type = QEMU_OPT_STRING,
23
- .help = "ID of secret providing the password",
24
- },
25
-
26
- /*
27
- * Keys for qemu_rbd_parse_filename(), not in the QAPI schema
28
- */
29
- {
30
- /*
31
- * HACK: name starts with '=' so that qemu_opts_parse()
32
- * can't set it
33
- */
34
- .name = "=keyvalue-pairs",
35
- .type = QEMU_OPT_STRING,
36
- .help = "Legacy rados key/value option parameters",
37
- },
38
- {
39
- .name = "filename",
40
- .type = QEMU_OPT_STRING,
41
- },
42
{ /* end of list */ }
43
},
44
};
45
@@ -XXX,XX +XXX,XX @@ out:
46
47
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
48
char **s_snap, char **s_image_name,
49
- QDict *options, bool cache, Error **errp)
50
+ QDict *options, bool cache,
51
+ const char *keypairs, const char *secretid,
52
+ Error **errp)
24
{
53
{
25
- int64_t target_sectors, ret, nb_sectors, sector_num = 0;
54
QemuOpts *opts;
26
+ int64_t target_size, ret, bytes, offset = 0;
55
char *mon_host = NULL;
27
BlockDriverState *bs = child->bs;
56
- const char *pool, *snap, *conf, *user, *image_name, *keypairs;
28
- int n;
57
- const char *secretid;
29
+ int n; /* sectors */
58
+ const char *pool, *snap, *conf, *user, *image_name;
30
59
Error *local_err = NULL;
31
- target_sectors = bdrv_nb_sectors(bs);
60
int r;
32
- if (target_sectors < 0) {
61
33
- return target_sectors;
62
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
34
+ target_size = bdrv_getlength(bs);
63
goto failed_opts;
35
+ if (target_size < 0) {
36
+ return target_size;
37
}
64
}
38
65
39
for (;;) {
66
- secretid = qemu_opt_get(opts, "password-secret");
40
- nb_sectors = MIN(target_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
67
-
41
- if (nb_sectors <= 0) {
68
pool = qemu_opt_get(opts, "pool");
42
+ bytes = MIN(target_size - offset, BDRV_REQUEST_MAX_BYTES);
69
conf = qemu_opt_get(opts, "conf");
43
+ if (bytes <= 0) {
70
snap = qemu_opt_get(opts, "snapshot");
44
return 0;
71
user = qemu_opt_get(opts, "user");
72
image_name = qemu_opt_get(opts, "image");
73
- keypairs = qemu_opt_get(opts, "=keyvalue-pairs");
74
75
if (!pool || !image_name) {
76
error_setg(errp, "Parameters 'pool' and 'image' are required");
77
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
78
BDRVRBDState *s = bs->opaque;
79
Error *local_err = NULL;
80
const char *filename;
81
+ char *keypairs, *secretid;
82
int r;
83
84
/* If we are given a filename, parse the filename, with precedence given to
85
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
86
"This is an unsupported option, and may be deprecated "
87
"in the future");
88
qemu_rbd_parse_filename(filename, options, &local_err);
89
+ qdict_del(options, "filename");
90
if (local_err) {
91
error_propagate(errp, local_err);
92
return -EINVAL;
45
}
93
}
46
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, NULL);
94
}
47
+ ret = bdrv_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
95
48
+ bytes >> BDRV_SECTOR_BITS, &n, NULL);
96
+ keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
49
if (ret < 0) {
97
+ if (keypairs) {
50
- error_report("error getting block status at sector %" PRId64 ": %s",
98
+ qdict_del(options, "=keyvalue-pairs");
51
- sector_num, strerror(-ret));
99
+ }
52
+ error_report("error getting block status at offset %" PRId64 ": %s",
100
+
53
+ offset, strerror(-ret));
101
+ secretid = g_strdup(qdict_get_try_str(options, "password-secret"));
54
return ret;
102
+ if (secretid) {
103
+ qdict_del(options, "password-secret");
104
+ }
105
+
106
r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
107
- options, !(flags & BDRV_O_NOCACHE), errp);
108
+ options, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
109
+ errp);
110
if (r < 0) {
111
- return r;
112
+ goto out;
113
}
114
115
/* rbd_open is always r/w */
116
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
55
}
117
}
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;
73
}
118
}
119
120
- return 0;
121
+ r = 0;
122
+ goto out;
123
124
failed_open:
125
rados_ioctx_destroy(s->io_ctx);
126
g_free(s->snap);
127
g_free(s->image_name);
128
rados_shutdown(s->cluster);
129
+out:
130
+ g_free(keypairs);
131
+ g_free(secretid);
132
return r;
74
}
133
}
75
134
76
--
135
--
77
2.13.6
136
2.13.6
78
137
79
138
diff view generated by jsdifflib
New patch
1
1
With the conversion to a QAPI options object, the function is now
2
prepared to be used in a .bdrv_co_create implementation.
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
7
block/rbd.c | 115 +++++++++++++++++++++++++++++-------------------------------
8
1 file changed, 55 insertions(+), 60 deletions(-)
9
10
diff --git a/block/rbd.c b/block/rbd.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/rbd.c
13
+++ b/block/rbd.c
14
@@ -XXX,XX +XXX,XX @@
15
#include "qapi/qmp/qdict.h"
16
#include "qapi/qmp/qjson.h"
17
#include "qapi/qmp/qlist.h"
18
+#include "qapi/qobject-input-visitor.h"
19
+#include "qapi/qapi-visit-block-core.h"
20
21
/*
22
* When specifying the image filename use:
23
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
24
qemu_aio_unref(acb);
25
}
26
27
-static char *qemu_rbd_mon_host(QDict *options, Error **errp)
28
+static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
29
{
30
- const char **vals = g_new(const char *, qdict_size(options) + 1);
31
- char keybuf[32];
32
+ const char **vals;
33
const char *host, *port;
34
char *rados_str;
35
- int i;
36
-
37
- for (i = 0;; i++) {
38
- sprintf(keybuf, "server.%d.host", i);
39
- host = qdict_get_try_str(options, keybuf);
40
- qdict_del(options, keybuf);
41
- sprintf(keybuf, "server.%d.port", i);
42
- port = qdict_get_try_str(options, keybuf);
43
- qdict_del(options, keybuf);
44
- if (!host && !port) {
45
- break;
46
- }
47
- if (!host) {
48
- error_setg(errp, "Parameter server.%d.host is missing", i);
49
- rados_str = NULL;
50
- goto out;
51
- }
52
+ InetSocketAddressBaseList *p;
53
+ int i, cnt;
54
+
55
+ if (!opts->has_server) {
56
+ return NULL;
57
+ }
58
+
59
+ for (cnt = 0, p = opts->server; p; p = p->next) {
60
+ cnt++;
61
+ }
62
+
63
+ vals = g_new(const char *, cnt + 1);
64
+
65
+ for (i = 0, p = opts->server; p; p = p->next, i++) {
66
+ host = p->value->host;
67
+ port = p->value->port;
68
69
if (strchr(host, ':')) {
70
- vals[i] = port ? g_strdup_printf("[%s]:%s", host, port)
71
- : g_strdup_printf("[%s]", host);
72
+ vals[i] = g_strdup_printf("[%s]:%s", host, port);
73
} else {
74
- vals[i] = port ? g_strdup_printf("%s:%s", host, port)
75
- : g_strdup(host);
76
+ vals[i] = g_strdup_printf("%s:%s", host, port);
77
}
78
}
79
vals[i] = NULL;
80
81
rados_str = i ? g_strjoinv(";", (char **)vals) : NULL;
82
-out:
83
g_strfreev((char **)vals);
84
return rados_str;
85
}
86
87
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
88
char **s_snap, char **s_image_name,
89
- QDict *options, bool cache,
90
+ BlockdevOptionsRbd *opts, bool cache,
91
const char *keypairs, const char *secretid,
92
Error **errp)
93
{
94
- QemuOpts *opts;
95
char *mon_host = NULL;
96
- const char *pool, *snap, *conf, *user, *image_name;
97
Error *local_err = NULL;
98
int r;
99
100
- opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
101
- qemu_opts_absorb_qdict(opts, options, &local_err);
102
- if (local_err) {
103
- error_propagate(errp, local_err);
104
- r = -EINVAL;
105
- goto failed_opts;
106
- }
107
-
108
- mon_host = qemu_rbd_mon_host(options, &local_err);
109
+ mon_host = qemu_rbd_mon_host(opts, &local_err);
110
if (local_err) {
111
error_propagate(errp, local_err);
112
r = -EINVAL;
113
goto failed_opts;
114
}
115
116
- pool = qemu_opt_get(opts, "pool");
117
- conf = qemu_opt_get(opts, "conf");
118
- snap = qemu_opt_get(opts, "snapshot");
119
- user = qemu_opt_get(opts, "user");
120
- image_name = qemu_opt_get(opts, "image");
121
-
122
- if (!pool || !image_name) {
123
- error_setg(errp, "Parameters 'pool' and 'image' are required");
124
- r = -EINVAL;
125
- goto failed_opts;
126
- }
127
-
128
- r = rados_create(cluster, user);
129
+ r = rados_create(cluster, opts->user);
130
if (r < 0) {
131
error_setg_errno(errp, -r, "error initializing");
132
goto failed_opts;
133
}
134
135
- *s_snap = g_strdup(snap);
136
- *s_image_name = g_strdup(image_name);
137
+ *s_snap = g_strdup(opts->snapshot);
138
+ *s_image_name = g_strdup(opts->image);
139
140
/* try default location when conf=NULL, but ignore failure */
141
- r = rados_conf_read_file(*cluster, conf);
142
- if (conf && r < 0) {
143
- error_setg_errno(errp, -r, "error reading conf file %s", conf);
144
+ r = rados_conf_read_file(*cluster, opts->conf);
145
+ if (opts->has_conf && r < 0) {
146
+ error_setg_errno(errp, -r, "error reading conf file %s", opts->conf);
147
goto failed_shutdown;
148
}
149
150
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
151
goto failed_shutdown;
152
}
153
154
- r = rados_ioctx_create(*cluster, pool, io_ctx);
155
+ r = rados_ioctx_create(*cluster, opts->pool, io_ctx);
156
if (r < 0) {
157
- error_setg_errno(errp, -r, "error opening pool %s", pool);
158
+ error_setg_errno(errp, -r, "error opening pool %s", opts->pool);
159
goto failed_shutdown;
160
}
161
162
- qemu_opts_del(opts);
163
return 0;
164
165
failed_shutdown:
166
@@ -XXX,XX +XXX,XX @@ failed_shutdown:
167
g_free(*s_snap);
168
g_free(*s_image_name);
169
failed_opts:
170
- qemu_opts_del(opts);
171
g_free(mon_host);
172
return r;
173
}
174
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
175
Error **errp)
176
{
177
BDRVRBDState *s = bs->opaque;
178
+ BlockdevOptionsRbd *opts = NULL;
179
+ Visitor *v;
180
+ QObject *crumpled = NULL;
181
Error *local_err = NULL;
182
const char *filename;
183
char *keypairs, *secretid;
184
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
185
qdict_del(options, "password-secret");
186
}
187
188
+ /* Convert the remaining options into a QAPI object */
189
+ crumpled = qdict_crumple(options, errp);
190
+ if (crumpled == NULL) {
191
+ r = -EINVAL;
192
+ goto out;
193
+ }
194
+
195
+ v = qobject_input_visitor_new_keyval(crumpled);
196
+ visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err);
197
+ visit_free(v);
198
+ qobject_decref(crumpled);
199
+
200
+ if (local_err) {
201
+ error_propagate(errp, local_err);
202
+ r = -EINVAL;
203
+ goto out;
204
+ }
205
+
206
r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
207
- options, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
208
+ opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
209
errp);
210
if (r < 0) {
211
goto out;
212
@@ -XXX,XX +XXX,XX @@ failed_open:
213
g_free(s->image_name);
214
rados_shutdown(s->cluster);
215
out:
216
+ qapi_free_BlockdevOptionsRbd(opts);
217
g_free(keypairs);
218
g_free(secretid);
219
return r;
220
--
221
2.13.6
222
223
diff view generated by jsdifflib
New patch
1
1
This adds the .bdrv_co_create driver callback to rbd, which enables
2
image creation over QMP.
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
7
qapi/block-core.json | 19 ++++++-
8
block/rbd.c | 150 ++++++++++++++++++++++++++++++++++-----------------
9
2 files changed, 118 insertions(+), 51 deletions(-)
10
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
12
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
14
+++ b/qapi/block-core.json
15
@@ -XXX,XX +XXX,XX @@
16
'*refcount-bits': 'int' } }
17
18
##
19
+# @BlockdevCreateOptionsRbd:
20
+#
21
+# Driver specific image creation options for rbd/Ceph.
22
+#
23
+# @location Where to store the new image file. This location cannot
24
+# point to a snapshot.
25
+# @size Size of the virtual disk in bytes
26
+# @cluster-size RBD object size
27
+#
28
+# Since: 2.12
29
+##
30
+{ 'struct': 'BlockdevCreateOptionsRbd',
31
+ 'data': { 'location': 'BlockdevOptionsRbd',
32
+ 'size': 'size',
33
+ '*cluster-size' : 'size' } }
34
+
35
+##
36
# @BlockdevCreateNotSupported:
37
#
38
# This is used for all drivers that don't support creating images.
39
@@ -XXX,XX +XXX,XX @@
40
'qed': 'BlockdevCreateNotSupported',
41
'quorum': 'BlockdevCreateNotSupported',
42
'raw': 'BlockdevCreateNotSupported',
43
- 'rbd': 'BlockdevCreateNotSupported',
44
+ 'rbd': 'BlockdevCreateOptionsRbd',
45
'replication': 'BlockdevCreateNotSupported',
46
'sheepdog': 'BlockdevCreateNotSupported',
47
'ssh': 'BlockdevCreateNotSupported',
48
diff --git a/block/rbd.c b/block/rbd.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/rbd.c
51
+++ b/block/rbd.c
52
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
53
},
54
};
55
56
-static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
57
- QemuOpts *opts,
58
- Error **errp)
59
+/* FIXME Deprecate and remove keypairs or make it available in QMP.
60
+ * password_secret should eventually be configurable in opts->location. Support
61
+ * for it in .bdrv_open will make it work here as well. */
62
+static int qemu_rbd_do_create(BlockdevCreateOptions *options,
63
+ const char *keypairs, const char *password_secret,
64
+ Error **errp)
65
{
66
- Error *local_err = NULL;
67
- int64_t bytes = 0;
68
- int64_t objsize;
69
- int obj_order = 0;
70
- const char *pool, *image_name, *conf, *user, *keypairs;
71
- const char *secretid;
72
+ BlockdevCreateOptionsRbd *opts = &options->u.rbd;
73
rados_t cluster;
74
rados_ioctx_t io_ctx;
75
- QDict *options = NULL;
76
- int ret = 0;
77
+ int obj_order = 0;
78
+ int ret;
79
+
80
+ assert(options->driver == BLOCKDEV_DRIVER_RBD);
81
+ if (opts->location->has_snapshot) {
82
+ error_setg(errp, "Can't use snapshot name for image creation");
83
+ return -EINVAL;
84
+ }
85
86
- secretid = qemu_opt_get(opts, "password-secret");
87
+ /* TODO Remove the limitation */
88
+ if (opts->location->has_server) {
89
+ error_setg(errp, "Can't specify server for image creation");
90
+ return -EINVAL;
91
+ }
92
93
- /* Read out options */
94
- bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
95
- BDRV_SECTOR_SIZE);
96
- objsize = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
97
- if (objsize) {
98
+ if (opts->has_cluster_size) {
99
+ int64_t objsize = opts->cluster_size;
100
if ((objsize - 1) & objsize) { /* not a power of 2? */
101
error_setg(errp, "obj size needs to be power of 2");
102
- ret = -EINVAL;
103
- goto exit;
104
+ return -EINVAL;
105
}
106
if (objsize < 4096) {
107
error_setg(errp, "obj size too small");
108
- ret = -EINVAL;
109
- goto exit;
110
+ return -EINVAL;
111
}
112
obj_order = ctz32(objsize);
113
}
114
115
- options = qdict_new();
116
- qemu_rbd_parse_filename(filename, options, &local_err);
117
- if (local_err) {
118
- ret = -EINVAL;
119
- error_propagate(errp, local_err);
120
- goto exit;
121
- }
122
-
123
- /*
124
- * Caution: while qdict_get_try_str() is fine, getting non-string
125
- * types would require more care. When @options come from -blockdev
126
- * or blockdev_add, its members are typed according to the QAPI
127
- * schema, but when they come from -drive, they're all QString.
128
- */
129
- pool = qdict_get_try_str(options, "pool");
130
- conf = qdict_get_try_str(options, "conf");
131
- user = qdict_get_try_str(options, "user");
132
- image_name = qdict_get_try_str(options, "image");
133
- keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
134
-
135
- ret = rados_create(&cluster, user);
136
+ ret = rados_create(&cluster, opts->location->user);
137
if (ret < 0) {
138
error_setg_errno(errp, -ret, "error initializing");
139
- goto exit;
140
+ return ret;
141
}
142
143
/* try default location when conf=NULL, but ignore failure */
144
- ret = rados_conf_read_file(cluster, conf);
145
- if (conf && ret < 0) {
146
- error_setg_errno(errp, -ret, "error reading conf file %s", conf);
147
+ ret = rados_conf_read_file(cluster, opts->location->conf);
148
+ if (opts->location->conf && ret < 0) {
149
+ error_setg_errno(errp, -ret, "error reading conf file %s",
150
+ opts->location->conf);
151
ret = -EIO;
152
goto shutdown;
153
}
154
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
155
goto shutdown;
156
}
157
158
- if (qemu_rbd_set_auth(cluster, secretid, errp) < 0) {
159
+ if (qemu_rbd_set_auth(cluster, password_secret, errp) < 0) {
160
ret = -EIO;
161
goto shutdown;
162
}
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
164
goto shutdown;
165
}
166
167
- ret = rados_ioctx_create(cluster, pool, &io_ctx);
168
+ ret = rados_ioctx_create(cluster, opts->location->pool, &io_ctx);
169
if (ret < 0) {
170
- error_setg_errno(errp, -ret, "error opening pool %s", pool);
171
+ error_setg_errno(errp, -ret, "error opening pool %s",
172
+ opts->location->pool);
173
goto shutdown;
174
}
175
176
- ret = rbd_create(io_ctx, image_name, bytes, &obj_order);
177
+ ret = rbd_create(io_ctx, opts->location->image, opts->size, &obj_order);
178
if (ret < 0) {
179
error_setg_errno(errp, -ret, "error rbd create");
180
}
181
182
rados_ioctx_destroy(io_ctx);
183
184
+ ret = 0;
185
shutdown:
186
rados_shutdown(cluster);
187
+ return ret;
188
+}
189
+
190
+static int qemu_rbd_co_create(BlockdevCreateOptions *options, Error **errp)
191
+{
192
+ return qemu_rbd_do_create(options, NULL, NULL, errp);
193
+}
194
+
195
+static int coroutine_fn qemu_rbd_co_create_opts(const char *filename,
196
+ QemuOpts *opts,
197
+ Error **errp)
198
+{
199
+ BlockdevCreateOptions *create_options;
200
+ BlockdevCreateOptionsRbd *rbd_opts;
201
+ BlockdevOptionsRbd *loc;
202
+ Error *local_err = NULL;
203
+ const char *keypairs, *password_secret;
204
+ QDict *options = NULL;
205
+ int ret = 0;
206
+
207
+ create_options = g_new0(BlockdevCreateOptions, 1);
208
+ create_options->driver = BLOCKDEV_DRIVER_RBD;
209
+ rbd_opts = &create_options->u.rbd;
210
+
211
+ rbd_opts->location = g_new0(BlockdevOptionsRbd, 1);
212
+
213
+ password_secret = qemu_opt_get(opts, "password-secret");
214
+
215
+ /* Read out options */
216
+ rbd_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
217
+ BDRV_SECTOR_SIZE);
218
+ rbd_opts->cluster_size = qemu_opt_get_size_del(opts,
219
+ BLOCK_OPT_CLUSTER_SIZE, 0);
220
+ rbd_opts->has_cluster_size = (rbd_opts->cluster_size != 0);
221
+
222
+ options = qdict_new();
223
+ qemu_rbd_parse_filename(filename, options, &local_err);
224
+ if (local_err) {
225
+ ret = -EINVAL;
226
+ error_propagate(errp, local_err);
227
+ goto exit;
228
+ }
229
+
230
+ /*
231
+ * Caution: while qdict_get_try_str() is fine, getting non-string
232
+ * types would require more care. When @options come from -blockdev
233
+ * or blockdev_add, its members are typed according to the QAPI
234
+ * schema, but when they come from -drive, they're all QString.
235
+ */
236
+ loc = rbd_opts->location;
237
+ loc->pool = g_strdup(qdict_get_try_str(options, "pool"));
238
+ loc->conf = g_strdup(qdict_get_try_str(options, "conf"));
239
+ loc->has_conf = !!loc->conf;
240
+ loc->user = g_strdup(qdict_get_try_str(options, "user"));
241
+ loc->has_user = !!loc->user;
242
+ loc->image = g_strdup(qdict_get_try_str(options, "image"));
243
+ keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
244
+
245
+ ret = qemu_rbd_do_create(create_options, keypairs, password_secret, errp);
246
+ if (ret < 0) {
247
+ goto exit;
248
+ }
249
250
exit:
251
QDECREF(options);
252
+ qapi_free_BlockdevCreateOptions(create_options);
253
return ret;
254
}
255
256
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
257
.bdrv_file_open = qemu_rbd_open,
258
.bdrv_close = qemu_rbd_close,
259
.bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
260
+ .bdrv_co_create = qemu_rbd_co_create,
261
.bdrv_co_create_opts = qemu_rbd_co_create_opts,
262
.bdrv_has_zero_init = bdrv_has_zero_init_1,
263
.bdrv_get_info = qemu_rbd_getinfo,
264
--
265
2.13.6
266
267
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
Now that the options are already available in qemu_rbd_open() and not
2
only parsed in qemu_rbd_connect(), we can assign s->snap and
3
s->image_name there instead of passing the fields by reference to
4
qemu_rbd_connect().
2
5
3
As long as we are querying the status for a chunk smaller than
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
the known image size, we are guaranteed that a successful return
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
will have set pnum to a non-zero size (pnum is zero only for
8
---
6
queries beyond the end of the file). Use that to slightly
9
block/rbd.c | 14 +++++---------
7
simplify the calculation of the current chunk size being compared.
10
1 file changed, 5 insertions(+), 9 deletions(-)
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
11
13
With these changes in place, sectors_to_process() is now dead code,
12
diff --git a/block/rbd.c b/block/rbd.c
14
and can be removed.
15
16
Signed-off-by: Eric Blake <eblake@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
qemu-img.c | 38 +++++++++++---------------------------
20
1 file changed, 11 insertions(+), 27 deletions(-)
21
22
diff --git a/qemu-img.c b/qemu-img.c
23
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
24
--- a/qemu-img.c
14
--- a/block/rbd.c
25
+++ b/qemu-img.c
15
+++ b/block/rbd.c
26
@@ -XXX,XX +XXX,XX @@ static int64_t sectors_to_bytes(int64_t sectors)
16
@@ -XXX,XX +XXX,XX @@ static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
27
return sectors << BDRV_SECTOR_BITS;
28
}
17
}
29
18
30
-static int64_t sectors_to_process(int64_t total, int64_t from)
19
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
31
-{
20
- char **s_snap, char **s_image_name,
32
- return MIN(total - from, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
21
BlockdevOptionsRbd *opts, bool cache,
33
-}
22
const char *keypairs, const char *secretid,
23
Error **errp)
24
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
25
goto failed_opts;
26
}
27
28
- *s_snap = g_strdup(opts->snapshot);
29
- *s_image_name = g_strdup(opts->image);
34
-
30
-
35
/*
31
/* try default location when conf=NULL, but ignore failure */
36
* Check if passed sectors are empty (not allocated or contain only 0 bytes)
32
r = rados_conf_read_file(*cluster, opts->conf);
37
*
33
if (opts->has_conf && r < 0) {
38
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
34
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
35
36
failed_shutdown:
37
rados_shutdown(*cluster);
38
- g_free(*s_snap);
39
- g_free(*s_image_name);
40
failed_opts:
41
g_free(mon_host);
42
return r;
43
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
39
goto out;
44
goto out;
40
}
45
}
41
46
42
- for (;;) {
47
- r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
43
+ while (sector_num < total_sectors) {
48
- opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
44
int status1, status2;
49
- errp);
45
50
+ r = qemu_rbd_connect(&s->cluster, &s->io_ctx, opts,
46
- nb_sectors = sectors_to_process(total_sectors, sector_num);
51
+ !(flags & BDRV_O_NOCACHE), keypairs, secretid, errp);
47
- if (nb_sectors <= 0) {
52
if (r < 0) {
48
- break;
53
goto out;
49
- }
54
}
50
status1 = bdrv_block_status_above(bs1, NULL,
55
51
sector_num * BDRV_SECTOR_SIZE,
56
+ s->snap = g_strdup(opts->snapshot);
52
(total_sectors1 - sector_num) *
57
+ s->image_name = g_strdup(opts->image);
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
+
58
+
64
+ assert(pnum1 && pnum2);
59
/* rbd_open is always r/w */
65
+ nb_sectors = MIN(pnum1, pnum2) >> BDRV_SECTOR_BITS;
60
r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
66
61
if (r < 0) {
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 {
85
-
86
+ nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
87
if (allocated1) {
88
ret = check_empty_sectors(blk1, sector_num, nb_sectors,
89
filename1, buf1, quiet);
90
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
91
92
if (total_sectors1 != total_sectors2) {
93
BlockBackend *blk_over;
94
- int64_t total_sectors_over;
95
const char *filename_over;
96
97
qprintf(quiet, "Warning: Image size mismatch!\n");
98
if (total_sectors1 > total_sectors2) {
99
- total_sectors_over = total_sectors1;
100
blk_over = blk1;
101
filename_over = filename1;
102
} else {
103
- total_sectors_over = total_sectors2;
104
blk_over = blk2;
105
filename_over = filename2;
106
}
107
108
- for (;;) {
109
+ while (sector_num < progress_base) {
110
int64_t count;
111
112
- nb_sectors = sectors_to_process(total_sectors_over, sector_num);
113
- if (nb_sectors <= 0) {
114
- break;
115
- }
116
ret = bdrv_is_allocated_above(blk_bs(blk_over), NULL,
117
sector_num * BDRV_SECTOR_SIZE,
118
- nb_sectors * BDRV_SECTOR_SIZE,
119
+ (progress_base - sector_num) *
120
+ BDRV_SECTOR_SIZE,
121
&count);
122
if (ret < 0) {
123
ret = 3;
124
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
125
assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
126
nb_sectors = count >> BDRV_SECTOR_BITS;
127
if (ret) {
128
+ nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
129
ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
130
filename_over, buf1, quiet);
131
if (ret) {
132
--
62
--
133
2.13.6
63
2.13.6
134
64
135
65
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
This is almost exactly the same code. The differences are that
2
qemu_rbd_connect() supports BlockdevOptionsRbd.server and that the cache
3
mode is set explicitly.
2
4
3
Continue on the quest to make more things byte-based instead of
5
Supporting 'server' is a welcome new feature for image creation.
4
sector-based.
6
Caching is disabled by default, so leave it that way.
5
7
6
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
10
---
10
qemu-img.c | 27 +++++++++++++++------------
11
block/rbd.c | 54 ++++++++++--------------------------------------------
11
1 file changed, 15 insertions(+), 12 deletions(-)
12
1 file changed, 10 insertions(+), 44 deletions(-)
12
13
13
diff --git a/qemu-img.c b/qemu-img.c
14
diff --git a/block/rbd.c b/block/rbd.c
14
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
15
--- a/qemu-img.c
16
--- a/block/rbd.c
16
+++ b/qemu-img.c
17
+++ b/block/rbd.c
17
@@ -XXX,XX +XXX,XX @@ static int64_t sectors_to_bytes(int64_t sectors)
18
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRBDState {
18
* an error message.
19
char *snap;
19
*
20
} BDRVRBDState;
20
* @param blk: BlockBackend for the image
21
21
- * @param sect_num: Number of first sector to check
22
+static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
22
- * @param sect_count: Number of sectors to check
23
+ BlockdevOptionsRbd *opts, bool cache,
23
+ * @param offset: Starting offset to check
24
+ const char *keypairs, const char *secretid,
24
+ * @param bytes: Number of bytes to check
25
+ Error **errp);
25
* @param filename: Name of disk file we are checking (logging purpose)
26
+
26
* @param buffer: Allocated buffer for storing read data
27
static char *qemu_rbd_next_tok(char *src, char delim, char **p)
27
* @param quiet: Flag for quiet mode
28
*/
29
-static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
30
- int sect_count, const char *filename,
31
+static int check_empty_sectors(BlockBackend *blk, int64_t offset,
32
+ int64_t bytes, const char *filename,
33
uint8_t *buffer, bool quiet)
34
{
28
{
35
int ret = 0;
29
char *end;
36
int64_t idx;
30
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
37
31
return -EINVAL;
38
- ret = blk_pread(blk, sect_num << BDRV_SECTOR_BITS, buffer,
32
}
39
- sect_count << BDRV_SECTOR_BITS);
33
40
+ ret = blk_pread(blk, offset, buffer, bytes);
34
- /* TODO Remove the limitation */
35
- if (opts->location->has_server) {
36
- error_setg(errp, "Can't specify server for image creation");
37
- return -EINVAL;
38
- }
39
-
40
if (opts->has_cluster_size) {
41
int64_t objsize = opts->cluster_size;
42
if ((objsize - 1) & objsize) { /* not a power of 2? */
43
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
44
obj_order = ctz32(objsize);
45
}
46
47
- ret = rados_create(&cluster, opts->location->user);
48
+ ret = qemu_rbd_connect(&cluster, &io_ctx, opts->location, false, keypairs,
49
+ password_secret, errp);
41
if (ret < 0) {
50
if (ret < 0) {
42
error_report("Error while reading offset %" PRId64 " of %s: %s",
51
- error_setg_errno(errp, -ret, "error initializing");
43
- sectors_to_bytes(sect_num), filename, strerror(-ret));
52
return ret;
44
+ offset, filename, strerror(-ret));
45
return 4;
46
}
53
}
47
- idx = find_nonzero(buffer, sect_count * BDRV_SECTOR_SIZE);
54
48
+ idx = find_nonzero(buffer, bytes);
55
- /* try default location when conf=NULL, but ignore failure */
49
if (idx >= 0) {
56
- ret = rados_conf_read_file(cluster, opts->location->conf);
50
qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
57
- if (opts->location->conf && ret < 0) {
51
- sectors_to_bytes(sect_num) + idx);
58
- error_setg_errno(errp, -ret, "error reading conf file %s",
52
+ offset + idx);
59
- opts->location->conf);
53
return 1;
60
- ret = -EIO;
61
- goto shutdown;
62
- }
63
-
64
- ret = qemu_rbd_set_keypairs(cluster, keypairs, errp);
65
- if (ret < 0) {
66
- ret = -EIO;
67
- goto shutdown;
68
- }
69
-
70
- if (qemu_rbd_set_auth(cluster, password_secret, errp) < 0) {
71
- ret = -EIO;
72
- goto shutdown;
73
- }
74
-
75
- ret = rados_connect(cluster);
76
- if (ret < 0) {
77
- error_setg_errno(errp, -ret, "error connecting");
78
- goto shutdown;
79
- }
80
-
81
- ret = rados_ioctx_create(cluster, opts->location->pool, &io_ctx);
82
- if (ret < 0) {
83
- error_setg_errno(errp, -ret, "error opening pool %s",
84
- opts->location->pool);
85
- goto shutdown;
86
- }
87
-
88
ret = rbd_create(io_ctx, opts->location->image, opts->size, &obj_order);
89
if (ret < 0) {
90
error_setg_errno(errp, -ret, "error rbd create");
91
+ goto out;
54
}
92
}
55
93
56
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
94
- rados_ioctx_destroy(io_ctx);
57
} else {
95
-
58
nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
96
ret = 0;
59
if (allocated1) {
97
-shutdown:
60
- ret = check_empty_sectors(blk1, sector_num, nb_sectors,
98
+out:
61
+ ret = check_empty_sectors(blk1, sector_num * BDRV_SECTOR_SIZE,
99
+ rados_ioctx_destroy(io_ctx);
62
+ nb_sectors * BDRV_SECTOR_SIZE,
100
rados_shutdown(cluster);
63
filename1, buf1, quiet);
101
return ret;
64
} else {
102
}
65
- ret = check_empty_sectors(blk2, sector_num, nb_sectors,
66
+ ret = check_empty_sectors(blk2, sector_num * BDRV_SECTOR_SIZE,
67
+ nb_sectors * BDRV_SECTOR_SIZE,
68
filename2, buf1, quiet);
69
}
70
if (ret) {
71
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
72
nb_sectors = count >> BDRV_SECTOR_BITS;
73
if (ret & BDRV_BLOCK_ALLOCATED && !(ret & BDRV_BLOCK_ZERO)) {
74
nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
75
- ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
76
+ ret = check_empty_sectors(blk_over,
77
+ sector_num * BDRV_SECTOR_SIZE,
78
+ nb_sectors * BDRV_SECTOR_SIZE,
79
filename_over, buf1, quiet);
80
if (ret) {
81
goto out;
82
--
103
--
83
2.13.6
104
2.13.6
84
105
85
106
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
Using the QAPI visitor to turn all options into QAPI BlockdevOptionsNfs
2
2
simplifies the code a lot. It will also be useful for implementing the
3
We are gradually converting to byte-based interfaces, as they are
3
QAPI based .bdrv_co_create callback.
4
easier to reason about than sector-based. Convert another internal
4
5
function (no semantic change).
6
7
Signed-off-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
---
7
---
10
block/io.c | 61 ++++++++++++++++++++++++++++++-------------------------------
8
block/nfs.c | 176 ++++++++++++++++++------------------------------------------
11
1 file changed, 30 insertions(+), 31 deletions(-)
9
1 file changed, 53 insertions(+), 123 deletions(-)
12
10
13
diff --git a/block/io.c b/block/io.c
11
diff --git a/block/nfs.c b/block/nfs.c
14
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
15
--- a/block/io.c
13
--- a/block/nfs.c
16
+++ b/block/io.c
14
+++ b/block/nfs.c
17
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
18
*
16
return task.ret;
19
* See bdrv_co_get_block_status_above() for details.
17
}
20
*/
18
21
-static int64_t bdrv_common_block_status_above(BlockDriverState *bs,
19
-static QemuOptsList runtime_opts = {
22
- BlockDriverState *base,
20
- .name = "nfs",
23
- bool want_zero,
21
- .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
24
- int64_t sector_num,
22
- .desc = {
25
- int nb_sectors, int *pnum,
23
- {
26
- BlockDriverState **file)
24
- .name = "path",
27
+static int bdrv_common_block_status_above(BlockDriverState *bs,
25
- .type = QEMU_OPT_STRING,
28
+ BlockDriverState *base,
26
- .help = "Path of the image on the host",
29
+ bool want_zero, int64_t offset,
27
- },
30
+ int64_t bytes, int64_t *pnum,
28
- {
31
+ int64_t *map,
29
- .name = "user",
32
+ BlockDriverState **file)
30
- .type = QEMU_OPT_NUMBER,
31
- .help = "UID value to use when talking to the server",
32
- },
33
- {
34
- .name = "group",
35
- .type = QEMU_OPT_NUMBER,
36
- .help = "GID value to use when talking to the server",
37
- },
38
- {
39
- .name = "tcp-syn-count",
40
- .type = QEMU_OPT_NUMBER,
41
- .help = "Number of SYNs to send during the session establish",
42
- },
43
- {
44
- .name = "readahead-size",
45
- .type = QEMU_OPT_NUMBER,
46
- .help = "Set the readahead size in bytes",
47
- },
48
- {
49
- .name = "page-cache-size",
50
- .type = QEMU_OPT_NUMBER,
51
- .help = "Set the pagecache size in bytes",
52
- },
53
- {
54
- .name = "debug",
55
- .type = QEMU_OPT_NUMBER,
56
- .help = "Set the NFS debug level (max 2)",
57
- },
58
- { /* end of list */ }
59
- },
60
-};
61
-
62
static void nfs_detach_aio_context(BlockDriverState *bs)
33
{
63
{
34
Coroutine *co;
64
NFSClient *client = bs->opaque;
35
- int64_t n;
65
@@ -XXX,XX +XXX,XX @@ static void nfs_file_close(BlockDriverState *bs)
36
- int64_t map;
66
nfs_client_close(client);
37
BdrvCoBlockStatusData data = {
38
.bs = bs,
39
.base = base,
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);
55
}
56
- if (data.ret < 0) {
57
- *pnum = 0;
58
- return data.ret;
59
- }
60
- assert(QEMU_IS_ALIGNED(n | map, BDRV_SECTOR_SIZE));
61
- *pnum = n >> BDRV_SECTOR_BITS;
62
- return data.ret | map;
63
+ return data.ret;
64
}
67
}
65
68
66
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
69
-static NFSServer *nfs_config(QDict *options, Error **errp)
67
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs,
70
-{
68
int nb_sectors, int *pnum,
71
- NFSServer *server = NULL;
69
BlockDriverState **file)
72
- QDict *addr = NULL;
73
- QObject *crumpled_addr = NULL;
74
- Visitor *iv = NULL;
75
- Error *local_error = NULL;
76
-
77
- qdict_extract_subqdict(options, &addr, "server.");
78
- if (!qdict_size(addr)) {
79
- error_setg(errp, "NFS server address missing");
80
- goto out;
81
- }
82
-
83
- crumpled_addr = qdict_crumple(addr, errp);
84
- if (!crumpled_addr) {
85
- goto out;
86
- }
87
-
88
- /*
89
- * Caution: this works only because all scalar members of
90
- * NFSServer are QString in @crumpled_addr. The visitor expects
91
- * @crumpled_addr to be typed according to the QAPI schema. It
92
- * is when @options come from -blockdev or blockdev_add. But when
93
- * they come from -drive, they're all QString.
94
- */
95
- iv = qobject_input_visitor_new(crumpled_addr);
96
- visit_type_NFSServer(iv, NULL, &server, &local_error);
97
- if (local_error) {
98
- error_propagate(errp, local_error);
99
- goto out;
100
- }
101
-
102
-out:
103
- QDECREF(addr);
104
- qobject_decref(crumpled_addr);
105
- visit_free(iv);
106
- return server;
107
-}
108
-
109
-
110
-static int64_t nfs_client_open(NFSClient *client, QDict *options,
111
+static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts,
112
int flags, int open_flags, Error **errp)
70
{
113
{
71
- return bdrv_common_block_status_above(bs, base, true, sector_num,
114
int64_t ret = -EINVAL;
72
- nb_sectors, pnum, file);
115
- QemuOpts *opts = NULL;
73
+ int64_t ret;
116
- Error *local_err = NULL;
74
+ int64_t n;
117
struct stat st;
75
+ int64_t map;
118
char *file = NULL, *strp = NULL;
76
+
119
77
+ ret = bdrv_common_block_status_above(bs, base, true,
120
qemu_mutex_init(&client->mutex);
78
+ sector_num * BDRV_SECTOR_SIZE,
121
- opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
79
+ nb_sectors * BDRV_SECTOR_SIZE,
122
- qemu_opts_absorb_qdict(opts, options, &local_err);
80
+ &n, &map, file);
123
- if (local_err) {
81
+ if (ret < 0) {
124
- error_propagate(errp, local_err);
82
+ *pnum = 0;
125
- ret = -EINVAL;
83
+ return ret;
126
- goto fail;
127
- }
128
129
- client->path = g_strdup(qemu_opt_get(opts, "path"));
130
- if (!client->path) {
131
- ret = -EINVAL;
132
- error_setg(errp, "No path was specified");
133
- goto fail;
134
- }
135
+ client->path = g_strdup(opts->path);
136
137
strp = strrchr(client->path, '/');
138
if (strp == NULL) {
139
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
140
file = g_strdup(strp);
141
*strp = 0;
142
143
- /* Pop the config into our state object, Exit if invalid */
144
- client->server = nfs_config(options, errp);
145
- if (!client->server) {
146
- ret = -EINVAL;
147
- goto fail;
148
- }
149
+ /* Steal the NFSServer object from opts; set the original pointer to NULL
150
+ * to avoid use after free and double free. */
151
+ client->server = opts->server;
152
+ opts->server = NULL;
153
154
client->context = nfs_init_context();
155
if (client->context == NULL) {
156
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
157
goto fail;
158
}
159
160
- if (qemu_opt_get(opts, "user")) {
161
- client->uid = qemu_opt_get_number(opts, "user", 0);
162
+ if (opts->has_user) {
163
+ client->uid = opts->user;
164
nfs_set_uid(client->context, client->uid);
165
}
166
167
- if (qemu_opt_get(opts, "group")) {
168
- client->gid = qemu_opt_get_number(opts, "group", 0);
169
+ if (opts->has_group) {
170
+ client->gid = opts->group;
171
nfs_set_gid(client->context, client->gid);
172
}
173
174
- if (qemu_opt_get(opts, "tcp-syn-count")) {
175
- client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
176
+ if (opts->has_tcp_syn_count) {
177
+ client->tcp_syncnt = opts->tcp_syn_count;
178
nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
179
}
180
181
#ifdef LIBNFS_FEATURE_READAHEAD
182
- if (qemu_opt_get(opts, "readahead-size")) {
183
+ if (opts->has_readahead_size) {
184
if (open_flags & BDRV_O_NOCACHE) {
185
error_setg(errp, "Cannot enable NFS readahead "
186
"if cache.direct = on");
187
goto fail;
188
}
189
- client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
190
+ client->readahead = opts->readahead_size;
191
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
192
warn_report("Truncating NFS readahead size to %d",
193
QEMU_NFS_MAX_READAHEAD_SIZE);
194
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
195
#endif
196
197
#ifdef LIBNFS_FEATURE_PAGECACHE
198
- if (qemu_opt_get(opts, "page-cache-size")) {
199
+ if (opts->has_page_cache_size) {
200
if (open_flags & BDRV_O_NOCACHE) {
201
error_setg(errp, "Cannot enable NFS pagecache "
202
"if cache.direct = on");
203
goto fail;
204
}
205
- client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
206
+ client->pagecache = opts->page_cache_size;
207
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
208
warn_report("Truncating NFS pagecache size to %d pages",
209
QEMU_NFS_MAX_PAGECACHE_SIZE);
210
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
211
#endif
212
213
#ifdef LIBNFS_FEATURE_DEBUG
214
- if (qemu_opt_get(opts, "debug")) {
215
- client->debug = qemu_opt_get_number(opts, "debug", 0);
216
+ if (opts->has_debug) {
217
+ client->debug = opts->debug;
218
/* limit the maximum debug level to avoid potential flooding
219
* of our log files. */
220
if (client->debug > QEMU_NFS_MAX_DEBUG_LEVEL) {
221
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
222
fail:
223
nfs_client_close(client);
224
out:
225
- qemu_opts_del(opts);
226
g_free(file);
227
return ret;
228
}
229
230
+static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
231
+ int flags, int open_flags, Error **errp)
232
+{
233
+ BlockdevOptionsNfs *opts = NULL;
234
+ QObject *crumpled = NULL;
235
+ Visitor *v;
236
+ Error *local_err = NULL;
237
+ int ret;
238
+
239
+ crumpled = qdict_crumple(options, errp);
240
+ if (crumpled == NULL) {
241
+ return -EINVAL;
84
+ }
242
+ }
85
+ assert(QEMU_IS_ALIGNED(n | map, BDRV_SECTOR_SIZE));
243
+
86
+ *pnum = n >> BDRV_SECTOR_BITS;
244
+ v = qobject_input_visitor_new_keyval(crumpled);
87
+ return ret | map;
245
+ visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
88
}
246
+ visit_free(v);
89
247
+
90
int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
248
+ if (local_err) {
91
@@ -XXX,XX +XXX,XX @@ int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
249
+ error_propagate(errp, local_err);
92
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
250
+ ret = -EINVAL;
93
int64_t bytes, int64_t *pnum)
251
+ goto fail;
94
{
252
+ }
95
- int64_t ret;
253
+
96
- int psectors;
254
+ ret = nfs_client_open(client, opts, flags, open_flags, errp);
97
+ int ret;
255
+fail:
98
+ int64_t dummy;
256
+ qobject_decref(crumpled);
99
257
+ qapi_free_BlockdevOptionsNfs(opts);
100
- assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
258
+ return ret;
101
- assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE) && bytes < INT_MAX);
259
+}
102
- ret = bdrv_common_block_status_above(bs, backing_bs(bs), false,
260
+
103
- offset >> BDRV_SECTOR_BITS,
261
static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
104
- bytes >> BDRV_SECTOR_BITS, &psectors,
262
Error **errp) {
105
+ ret = bdrv_common_block_status_above(bs, backing_bs(bs), false, offset,
263
NFSClient *client = bs->opaque;
106
+ bytes, pnum ? pnum : &dummy, NULL,
264
@@ -XXX,XX +XXX,XX @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
107
NULL);
265
266
client->aio_context = bdrv_get_aio_context(bs);
267
268
- ret = nfs_client_open(client, options,
269
- (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
270
- bs->open_flags, errp);
271
+ ret = nfs_client_open_qdict(client, options,
272
+ (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
273
+ bs->open_flags, errp);
108
if (ret < 0) {
274
if (ret < 0) {
109
return ret;
275
return ret;
110
}
276
}
111
- if (pnum) {
277
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
112
- *pnum = psectors * BDRV_SECTOR_SIZE;
278
goto out;
113
- }
279
}
114
return !!(ret & BDRV_BLOCK_ALLOCATED);
280
115
}
281
- ret = nfs_client_open(client, options, O_CREAT, 0, errp);
116
282
+ ret = nfs_client_open_qdict(client, options, O_CREAT, 0, errp);
283
if (ret < 0) {
284
goto out;
285
}
117
--
286
--
118
2.13.6
287
2.13.6
119
288
120
289
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
This adds the .bdrv_co_create driver callback to nfs, which enables
2
image creation over QMP.
2
3
3
We are gradually converting to byte-based interfaces, as they are
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
easier to reason about than sector-based. Convert another internal
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
function (no semantic change); and as with its public counterpart,
6
---
6
rename to bdrv_co_block_status() and split the offset return, to
7
qapi/block-core.json | 16 ++++++++++-
7
make the compiler enforce that we catch all uses. For now, we
8
block/nfs.c | 76 +++++++++++++++++++++++++++++++++++++++++-----------
8
assert that callers and the return value still use aligned data,
9
2 files changed, 75 insertions(+), 17 deletions(-)
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
10
15
Note that we are now prepared to accepts 'bytes' larger than INT_MAX;
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
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>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
---
27
block/io.c | 124 ++++++++++++++++++++++++++++++++++++++++---------------------
28
1 file changed, 81 insertions(+), 43 deletions(-)
29
30
diff --git a/block/io.c b/block/io.c
31
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
32
--- a/block/io.c
13
--- a/qapi/block-core.json
33
+++ b/block/io.c
14
+++ b/qapi/block-core.json
34
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
15
@@ -XXX,XX +XXX,XX @@
35
* BDRV_BLOCK_ZERO where possible; otherwise, the result may omit those
16
'*preallocation': 'PreallocMode' } }
36
* bits particularly if it allows for a larger value in 'pnum'.
17
37
*
18
##
38
- * If 'sector_num' is beyond the end of the disk image the return value is
19
+# @BlockdevCreateOptionsNfs:
39
+ * If 'offset' is beyond the end of the disk image the return value is
20
+#
40
* BDRV_BLOCK_EOF and 'pnum' is set to 0.
21
+# Driver specific image creation options for NFS.
41
*
22
+#
42
- * 'pnum' is set to the number of sectors (including and immediately following
23
+# @location Where to store the new image file
43
- * the specified sector) that are known to be in the same
24
+# @size Size of the virtual disk in bytes
44
- * allocated/unallocated state.
25
+#
45
- *
26
+# Since: 2.12
46
- * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
27
+##
47
+ * 'bytes' is the max value 'pnum' should be set to. If bytes goes
28
+{ 'struct': 'BlockdevCreateOptionsNfs',
48
* beyond the end of the disk image it will be clamped; if 'pnum' is set to
29
+ 'data': { 'location': 'BlockdevOptionsNfs',
49
* the end of the image, then the returned value will include BDRV_BLOCK_EOF.
30
+ 'size': 'size' } }
50
*
31
+
51
- * If returned value is positive, BDRV_BLOCK_OFFSET_VALID bit is set, and
32
+##
52
- * 'file' is non-NULL, then '*file' points to the BDS which the sector range
33
# @BlockdevQcow2Version:
53
- * is allocated in.
34
#
54
+ * 'pnum' is set to the number of bytes (including and immediately
35
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
55
+ * following the specified offset) that are easily known to be in the
36
@@ -XXX,XX +XXX,XX @@
56
+ * same allocated/unallocated state. Note that a second call starting
37
'iscsi': 'BlockdevCreateNotSupported',
57
+ * at the original offset plus returned pnum may have the same status.
38
'luks': 'BlockdevCreateNotSupported',
58
+ * The returned value is non-zero on success except at end-of-file.
39
'nbd': 'BlockdevCreateNotSupported',
59
+ *
40
- 'nfs': 'BlockdevCreateNotSupported',
60
+ * Returns negative errno on failure. Otherwise, if the
41
+ 'nfs': 'BlockdevCreateOptionsNfs',
61
+ * BDRV_BLOCK_OFFSET_VALID bit is set, 'map' and 'file' (if non-NULL) are
42
'null-aio': 'BlockdevCreateNotSupported',
62
+ * set to the host mapping and BDS corresponding to the guest offset.
43
'null-co': 'BlockdevCreateNotSupported',
63
*/
44
'nvme': 'BlockdevCreateNotSupported',
64
-static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
45
diff --git a/block/nfs.c b/block/nfs.c
65
- bool want_zero,
46
index XXXXXXX..XXXXXXX 100644
66
- int64_t sector_num,
47
--- a/block/nfs.c
67
- int nb_sectors, int *pnum,
48
+++ b/block/nfs.c
68
- BlockDriverState **file)
49
@@ -XXX,XX +XXX,XX @@ out:
69
-{
50
return ret;
70
- int64_t total_sectors;
51
}
71
- int64_t n;
52
72
- int64_t ret, ret2;
53
-static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
73
+static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
54
- int flags, int open_flags, Error **errp)
74
+ bool want_zero,
55
+static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
75
+ int64_t offset, int64_t bytes,
56
+ Error **errp)
76
+ int64_t *pnum, int64_t *map,
57
{
77
+ BlockDriverState **file)
58
BlockdevOptionsNfs *opts = NULL;
59
QObject *crumpled = NULL;
60
Visitor *v;
61
Error *local_err = NULL;
62
- int ret;
63
64
crumpled = qdict_crumple(options, errp);
65
if (crumpled == NULL) {
66
- return -EINVAL;
67
+ return NULL;
68
}
69
70
v = qobject_input_visitor_new_keyval(crumpled);
71
visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
72
visit_free(v);
73
+ qobject_decref(crumpled);
74
75
if (local_err) {
76
- error_propagate(errp, local_err);
77
+ return NULL;
78
+ }
79
+
80
+ return opts;
81
+}
82
+
83
+static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
84
+ int flags, int open_flags, Error **errp)
78
+{
85
+{
79
+ int64_t total_size;
86
+ BlockdevOptionsNfs *opts;
80
+ int64_t n; /* bytes */
87
+ int ret;
81
+ int64_t ret;
88
+
82
+ int64_t local_map = 0;
89
+ opts = nfs_options_qdict_to_qapi(options, errp);
83
BlockDriverState *local_file = NULL;
90
+ if (opts == NULL) {
84
+ int count; /* sectors */
91
ret = -EINVAL;
85
92
goto fail;
86
assert(pnum);
87
*pnum = 0;
88
- total_sectors = bdrv_nb_sectors(bs);
89
- if (total_sectors < 0) {
90
- ret = total_sectors;
91
+ total_size = bdrv_getlength(bs);
92
+ if (total_size < 0) {
93
+ ret = total_size;
94
goto early_out;
95
}
93
}
96
94
97
- if (sector_num >= total_sectors) {
95
ret = nfs_client_open(client, opts, flags, open_flags, errp);
98
+ if (offset >= total_size) {
96
fail:
99
ret = BDRV_BLOCK_EOF;
97
- qobject_decref(crumpled);
100
goto early_out;
98
qapi_free_BlockdevOptionsNfs(opts);
99
return ret;
100
}
101
@@ -XXX,XX +XXX,XX @@ static QemuOptsList nfs_create_opts = {
101
}
102
}
102
- if (!nb_sectors) {
103
};
103
+ if (!bytes) {
104
104
ret = 0;
105
-static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
105
goto early_out;
106
- Error **errp)
106
}
107
+static int nfs_file_co_create(BlockdevCreateOptions *options, Error **errp)
107
108
{
108
- n = total_sectors - sector_num;
109
- int64_t ret, total_size;
109
- if (n < nb_sectors) {
110
+ BlockdevCreateOptionsNfs *opts = &options->u.nfs;
110
- nb_sectors = n;
111
NFSClient *client = g_new0(NFSClient, 1);
111
+ n = total_size - offset;
112
- QDict *options = NULL;
112
+ if (n < bytes) {
113
+ int ret;
113
+ bytes = n;
114
+
114
}
115
+ assert(options->driver == BLOCKDEV_DRIVER_NFS);
115
116
116
if (!bs->drv->bdrv_co_get_block_status) {
117
client->aio_context = qemu_get_aio_context();
117
- *pnum = nb_sectors;
118
118
+ *pnum = bytes;
119
+ ret = nfs_client_open(client, opts->location, O_CREAT, 0, errp);
119
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
120
+ if (ret < 0) {
120
- if (sector_num + nb_sectors == total_sectors) {
121
+ goto out;
121
+ if (offset + bytes == total_size) {
122
+ }
122
ret |= BDRV_BLOCK_EOF;
123
+ ret = nfs_ftruncate(client->context, client->fh, opts->size);
123
}
124
+ nfs_client_close(client);
124
if (bs->drv->protocol_name) {
125
+
125
- ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
126
+out:
126
+ ret |= BDRV_BLOCK_OFFSET_VALID;
127
+ g_free(client);
127
+ local_map = offset;
128
+ return ret;
128
local_file = bs;
129
+}
129
}
130
+
130
goto early_out;
131
+static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
131
}
132
+ Error **errp)
132
133
+{
133
bdrv_inc_in_flight(bs);
134
+ BlockdevCreateOptions *create_options;
134
- ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
135
+ BlockdevCreateOptionsNfs *nfs_opts;
135
+ /*
136
+ QDict *options;
136
+ * TODO: Rather than require aligned offsets, we could instead
137
+ int ret;
137
+ * round to the driver's request_alignment here, then touch up
138
+
138
+ * count afterwards back to the caller's expectations.
139
+ create_options = g_new0(BlockdevCreateOptions, 1);
139
+ */
140
+ create_options->driver = BLOCKDEV_DRIVER_NFS;
140
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
141
+ nfs_opts = &create_options->u.nfs;
141
+ /*
142
+
142
+ * The contract allows us to return pnum smaller than bytes, even
143
/* Read out options */
143
+ * if the next query would see the same status; we truncate the
144
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
144
+ * request to avoid overflowing the driver's 32-bit interface.
145
- BDRV_SECTOR_SIZE);
145
+ */
146
+ nfs_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
146
+ bytes = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
147
+ BDRV_SECTOR_SIZE);
147
+ ret = bs->drv->bdrv_co_get_block_status(bs, offset >> BDRV_SECTOR_BITS,
148
148
+ bytes >> BDRV_SECTOR_BITS, &count,
149
options = qdict_new();
149
&local_file);
150
ret = nfs_parse_uri(url, options, errp);
150
if (ret < 0) {
151
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
151
- *pnum = 0;
152
goto out;
152
goto out;
153
}
153
}
154
+ if (ret & BDRV_BLOCK_OFFSET_VALID) {
154
155
+ local_map = ret & BDRV_BLOCK_OFFSET_MASK;
155
- ret = nfs_client_open_qdict(client, options, O_CREAT, 0, errp);
156
+ nfs_opts->location = nfs_options_qdict_to_qapi(options, errp);
157
+ if (nfs_opts->location == NULL) {
158
+ ret = -EINVAL;
159
+ goto out;
156
+ }
160
+ }
157
+ *pnum = count * BDRV_SECTOR_SIZE;
161
+
158
162
+ ret = nfs_file_co_create(create_options, errp);
159
if (ret & BDRV_BLOCK_RAW) {
163
if (ret < 0) {
160
assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
161
- ret = bdrv_co_get_block_status(local_file, want_zero,
162
- ret >> BDRV_SECTOR_BITS,
163
- *pnum, pnum, &local_file);
164
+ ret = bdrv_co_block_status(local_file, want_zero, local_map,
165
+ *pnum, pnum, &local_map, &local_file);
166
+ assert(ret < 0 ||
167
+ QEMU_IS_ALIGNED(*pnum | local_map, BDRV_SECTOR_SIZE));
168
goto out;
164
goto out;
169
}
165
}
170
166
- ret = nfs_ftruncate(client->context, client->fh, total_size);
171
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
167
- nfs_client_close(client);
172
ret |= BDRV_BLOCK_ZERO;
168
+
173
} else if (bs->backing) {
169
+ ret = 0;
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:
170
out:
202
bdrv_dec_in_flight(bs);
171
QDECREF(options);
203
- if (ret >= 0 && sector_num + *pnum == total_sectors) {
172
- g_free(client);
204
+ if (ret >= 0 && offset + *pnum == total_size) {
173
+ qapi_free_BlockdevCreateOptions(create_options);
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;
216
+ } else {
217
+ assert(INT_MIN <= ret);
218
+ }
219
return ret;
174
return ret;
220
}
175
}
221
176
222
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
177
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
223
BlockDriverState *p;
178
224
int64_t ret = 0;
179
.bdrv_file_open = nfs_file_open,
225
bool first = true;
180
.bdrv_close = nfs_file_close,
226
+ int64_t map = 0;
181
+ .bdrv_co_create = nfs_file_co_create,
227
182
.bdrv_co_create_opts = nfs_file_co_create_opts,
228
assert(bs != base);
183
.bdrv_reopen_prepare = nfs_reopen_prepare,
229
for (p = bs; p != base; p = backing_bs(p)) {
184
230
- ret = bdrv_co_get_block_status(p, want_zero, sector_num, nb_sectors,
231
- pnum, file);
232
+ int64_t count;
233
+
234
+ ret = bdrv_co_block_status(p, want_zero,
235
+ sector_num * BDRV_SECTOR_SIZE,
236
+ nb_sectors * BDRV_SECTOR_SIZE, &count,
237
+ &map, file);
238
if (ret < 0) {
239
break;
240
}
241
+ assert(QEMU_IS_ALIGNED(count | map, BDRV_SECTOR_SIZE));
242
+ ret |= map;
243
+ *pnum = count >> BDRV_SECTOR_BITS;
244
if (ret & BDRV_BLOCK_ZERO && ret & BDRV_BLOCK_EOF && !first) {
245
/*
246
* Reading beyond the end of the file continues to read
247
--
185
--
248
2.13.6
186
2.13.6
249
187
250
188
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
The "redundancy" option for Sheepdog image creation is currently a
2
2
string that can encode one or two integers depending on its format,
3
In the continuing quest to make more things byte-based, change
3
which at the same time implicitly selects a mode.
4
compare_sectors(), renaming it to compare_buffers() in the
4
5
process. Note that one caller (qemu-img compare) only cares
5
This patch turns it into a QAPI union and converts the string into such
6
about the first difference, while the other (qemu-img rebase)
6
a QAPI object before interpreting the values.
7
cares about how many consecutive sectors have the same
7
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>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
---
10
---
18
qemu-img.c | 55 +++++++++++++++++++++++++++----------------------------
11
qapi/block-core.json | 45 +++++++++++++++++++++++++
19
1 file changed, 27 insertions(+), 28 deletions(-)
12
block/sheepdog.c | 94 +++++++++++++++++++++++++++++++++++++---------------
20
13
2 files changed, 112 insertions(+), 27 deletions(-)
21
diff --git a/qemu-img.c b/qemu-img.c
14
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
22
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
23
--- a/qemu-img.c
17
--- a/qapi/block-core.json
24
+++ b/qemu-img.c
18
+++ b/qapi/block-core.json
25
@@ -XXX,XX +XXX,XX @@ static int is_allocated_sectors_min(const uint8_t *buf, int n, int *pnum,
19
@@ -XXX,XX +XXX,XX @@
20
'*cluster-size' : 'size' } }
21
22
##
23
+# @SheepdogRedundancyType:
24
+#
25
+# @full Create a fully replicated vdi with x copies
26
+# @erasure-coded Create an erasure coded vdi with x data strips and
27
+# y parity strips
28
+#
29
+# Since: 2.12
30
+##
31
+{ 'enum': 'SheepdogRedundancyType',
32
+ 'data': [ 'full', 'erasure-coded' ] }
33
+
34
+##
35
+# @SheepdogRedundancyFull:
36
+#
37
+# @copies Number of copies to use (between 1 and 31)
38
+#
39
+# Since: 2.12
40
+##
41
+{ 'struct': 'SheepdogRedundancyFull',
42
+ 'data': { 'copies': 'int' }}
43
+
44
+##
45
+# @SheepdogRedundancyErasureCoded:
46
+#
47
+# @data-strips Number of data strips to use (one of {2,4,8,16})
48
+# @parity-strips Number of parity strips to use (between 1 and 15)
49
+#
50
+# Since: 2.12
51
+##
52
+{ 'struct': 'SheepdogRedundancyErasureCoded',
53
+ 'data': { 'data-strips': 'int',
54
+ 'parity-strips': 'int' }}
55
+
56
+##
57
+# @SheepdogRedundancy:
58
+#
59
+# Since: 2.12
60
+##
61
+{ 'union': 'SheepdogRedundancy',
62
+ 'base': { 'type': 'SheepdogRedundancyType' },
63
+ 'discriminator': 'type',
64
+ 'data': { 'full': 'SheepdogRedundancyFull',
65
+ 'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
66
+
67
+##
68
# @BlockdevCreateNotSupported:
69
#
70
# This is used for all drivers that don't support creating images.
71
diff --git a/block/sheepdog.c b/block/sheepdog.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/block/sheepdog.c
74
+++ b/block/sheepdog.c
75
@@ -XXX,XX +XXX,XX @@ out_with_err_set:
76
return ret;
26
}
77
}
27
78
79
+static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
80
+{
81
+ struct SheepdogInode *inode = &s->inode;
82
+
83
+ switch (opt->type) {
84
+ case SHEEPDOG_REDUNDANCY_TYPE_FULL:
85
+ if (opt->u.full.copies > SD_MAX_COPIES || opt->u.full.copies < 1) {
86
+ return -EINVAL;
87
+ }
88
+ inode->copy_policy = 0;
89
+ inode->nr_copies = opt->u.full.copies;
90
+ return 0;
91
+
92
+ case SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED:
93
+ {
94
+ int64_t copy = opt->u.erasure_coded.data_strips;
95
+ int64_t parity = opt->u.erasure_coded.parity_strips;
96
+
97
+ if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
98
+ return -EINVAL;
99
+ }
100
+
101
+ if (parity >= SD_EC_MAX_STRIP || parity < 1) {
102
+ return -EINVAL;
103
+ }
104
+
105
+ /*
106
+ * 4 bits for parity and 4 bits for data.
107
+ * We have to compress upper data bits because it can't represent 16
108
+ */
109
+ inode->copy_policy = ((copy / 2) << 4) + parity;
110
+ inode->nr_copies = copy + parity;
111
+ return 0;
112
+ }
113
+
114
+ default:
115
+ g_assert_not_reached();
116
+ }
117
+
118
+ return -EINVAL;
119
+}
120
+
28
/*
121
/*
29
- * Compares two buffers sector by sector. Returns 0 if the first sector of both
122
* Sheepdog support two kinds of redundancy, full replication and erasure
30
- * buffers matches, non-zero otherwise.
123
* coding.
31
+ * Compares two buffers sector by sector. Returns 0 if the first
124
@@ -XXX,XX +XXX,XX @@ out_with_err_set:
32
+ * sector of each buffer matches, non-zero otherwise.
125
* # create a erasure coded vdi with x data strips and y parity strips
33
*
126
* -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
34
- * pnum is set to the number of sectors (including and immediately following
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
*/
127
*/
39
-static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
128
-static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
40
- int *pnum)
129
+static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
41
+static int compare_buffers(const uint8_t *buf1, const uint8_t *buf2,
42
+ int64_t bytes, int64_t *pnum)
43
{
130
{
44
bool res;
131
- struct SheepdogInode *inode = &s->inode;
45
- int i;
132
+ struct SheepdogRedundancy redundancy;
46
+ int64_t i = MIN(bytes, BDRV_SECTOR_SIZE);
133
const char *n1, *n2;
47
134
long copy, parity;
48
- if (n <= 0) {
135
char p[10];
49
- *pnum = 0;
136
+ int ret;
137
138
pstrcpy(p, sizeof(p), opt);
139
n1 = strtok(p, ":");
140
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
141
return -EINVAL;
142
}
143
144
- copy = strtol(n1, NULL, 10);
145
- /* FIXME fix error checking by switching to qemu_strtol() */
146
- if (copy > SD_MAX_COPIES || copy < 1) {
147
- return -EINVAL;
148
- }
149
- if (!n2) {
150
- inode->copy_policy = 0;
151
- inode->nr_copies = copy;
50
- return 0;
152
- return 0;
153
+ ret = qemu_strtol(n1, NULL, 10, &copy);
154
+ if (ret < 0) {
155
+ return ret;
156
}
157
158
- if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
159
- return -EINVAL;
51
- }
160
- }
52
+ assert(bytes > 0);
161
+ if (!n2) {
53
162
+ redundancy = (SheepdogRedundancy) {
54
- res = !!memcmp(buf1, buf2, 512);
163
+ .type = SHEEPDOG_REDUNDANCY_TYPE_FULL,
55
- for(i = 1; i < n; i++) {
164
+ .u.full.copies = copy,
56
- buf1 += 512;
165
+ };
57
- buf2 += 512;
166
+ } else {
58
+ res = !!memcmp(buf1, buf2, i);
167
+ ret = qemu_strtol(n2, NULL, 10, &parity);
59
+ while (i < bytes) {
168
+ if (ret < 0) {
60
+ int64_t len = MIN(bytes - i, BDRV_SECTOR_SIZE);
169
+ return ret;
61
170
+ }
62
- if (!!memcmp(buf1, buf2, 512) != res) {
171
63
+ if (!!memcmp(buf1 + i, buf2 + i, len) != res) {
172
- parity = strtol(n2, NULL, 10);
64
break;
173
- /* FIXME fix error checking by switching to qemu_strtol() */
65
}
174
- if (parity >= SD_EC_MAX_STRIP || parity < 1) {
66
+ i += len;
175
- return -EINVAL;
176
+ redundancy = (SheepdogRedundancy) {
177
+ .type = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED,
178
+ .u.erasure_coded = {
179
+ .data_strips = copy,
180
+ .parity_strips = parity,
181
+ },
182
+ };
67
}
183
}
68
184
69
*pnum = i;
185
- /*
70
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
186
- * 4 bits for parity and 4 bits for data.
71
int64_t total_sectors;
187
- * We have to compress upper data bits because it can't represent 16
72
int64_t sector_num = 0;
188
- */
73
int64_t nb_sectors;
189
- inode->copy_policy = ((copy / 2) << 4) + parity;
74
- int c, pnum;
190
- inode->nr_copies = copy + parity;
75
+ int c;
191
-
76
uint64_t progress_base;
192
- return 0;
77
bool image_opts = false;
193
+ return parse_redundancy(s, &redundancy);
78
bool force_share = false;
194
}
79
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
195
80
/* nothing to do */
196
static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
81
} else if (allocated1 == allocated2) {
197
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
82
if (allocated1) {
198
g_free(buf);
83
+ int64_t pnum;
199
buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
84
+
200
if (buf) {
85
nb_sectors = MIN(nb_sectors, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
201
- ret = parse_redundancy(s, buf);
86
ret = blk_pread(blk1, sector_num << BDRV_SECTOR_BITS, buf1,
202
+ ret = parse_redundancy_str(s, buf);
87
nb_sectors << BDRV_SECTOR_BITS);
203
if (ret < 0) {
88
@@ -XXX,XX +XXX,XX @@ static int img_compare(int argc, char **argv)
204
error_setg(errp, "Invalid redundancy mode: '%s'", buf);
89
ret = 4;
205
goto out;
90
goto out;
91
}
92
- ret = compare_sectors(buf1, buf2, nb_sectors, &pnum);
93
- if (ret || pnum != nb_sectors) {
94
+ ret = compare_buffers(buf1, buf2,
95
+ nb_sectors * BDRV_SECTOR_SIZE, &pnum);
96
+ if (ret || pnum != nb_sectors * BDRV_SECTOR_SIZE) {
97
qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
98
- sectors_to_bytes(
99
- ret ? sector_num : sector_num + pnum));
100
+ sectors_to_bytes(sector_num) + (ret ? 0 : pnum));
101
ret = 1;
102
goto out;
103
}
104
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
105
/* If they differ, we need to write to the COW file */
106
uint64_t written = 0;
107
108
- while (written < n) {
109
- int pnum;
110
+ while (written < n * BDRV_SECTOR_SIZE) {
111
+ int64_t pnum;
112
113
- if (compare_sectors(buf_old + written * 512,
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));
128
--
206
--
129
2.13.6
207
2.13.6
130
208
131
209
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
This adds the .bdrv_co_create driver callback to sheepdog, which enables
2
image creation over QMP.
2
3
3
Tests 067 and 087 filter the actual image size because it depends on the
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
host filesystem (and is not part of the respective test). Since this is
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
generally true, we should have a common filter function for this, so
6
---
6
let's pull out the sed line from both tests into such a function.
7
qapi/block-core.json | 24 ++++-
8
block/sheepdog.c | 243 +++++++++++++++++++++++++++++++++++----------------
9
2 files changed, 192 insertions(+), 75 deletions(-)
7
10
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
9
Message-id: 20171009163456.485-2-mreitz@redhat.com
12
index XXXXXXX..XXXXXXX 100644
10
Reviewed-by: Eric Blake <eblake@redhat.com>
13
--- a/qapi/block-core.json
11
Reviewed-by: Jeff Cody <jcody@redhat.com>
14
+++ b/qapi/block-core.json
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
@@ -XXX,XX +XXX,XX @@
13
---
16
'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
14
tests/qemu-iotests/067 | 2 +-
17
15
tests/qemu-iotests/087 | 2 +-
18
##
16
tests/qemu-iotests/common.filter | 6 ++++++
19
+# @BlockdevCreateOptionsSheepdog:
17
3 files changed, 8 insertions(+), 2 deletions(-)
20
+#
18
21
+# Driver specific image creation options for Sheepdog.
19
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
22
+#
20
index XXXXXXX..XXXXXXX 100755
23
+# @location Where to store the new image file
21
--- a/tests/qemu-iotests/067
24
+# @size Size of the virtual disk in bytes
22
+++ b/tests/qemu-iotests/067
25
+# @backing-file File name of a base image
23
@@ -XXX,XX +XXX,XX @@ _filter_qmp_events()
26
+# @preallocation Preallocation mode (allowed values: off, full)
24
function run_qemu()
27
+# @redundancy Redundancy of the image
25
{
28
+# @object-size Object size of the image
26
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \
29
+#
27
- | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' \
30
+# Since: 2.12
28
+ | _filter_actual_image_size \
31
+##
29
| _filter_generated_node_ids | _filter_qmp_events
32
+{ 'struct': 'BlockdevCreateOptionsSheepdog',
33
+ 'data': { 'location': 'BlockdevOptionsSheepdog',
34
+ 'size': 'size',
35
+ '*backing-file': 'str',
36
+ '*preallocation': 'PreallocMode',
37
+ '*redundancy': 'SheepdogRedundancy',
38
+ '*object-size': 'size' } }
39
+
40
+##
41
# @BlockdevCreateNotSupported:
42
#
43
# This is used for all drivers that don't support creating images.
44
@@ -XXX,XX +XXX,XX @@
45
'raw': 'BlockdevCreateNotSupported',
46
'rbd': 'BlockdevCreateOptionsRbd',
47
'replication': 'BlockdevCreateNotSupported',
48
- 'sheepdog': 'BlockdevCreateNotSupported',
49
+ 'sheepdog': 'BlockdevCreateOptionsSheepdog',
50
'ssh': 'BlockdevCreateNotSupported',
51
'throttle': 'BlockdevCreateNotSupported',
52
'vdi': 'BlockdevCreateNotSupported',
53
diff --git a/block/sheepdog.c b/block/sheepdog.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/sheepdog.c
56
+++ b/block/sheepdog.c
57
@@ -XXX,XX +XXX,XX @@
58
#include "qemu/osdep.h"
59
#include "qapi/error.h"
60
#include "qapi/qapi-visit-sockets.h"
61
+#include "qapi/qapi-visit-block-core.h"
62
#include "qapi/qmp/qdict.h"
63
#include "qapi/qobject-input-visitor.h"
64
+#include "qapi/qobject-output-visitor.h"
65
#include "qemu/uri.h"
66
#include "qemu/error-report.h"
67
#include "qemu/option.h"
68
@@ -XXX,XX +XXX,XX @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
69
qemu_co_mutex_unlock(&s->queue_lock);
30
}
70
}
31
71
32
diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
72
-static SocketAddress *sd_socket_address(const char *path,
33
index XXXXXXX..XXXXXXX 100755
73
- const char *host, const char *port)
34
--- a/tests/qemu-iotests/087
74
-{
35
+++ b/tests/qemu-iotests/087
75
- SocketAddress *addr = g_new0(SocketAddress, 1);
36
@@ -XXX,XX +XXX,XX @@ function run_qemu()
76
-
37
{
77
- if (path) {
38
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
78
- addr->type = SOCKET_ADDRESS_TYPE_UNIX;
39
| _filter_qemu | _filter_imgfmt \
79
- addr->u.q_unix.path = g_strdup(path);
40
- | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
80
- } else {
41
+ | _filter_actual_image_size
81
- addr->type = SOCKET_ADDRESS_TYPE_INET;
82
- addr->u.inet.host = g_strdup(host ?: SD_DEFAULT_ADDR);
83
- addr->u.inet.port = g_strdup(port ?: stringify(SD_DEFAULT_PORT));
84
- }
85
-
86
- return addr;
87
-}
88
-
89
static SocketAddress *sd_server_config(QDict *options, Error **errp)
90
{
91
QDict *server = NULL;
92
@@ -XXX,XX +XXX,XX @@ out_with_err_set:
93
return ret;
42
}
94
}
43
95
44
size=128M
96
+static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size,
45
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
97
+ Error **errp)
46
index XXXXXXX..XXXXXXX 100644
98
+{
47
--- a/tests/qemu-iotests/common.filter
99
+ BlockDriverState *bs;
48
+++ b/tests/qemu-iotests/common.filter
100
+ Visitor *v;
49
@@ -XXX,XX +XXX,XX @@ _filter_block_job_len()
101
+ QObject *obj = NULL;
50
sed -e 's/, "len": [0-9]\+,/, "len": LEN,/g'
102
+ QDict *qdict;
103
+ Error *local_err = NULL;
104
+ int ret;
105
+
106
+ v = qobject_output_visitor_new(&obj);
107
+ visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &local_err);
108
+ visit_free(v);
109
+
110
+ if (local_err) {
111
+ error_propagate(errp, local_err);
112
+ qobject_decref(obj);
113
+ return -EINVAL;
114
+ }
115
+
116
+ qdict = qobject_to_qdict(obj);
117
+ qdict_flatten(qdict);
118
+
119
+ qdict_put_str(qdict, "driver", "sheepdog");
120
+
121
+ bs = bdrv_open(NULL, NULL, qdict, BDRV_O_PROTOCOL | BDRV_O_RDWR, errp);
122
+ if (bs == NULL) {
123
+ ret = -EIO;
124
+ goto fail;
125
+ }
126
+
127
+ ret = sd_prealloc(bs, 0, size, errp);
128
+fail:
129
+ bdrv_unref(bs);
130
+ QDECREF(qdict);
131
+ return ret;
132
+}
133
+
134
static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
135
{
136
struct SheepdogInode *inode = &s->inode;
137
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
138
* # create a erasure coded vdi with x data strips and y parity strips
139
* -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
140
*/
141
-static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
142
+static SheepdogRedundancy *parse_redundancy_str(const char *opt)
143
{
144
- struct SheepdogRedundancy redundancy;
145
+ SheepdogRedundancy *redundancy;
146
const char *n1, *n2;
147
long copy, parity;
148
char p[10];
149
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
150
n2 = strtok(NULL, ":");
151
152
if (!n1) {
153
- return -EINVAL;
154
+ return NULL;
155
}
156
157
ret = qemu_strtol(n1, NULL, 10, &copy);
158
if (ret < 0) {
159
- return ret;
160
+ return NULL;
161
}
162
163
+ redundancy = g_new0(SheepdogRedundancy, 1);
164
if (!n2) {
165
- redundancy = (SheepdogRedundancy) {
166
+ *redundancy = (SheepdogRedundancy) {
167
.type = SHEEPDOG_REDUNDANCY_TYPE_FULL,
168
.u.full.copies = copy,
169
};
170
} else {
171
ret = qemu_strtol(n2, NULL, 10, &parity);
172
if (ret < 0) {
173
- return ret;
174
+ return NULL;
175
}
176
177
- redundancy = (SheepdogRedundancy) {
178
+ *redundancy = (SheepdogRedundancy) {
179
.type = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED,
180
.u.erasure_coded = {
181
.data_strips = copy,
182
@@ -XXX,XX +XXX,XX @@ static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
183
};
184
}
185
186
- return parse_redundancy(s, &redundancy);
187
+ return redundancy;
51
}
188
}
52
189
53
+# replace actual image size (depends on the host filesystem)
190
-static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
54
+_filter_actual_image_size()
191
+static int parse_block_size_shift(BDRVSheepdogState *s,
192
+ BlockdevCreateOptionsSheepdog *opts)
193
{
194
struct SheepdogInode *inode = &s->inode;
195
uint64_t object_size;
196
int obj_order;
197
198
- object_size = qemu_opt_get_size_del(opt, BLOCK_OPT_OBJECT_SIZE, 0);
199
- if (object_size) {
200
+ if (opts->has_object_size) {
201
+ object_size = opts->object_size;
202
+
203
if ((object_size - 1) & object_size) { /* not a power of 2? */
204
return -EINVAL;
205
}
206
@@ -XXX,XX +XXX,XX @@ static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
207
return 0;
208
}
209
210
-static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
211
- Error **errp)
212
+static int sd_co_create(BlockdevCreateOptions *options, Error **errp)
213
{
214
- Error *err = NULL;
215
+ BlockdevCreateOptionsSheepdog *opts = &options->u.sheepdog;
216
int ret = 0;
217
uint32_t vid = 0;
218
char *backing_file = NULL;
219
char *buf = NULL;
220
BDRVSheepdogState *s;
221
- SheepdogConfig cfg;
222
uint64_t max_vdi_size;
223
bool prealloc = false;
224
225
+ assert(options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
226
+
227
s = g_new0(BDRVSheepdogState, 1);
228
229
- if (strstr(filename, "://")) {
230
- sd_parse_uri(&cfg, filename, &err);
231
- } else {
232
- parse_vdiname(&cfg, filename, &err);
233
- }
234
- if (err) {
235
- error_propagate(errp, err);
236
+ /* Steal SocketAddress from QAPI, set NULL to prevent double free */
237
+ s->addr = opts->location->server;
238
+ opts->location->server = NULL;
239
+
240
+ if (strlen(opts->location->vdi) >= sizeof(s->name)) {
241
+ error_setg(errp, "'vdi' string too long");
242
+ ret = -EINVAL;
243
goto out;
244
}
245
+ pstrcpy(s->name, sizeof(s->name), opts->location->vdi);
246
247
- buf = cfg.port ? g_strdup_printf("%d", cfg.port) : NULL;
248
- s->addr = sd_socket_address(cfg.path, cfg.host, buf);
249
- g_free(buf);
250
- strcpy(s->name, cfg.vdi);
251
- sd_config_done(&cfg);
252
+ s->inode.vdi_size = opts->size;
253
+ backing_file = opts->backing_file;
254
255
- s->inode.vdi_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
256
- BDRV_SECTOR_SIZE);
257
- backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
258
- buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
259
- if (!buf || !strcmp(buf, "off")) {
260
+ if (!opts->has_preallocation) {
261
+ opts->preallocation = PREALLOC_MODE_OFF;
262
+ }
263
+ switch (opts->preallocation) {
264
+ case PREALLOC_MODE_OFF:
265
prealloc = false;
266
- } else if (!strcmp(buf, "full")) {
267
+ break;
268
+ case PREALLOC_MODE_FULL:
269
prealloc = true;
270
- } else {
271
- error_setg(errp, "Invalid preallocation mode: '%s'", buf);
272
+ break;
273
+ default:
274
+ error_setg(errp, "Preallocation mode not supported for Sheepdog");
275
ret = -EINVAL;
276
goto out;
277
}
278
279
- g_free(buf);
280
- buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
281
- if (buf) {
282
- ret = parse_redundancy_str(s, buf);
283
+ if (opts->has_redundancy) {
284
+ ret = parse_redundancy(s, opts->redundancy);
285
if (ret < 0) {
286
- error_setg(errp, "Invalid redundancy mode: '%s'", buf);
287
+ error_setg(errp, "Invalid redundancy mode");
288
goto out;
289
}
290
}
291
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
292
goto out;
293
}
294
295
- if (backing_file) {
296
+ if (opts->has_backing_file) {
297
BlockBackend *blk;
298
BDRVSheepdogState *base;
299
BlockDriver *drv;
300
301
/* Currently, only Sheepdog backing image is supported. */
302
- drv = bdrv_find_protocol(backing_file, true, NULL);
303
+ drv = bdrv_find_protocol(opts->backing_file, true, NULL);
304
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
305
error_setg(errp, "backing_file must be a sheepdog image");
306
ret = -EINVAL;
307
goto out;
308
}
309
310
- blk = blk_new_open(backing_file, NULL, NULL,
311
+ blk = blk_new_open(opts->backing_file, NULL, NULL,
312
BDRV_O_PROTOCOL, errp);
313
if (blk == NULL) {
314
ret = -EIO;
315
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
316
}
317
318
if (prealloc) {
319
- BlockDriverState *bs;
320
- QDict *opts;
321
-
322
- opts = qdict_new();
323
- qdict_put_str(opts, "driver", "sheepdog");
324
- bs = bdrv_open(filename, NULL, opts, BDRV_O_PROTOCOL | BDRV_O_RDWR,
325
- errp);
326
- if (!bs) {
327
- goto out;
328
- }
329
-
330
- ret = sd_prealloc(bs, 0, s->inode.vdi_size, errp);
331
-
332
- bdrv_unref(bs);
333
+ ret = sd_create_prealloc(opts->location, opts->size, errp);
334
}
335
out:
336
g_free(backing_file);
337
g_free(buf);
338
+ g_free(s->addr);
339
g_free(s);
340
return ret;
341
}
342
343
+static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
344
+ Error **errp)
55
+{
345
+{
56
+ sed -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
346
+ BlockdevCreateOptions *create_options = NULL;
347
+ QDict *qdict, *location_qdict;
348
+ QObject *crumpled;
349
+ Visitor *v;
350
+ const char *redundancy;
351
+ Error *local_err = NULL;
352
+ int ret;
353
+
354
+ redundancy = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
355
+
356
+ qdict = qemu_opts_to_qdict(opts, NULL);
357
+ qdict_put_str(qdict, "driver", "sheepdog");
358
+
359
+ location_qdict = qdict_new();
360
+ qdict_put(qdict, "location", location_qdict);
361
+
362
+ sd_parse_filename(filename, location_qdict, &local_err);
363
+ if (local_err) {
364
+ error_propagate(errp, local_err);
365
+ ret = -EINVAL;
366
+ goto fail;
367
+ }
368
+
369
+ qdict_flatten(qdict);
370
+
371
+ /* Change legacy command line options into QMP ones */
372
+ static const QDictRenames opt_renames[] = {
373
+ { BLOCK_OPT_BACKING_FILE, "backing-file" },
374
+ { BLOCK_OPT_OBJECT_SIZE, "object-size" },
375
+ { NULL, NULL },
376
+ };
377
+
378
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
379
+ ret = -EINVAL;
380
+ goto fail;
381
+ }
382
+
383
+ /* Get the QAPI object */
384
+ crumpled = qdict_crumple(qdict, errp);
385
+ if (crumpled == NULL) {
386
+ ret = -EINVAL;
387
+ goto fail;
388
+ }
389
+
390
+ v = qobject_input_visitor_new_keyval(crumpled);
391
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
392
+ visit_free(v);
393
+ qobject_decref(crumpled);
394
+
395
+ if (local_err) {
396
+ error_propagate(errp, local_err);
397
+ ret = -EINVAL;
398
+ goto fail;
399
+ }
400
+
401
+ assert(create_options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
402
+ create_options->u.sheepdog.size =
403
+ ROUND_UP(create_options->u.sheepdog.size, BDRV_SECTOR_SIZE);
404
+
405
+ if (redundancy) {
406
+ create_options->u.sheepdog.has_redundancy = true;
407
+ create_options->u.sheepdog.redundancy =
408
+ parse_redundancy_str(redundancy);
409
+ if (create_options->u.sheepdog.redundancy == NULL) {
410
+ error_setg(errp, "Invalid redundancy mode");
411
+ ret = -EINVAL;
412
+ goto fail;
413
+ }
414
+ }
415
+
416
+ ret = sd_co_create(create_options, errp);
417
+fail:
418
+ qapi_free_BlockdevCreateOptions(create_options);
419
+ QDECREF(qdict);
420
+ return ret;
57
+}
421
+}
58
+
422
+
59
# replace driver-specific options in the "Formatting..." line
423
static void sd_close(BlockDriverState *bs)
60
_filter_img_create()
424
{
61
{
425
Error *local_err = NULL;
426
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog = {
427
.bdrv_reopen_commit = sd_reopen_commit,
428
.bdrv_reopen_abort = sd_reopen_abort,
429
.bdrv_close = sd_close,
430
+ .bdrv_co_create = sd_co_create,
431
.bdrv_co_create_opts = sd_co_create_opts,
432
.bdrv_has_zero_init = bdrv_has_zero_init_1,
433
.bdrv_getlength = sd_getlength,
434
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_tcp = {
435
.bdrv_reopen_commit = sd_reopen_commit,
436
.bdrv_reopen_abort = sd_reopen_abort,
437
.bdrv_close = sd_close,
438
+ .bdrv_co_create = sd_co_create,
439
.bdrv_co_create_opts = sd_co_create_opts,
440
.bdrv_has_zero_init = bdrv_has_zero_init_1,
441
.bdrv_getlength = sd_getlength,
442
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog_unix = {
443
.bdrv_reopen_commit = sd_reopen_commit,
444
.bdrv_reopen_abort = sd_reopen_abort,
445
.bdrv_close = sd_close,
446
+ .bdrv_co_create = sd_co_create,
447
.bdrv_co_create_opts = sd_co_create_opts,
448
.bdrv_has_zero_init = bdrv_has_zero_init_1,
449
.bdrv_getlength = sd_getlength,
62
--
450
--
63
2.13.6
451
2.13.6
64
452
65
453
diff view generated by jsdifflib
New patch
1
1
Create a BlockdevOptionsSsh object in connect_to_ssh() and take the
2
options from there. 'host_key_check' is still processed separately
3
because it's not in the schema yet.
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
8
block/ssh.c | 137 +++++++++++++++++++++++++++---------------------------------
9
1 file changed, 62 insertions(+), 75 deletions(-)
10
11
diff --git a/block/ssh.c b/block/ssh.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/ssh.c
14
+++ b/block/ssh.c
15
@@ -XXX,XX +XXX,XX @@
16
#include "qemu/sockets.h"
17
#include "qemu/uri.h"
18
#include "qapi/qapi-visit-sockets.h"
19
+#include "qapi/qapi-visit-block-core.h"
20
#include "qapi/qmp/qdict.h"
21
#include "qapi/qmp/qstring.h"
22
#include "qapi/qobject-input-visitor.h"
23
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_runtime_opts = {
24
.type = QEMU_OPT_NUMBER,
25
.help = "Port to connect to",
26
},
27
- {
28
- .name = "path",
29
- .type = QEMU_OPT_STRING,
30
- .help = "Path of the image on the host",
31
- },
32
- {
33
- .name = "user",
34
- .type = QEMU_OPT_STRING,
35
- .help = "User as which to connect",
36
- },
37
- {
38
- .name = "host_key_check",
39
- .type = QEMU_OPT_STRING,
40
- .help = "Defines how and what to check the host key against",
41
- },
42
{ /* end of list */ }
43
},
44
};
45
@@ -XXX,XX +XXX,XX @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
46
return true;
47
}
48
49
-static InetSocketAddress *ssh_config(QDict *options, Error **errp)
50
+static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
51
{
52
- InetSocketAddress *inet = NULL;
53
- QDict *addr = NULL;
54
- QObject *crumpled_addr = NULL;
55
- Visitor *iv = NULL;
56
- Error *local_error = NULL;
57
-
58
- qdict_extract_subqdict(options, &addr, "server.");
59
- if (!qdict_size(addr)) {
60
- error_setg(errp, "SSH server address missing");
61
- goto out;
62
+ BlockdevOptionsSsh *result = NULL;
63
+ QemuOpts *opts = NULL;
64
+ Error *local_err = NULL;
65
+ QObject *crumpled;
66
+ const QDictEntry *e;
67
+ Visitor *v;
68
+
69
+ /* Translate legacy options */
70
+ opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort);
71
+ qemu_opts_absorb_qdict(opts, options, &local_err);
72
+ if (local_err) {
73
+ error_propagate(errp, local_err);
74
+ goto fail;
75
}
76
77
- crumpled_addr = qdict_crumple(addr, errp);
78
- if (!crumpled_addr) {
79
- goto out;
80
+ if (!ssh_process_legacy_socket_options(options, opts, errp)) {
81
+ goto fail;
82
+ }
83
+
84
+ /* Create the QAPI object */
85
+ crumpled = qdict_crumple(options, errp);
86
+ if (crumpled == NULL) {
87
+ goto fail;
88
}
89
90
/*
91
@@ -XXX,XX +XXX,XX @@ static InetSocketAddress *ssh_config(QDict *options, Error **errp)
92
* but when they come from -drive, they're all QString. The
93
* visitor expects the former.
94
*/
95
- iv = qobject_input_visitor_new(crumpled_addr);
96
- visit_type_InetSocketAddress(iv, NULL, &inet, &local_error);
97
- if (local_error) {
98
- error_propagate(errp, local_error);
99
- goto out;
100
+ v = qobject_input_visitor_new(crumpled);
101
+ visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err);
102
+ visit_free(v);
103
+ qobject_decref(crumpled);
104
+
105
+ if (local_err) {
106
+ error_propagate(errp, local_err);
107
+ goto fail;
108
}
109
110
-out:
111
- QDECREF(addr);
112
- qobject_decref(crumpled_addr);
113
- visit_free(iv);
114
- return inet;
115
+ /* Remove the processed options from the QDict (the visitor processes
116
+ * _all_ options in the QDict) */
117
+ while ((e = qdict_first(options))) {
118
+ qdict_del(options, e->key);
119
+ }
120
+
121
+fail:
122
+ qemu_opts_del(opts);
123
+ return result;
124
}
125
126
static int connect_to_ssh(BDRVSSHState *s, QDict *options,
127
int ssh_flags, int creat_mode, Error **errp)
128
{
129
+ BlockdevOptionsSsh *opts;
130
int r, ret;
131
- QemuOpts *opts = NULL;
132
- Error *local_err = NULL;
133
- const char *user, *path, *host_key_check;
134
+ const char *user, *host_key_check;
135
long port = 0;
136
137
- opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort);
138
- qemu_opts_absorb_qdict(opts, options, &local_err);
139
- if (local_err) {
140
- ret = -EINVAL;
141
- error_propagate(errp, local_err);
142
- goto err;
143
- }
144
-
145
- if (!ssh_process_legacy_socket_options(options, opts, errp)) {
146
- ret = -EINVAL;
147
- goto err;
148
+ host_key_check = qdict_get_try_str(options, "host_key_check");
149
+ if (!host_key_check) {
150
+ host_key_check = "yes";
151
+ } else {
152
+ qdict_del(options, "host_key_check");
153
}
154
155
- path = qemu_opt_get(opts, "path");
156
- if (!path) {
157
- ret = -EINVAL;
158
- error_setg(errp, "No path was specified");
159
- goto err;
160
+ opts = ssh_parse_options(options, errp);
161
+ if (opts == NULL) {
162
+ return -EINVAL;
163
}
164
165
- user = qemu_opt_get(opts, "user");
166
- if (!user) {
167
+ if (opts->has_user) {
168
+ user = opts->user;
169
+ } else {
170
user = g_get_user_name();
171
if (!user) {
172
error_setg_errno(errp, errno, "Can't get user name");
173
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
174
}
175
}
176
177
- host_key_check = qemu_opt_get(opts, "host_key_check");
178
- if (!host_key_check) {
179
- host_key_check = "yes";
180
- }
181
-
182
/* Pop the config into our state object, Exit if invalid */
183
- s->inet = ssh_config(options, errp);
184
- if (!s->inet) {
185
- ret = -EINVAL;
186
- goto err;
187
- }
188
+ s->inet = opts->server;
189
+ opts->server = NULL;
190
191
if (qemu_strtol(s->inet->port, NULL, 10, &port) < 0) {
192
error_setg(errp, "Use only numeric port value");
193
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
194
195
/* Open the remote file. */
196
DPRINTF("opening file %s flags=0x%x creat_mode=0%o",
197
- path, ssh_flags, creat_mode);
198
- s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode);
199
+ opts->path, ssh_flags, creat_mode);
200
+ s->sftp_handle = libssh2_sftp_open(s->sftp, opts->path, ssh_flags,
201
+ creat_mode);
202
if (!s->sftp_handle) {
203
- session_error_setg(errp, s, "failed to open remote file '%s'", path);
204
+ session_error_setg(errp, s, "failed to open remote file '%s'",
205
+ opts->path);
206
ret = -EINVAL;
207
goto err;
208
}
209
210
- qemu_opts_del(opts);
211
+ qapi_free_BlockdevOptionsSsh(opts);
212
213
r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
214
if (r < 0) {
215
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
216
}
217
s->session = NULL;
218
219
- qemu_opts_del(opts);
220
+ qapi_free_BlockdevOptionsSsh(opts);
221
222
return ret;
223
}
224
--
225
2.13.6
226
227
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
This makes the host-key-check option available in blockdev-add.
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>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
---
5
---
11
block/io.c | 56 ++++++++++++++++++++++++++++++++++++++------------------
6
qapi/block-core.json | 63 +++++++++++++++++++++++++++++++++++--
12
1 file changed, 38 insertions(+), 18 deletions(-)
7
block/ssh.c | 88 +++++++++++++++++++++++++++++++++-------------------
13
8
2 files changed, 117 insertions(+), 34 deletions(-)
14
diff --git a/block/io.c b/block/io.c
9
10
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
16
--- a/block/io.c
12
--- a/qapi/block-core.json
17
+++ b/block/io.c
13
+++ b/qapi/block-core.json
18
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
14
@@ -XXX,XX +XXX,XX @@
15
'*encrypt': 'BlockdevQcow2Encryption' } }
16
17
##
18
+# @SshHostKeyCheckMode:
19
+#
20
+# @none Don't check the host key at all
21
+# @hash Compare the host key with a given hash
22
+# @known_hosts Check the host key against the known_hosts file
23
+#
24
+# Since: 2.12
25
+##
26
+{ 'enum': 'SshHostKeyCheckMode',
27
+ 'data': [ 'none', 'hash', 'known_hosts' ] }
28
+
29
+##
30
+# @SshHostKeyCheckHashType:
31
+#
32
+# @md5 The given hash is an md5 hash
33
+# @sha1 The given hash is an sha1 hash
34
+#
35
+# Since: 2.12
36
+##
37
+{ 'enum': 'SshHostKeyCheckHashType',
38
+ 'data': [ 'md5', 'sha1' ] }
39
+
40
+##
41
+# @SshHostKeyHash:
42
+#
43
+# @type The hash algorithm used for the hash
44
+# @hash The expected hash value
45
+#
46
+# Since: 2.12
47
+##
48
+{ 'struct': 'SshHostKeyHash',
49
+ 'data': { 'type': 'SshHostKeyCheckHashType',
50
+ 'hash': 'str' }}
51
+
52
+##
53
+# @SshHostKeyDummy:
54
+#
55
+# For those union branches that don't need additional fields.
56
+#
57
+# Since: 2.12
58
+##
59
+{ 'struct': 'SshHostKeyDummy',
60
+ 'data': {} }
61
+
62
+##
63
+# @SshHostKeyCheck:
64
+#
65
+# Since: 2.12
66
+##
67
+{ 'union': 'SshHostKeyCheck',
68
+ 'base': { 'mode': 'SshHostKeyCheckMode' },
69
+ 'discriminator': 'mode',
70
+ 'data': { 'none': 'SshHostKeyDummy',
71
+ 'hash': 'SshHostKeyHash',
72
+ 'known_hosts': 'SshHostKeyDummy' } }
73
+
74
+##
75
# @BlockdevOptionsSsh:
76
#
77
# @server: host address
78
@@ -XXX,XX +XXX,XX @@
79
# @user: user as which to connect, defaults to current
80
# local user name
81
#
82
-# TODO: Expose the host_key_check option in QMP
83
+# @host-key-check: Defines how and what to check the host key against
84
+# (default: known_hosts)
85
#
86
# Since: 2.9
87
##
88
{ 'struct': 'BlockdevOptionsSsh',
89
'data': { 'server': 'InetSocketAddress',
90
'path': 'str',
91
- '*user': 'str' } }
92
+ '*user': 'str',
93
+ '*host-key-check': 'SshHostKeyCheck' } }
94
95
96
##
97
diff --git a/block/ssh.c b/block/ssh.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/ssh.c
100
+++ b/block/ssh.c
101
@@ -XXX,XX +XXX,XX @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
19
}
102
}
20
103
21
104
static int check_host_key(BDRVSSHState *s, const char *host, int port,
22
-typedef struct BdrvCoGetBlockStatusData {
105
- const char *host_key_check, Error **errp)
23
+typedef struct BdrvCoBlockStatusData {
106
+ SshHostKeyCheck *hkc, Error **errp)
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)
46
{
107
{
47
- BdrvCoGetBlockStatusData *data = opaque;
108
- /* host_key_check=no */
48
+ BdrvCoBlockStatusData *data = opaque;
109
- if (strcmp(host_key_check, "no") == 0) {
49
+ int n = 0;
110
- return 0;
50
+ int64_t ret;
111
- }
51
112
+ SshHostKeyCheckMode mode;
52
- data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
113
53
- data->want_zero,
114
- /* host_key_check=md5:xx:yy:zz:... */
54
- data->sector_num,
115
- if (strncmp(host_key_check, "md5:", 4) == 0) {
55
- data->nb_sectors,
116
- return check_host_key_hash(s, &host_key_check[4],
56
- data->pnum,
117
- LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
57
- data->file);
118
- }
58
+ ret = bdrv_co_get_block_status_above(data->bs, data->base,
119
-
59
+ data->want_zero,
120
- /* host_key_check=sha1:xx:yy:zz:... */
60
+ data->offset >> BDRV_SECTOR_BITS,
121
- if (strncmp(host_key_check, "sha1:", 5) == 0) {
61
+ data->bytes >> BDRV_SECTOR_BITS,
122
- return check_host_key_hash(s, &host_key_check[5],
62
+ &n,
123
- LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
63
+ data->file);
124
+ if (hkc) {
64
+ if (ret < 0) {
125
+ mode = hkc->mode;
65
+ assert(INT_MIN <= ret);
66
+ data->ret = ret;
67
+ } else {
126
+ } else {
68
+ *data->pnum = n * BDRV_SECTOR_SIZE;
127
+ mode = SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS;
69
+ *data->map = ret & BDRV_BLOCK_OFFSET_MASK;
128
}
70
+ data->ret = ret & ~BDRV_BLOCK_OFFSET_MASK;
129
130
- /* host_key_check=yes */
131
- if (strcmp(host_key_check, "yes") == 0) {
132
+ switch (mode) {
133
+ case SSH_HOST_KEY_CHECK_MODE_NONE:
134
+ return 0;
135
+ case SSH_HOST_KEY_CHECK_MODE_HASH:
136
+ if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) {
137
+ return check_host_key_hash(s, hkc->u.hash.hash,
138
+ LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
139
+ } else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) {
140
+ return check_host_key_hash(s, hkc->u.hash.hash,
141
+ LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
142
+ }
143
+ g_assert_not_reached();
144
+ break;
145
+ case SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS:
146
return check_host_key_knownhosts(s, host, port, errp);
147
+ default:
148
+ g_assert_not_reached();
149
}
150
151
- error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
152
return -EINVAL;
153
}
154
155
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_runtime_opts = {
156
.type = QEMU_OPT_NUMBER,
157
.help = "Port to connect to",
158
},
159
+ {
160
+ .name = "host_key_check",
161
+ .type = QEMU_OPT_STRING,
162
+ .help = "Defines how and what to check the host key against",
163
+ },
164
{ /* end of list */ }
165
},
166
};
167
168
-static bool ssh_process_legacy_socket_options(QDict *output_opts,
169
- QemuOpts *legacy_opts,
170
- Error **errp)
171
+static bool ssh_process_legacy_options(QDict *output_opts,
172
+ QemuOpts *legacy_opts,
173
+ Error **errp)
174
{
175
const char *host = qemu_opt_get(legacy_opts, "host");
176
const char *port = qemu_opt_get(legacy_opts, "port");
177
+ const char *host_key_check = qemu_opt_get(legacy_opts, "host_key_check");
178
179
if (!host && port) {
180
error_setg(errp, "port may not be used without host");
181
@@ -XXX,XX +XXX,XX @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
182
qdict_put_str(output_opts, "server.port", port ?: stringify(22));
183
}
184
185
+ if (host_key_check) {
186
+ if (strcmp(host_key_check, "no") == 0) {
187
+ qdict_put_str(output_opts, "host-key-check.mode", "none");
188
+ } else if (strncmp(host_key_check, "md5:", 4) == 0) {
189
+ qdict_put_str(output_opts, "host-key-check.mode", "hash");
190
+ qdict_put_str(output_opts, "host-key-check.type", "md5");
191
+ qdict_put_str(output_opts, "host-key-check.hash",
192
+ &host_key_check[4]);
193
+ } else if (strncmp(host_key_check, "sha1:", 5) == 0) {
194
+ qdict_put_str(output_opts, "host-key-check.mode", "hash");
195
+ qdict_put_str(output_opts, "host-key-check.type", "sha1");
196
+ qdict_put_str(output_opts, "host-key-check.hash",
197
+ &host_key_check[5]);
198
+ } else if (strcmp(host_key_check, "yes") == 0) {
199
+ qdict_put_str(output_opts, "host-key-check.mode", "known_hosts");
200
+ } else {
201
+ error_setg(errp, "unknown host_key_check setting (%s)",
202
+ host_key_check);
203
+ return false;
204
+ }
71
+ }
205
+ }
72
data->done = true;
206
+
207
return true;
73
}
208
}
74
209
75
@@ -XXX,XX +XXX,XX @@ static int64_t bdrv_common_block_status_above(BlockDriverState *bs,
210
@@ -XXX,XX +XXX,XX @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
76
BlockDriverState **file)
211
goto fail;
212
}
213
214
- if (!ssh_process_legacy_socket_options(options, opts, errp)) {
215
+ if (!ssh_process_legacy_options(options, opts, errp)) {
216
goto fail;
217
}
218
219
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
77
{
220
{
78
Coroutine *co;
221
BlockdevOptionsSsh *opts;
79
- BdrvCoGetBlockStatusData data = {
222
int r, ret;
80
+ int64_t n;
223
- const char *user, *host_key_check;
81
+ int64_t map;
224
+ const char *user;
82
+ BdrvCoBlockStatusData data = {
225
long port = 0;
83
.bs = bs,
226
84
.base = base,
227
- host_key_check = qdict_get_try_str(options, "host_key_check");
85
.want_zero = want_zero,
228
- if (!host_key_check) {
86
- .sector_num = sector_num,
229
- host_key_check = "yes";
87
- .nb_sectors = nb_sectors,
230
- } else {
88
- .pnum = pnum,
231
- qdict_del(options, "host_key_check");
89
+ .offset = sector_num * BDRV_SECTOR_SIZE,
232
- }
90
+ .bytes = nb_sectors * BDRV_SECTOR_SIZE,
233
-
91
+ .pnum = &n,
234
opts = ssh_parse_options(options, errp);
92
+ .map = &map,
235
if (opts == NULL) {
93
.file = file,
236
return -EINVAL;
94
.done = false,
237
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
95
};
238
}
96
@@ -XXX,XX +XXX,XX @@ static int64_t bdrv_common_block_status_above(BlockDriverState *bs,
239
97
bdrv_coroutine_enter(bs, co);
240
/* Check the remote host's key against known_hosts. */
98
BDRV_POLL_WHILE(bs, !data.done);
241
- ret = check_host_key(s, s->inet->host, port, host_key_check,
99
}
242
- errp);
100
- return data.ret;
243
+ ret = check_host_key(s, s->inet->host, port, opts->host_key_check, errp);
101
+ if (data.ret < 0) {
244
if (ret < 0) {
102
+ *pnum = 0;
245
goto err;
103
+ return data.ret;
246
}
104
+ }
105
+ assert(QEMU_IS_ALIGNED(n | map, BDRV_SECTOR_SIZE));
106
+ *pnum = n >> BDRV_SECTOR_BITS;
107
+ return data.ret | map;
108
}
109
110
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
111
--
247
--
112
2.13.6
248
2.13.6
113
249
114
250
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
Move the parsing of the QDict options up to the callers, in preparation
2
for the .bdrv_co_create implementation that directly gets a QAPI type.
2
3
3
We are gradually converting to byte-based interfaces, as they are
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
easier to reason about than sector-based. Convert another internal
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
type (no semantic change), and rename it to match the corresponding
6
---
6
public function rename.
7
block/ssh.c | 34 +++++++++++++++++++++-------------
8
1 file changed, 21 insertions(+), 13 deletions(-)
7
9
8
Signed-off-by: Eric Blake <eblake@redhat.com>
10
diff --git a/block/ssh.c b/block/ssh.c
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block/io.c | 68 ++++++++++++++++++++++----------------------------------------
12
1 file changed, 24 insertions(+), 44 deletions(-)
13
14
diff --git a/block/io.c b/block/io.c
15
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
16
--- a/block/io.c
12
--- a/block/ssh.c
17
+++ b/block/io.c
13
+++ b/block/ssh.c
18
@@ -XXX,XX +XXX,XX @@ early_out:
14
@@ -XXX,XX +XXX,XX @@ fail:
15
return result;
16
}
17
18
-static int connect_to_ssh(BDRVSSHState *s, QDict *options,
19
+static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
20
int ssh_flags, int creat_mode, Error **errp)
21
{
22
- BlockdevOptionsSsh *opts;
23
int r, ret;
24
const char *user;
25
long port = 0;
26
27
- opts = ssh_parse_options(options, errp);
28
- if (opts == NULL) {
29
- return -EINVAL;
30
- }
31
-
32
if (opts->has_user) {
33
user = opts->user;
34
} else {
35
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
36
goto err;
37
}
38
39
- qapi_free_BlockdevOptionsSsh(opts);
40
-
41
r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
42
if (r < 0) {
43
sftp_error_setg(errp, s, "failed to read file attributes");
44
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
45
}
46
s->session = NULL;
47
48
- qapi_free_BlockdevOptionsSsh(opts);
49
-
19
return ret;
50
return ret;
20
}
51
}
21
52
22
-static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
53
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
23
- BlockDriverState *base,
54
Error **errp)
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)
37
{
55
{
38
BlockDriverState *p;
56
BDRVSSHState *s = bs->opaque;
39
- int64_t ret = 0;
57
+ BlockdevOptionsSsh *opts;
40
+ int ret = 0;
58
int ret;
41
bool first = true;
59
int ssh_flags;
42
- int64_t map = 0;
60
43
61
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
44
assert(bs != base);
62
ssh_flags |= LIBSSH2_FXF_WRITE;
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;
80
}
63
}
64
65
+ opts = ssh_parse_options(options, errp);
66
+ if (opts == NULL) {
67
+ return -EINVAL;
68
+ }
69
+
70
/* Start up SSH. */
71
- ret = connect_to_ssh(s, options, ssh_flags, 0, errp);
72
+ ret = connect_to_ssh(s, opts, ssh_flags, 0, errp);
73
if (ret < 0) {
74
goto err;
75
}
76
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
77
/* Go non-blocking. */
78
libssh2_session_set_blocking(s->session, 0);
79
80
+ qapi_free_BlockdevOptionsSsh(opts);
81
+
82
return 0;
83
84
err:
85
@@ -XXX,XX +XXX,XX @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
86
}
87
s->sock = -1;
88
89
+ qapi_free_BlockdevOptionsSsh(opts);
90
+
81
return ret;
91
return ret;
82
}
92
}
83
93
84
/* Coroutine wrapper for bdrv_get_block_status_above() */
94
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
85
-static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
95
int r, ret;
86
+static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
96
int64_t total_size = 0;
87
{
97
QDict *uri_options = NULL;
88
BdrvCoBlockStatusData *data = opaque;
98
+ BlockdevOptionsSsh *ssh_opts = NULL;
89
- int n = 0;
99
BDRVSSHState s;
90
- int64_t ret;
100
91
101
ssh_state_init(&s);
92
- ret = bdrv_co_get_block_status_above(data->bs, data->base,
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
93
- data->want_zero,
103
goto out;
94
- data->offset >> BDRV_SECTOR_BITS,
104
}
95
- data->bytes >> BDRV_SECTOR_BITS,
105
96
- &n,
106
- r = connect_to_ssh(&s, uri_options,
97
- data->file);
107
+ ssh_opts = ssh_parse_options(uri_options, errp);
98
- if (ret < 0) {
108
+ if (ssh_opts == NULL) {
99
- assert(INT_MIN <= ret);
109
+ ret = -EINVAL;
100
- data->ret = ret;
110
+ goto out;
101
- } else {
111
+ }
102
- *data->pnum = n * BDRV_SECTOR_SIZE;
112
+
103
- *data->map = ret & BDRV_BLOCK_OFFSET_MASK;
113
+ r = connect_to_ssh(&s, ssh_opts,
104
- data->ret = ret & ~BDRV_BLOCK_OFFSET_MASK;
114
LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
105
- }
115
LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
106
+ data->ret = bdrv_co_block_status_above(data->bs, data->base,
116
0644, errp);
107
+ data->want_zero,
117
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
108
+ data->offset, data->bytes,
118
if (uri_options != NULL) {
109
+ data->pnum, data->map, data->file);
119
QDECREF(uri_options);
110
data->done = true;
120
}
121
+ qapi_free_BlockdevOptionsSsh(ssh_opts);
122
return ret;
111
}
123
}
112
124
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);
134
}
135
--
125
--
136
2.13.6
126
2.13.6
137
127
138
128
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
This adds the .bdrv_co_create driver callback to ssh, which enables
2
image creation over QMP.
2
3
3
Not all callers care about which BDS owns the mapping for a given
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
range of the file, or where the zeroes lie within that mapping. In
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
particular, bdrv_is_allocated() cares more about finding the
6
---
6
largest run of allocated data from the guest perspective, whether
7
qapi/block-core.json | 16 +++++++++-
7
or not that data is consecutive from the host perspective, and
8
block/ssh.c | 83 ++++++++++++++++++++++++++++++----------------------
8
whether or not the data reads as zero. Therefore, doing subsequent
9
2 files changed, 63 insertions(+), 36 deletions(-)
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
10
17
This patch only optimizes the block layer (no behavior change when
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
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>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
---
29
block/io.c | 57 +++++++++++++++++++++++++++++++++++++++++----------------
30
1 file changed, 41 insertions(+), 16 deletions(-)
31
32
diff --git a/block/io.c b/block/io.c
33
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
34
--- a/block/io.c
13
--- a/qapi/block-core.json
35
+++ b/block/io.c
14
+++ b/qapi/block-core.json
36
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
15
@@ -XXX,XX +XXX,XX @@
37
typedef struct BdrvCoGetBlockStatusData {
16
'*object-size': 'size' } }
38
BlockDriverState *bs;
17
39
BlockDriverState *base;
18
##
40
- BlockDriverState **file;
19
+# @BlockdevCreateOptionsSsh:
41
+ bool want_zero;
20
+#
42
int64_t sector_num;
21
+# Driver specific image creation options for SSH.
43
int nb_sectors;
22
+#
44
int *pnum;
23
+# @location Where to store the new image file
45
+ BlockDriverState **file;
24
+# @size Size of the virtual disk in bytes
46
int64_t ret;
25
+#
47
bool done;
26
+# Since: 2.12
48
} BdrvCoGetBlockStatusData;
27
+##
49
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
28
+{ 'struct': 'BlockdevCreateOptionsSsh',
50
* Drivers not implementing the functionality are assumed to not support
29
+ 'data': { 'location': 'BlockdevOptionsSsh',
51
* backing files, hence all their sectors are reported as allocated.
30
+ 'size': 'size' } }
52
*
31
+
53
+ * If 'want_zero' is true, the caller is querying for mapping purposes,
32
+##
54
+ * and the result should include BDRV_BLOCK_OFFSET_VALID and
33
# @BlockdevCreateNotSupported:
55
+ * BDRV_BLOCK_ZERO where possible; otherwise, the result may omit those
34
#
56
+ * bits particularly if it allows for a larger value in 'pnum'.
35
# This is used for all drivers that don't support creating images.
57
+ *
36
@@ -XXX,XX +XXX,XX @@
58
* If 'sector_num' is beyond the end of the disk image the return value is
37
'rbd': 'BlockdevCreateOptionsRbd',
59
* BDRV_BLOCK_EOF and 'pnum' is set to 0.
38
'replication': 'BlockdevCreateNotSupported',
60
*
39
'sheepdog': 'BlockdevCreateOptionsSheepdog',
61
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
40
- 'ssh': 'BlockdevCreateNotSupported',
62
* is allocated in.
41
+ 'ssh': 'BlockdevCreateOptionsSsh',
63
*/
42
'throttle': 'BlockdevCreateNotSupported',
64
static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
43
'vdi': 'BlockdevCreateNotSupported',
65
+ bool want_zero,
44
'vhdx': 'BlockdevCreateNotSupported',
66
int64_t sector_num,
45
diff --git a/block/ssh.c b/block/ssh.c
67
int nb_sectors, int *pnum,
46
index XXXXXXX..XXXXXXX 100644
68
BlockDriverState **file)
47
--- a/block/ssh.c
69
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
48
+++ b/block/ssh.c
70
49
@@ -XXX,XX +XXX,XX @@ static QemuOptsList ssh_create_opts = {
71
if (ret & BDRV_BLOCK_RAW) {
50
}
72
assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
51
};
73
- ret = bdrv_co_get_block_status(local_file, ret >> BDRV_SECTOR_BITS,
52
74
+ ret = bdrv_co_get_block_status(local_file, want_zero,
53
+static int ssh_co_create(BlockdevCreateOptions *options, Error **errp)
75
+ ret >> BDRV_SECTOR_BITS,
54
+{
76
*pnum, pnum, &local_file);
55
+ BlockdevCreateOptionsSsh *opts = &options->u.ssh;
56
+ BDRVSSHState s;
57
+ int ret;
58
+
59
+ assert(options->driver == BLOCKDEV_DRIVER_SSH);
60
+
61
+ ssh_state_init(&s);
62
+
63
+ ret = connect_to_ssh(&s, opts->location,
64
+ LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
65
+ LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
66
+ 0644, errp);
67
+ if (ret < 0) {
68
+ goto fail;
69
+ }
70
+
71
+ if (opts->size > 0) {
72
+ ret = ssh_grow_file(&s, opts->size, errp);
73
+ if (ret < 0) {
74
+ goto fail;
75
+ }
76
+ }
77
+
78
+ ret = 0;
79
+fail:
80
+ ssh_state_free(&s);
81
+ return ret;
82
+}
83
+
84
static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
85
Error **errp)
86
{
87
- int r, ret;
88
- int64_t total_size = 0;
89
+ BlockdevCreateOptions *create_options;
90
+ BlockdevCreateOptionsSsh *ssh_opts;
91
+ int ret;
92
QDict *uri_options = NULL;
93
- BlockdevOptionsSsh *ssh_opts = NULL;
94
- BDRVSSHState s;
95
96
- ssh_state_init(&s);
97
+ create_options = g_new0(BlockdevCreateOptions, 1);
98
+ create_options->driver = BLOCKDEV_DRIVER_SSH;
99
+ ssh_opts = &create_options->u.ssh;
100
101
/* Get desired file size. */
102
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
103
- BDRV_SECTOR_SIZE);
104
- DPRINTF("total_size=%" PRIi64, total_size);
105
+ ssh_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
106
+ BDRV_SECTOR_SIZE);
107
+ DPRINTF("total_size=%" PRIi64, ssh_opts->size);
108
109
uri_options = qdict_new();
110
- r = parse_uri(filename, uri_options, errp);
111
- if (r < 0) {
112
- ret = r;
113
+ ret = parse_uri(filename, uri_options, errp);
114
+ if (ret < 0) {
77
goto out;
115
goto out;
78
}
116
}
79
117
80
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
118
- ssh_opts = ssh_parse_options(uri_options, errp);
81
ret |= BDRV_BLOCK_ALLOCATED;
119
- if (ssh_opts == NULL) {
82
- } else {
120
+ ssh_opts->location = ssh_parse_options(uri_options, errp);
83
+ } else if (want_zero) {
121
+ if (ssh_opts->location == NULL) {
84
if (bdrv_unallocated_blocks_are_zero(bs)) {
122
ret = -EINVAL;
85
ret |= BDRV_BLOCK_ZERO;
123
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
}
94
}
124
}
95
125
96
- if (local_file && local_file != bs &&
126
- r = connect_to_ssh(&s, ssh_opts,
97
+ if (want_zero && local_file && local_file != bs &&
127
- LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
98
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
128
- LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
99
(ret & BDRV_BLOCK_OFFSET_VALID)) {
129
- 0644, errp);
100
int file_pnum;
130
- if (r < 0) {
101
131
- ret = r;
102
- ret2 = bdrv_co_get_block_status(local_file, ret >> BDRV_SECTOR_BITS,
132
- goto out;
103
+ ret2 = bdrv_co_get_block_status(local_file, want_zero,
133
- }
104
+ ret >> BDRV_SECTOR_BITS,
134
-
105
*pnum, &file_pnum, NULL);
135
- if (total_size > 0) {
106
if (ret2 >= 0) {
136
- ret = ssh_grow_file(&s, total_size, errp);
107
/* Ignore errors. This is just providing extra information, it
137
- if (ret < 0) {
108
@@ -XXX,XX +XXX,XX @@ early_out:
138
- goto out;
109
139
- }
110
static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
140
- }
111
BlockDriverState *base,
141
-
112
+ bool want_zero,
142
- ret = 0;
113
int64_t sector_num,
143
+ ret = ssh_co_create(create_options, errp);
114
int nb_sectors,
144
115
int *pnum,
145
out:
116
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
146
- ssh_state_free(&s);
117
147
- if (uri_options != NULL) {
118
assert(bs != base);
148
- QDECREF(uri_options);
119
for (p = bs; p != base; p = backing_bs(p)) {
149
- }
120
- ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum, file);
150
- qapi_free_BlockdevOptionsSsh(ssh_opts);
121
+ ret = bdrv_co_get_block_status(p, want_zero, sector_num, nb_sectors,
151
+ QDECREF(uri_options);
122
+ pnum, file);
152
+ qapi_free_BlockdevCreateOptions(create_options);
123
if (ret < 0) {
153
return ret;
124
break;
125
}
126
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
127
BdrvCoGetBlockStatusData *data = opaque;
128
129
data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
130
+ data->want_zero,
131
data->sector_num,
132
data->nb_sectors,
133
data->pnum,
134
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
135
*
136
* See bdrv_co_get_block_status_above() for details.
137
*/
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
}
154
}
166
155
167
+int64_t bdrv_get_block_status_above(BlockDriverState *bs,
156
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ssh = {
168
+ BlockDriverState *base,
157
.instance_size = sizeof(BDRVSSHState),
169
+ int64_t sector_num,
158
.bdrv_parse_filename = ssh_parse_filename,
170
+ int nb_sectors, int *pnum,
159
.bdrv_file_open = ssh_file_open,
171
+ BlockDriverState **file)
160
+ .bdrv_co_create = ssh_co_create,
172
+{
161
.bdrv_co_create_opts = ssh_co_create_opts,
173
+ return bdrv_common_block_status_above(bs, base, true, sector_num,
162
.bdrv_close = ssh_close,
174
+ nb_sectors, pnum, file);
163
.bdrv_has_zero_init = ssh_has_zero_init,
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);
197
if (ret < 0) {
198
return ret;
199
}
200
--
164
--
201
2.13.6
165
2.13.6
202
166
203
167
diff view generated by jsdifflib
1
This changes test case 191 to include a backing image that has
1
If bdrv_truncate() is called, but the requested size is the same as
2
backing_fmt set in the image file, but is referenced by node name in the
2
before, don't call posix_fallocate(), which returns -EINVAL for length
3
qemu command line.
3
zero and would therefore make bdrv_truncate() fail.
4
5
The problem can be triggered by creating a zero-sized raw image with
6
'falloc' preallocation mode.
4
7
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
11
---
8
tests/qemu-iotests/191 | 3 ++-
12
block/file-posix.c | 14 +++++++++-----
9
tests/qemu-iotests/191.out | 2 +-
13
1 file changed, 9 insertions(+), 5 deletions(-)
10
2 files changed, 3 insertions(+), 2 deletions(-)
11
14
12
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
15
diff --git a/block/file-posix.c b/block/file-posix.c
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
27
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
28
--- a/tests/qemu-iotests/191.out
17
--- a/block/file-posix.c
29
+++ b/tests/qemu-iotests/191.out
18
+++ b/block/file-posix.c
30
@@ -XXX,XX +XXX,XX @@ QA output created by 191
19
@@ -XXX,XX +XXX,XX @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
31
=== Preparing and starting VM ===
20
* file systems that do not support fallocate(), trying to check if a
32
21
* block is allocated before allocating it, so don't do that here.
33
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
22
*/
34
-Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
23
- result = -posix_fallocate(fd, current_length, offset - current_length);
35
+Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
24
- if (result != 0) {
36
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
25
- /* posix_fallocate() doesn't set errno. */
37
Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
26
- error_setg_errno(errp, -result,
38
wrote 65536/65536 bytes at offset 1048576
27
- "Could not preallocate new data");
28
+ if (offset != current_length) {
29
+ result = -posix_fallocate(fd, current_length, offset - current_length);
30
+ if (result != 0) {
31
+ /* posix_fallocate() doesn't set errno. */
32
+ error_setg_errno(errp, -result,
33
+ "Could not preallocate new data");
34
+ }
35
+ } else {
36
+ result = 0;
37
}
38
goto out;
39
#endif
39
--
40
--
40
2.13.6
41
2.13.6
41
42
42
43
diff view generated by jsdifflib
1
From: Peter Krempa <pkrempa@redhat.com>
1
Most callers have their own checks, but something like this should also
2
be checked centrally. As it happens, x-blockdev-create can pass negative
3
image sizes to format drivers (because there is no QAPI type that would
4
reject negative numbers) and triggers the check added by this patch.
2
5
3
When referring to a backing file of an image via node name
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.
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>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
18
---
9
---
19
block.c | 3 ++-
10
block.c | 5 +++++
20
1 file changed, 2 insertions(+), 1 deletion(-)
11
1 file changed, 5 insertions(+)
21
12
22
diff --git a/block.c b/block.c
13
diff --git a/block.c b/block.c
23
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
24
--- a/block.c
15
--- a/block.c
25
+++ b/block.c
16
+++ b/block.c
26
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
17
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
27
goto free_exit;
18
error_setg(errp, "No medium inserted");
19
return -ENOMEDIUM;
28
}
20
}
29
21
+ if (offset < 0) {
30
- if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
22
+ error_setg(errp, "Image size cannot be negative");
31
+ if (!reference &&
23
+ return -EINVAL;
32
+ bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
24
+ }
33
qdict_put_str(options, "driver", bs->backing_format);
25
+
34
}
26
if (!drv->bdrv_truncate) {
35
27
if (bs->file && drv->is_filter) {
28
return bdrv_truncate(bs->file, offset, prealloc, errp);
36
--
29
--
37
2.13.6
30
2.13.6
38
31
39
32
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
---
4
tests/qemu-iotests/206 | 436 +++++++++++++++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/206.out | 209 ++++++++++++++++++++++
6
tests/qemu-iotests/group | 1 +
7
3 files changed, 646 insertions(+)
8
create mode 100755 tests/qemu-iotests/206
9
create mode 100644 tests/qemu-iotests/206.out
2
10
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
4
Message-id: 20170929170843.3711-1-mreitz@redhat.com
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/127 | 97 ++++++++++++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/127.out | 14 +++++++
10
tests/qemu-iotests/group | 1 +
11
3 files changed, 112 insertions(+)
12
create mode 100755 tests/qemu-iotests/127
13
create mode 100644 tests/qemu-iotests/127.out
14
15
diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127
16
new file mode 100755
12
new file mode 100755
17
index XXXXXXX..XXXXXXX
13
index XXXXXXX..XXXXXXX
18
--- /dev/null
14
--- /dev/null
19
+++ b/tests/qemu-iotests/127
15
+++ b/tests/qemu-iotests/206
20
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@
21
+#!/bin/bash
17
+#!/bin/bash
22
+#
18
+#
23
+# Test case for mirroring with dataplane
19
+# Test qcow2 and file image creation
24
+#
20
+#
25
+# Copyright (C) 2017 Red Hat, Inc.
21
+# Copyright (C) 2018 Red Hat, Inc.
26
+#
22
+#
27
+# This program is free software; you can redistribute it and/or modify
23
+# 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
24
+# it under the terms of the GNU General Public License as published by
29
+# the Free Software Foundation; either version 2 of the License, or
25
+# the Free Software Foundation; either version 2 of the License, or
30
+# (at your option) any later version.
26
+# (at your option) any later version.
...
...
37
+# You should have received a copy of the GNU General Public License
33
+# 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/>.
34
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
39
+#
35
+#
40
+
36
+
41
+# creator
37
+# creator
42
+owner=mreitz@redhat.com
38
+owner=kwolf@redhat.com
43
+
39
+
44
+seq=$(basename $0)
40
+seq=`basename $0`
45
+echo "QA output created by $seq"
41
+echo "QA output created by $seq"
46
+
42
+
47
+here=$PWD
43
+here=`pwd`
48
+status=1 # failure is the default!
44
+status=1    # failure is the default!
49
+
45
+
50
+_cleanup()
46
+# get standard environment, filters and checks
51
+{
52
+ _cleanup_qemu
53
+ _cleanup_test_img
54
+ _rm_test_img "$TEST_IMG.overlay0"
55
+ _rm_test_img "$TEST_IMG.overlay1"
56
+}
57
+trap "_cleanup; exit \$status" 0 1 2 3 15
58
+
59
+# get standard environment, filters and qemu instance handling
60
+. ./common.rc
47
+. ./common.rc
61
+. ./common.filter
48
+. ./common.filter
62
+. ./common.qemu
63
+
49
+
64
+_supported_fmt qcow2
50
+_supported_fmt qcow2
65
+_supported_proto file
51
+_supported_proto file
66
+_supported_os Linux
52
+_supported_os Linux
67
+
53
+
68
+IMG_SIZE=64K
54
+function do_run_qemu()
69
+
55
+{
70
+_make_test_img $IMG_SIZE
56
+ echo Testing: "$@"
71
+TEST_IMG="$TEST_IMG.overlay0" _make_test_img -b "$TEST_IMG" $IMG_SIZE
57
+ $QEMU -nographic -qmp stdio -serial none "$@"
72
+TEST_IMG="$TEST_IMG.overlay1" _make_test_img -b "$TEST_IMG" $IMG_SIZE
58
+ echo
73
+
59
+}
74
+# So that we actually have something to mirror and the job does not return
60
+
75
+# immediately (which may be bad because then we cannot know whether the
61
+function run_qemu()
76
+# 'return' or the 'BLOCK_JOB_READY' comes first).
62
+{
77
+$QEMU_IO -c 'write 0 42' "$TEST_IMG.overlay0" | _filter_qemu_io
63
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
78
+
64
+ | _filter_qemu | _filter_imgfmt \
79
+# We cannot use virtio-blk here because that does not actually set the attached
65
+ | _filter_actual_image_size
80
+# BB's AioContext in qtest mode
66
+}
81
+_launch_qemu \
67
+
82
+ -object iothread,id=iothr \
68
+echo
83
+ -blockdev node-name=source,driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG.overlay0" \
69
+echo "=== Successful image creation (defaults) ==="
84
+ -device virtio-scsi,id=scsi-bus,iothread=iothr \
70
+echo
85
+ -device scsi-hd,bus=scsi-bus.0,drive=source
71
+
86
+
72
+size=$((128 * 1024 * 1024))
87
+_send_qemu_cmd $QEMU_HANDLE \
73
+
88
+ "{ 'execute': 'qmp_capabilities' }" \
74
+run_qemu <<EOF
89
+ 'return'
75
+{ "execute": "qmp_capabilities" }
90
+
76
+{ "execute": "x-blockdev-create",
91
+_send_qemu_cmd $QEMU_HANDLE \
77
+ "arguments": {
92
+ "{ 'execute': 'drive-mirror',
78
+ "driver": "file",
93
+ 'arguments': {
79
+ "filename": "$TEST_IMG",
94
+ 'job-id': 'mirror',
80
+ "size": 0
95
+ 'device': 'source',
81
+ }
96
+ 'target': '$TEST_IMG.overlay1',
82
+}
97
+ 'mode': 'existing',
83
+{ "execute": "blockdev-add",
98
+ 'sync': 'top'
84
+ "arguments": {
99
+ } }" \
85
+ "driver": "file",
100
+ 'BLOCK_JOB_READY'
86
+ "node-name": "imgfile",
101
+
87
+ "filename": "$TEST_IMG"
102
+# The backing BDS should be assigned the overlay's AioContext
88
+ }
103
+_send_qemu_cmd $QEMU_HANDLE \
89
+}
104
+ "{ 'execute': 'block-job-complete',
90
+{ "execute": "x-blockdev-create",
105
+ 'arguments': { 'device': 'mirror' } }" \
91
+ "arguments": {
106
+ 'BLOCK_JOB_COMPLETED'
92
+ "driver": "$IMGFMT",
107
+
93
+ "file": "imgfile",
108
+_send_qemu_cmd $QEMU_HANDLE \
94
+ "size": $size
109
+ "{ 'execute': 'quit' }" \
95
+ }
110
+ 'return'
96
+}
111
+
97
+{ "execute": "quit" }
112
+wait=yes _cleanup_qemu
98
+EOF
99
+
100
+_img_info --format-specific
101
+
102
+echo
103
+echo "=== Successful image creation (inline blockdev-add, explicit defaults) ==="
104
+echo
105
+
106
+# Choose a different size to show that we got a new image
107
+size=$((64 * 1024 * 1024))
108
+
109
+run_qemu <<EOF
110
+{ "execute": "qmp_capabilities" }
111
+{ "execute": "x-blockdev-create",
112
+ "arguments": {
113
+ "driver": "file",
114
+ "filename": "$TEST_IMG",
115
+ "size": 0,
116
+ "preallocation": "off",
117
+ "nocow": false
118
+ }
119
+}
120
+{ "execute": "x-blockdev-create",
121
+ "arguments": {
122
+ "driver": "$IMGFMT",
123
+ "file": {
124
+ "driver": "file",
125
+ "filename": "$TEST_IMG"
126
+ },
127
+ "size": $size,
128
+ "version": "v3",
129
+ "cluster-size": 65536,
130
+ "preallocation": "off",
131
+ "lazy-refcounts": false,
132
+ "refcount-bits": 16
133
+ }
134
+}
135
+{ "execute": "quit" }
136
+EOF
137
+
138
+_img_info --format-specific
139
+
140
+echo
141
+echo "=== Successful image creation (v3 non-default options) ==="
142
+echo
143
+
144
+# Choose a different size to show that we got a new image
145
+size=$((32 * 1024 * 1024))
146
+
147
+run_qemu <<EOF
148
+{ "execute": "qmp_capabilities" }
149
+{ "execute": "x-blockdev-create",
150
+ "arguments": {
151
+ "driver": "file",
152
+ "filename": "$TEST_IMG",
153
+ "size": 0,
154
+ "preallocation": "falloc",
155
+ "nocow": true
156
+ }
157
+}
158
+{ "execute": "x-blockdev-create",
159
+ "arguments": {
160
+ "driver": "$IMGFMT",
161
+ "file": {
162
+ "driver": "file",
163
+ "filename": "$TEST_IMG"
164
+ },
165
+ "size": $size,
166
+ "version": "v3",
167
+ "cluster-size": 2097152,
168
+ "preallocation": "metadata",
169
+ "lazy-refcounts": true,
170
+ "refcount-bits": 1
171
+ }
172
+}
173
+{ "execute": "quit" }
174
+EOF
175
+
176
+_img_info --format-specific
177
+
178
+echo
179
+echo "=== Successful image creation (v2 non-default options) ==="
180
+echo
181
+
182
+mv $TEST_IMG $TEST_IMG.base
183
+
184
+run_qemu <<EOF
185
+{ "execute": "qmp_capabilities" }
186
+{ "execute": "x-blockdev-create",
187
+ "arguments": {
188
+ "driver": "file",
189
+ "filename": "$TEST_IMG",
190
+ "size": 0
191
+ }
192
+}
193
+{ "execute": "x-blockdev-create",
194
+ "arguments": {
195
+ "driver": "$IMGFMT",
196
+ "file": {
197
+ "driver": "file",
198
+ "filename": "$TEST_IMG"
199
+ },
200
+ "size": $size,
201
+ "backing-file": "$TEST_IMG.base",
202
+ "backing-fmt": "qcow2",
203
+ "version": "v2",
204
+ "cluster-size": 512
205
+ }
206
+}
207
+{ "execute": "quit" }
208
+EOF
209
+
210
+_img_info --format-specific
211
+
212
+echo
213
+echo "=== Successful image creation (encrypted) ==="
214
+echo
215
+
216
+run_qemu -object secret,id=keysec0,data="foo" <<EOF
217
+{ "execute": "qmp_capabilities" }
218
+{ "execute": "x-blockdev-create",
219
+ "arguments": {
220
+ "driver": "$IMGFMT",
221
+ "file": {
222
+ "driver": "file",
223
+ "filename": "$TEST_IMG"
224
+ },
225
+ "size": $size,
226
+ "encrypt": {
227
+ "format": "luks",
228
+ "key-secret": "keysec0",
229
+ "cipher-alg": "twofish-128",
230
+ "cipher-mode": "ctr",
231
+ "ivgen-alg": "plain64",
232
+ "ivgen-hash-alg": "md5",
233
+ "hash-alg": "sha1",
234
+ "iter-time": 10
235
+ }
236
+ }
237
+}
238
+{ "execute": "quit" }
239
+EOF
240
+
241
+_img_info --format-specific | _filter_img_info --format-specific
242
+
243
+echo
244
+echo "=== Invalid BlockdevRef ==="
245
+echo
246
+
247
+run_qemu <<EOF
248
+{ "execute": "qmp_capabilities" }
249
+{ "execute": "x-blockdev-create",
250
+ "arguments": {
251
+ "driver": "$IMGFMT",
252
+ "file": "this doesn't exist",
253
+ "size": $size
254
+ }
255
+}
256
+{ "execute": "quit" }
257
+EOF
258
+
259
+
260
+echo
261
+echo "=== Invalid sizes ==="
262
+echo
263
+
264
+# TODO Negative image sizes aren't handled correctly, but this is a problem
265
+# with QAPI's implementation of the 'size' type and affects other commands as
266
+# well. Once this is fixed, we may want to add a test case here.
267
+
268
+# 1. Misaligned image size
269
+# 2. 2^64 - 512
270
+# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
271
+# 4. 2^63 - 512 (generally valid, but qcow2 can't handle images this size)
272
+
273
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
274
+{ "execute": "qmp_capabilities" }
275
+{ "execute": "x-blockdev-create",
276
+ "arguments": {
277
+ "driver": "$IMGFMT",
278
+ "file": "node0",
279
+ "size": 1234
280
+ }
281
+}
282
+{ "execute": "x-blockdev-create",
283
+ "arguments": {
284
+ "driver": "$IMGFMT",
285
+ "file": "node0",
286
+ "size": 18446744073709551104
287
+ }
288
+}
289
+{ "execute": "x-blockdev-create",
290
+ "arguments": {
291
+ "driver": "$IMGFMT",
292
+ "file": "node0",
293
+ "size": 9223372036854775808
294
+ }
295
+}
296
+{ "execute": "x-blockdev-create",
297
+ "arguments": {
298
+ "driver": "$IMGFMT",
299
+ "file": "node0",
300
+ "size": 9223372036854775296
301
+ }
302
+}
303
+{ "execute": "quit" }
304
+EOF
305
+
306
+echo
307
+echo "=== Invalid version ==="
308
+echo
309
+
310
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
311
+{ "execute": "qmp_capabilities" }
312
+{ "execute": "x-blockdev-create",
313
+ "arguments": {
314
+ "driver": "$IMGFMT",
315
+ "file": "node0",
316
+ "size": 67108864,
317
+ "version": "v1"
318
+ }
319
+}
320
+{ "execute": "x-blockdev-create",
321
+ "arguments": {
322
+ "driver": "$IMGFMT",
323
+ "file": "node0",
324
+ "size": 67108864,
325
+ "version": "v2",
326
+ "lazy-refcounts": true
327
+ }
328
+}
329
+{ "execute": "x-blockdev-create",
330
+ "arguments": {
331
+ "driver": "$IMGFMT",
332
+ "file": "node0",
333
+ "size": 67108864,
334
+ "version": "v2",
335
+ "refcount-bits": 8
336
+ }
337
+}
338
+{ "execute": "quit" }
339
+EOF
340
+
341
+echo
342
+echo "=== Invalid backing file options ==="
343
+echo
344
+
345
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
346
+{ "execute": "qmp_capabilities" }
347
+{ "execute": "x-blockdev-create",
348
+ "arguments": {
349
+ "driver": "$IMGFMT",
350
+ "file": "node0",
351
+ "size": 67108864,
352
+ "backing-file": "/dev/null",
353
+ "preallocation": "full"
354
+ }
355
+}
356
+{ "execute": "x-blockdev-create",
357
+ "arguments": {
358
+ "driver": "$IMGFMT",
359
+ "file": "node0",
360
+ "size": 67108864,
361
+ "backing-fmt": "$IMGFMT"
362
+ }
363
+}
364
+{ "execute": "quit" }
365
+EOF
366
+
367
+echo
368
+echo "=== Invalid cluster size ==="
369
+echo
370
+
371
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
372
+{ "execute": "qmp_capabilities" }
373
+{ "execute": "x-blockdev-create",
374
+ "arguments": {
375
+ "driver": "$IMGFMT",
376
+ "file": "node0",
377
+ "size": 67108864,
378
+ "cluster-size": 1234
379
+ }
380
+}
381
+{ "execute": "x-blockdev-create",
382
+ "arguments": {
383
+ "driver": "$IMGFMT",
384
+ "file": "node0",
385
+ "size": 67108864,
386
+ "cluster-size": 128
387
+ }
388
+}
389
+{ "execute": "x-blockdev-create",
390
+ "arguments": {
391
+ "driver": "$IMGFMT",
392
+ "file": "node0",
393
+ "size": 67108864,
394
+ "cluster-size": 4194304
395
+ }
396
+}
397
+{ "execute": "x-blockdev-create",
398
+ "arguments": {
399
+ "driver": "$IMGFMT",
400
+ "file": "node0",
401
+ "size": 67108864,
402
+ "cluster-size": 0
403
+ }
404
+}
405
+{ "execute": "x-blockdev-create",
406
+ "arguments": {
407
+ "driver": "$IMGFMT",
408
+ "file": "node0",
409
+ "size": 281474976710656,
410
+ "cluster-size": 512
411
+ }
412
+}
413
+{ "execute": "quit" }
414
+EOF
415
+
416
+echo
417
+echo "=== Invalid refcount width ==="
418
+echo
419
+
420
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
421
+{ "execute": "qmp_capabilities" }
422
+{ "execute": "x-blockdev-create",
423
+ "arguments": {
424
+ "driver": "$IMGFMT",
425
+ "file": "node0",
426
+ "size": 67108864,
427
+ "refcount-bits": 128
428
+ }
429
+}
430
+{ "execute": "x-blockdev-create",
431
+ "arguments": {
432
+ "driver": "$IMGFMT",
433
+ "file": "node0",
434
+ "size": 67108864,
435
+ "refcount-bits": 0
436
+ }
437
+}
438
+{ "execute": "x-blockdev-create",
439
+ "arguments": {
440
+ "driver": "$IMGFMT",
441
+ "file": "node0",
442
+ "size": 67108864,
443
+ "refcount-bits": 7
444
+ }
445
+}
446
+{ "execute": "quit" }
447
+EOF
113
+
448
+
114
+# success, all done
449
+# success, all done
115
+echo '*** done'
450
+echo "*** done"
116
+rm -f $seq.full
451
+rm -f $seq.full
117
+status=0
452
+status=0
118
diff --git a/tests/qemu-iotests/127.out b/tests/qemu-iotests/127.out
453
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
119
new file mode 100644
454
new file mode 100644
120
index XXXXXXX..XXXXXXX
455
index XXXXXXX..XXXXXXX
121
--- /dev/null
456
--- /dev/null
122
+++ b/tests/qemu-iotests/127.out
457
+++ b/tests/qemu-iotests/206.out
123
@@ -XXX,XX +XXX,XX @@
458
@@ -XXX,XX +XXX,XX @@
124
+QA output created by 127
459
+QA output created by 206
125
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
460
+
126
+Formatting 'TEST_DIR/t.IMGFMT.overlay0', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT
461
+=== Successful image creation (defaults) ===
127
+Formatting 'TEST_DIR/t.IMGFMT.overlay1', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT
462
+
128
+wrote 42/42 bytes at offset 0
463
+Testing:
129
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
464
+QMP_VERSION
130
+{"return": {}}
465
+{"return": {}}
131
+{"return": {}}
466
+{"return": {}}
132
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "mirror", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
467
+{"return": {}}
133
+{"return": {}}
468
+{"return": {}}
134
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "mirror", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
469
+{"return": {}}
135
+{"return": {}}
470
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
136
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
471
+
472
+image: TEST_DIR/t.IMGFMT
473
+file format: IMGFMT
474
+virtual size: 128M (134217728 bytes)
475
+cluster_size: 65536
476
+Format specific information:
477
+ compat: 1.1
478
+ lazy refcounts: false
479
+ refcount bits: 16
480
+ corrupt: false
481
+
482
+=== Successful image creation (inline blockdev-add, explicit defaults) ===
483
+
484
+Testing:
485
+QMP_VERSION
486
+{"return": {}}
487
+{"return": {}}
488
+{"return": {}}
489
+{"return": {}}
490
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
491
+
492
+image: TEST_DIR/t.IMGFMT
493
+file format: IMGFMT
494
+virtual size: 64M (67108864 bytes)
495
+cluster_size: 65536
496
+Format specific information:
497
+ compat: 1.1
498
+ lazy refcounts: false
499
+ refcount bits: 16
500
+ corrupt: false
501
+
502
+=== Successful image creation (v3 non-default options) ===
503
+
504
+Testing:
505
+QMP_VERSION
506
+{"return": {}}
507
+{"return": {}}
508
+{"return": {}}
509
+{"return": {}}
510
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
511
+
512
+image: TEST_DIR/t.IMGFMT
513
+file format: IMGFMT
514
+virtual size: 32M (33554432 bytes)
515
+cluster_size: 2097152
516
+Format specific information:
517
+ compat: 1.1
518
+ lazy refcounts: true
519
+ refcount bits: 1
520
+ corrupt: false
521
+
522
+=== Successful image creation (v2 non-default options) ===
523
+
524
+Testing:
525
+QMP_VERSION
526
+{"return": {}}
527
+{"return": {}}
528
+{"return": {}}
529
+{"return": {}}
530
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
531
+
532
+image: TEST_DIR/t.IMGFMT
533
+file format: IMGFMT
534
+virtual size: 32M (33554432 bytes)
535
+cluster_size: 512
536
+backing file: TEST_DIR/t.IMGFMT.base
537
+backing file format: IMGFMT
538
+Format specific information:
539
+ compat: 0.10
540
+ refcount bits: 16
541
+
542
+=== Successful image creation (encrypted) ===
543
+
544
+Testing: -object secret,id=keysec0,data=foo
545
+QMP_VERSION
546
+{"return": {}}
547
+{"return": {}}
548
+{"return": {}}
549
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
550
+
551
+image: TEST_DIR/t.IMGFMT
552
+file format: IMGFMT
553
+virtual size: 32M (33554432 bytes)
554
+Format specific information:
555
+ compat: 1.1
556
+ lazy refcounts: false
557
+ refcount bits: 16
558
+ encrypt:
559
+ ivgen alg: plain64
560
+ hash alg: sha1
561
+ cipher alg: twofish-128
562
+ uuid: 00000000-0000-0000-0000-000000000000
563
+ format: luks
564
+ cipher mode: ctr
565
+ slots:
566
+ [0]:
567
+ active: true
568
+ iters: 1024
569
+ key offset: 4096
570
+ stripes: 4000
571
+ [1]:
572
+ active: false
573
+ key offset: 69632
574
+ [2]:
575
+ active: false
576
+ key offset: 135168
577
+ [3]:
578
+ active: false
579
+ key offset: 200704
580
+ [4]:
581
+ active: false
582
+ key offset: 266240
583
+ [5]:
584
+ active: false
585
+ key offset: 331776
586
+ [6]:
587
+ active: false
588
+ key offset: 397312
589
+ [7]:
590
+ active: false
591
+ key offset: 462848
592
+ payload offset: 528384
593
+ master key iters: 1024
594
+ corrupt: false
595
+
596
+=== Invalid BlockdevRef ===
597
+
598
+Testing:
599
+QMP_VERSION
600
+{"return": {}}
601
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
602
+{"return": {}}
603
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
604
+
605
+
606
+=== Invalid sizes ===
607
+
608
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
609
+QMP_VERSION
610
+{"return": {}}
611
+{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
612
+{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
613
+{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
614
+{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
615
+{"return": {}}
616
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
617
+
618
+
619
+=== Invalid version ===
620
+
621
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
622
+QMP_VERSION
623
+{"return": {}}
624
+{"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}}
625
+{"error": {"class": "GenericError", "desc": "Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)"}}
626
+{"error": {"class": "GenericError", "desc": "Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)"}}
627
+{"return": {}}
628
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
629
+
630
+
631
+=== Invalid backing file options ===
632
+
633
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
634
+QMP_VERSION
635
+{"return": {}}
636
+{"error": {"class": "GenericError", "desc": "Backing file and preallocation cannot be used at the same time"}}
637
+{"error": {"class": "GenericError", "desc": "Backing format cannot be used without backing file"}}
638
+{"return": {}}
639
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
640
+
641
+
642
+=== Invalid cluster size ===
643
+
644
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
645
+QMP_VERSION
646
+{"return": {}}
647
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
648
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
649
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
650
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
651
+{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
652
+{"return": {}}
653
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
654
+
655
+
656
+=== Invalid refcount width ===
657
+
658
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
659
+QMP_VERSION
660
+{"return": {}}
661
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
662
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
663
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
664
+{"return": {}}
665
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
666
+
137
+*** done
667
+*** done
138
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
668
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
139
index XXXXXXX..XXXXXXX 100644
669
index XXXXXXX..XXXXXXX 100644
140
--- a/tests/qemu-iotests/group
670
--- a/tests/qemu-iotests/group
141
+++ b/tests/qemu-iotests/group
671
+++ b/tests/qemu-iotests/group
142
@@ -XXX,XX +XXX,XX @@
672
@@ -XXX,XX +XXX,XX @@
143
124 rw auto backing
673
203 rw auto
144
125 rw auto
674
204 rw auto quick
145
126 rw auto backing
675
205 rw auto quick
146
+127 rw auto backing quick
676
+206 rw auto
147
128 rw auto quick
148
129 rw auto quick
149
130 rw auto quick
150
--
677
--
151
2.13.6
678
2.13.6
152
679
153
680
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
---
4
tests/qemu-iotests/207 | 261 +++++++++++++++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/207.out | 75 +++++++++++++
6
tests/qemu-iotests/group | 1 +
7
3 files changed, 337 insertions(+)
8
create mode 100755 tests/qemu-iotests/207
9
create mode 100644 tests/qemu-iotests/207.out
1
10
11
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
12
new file mode 100755
13
index XXXXXXX..XXXXXXX
14
--- /dev/null
15
+++ b/tests/qemu-iotests/207
16
@@ -XXX,XX +XXX,XX @@
17
+#!/bin/bash
18
+#
19
+# Test ssh image creation
20
+#
21
+# Copyright (C) 2018 Red Hat, Inc.
22
+#
23
+# This program is free software; you can redistribute it and/or modify
24
+# it under the terms of the GNU General Public License as published by
25
+# the Free Software Foundation; either version 2 of the License, or
26
+# (at your option) any later version.
27
+#
28
+# This program is distributed in the hope that it will be useful,
29
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
30
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
+# GNU General Public License for more details.
32
+#
33
+# You should have received a copy of the GNU General Public License
34
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+#
36
+
37
+# creator
38
+owner=kwolf@redhat.com
39
+
40
+seq=`basename $0`
41
+echo "QA output created by $seq"
42
+
43
+here=`pwd`
44
+status=1    # failure is the default!
45
+
46
+# get standard environment, filters and checks
47
+. ./common.rc
48
+. ./common.filter
49
+
50
+_supported_fmt raw
51
+_supported_proto ssh
52
+_supported_os Linux
53
+
54
+function do_run_qemu()
55
+{
56
+ echo Testing: "$@"
57
+ $QEMU -nographic -qmp stdio -serial none "$@"
58
+ echo
59
+}
60
+
61
+function run_qemu()
62
+{
63
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
64
+ | _filter_qemu | _filter_imgfmt \
65
+ | _filter_actual_image_size
66
+}
67
+
68
+echo
69
+echo "=== Successful image creation (defaults) ==="
70
+echo
71
+
72
+run_qemu <<EOF
73
+{ "execute": "qmp_capabilities" }
74
+{ "execute": "x-blockdev-create",
75
+ "arguments": {
76
+ "driver": "ssh",
77
+ "location": {
78
+ "path": "$TEST_IMG_FILE",
79
+ "server": {
80
+ "host": "127.0.0.1",
81
+ "port": "22"
82
+ }
83
+ },
84
+ "size": 4194304
85
+ }
86
+}
87
+{ "execute": "quit" }
88
+EOF
89
+
90
+_img_info | _filter_img_info
91
+echo
92
+TEST_IMG=$TEST_IMG_FILE _img_info | _filter_img_info
93
+
94
+echo
95
+echo "=== Test host-key-check options ==="
96
+echo
97
+
98
+run_qemu <<EOF
99
+{ "execute": "qmp_capabilities" }
100
+{ "execute": "x-blockdev-create",
101
+ "arguments": {
102
+ "driver": "ssh",
103
+ "location": {
104
+ "path": "$TEST_IMG_FILE",
105
+ "server": {
106
+ "host": "127.0.0.1",
107
+ "port": "22"
108
+ },
109
+ "host-key-check": {
110
+ "mode": "none"
111
+ }
112
+ },
113
+ "size": 8388608
114
+ }
115
+}
116
+{ "execute": "quit" }
117
+EOF
118
+
119
+_img_info | _filter_img_info
120
+
121
+run_qemu <<EOF
122
+{ "execute": "qmp_capabilities" }
123
+{ "execute": "x-blockdev-create",
124
+ "arguments": {
125
+ "driver": "ssh",
126
+ "location": {
127
+ "path": "$TEST_IMG_FILE",
128
+ "server": {
129
+ "host": "127.0.0.1",
130
+ "port": "22"
131
+ },
132
+ "host-key-check": {
133
+ "mode": "known_hosts"
134
+ }
135
+ },
136
+ "size": 4194304
137
+ }
138
+}
139
+{ "execute": "quit" }
140
+EOF
141
+
142
+_img_info | _filter_img_info
143
+
144
+
145
+key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
146
+ cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1)
147
+
148
+run_qemu <<EOF
149
+{ "execute": "qmp_capabilities" }
150
+{ "execute": "x-blockdev-create",
151
+ "arguments": {
152
+ "driver": "ssh",
153
+ "location": {
154
+ "path": "$TEST_IMG_FILE",
155
+ "server": {
156
+ "host": "127.0.0.1",
157
+ "port": "22"
158
+ },
159
+ "host-key-check": {
160
+ "mode": "hash",
161
+ "type": "md5",
162
+ "hash": "wrong"
163
+ }
164
+ },
165
+ "size": 8388608
166
+ }
167
+}
168
+{ "execute": "x-blockdev-create",
169
+ "arguments": {
170
+ "driver": "ssh",
171
+ "location": {
172
+ "path": "$TEST_IMG_FILE",
173
+ "server": {
174
+ "host": "127.0.0.1",
175
+ "port": "22"
176
+ },
177
+ "host-key-check": {
178
+ "mode": "hash",
179
+ "type": "md5",
180
+ "hash": "$key"
181
+ }
182
+ },
183
+ "size": 8388608
184
+ }
185
+}
186
+{ "execute": "quit" }
187
+EOF
188
+
189
+_img_info | _filter_img_info
190
+
191
+
192
+key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
193
+ cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1)
194
+
195
+run_qemu <<EOF
196
+{ "execute": "qmp_capabilities" }
197
+{ "execute": "x-blockdev-create",
198
+ "arguments": {
199
+ "driver": "ssh",
200
+ "location": {
201
+ "path": "$TEST_IMG_FILE",
202
+ "server": {
203
+ "host": "127.0.0.1",
204
+ "port": "22"
205
+ },
206
+ "host-key-check": {
207
+ "mode": "hash",
208
+ "type": "sha1",
209
+ "hash": "wrong"
210
+ }
211
+ },
212
+ "size": 4194304
213
+ }
214
+}
215
+{ "execute": "x-blockdev-create",
216
+ "arguments": {
217
+ "driver": "ssh",
218
+ "location": {
219
+ "path": "$TEST_IMG_FILE",
220
+ "server": {
221
+ "host": "127.0.0.1",
222
+ "port": "22"
223
+ },
224
+ "host-key-check": {
225
+ "mode": "hash",
226
+ "type": "sha1",
227
+ "hash": "$key"
228
+ }
229
+ },
230
+ "size": 4194304
231
+ }
232
+}
233
+{ "execute": "quit" }
234
+EOF
235
+
236
+_img_info | _filter_img_info
237
+
238
+echo
239
+echo "=== Invalid path and user ==="
240
+echo
241
+
242
+run_qemu <<EOF
243
+{ "execute": "qmp_capabilities" }
244
+{ "execute": "x-blockdev-create",
245
+ "arguments": {
246
+ "driver": "ssh",
247
+ "location": {
248
+ "path": "/this/is/not/an/existing/path",
249
+ "server": {
250
+ "host": "127.0.0.1",
251
+ "port": "22"
252
+ }
253
+ },
254
+ "size": 4194304
255
+ }
256
+}
257
+{ "execute": "x-blockdev-create",
258
+ "arguments": {
259
+ "driver": "ssh",
260
+ "location": {
261
+ "path": "$TEST_IMG_FILE",
262
+ "user": "invalid user",
263
+ "server": {
264
+ "host": "127.0.0.1",
265
+ "port": "22"
266
+ }
267
+ },
268
+ "size": 4194304
269
+ }
270
+}
271
+{ "execute": "quit" }
272
+EOF
273
+
274
+# success, all done
275
+echo "*** done"
276
+rm -f $seq.full
277
+status=0
278
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
279
new file mode 100644
280
index XXXXXXX..XXXXXXX
281
--- /dev/null
282
+++ b/tests/qemu-iotests/207.out
283
@@ -XXX,XX +XXX,XX @@
284
+QA output created by 207
285
+
286
+=== Successful image creation (defaults) ===
287
+
288
+Testing:
289
+QMP_VERSION
290
+{"return": {}}
291
+{"return": {}}
292
+{"return": {}}
293
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
294
+
295
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
296
+file format: IMGFMT
297
+virtual size: 4.0M (4194304 bytes)
298
+
299
+image: TEST_DIR/t.IMGFMT
300
+file format: IMGFMT
301
+virtual size: 4.0M (4194304 bytes)
302
+
303
+=== Test host-key-check options ===
304
+
305
+Testing:
306
+QMP_VERSION
307
+{"return": {}}
308
+{"return": {}}
309
+{"return": {}}
310
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
311
+
312
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
313
+file format: IMGFMT
314
+virtual size: 8.0M (8388608 bytes)
315
+Testing:
316
+QMP_VERSION
317
+{"return": {}}
318
+{"return": {}}
319
+{"return": {}}
320
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
321
+
322
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
323
+file format: IMGFMT
324
+virtual size: 4.0M (4194304 bytes)
325
+Testing:
326
+QMP_VERSION
327
+{"return": {}}
328
+{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
329
+{"return": {}}
330
+{"return": {}}
331
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
332
+
333
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
334
+file format: IMGFMT
335
+virtual size: 8.0M (8388608 bytes)
336
+Testing:
337
+QMP_VERSION
338
+{"return": {}}
339
+{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
340
+{"return": {}}
341
+{"return": {}}
342
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
343
+
344
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
345
+file format: IMGFMT
346
+virtual size: 4.0M (4194304 bytes)
347
+
348
+=== Invalid path and user ===
349
+
350
+Testing:
351
+QMP_VERSION
352
+{"return": {}}
353
+{"error": {"class": "GenericError", "desc": "failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)"}}
354
+{"error": {"class": "GenericError", "desc": "failed to authenticate using publickey authentication and the identities held by your ssh-agent"}}
355
+{"return": {}}
356
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
357
+
358
+*** done
359
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
360
index XXXXXXX..XXXXXXX 100644
361
--- a/tests/qemu-iotests/group
362
+++ b/tests/qemu-iotests/group
363
@@ -XXX,XX +XXX,XX @@
364
204 rw auto quick
365
205 rw auto quick
366
206 rw auto
367
+207 rw auto
368
--
369
2.13.6
370
371
diff view generated by jsdifflib
New patch
1
From: Fam Zheng <famz@redhat.com>
1
2
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
Message-id: 20171225025107.23985-1-famz@redhat.com
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/153 | 8 +++++---
9
tests/qemu-iotests/153.out | 7 ++++---
10
2 files changed, 9 insertions(+), 6 deletions(-)
11
12
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/153
15
+++ b/tests/qemu-iotests/153
16
@@ -XXX,XX +XXX,XX @@ _cleanup()
17
{
18
_cleanup_test_img
19
rm -f "${TEST_IMG}.base"
20
+ rm -f "${TEST_IMG}.overlay"
21
rm -f "${TEST_IMG}.convert"
22
rm -f "${TEST_IMG}.a"
23
rm -f "${TEST_IMG}.b"
24
@@ -XXX,XX +XXX,XX @@ rm -f "${TEST_IMG}.lnk" &>/dev/null
25
ln -s ${TEST_IMG} "${TEST_IMG}.lnk" || echo "Failed to create link"
26
_run_qemu_with_images "${TEST_IMG}.lnk" "${TEST_IMG}"
27
28
-echo
29
-echo "== Closing an image should unlock it =="
30
_launch_qemu
31
32
_send_qemu_cmd $QEMU_HANDLE \
33
@@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \
34
35
_run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512'
36
37
-echo "Closing drive"
38
+echo "Creating overlay with qemu-img when the guest is running should be allowed"
39
+_run_cmd $QEMU_IMG create -f $IMGFMT -b "${TEST_IMG}" "${TEST_IMG}.overlay"
40
+
41
+echo "== Closing an image should unlock it =="
42
_send_qemu_cmd $QEMU_HANDLE \
43
"{ 'execute': 'human-monitor-command',
44
'arguments': { 'command-line': 'drive_del d0' } }" \
45
diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out
46
index XXXXXXX..XXXXXXX 100644
47
--- a/tests/qemu-iotests/153.out
48
+++ b/tests/qemu-iotests/153.out
49
@@ -XXX,XX +XXX,XX @@ Is another process using the image?
50
== Symbolic link ==
51
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2: Failed to get "write" lock
52
Is another process using the image?
53
-
54
-== Closing an image should unlock it ==
55
{"return": {}}
56
Adding drive
57
58
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
59
can't open device TEST_DIR/t.qcow2: Failed to get "write" lock
60
Is another process using the image?
61
-Closing drive
62
+Creating overlay with qemu-img when the guest is running should be allowed
63
+
64
+_qemu_img_wrapper create -f qcow2 -b TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.overlay
65
+== Closing an image should unlock it ==
66
67
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
68
Adding two and closing one
69
--
70
2.13.6
71
72
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
Apparently it would be a good idea to test that, too.
3
The AFL image is to exercise the code validating image size, which
4
doesn't work on 32 bit or when out of memory (there is a large
5
allocation before the interesting point). So check that and skip the
6
test, instead of faking the result.
4
7
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Fam Zheng <famz@redhat.com>
6
Message-id: 20171009215533.12530-4-mreitz@redhat.com
9
Message-id: 20180301011413.11531-1-famz@redhat.com
7
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Jeff Cody <jcody@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
---
12
tests/qemu-iotests/125 | 7 +-
13
tests/qemu-iotests/059 | 5 ++---
13
tests/qemu-iotests/125.out | 480 ++++++++++++++++++++++++++++++++++++++++-----
14
1 file changed, 2 insertions(+), 3 deletions(-)
14
2 files changed, 437 insertions(+), 50 deletions(-)
15
15
16
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
16
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
17
index XXXXXXX..XXXXXXX 100755
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/125
18
--- a/tests/qemu-iotests/059
19
+++ b/tests/qemu-iotests/125
19
+++ b/tests/qemu-iotests/059
20
@@ -XXX,XX +XXX,XX @@ fi
20
@@ -XXX,XX +XXX,XX @@ done
21
# in B
21
echo
22
CREATION_SIZE=$((2 * 1024 * 1024 - 48 * 1024))
22
echo "=== Testing afl image with a very large capacity ==="
23
23
_use_sample_img afl9.vmdk.bz2
24
+# 512 is the actual test -- but it's good to test 64k as well, just to be sure.
24
-# The sed makes this test pass on machines with little RAM
25
+for cluster_size in 512 64k; do
25
-# (and also with 32 bit builds)
26
# in kB
26
-_img_info | sed -e 's/Cannot allocate memory/Invalid argument/'
27
for GROWTH_SIZE in 16 48 80; do
27
+_img_info | grep -q 'Cannot allocate memory' && _notrun "Insufficent memory, skipped test"
28
for create_mode in off metadata falloc full; do
28
+_img_info
29
for growth_mode in off metadata falloc full; do
29
_cleanup_test_img
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
30
44
# success, all done
31
# success, all done
45
echo '*** done'
46
diff --git a/tests/qemu-iotests/125.out b/tests/qemu-iotests/125.out
47
index XXXXXXX..XXXXXXX 100644
48
--- a/tests/qemu-iotests/125.out
49
+++ b/tests/qemu-iotests/125.out
50
@@ -XXX,XX +XXX,XX @@
51
QA output created by 125
52
---- growth_size=16 create_mode=off growth_mode=off ---
53
+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=off ---
54
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
55
Image resized.
56
wrote 2048000/2048000 bytes at offset 0
57
@@ -XXX,XX +XXX,XX @@ wrote 2048000/2048000 bytes at offset 0
58
wrote 16384/16384 bytes at offset 2048000
59
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
60
61
---- growth_size=16 create_mode=off growth_mode=metadata ---
62
+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=metadata ---
63
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off
64
Image resized.
65
wrote 2048000/2048000 bytes at offset 0
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
864
--
32
--
865
2.13.6
33
2.13.6
866
34
867
35
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This patch tweaks TestParallelOps in iotest 030 so it allocates data
4
in smaller regions (256KB/512KB instead of 512KB/1MB) and the
5
block-stream job in test_stream_commit() only needs to copy data that
6
is at the very end of the image.
7
8
This way when the block-stream job is awakened it will finish right
9
away without any chance of being stopped by block_job_sleep_ns(). This
10
triggers the bug that was fixed by 3d5d319e1221082974711af1d09d82f and
11
1a63a907507fbbcfaee3f622907ec24 and is therefore a more useful test
12
case for parallel block jobs.
13
14
After this patch the aforementiond bug can also be reproduced with the
15
test_stream_parallel() test case.
16
17
Since with this change the stream job in test_stream_commit() finishes
18
early, this patch introduces a similar test case where both jobs are
19
slowed down so they can actually run in parallel.
20
21
Signed-off-by: Alberto Garcia <berto@igalia.com>
22
Cc: John Snow <jsnow@redhat.com>
23
Message-id: 20180306130121.30243-1-berto@igalia.com
24
Signed-off-by: Max Reitz <mreitz@redhat.com>
25
---
26
tests/qemu-iotests/030 | 52 ++++++++++++++++++++++++++++++++++++++--------
27
tests/qemu-iotests/030.out | 4 ++--
28
2 files changed, 45 insertions(+), 11 deletions(-)
29
30
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
31
index XXXXXXX..XXXXXXX 100755
32
--- a/tests/qemu-iotests/030
33
+++ b/tests/qemu-iotests/030
34
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
35
class TestParallelOps(iotests.QMPTestCase):
36
num_ops = 4 # Number of parallel block-stream operations
37
num_imgs = num_ops * 2 + 1
38
- image_len = num_ops * 1024 * 1024
39
+ image_len = num_ops * 512 * 1024
40
imgs = []
41
42
def setUp(self):
43
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
44
'-o', 'backing_file=%s' % self.imgs[i-1], self.imgs[i])
45
46
# Put data into the images we are copying data from
47
- for i in range(self.num_imgs / 2):
48
- img_index = i * 2 + 1
49
- # Alternate between 512k and 1M.
50
+ odd_img_indexes = [x for x in reversed(range(self.num_imgs)) if x % 2 == 1]
51
+ for i in range(len(odd_img_indexes)):
52
+ # Alternate between 256KB and 512KB.
53
# This way jobs will not finish in the same order they were created
54
- num_kb = 512 + 512 * (i % 2)
55
+ num_kb = 256 + 256 * (i % 2)
56
qemu_io('-f', iotests.imgfmt,
57
- '-c', 'write -P %d %d %d' % (i, i*1024*1024, num_kb * 1024),
58
- self.imgs[img_index])
59
+ '-c', 'write -P 0xFF %dk %dk' % (i * 512, num_kb),
60
+ self.imgs[odd_img_indexes[i]])
61
62
# Attach the drive to the VM
63
self.vm = iotests.VM()
64
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
65
self.wait_until_completed(drive='commit-drive0')
66
67
# Test a block-stream and a block-commit job in parallel
68
- def test_stream_commit(self):
69
+ # Here the stream job is supposed to finish quickly in order to reproduce
70
+ # the scenario that triggers the bug fixed in 3d5d319e1221 and 1a63a907507
71
+ def test_stream_commit_1(self):
72
self.assertLessEqual(8, self.num_imgs)
73
self.assert_no_active_block_jobs()
74
75
# Stream from node0 into node2
76
- result = self.vm.qmp('block-stream', device='node2', job_id='node2')
77
+ result = self.vm.qmp('block-stream', device='node2', base_node='node0', job_id='node2')
78
self.assert_qmp(result, 'return', {})
79
80
# Commit from the active layer into node3
81
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
82
83
self.assert_no_active_block_jobs()
84
85
+ # This is similar to test_stream_commit_1 but both jobs are slowed
86
+ # down so they can run in parallel for a little while.
87
+ def test_stream_commit_2(self):
88
+ self.assertLessEqual(8, self.num_imgs)
89
+ self.assert_no_active_block_jobs()
90
+
91
+ # Stream from node0 into node4
92
+ result = self.vm.qmp('block-stream', device='node4', base_node='node0', job_id='node4', speed=1024*1024)
93
+ self.assert_qmp(result, 'return', {})
94
+
95
+ # Commit from the active layer into node5
96
+ result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[5], speed=1024*1024)
97
+ self.assert_qmp(result, 'return', {})
98
+
99
+ # Wait for all jobs to be finished.
100
+ pending_jobs = ['node4', 'drive0']
101
+ while len(pending_jobs) > 0:
102
+ for event in self.vm.get_qmp_events(wait=True):
103
+ if event['event'] == 'BLOCK_JOB_COMPLETED':
104
+ node_name = self.dictpath(event, 'data/device')
105
+ self.assertTrue(node_name in pending_jobs)
106
+ self.assert_qmp_absent(event, 'data/error')
107
+ pending_jobs.remove(node_name)
108
+ if event['event'] == 'BLOCK_JOB_READY':
109
+ self.assert_qmp(event, 'data/device', 'drive0')
110
+ self.assert_qmp(event, 'data/type', 'commit')
111
+ self.assert_qmp_absent(event, 'data/error')
112
+ self.assertTrue('drive0' in pending_jobs)
113
+ self.vm.qmp('block-job-complete', device='drive0')
114
+
115
+ self.assert_no_active_block_jobs()
116
+
117
# Test the base_node parameter
118
def test_stream_base_node_name(self):
119
self.assert_no_active_block_jobs()
120
diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out
121
index XXXXXXX..XXXXXXX 100644
122
--- a/tests/qemu-iotests/030.out
123
+++ b/tests/qemu-iotests/030.out
124
@@ -XXX,XX +XXX,XX @@
125
-.......................
126
+........................
127
----------------------------------------------------------------------
128
-Ran 23 tests
129
+Ran 24 tests
130
131
OK
132
--
133
2.13.6
134
135
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Whenever the actual image size is not part of the test, it should be
3
There is a race between the test's 'query-migrate' QMP command after the
4
filtered as it depends on the host filesystem.
4
QMP 'STOP' event and completing the migration:
5
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
The test case invokes 'query-migrate' upon receiving 'STOP'. At this
7
Message-id: 20171009163456.485-3-mreitz@redhat.com
7
point the migration thread may still be in the process of completing.
8
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Therefore 'query-migrate' can return 'status': 'active' for a brief
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
9
window of time instead of 'status': 'completed'. This results in
10
qemu-iotests 203 hanging.
11
12
Solve the race by enabling the 'events' migration capability, which
13
causes QEMU to emit migration-specific QMP events that do not suffer
14
from this race condition. Wait for the QMP 'MIGRATION' event with
15
'status': 'completed'.
16
17
Reported-by: Max Reitz <mreitz@redhat.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Message-id: 20180305155926.25858-1-stefanha@redhat.com
20
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
22
---
12
tests/qemu-iotests/184 | 3 ++-
23
tests/qemu-iotests/203 | 15 +++++++++++----
13
tests/qemu-iotests/184.out | 6 +++---
24
tests/qemu-iotests/203.out | 5 +++++
14
tests/qemu-iotests/191 | 4 ++--
25
2 files changed, 16 insertions(+), 4 deletions(-)
15
tests/qemu-iotests/191.out | 46 +++++++++++++++++++++++-----------------------
16
4 files changed, 30 insertions(+), 29 deletions(-)
17
26
18
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
27
diff --git a/tests/qemu-iotests/203 b/tests/qemu-iotests/203
19
index XXXXXXX..XXXXXXX 100755
28
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/184
29
--- a/tests/qemu-iotests/203
21
+++ b/tests/qemu-iotests/184
30
+++ b/tests/qemu-iotests/203
22
@@ -XXX,XX +XXX,XX @@ function do_run_qemu()
31
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('disk0.img') as disk0_img_path, \
23
function run_qemu()
32
node_name='drive1-node', iothread='iothread0',
24
{
33
force=True))
25
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
34
26
- | _filter_qemu_io | _filter_generated_node_ids
35
+ iotests.log('Enabling migration QMP events...')
27
+ | _filter_qemu_io | _filter_generated_node_ids \
36
+ iotests.log(vm.qmp('migrate-set-capabilities', capabilities=[
28
+ | _filter_actual_image_size
37
+ {
29
}
38
+ 'capability': 'events',
30
39
+ 'state': True
31
_make_test_img 64M
40
+ }
32
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
41
+ ]))
42
+
43
iotests.log('Starting migration...')
44
iotests.log(vm.qmp('migrate', uri='exec:cat >/dev/null'))
45
while True:
46
- vm.get_qmp_event(wait=60.0)
47
- result = vm.qmp('query-migrate')
48
- status = result.get('return', {}).get('status', None)
49
- if status == 'completed':
50
+ event = vm.event_wait('MIGRATION')
51
+ iotests.log(event, filters=[iotests.filter_qmp_event])
52
+ if event['data']['status'] == 'completed':
53
break
54
diff --git a/tests/qemu-iotests/203.out b/tests/qemu-iotests/203.out
33
index XXXXXXX..XXXXXXX 100644
55
index XXXXXXX..XXXXXXX 100644
34
--- a/tests/qemu-iotests/184.out
56
--- a/tests/qemu-iotests/203.out
35
+++ b/tests/qemu-iotests/184.out
57
+++ b/tests/qemu-iotests/203.out
36
@@ -XXX,XX +XXX,XX @@ Testing:
58
@@ -XXX,XX +XXX,XX @@ Launching VM...
37
"filename": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"qcow2\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/t.qcow2\"}}}",
59
Setting IOThreads...
38
"cluster-size": 65536,
60
{u'return': {}}
39
"format": "throttle",
61
{u'return': {}}
40
- "actual-size": 200704,
62
+Enabling migration QMP events...
41
+ "actual-size": SIZE,
63
+{u'return': {}}
42
"dirty-flag": false
64
Starting migration...
43
},
65
{u'return': {}}
44
"iops_wr": 0,
66
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'}
45
@@ -XXX,XX +XXX,XX @@ Testing:
67
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'active'}, u'event': u'MIGRATION'}
46
"filename": "TEST_DIR/t.qcow2",
68
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'completed'}, u'event': u'MIGRATION'}
47
"cluster-size": 65536,
48
"format": "qcow2",
49
- "actual-size": 200704,
50
+ "actual-size": SIZE,
51
"format-specific": {
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,
296
--
69
--
297
2.13.6
70
2.13.6
298
71
299
72
diff view generated by jsdifflib