Skip to content

Commit a0ddbcf

Browse files
kevmwmdroth
authored andcommitted
block: Skip implicit nodes in query-block/blockstats
Commits 0db832f and 6cdbceb introduced the automatic insertion of filter nodes above the top layer of mirror and commit block jobs. The assumption made there was that since libvirt doesn't do node-level management of the block layer yet, it shouldn't be affected by added nodes. This is true as far as commands issued by libvirt are concerned. It only uses BlockBackend names to address nodes, so any operations it performs still operate on the root of the tree as intended. However, the assumption breaks down when you consider query commands, which return data for the wrong node now. These commands also return information on some child nodes (bs->file and/or bs->backing), which libvirt does make use of, and which refer to the wrong nodes, too. One of the consequences is that oVirt gets wrong information about the image size and stops the VM in response as long as a mirror or commit job is running: https://bugzilla.redhat.com/show_bug.cgi?id=1470634 This patch fixes the problem by hiding the implicit nodes created automatically by the mirror and commit block jobs in the output of query-block and BlockBackend-based query-blockstats as long as the user doesn't indicate that they are aware of those nodes by providing a node name for them in the QMP command to start the block job. The node-based commands query-named-block-nodes and query-blockstats with query-nodes=true still show all nodes, including implicit ones. This ensures that users that are capable of node-level management can still access the full information; users that only know BlockBackends won't use these commands. Cc: [email protected] Signed-off-by: Kevin Wolf <[email protected]> Reviewed-by: Peter Krempa <[email protected]> Reviewed-by: Max Reitz <[email protected]> Tested-by: Eric Blake <[email protected]> (cherry picked from commit d3c8c67) Conflicts: block/qapi.c include/block/block_int.h * fix context deps on 46eade7 and 5a9347c Signed-off-by: Michael Roth <[email protected]>
1 parent d445e0a commit a0ddbcf

File tree

11 files changed

+109
-28
lines changed

11 files changed

+109
-28
lines changed

block.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3863,19 +3863,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
38633863
return retval;
38643864
}
38653865

3866-
int bdrv_get_backing_file_depth(BlockDriverState *bs)
3867-
{
3868-
if (!bs->drv) {
3869-
return 0;
3870-
}
3871-
3872-
if (!bs->backing) {
3873-
return 0;
3874-
}
3875-
3876-
return 1 + bdrv_get_backing_file_depth(bs->backing->bs);
3877-
}
3878-
38793866
void bdrv_init(void)
38803867
{
38813868
module_call_init(MODULE_INIT_BLOCK);

block/commit.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,9 @@ void commit_start(const char *job_id, BlockDriverState *bs,
351351
if (commit_top_bs == NULL) {
352352
goto fail;
353353
}
354+
if (!filter_node_name) {
355+
commit_top_bs->implicit = true;
356+
}
354357
commit_top_bs->total_sectors = top->total_sectors;
355358
bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
356359

block/mirror.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,9 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
11521152
if (mirror_top_bs == NULL) {
11531153
return;
11541154
}
1155+
if (!filter_node_name) {
1156+
mirror_top_bs->implicit = true;
1157+
}
11551158
mirror_top_bs->total_sectors = bs->total_sectors;
11561159
bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
11571160

block/qapi.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
6464
info->backing_file = g_strdup(bs->backing_file);
6565
}
6666

67-
info->backing_file_depth = bdrv_get_backing_file_depth(bs);
6867
info->detect_zeroes = bs->detect_zeroes;
6968

7069
if (blk && blk_get_public(blk)->throttle_state) {
@@ -125,6 +124,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
125124

126125
bs0 = bs;
127126
p_image_info = &info->image;
127+
info->backing_file_depth = 0;
128128
while (1) {
129129
Error *local_err = NULL;
130130
bdrv_query_image_info(bs0, p_image_info, &local_err);
@@ -133,13 +133,21 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
133133
qapi_free_BlockDeviceInfo(info);
134134
return NULL;
135135
}
136+
136137
if (bs0->drv && bs0->backing) {
138+
info->backing_file_depth++;
137139
bs0 = bs0->backing->bs;
138140
(*p_image_info)->has_backing_image = true;
139141
p_image_info = &((*p_image_info)->backing_image);
140142
} else {
141143
break;
142144
}
145+
146+
/* Skip automatically inserted nodes that the user isn't aware of for
147+
* query-block (blk != NULL), but not for query-named-block-nodes */
148+
while (blk && bs0 && bs0->drv && bs0->implicit) {
149+
bs0 = backing_bs(bs0);
150+
}
143151
}
144152

145153
return info;
@@ -322,6 +330,12 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
322330
{
323331
BlockInfo *info = g_malloc0(sizeof(*info));
324332
BlockDriverState *bs = blk_bs(blk);
333+
334+
/* Skip automatically inserted nodes that the user isn't aware of */
335+
while (bs && bs->drv && bs->implicit) {
336+
bs = backing_bs(bs);
337+
}
338+
325339
info->device = g_strdup(blk_name(blk));
326340
info->type = g_strdup("unknown");
327341
info->locked = blk_dev_is_medium_locked(blk);
@@ -424,8 +438,8 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
424438
}
425439
}
426440

427-
static BlockStats *bdrv_query_bds_stats(const BlockDriverState *bs,
428-
bool query_backing)
441+
static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs,
442+
bool blk_level)
429443
{
430444
BlockStats *s = NULL;
431445

@@ -436,6 +450,14 @@ static BlockStats *bdrv_query_bds_stats(const BlockDriverState *bs,
436450
return s;
437451
}
438452

453+
/* Skip automatically inserted nodes that the user isn't aware of in
454+
* a BlockBackend-level command. Stay at the exact node for a node-level
455+
* command. */
456+
while (blk_level && bs->drv && bs->implicit) {
457+
bs = backing_bs(bs);
458+
assert(bs);
459+
}
460+
439461
if (bdrv_get_node_name(bs)[0]) {
440462
s->has_node_name = true;
441463
s->node_name = g_strdup(bdrv_get_node_name(bs));
@@ -445,12 +467,12 @@ static BlockStats *bdrv_query_bds_stats(const BlockDriverState *bs,
445467

446468
if (bs->file) {
447469
s->has_parent = true;
448-
s->parent = bdrv_query_bds_stats(bs->file->bs, query_backing);
470+
s->parent = bdrv_query_bds_stats(bs->file->bs, blk_level);
449471
}
450472

451-
if (query_backing && bs->backing) {
473+
if (blk_level && bs->backing) {
452474
s->has_backing = true;
453-
s->backing = bdrv_query_bds_stats(bs->backing->bs, query_backing);
475+
s->backing = bdrv_query_bds_stats(bs->backing->bs, blk_level);
454476
}
455477

456478
return s;

include/block/block.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,6 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
292292
int count, BdrvRequestFlags flags);
293293
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
294294
const char *backing_file);
295-
int bdrv_get_backing_file_depth(BlockDriverState *bs);
296295
void bdrv_refresh_filename(BlockDriverState *bs);
297296
int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp);
298297
int64_t bdrv_nb_sectors(BlockDriverState *bs);

include/block/block_int.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ struct BlockDriverState {
518518
bool valid_key; /* if true, a valid encryption key has been set */
519519
bool sg; /* if true, the device is a /dev/sg* */
520520
bool probed; /* if true, format was probed rather than specified */
521+
bool implicit; /* if true, this filter node was automatically inserted */
521522

522523
BlockDriver *drv; /* NULL means no media */
523524
void *opaque;

qapi/block-core.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,8 @@
467467
#
468468
# Get a list of BlockInfo for all virtual block devices.
469469
#
470-
# Returns: a list of @BlockInfo describing each virtual block device
470+
# Returns: a list of @BlockInfo describing each virtual block device. Filter
471+
# nodes that were created implicitly are skipped over.
471472
#
472473
# Since: 0.14.0
473474
#
@@ -723,7 +724,8 @@
723724
# information, but not "backing".
724725
# If false or omitted, the behavior is as before - query all the
725726
# device backends, recursively including their "parent" and
726-
# "backing". (Since 2.3)
727+
# "backing". Filter nodes that were created implicitly are
728+
# skipped over in this mode. (Since 2.3)
727729
#
728730
# Returns: A list of @BlockStats for each virtual block devices.
729731
#

tests/qemu-iotests/040

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class TestSingleDrive(ImageCommitTestCase):
8181
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
8282
qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img)
8383
qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img)
84-
self.vm = iotests.VM().add_drive(test_img, interface="none")
84+
self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=mid,backing.backing.node-name=base", interface="none")
8585
self.vm.add_device("virtio-scsi-pci")
8686
self.vm.add_device("scsi-hd,id=scsi0,drive=drive0")
8787
self.vm.launch()
@@ -163,6 +163,34 @@ class TestSingleDrive(ImageCommitTestCase):
163163

164164
self.assert_no_active_block_jobs()
165165

166+
# Tests that the insertion of the commit_top filter node doesn't make a
167+
# difference to query-blockstat
168+
def test_implicit_node(self):
169+
if self.image_len == 0:
170+
return
171+
172+
self.assert_no_active_block_jobs()
173+
result = self.vm.qmp('block-commit', device='drive0', top=mid_img,
174+
base=backing_img, speed=(self.image_len / 4))
175+
self.assert_qmp(result, 'return', {})
176+
177+
result = self.vm.qmp('query-block')
178+
self.assert_qmp(result, 'return[0]/inserted/file', test_img)
179+
self.assert_qmp(result, 'return[0]/inserted/drv', iotests.imgfmt)
180+
self.assert_qmp(result, 'return[0]/inserted/backing_file', mid_img)
181+
self.assert_qmp(result, 'return[0]/inserted/backing_file_depth', 2)
182+
self.assert_qmp(result, 'return[0]/inserted/image/filename', test_img)
183+
self.assert_qmp(result, 'return[0]/inserted/image/backing-image/filename', mid_img)
184+
self.assert_qmp(result, 'return[0]/inserted/image/backing-image/backing-image/filename', backing_img)
185+
186+
result = self.vm.qmp('query-blockstats')
187+
self.assert_qmp(result, 'return[0]/node-name', 'top')
188+
self.assert_qmp(result, 'return[0]/backing/node-name', 'mid')
189+
self.assert_qmp(result, 'return[0]/backing/backing/node-name', 'base')
190+
191+
self.cancel_and_wait()
192+
self.assert_no_active_block_jobs()
193+
166194
class TestRelativePaths(ImageCommitTestCase):
167195
image_len = 1 * 1024 * 1024
168196
test_len = 1 * 1024 * 256

tests/qemu-iotests/040.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
...........................
1+
.............................
22
----------------------------------------------------------------------
3-
Ran 27 tests
3+
Ran 29 tests
44

55
OK

tests/qemu-iotests/041

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class TestSingleDrive(iotests.QMPTestCase):
4242
def setUp(self):
4343
iotests.create_image(backing_img, self.image_len)
4444
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
45-
self.vm = iotests.VM().add_drive(test_img)
45+
self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=base")
4646
if iotests.qemu_default_machine == 'pc':
4747
self.vm.add_drive(None, 'media=cdrom', 'ide')
4848
self.vm.launch()
@@ -169,6 +169,42 @@ class TestSingleDrive(iotests.QMPTestCase):
169169
self.assertTrue(iotests.compare_images(test_img, target_img),
170170
'target image does not match source after mirroring')
171171

172+
# Tests that the insertion of the mirror_top filter node doesn't make a
173+
# difference to query-block
174+
def test_implicit_node(self):
175+
self.assert_no_active_block_jobs()
176+
177+
result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
178+
target=self.qmp_target)
179+
self.assert_qmp(result, 'return', {})
180+
181+
result = self.vm.qmp('query-block')
182+
self.assert_qmp(result, 'return[0]/inserted/file', test_img)
183+
self.assert_qmp(result, 'return[0]/inserted/drv', iotests.imgfmt)
184+
self.assert_qmp(result, 'return[0]/inserted/backing_file', backing_img)
185+
self.assert_qmp(result, 'return[0]/inserted/backing_file_depth', 1)
186+
self.assert_qmp(result, 'return[0]/inserted/image/filename', test_img)
187+
self.assert_qmp(result, 'return[0]/inserted/image/backing-image/filename', backing_img)
188+
189+
result = self.vm.qmp('query-blockstats')
190+
self.assert_qmp(result, 'return[0]/node-name', 'top')
191+
self.assert_qmp(result, 'return[0]/backing/node-name', 'base')
192+
193+
self.cancel_and_wait(force=True)
194+
result = self.vm.qmp('query-block')
195+
self.assert_qmp(result, 'return[0]/inserted/file', test_img)
196+
self.assert_qmp(result, 'return[0]/inserted/drv', iotests.imgfmt)
197+
self.assert_qmp(result, 'return[0]/inserted/backing_file', backing_img)
198+
self.assert_qmp(result, 'return[0]/inserted/backing_file_depth', 1)
199+
self.assert_qmp(result, 'return[0]/inserted/image/filename', test_img)
200+
self.assert_qmp(result, 'return[0]/inserted/image/backing-image/filename', backing_img)
201+
202+
result = self.vm.qmp('query-blockstats')
203+
self.assert_qmp(result, 'return[0]/node-name', 'top')
204+
self.assert_qmp(result, 'return[0]/backing/node-name', 'base')
205+
206+
self.vm.shutdown()
207+
172208
def test_medium_not_found(self):
173209
if iotests.qemu_default_machine != 'pc':
174210
return

tests/qemu-iotests/041.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
...............................................................................
1+
.....................................................................................
22
----------------------------------------------------------------------
3-
Ran 79 tests
3+
Ran 85 tests
44

55
OK

0 commit comments

Comments
 (0)