@@ -847,11 +847,20 @@ struct BlockDriverState {
bool walking_aio_notifiers; /* to make removal during iteration safe */
char filename[PATH_MAX];
- char backing_file[PATH_MAX]; /* if non zero, the image is a diff of
- this file image */
- /* The backing filename indicated by the image header; if we ever
- * open this file, then this is replaced by the resulting BDS's
- * filename (i.e. after a bdrv_refresh_filename() run). */
+ /*
+ * If not empty, this image is a diff in relation to backing_file.
+ * Note that this is the name given in the image header and
+ * therefore may or may not be equal to .backing->bs->filename.
+ * If this field contains a relative path, it is to be resolved
+ * relatively to the overlay's location.
+ */
+ char backing_file[PATH_MAX];
+ /*
+ * The backing filename indicated by the image header. Contrary
+ * to backing_file, if we ever open this file, auto_backing_file
+ * is replaced by the resulting BDS's filename (i.e. after a
+ * bdrv_refresh_filename() run).
+ */
char auto_backing_file[PATH_MAX];
char backing_format[16]; /* if non-zero and backing_file exists */
@@ -1053,6 +1062,8 @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
QDict *options);
+bool bdrv_backing_overridden(BlockDriverState *bs);
+
/**
* bdrv_add_before_write_notifier:
@@ -1155,10 +1155,6 @@ static void bdrv_backing_attach(BdrvChild *c)
bdrv_refresh_filename(backing_hd);
parent->open_flags &= ~BDRV_O_NO_BACKING;
- pstrcpy(parent->backing_file, sizeof(parent->backing_file),
- backing_hd->filename);
- pstrcpy(parent->backing_format, sizeof(parent->backing_format),
- backing_hd->drv ? backing_hd->drv->format_name : "");
bdrv_op_block_all(backing_hd, parent->backing_blocker);
/* Otherwise we won't be able to commit or stream */
@@ -5673,6 +5669,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
char *backing_file_full = NULL;
char *filename_tmp = NULL;
int is_protocol = 0;
+ bool filenames_refreshed = false;
BlockDriverState *curr_bs = NULL;
BlockDriverState *retval = NULL;
BlockDriverState *bs_below;
@@ -5698,9 +5695,31 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
{
bs_below = bdrv_backing_chain_next(curr_bs);
- /* If either of the filename paths is actually a protocol, then
- * compare unmodified paths; otherwise make paths relative */
- if (is_protocol || path_has_protocol(curr_bs->backing_file)) {
+ if (bdrv_backing_overridden(curr_bs)) {
+ /*
+ * If the backing file was overridden, we can only compare
+ * directly against the backing node's filename.
+ */
+
+ if (!filenames_refreshed) {
+ /*
+ * This will automatically refresh all of the
+ * filenames in the rest of the backing chain, so we
+ * only need to do this once.
+ */
+ bdrv_refresh_filename(bs_below);
+ filenames_refreshed = true;
+ }
+
+ if (strcmp(backing_file, bs_below->filename) == 0) {
+ retval = bs_below;
+ break;
+ }
+ } else if (is_protocol || path_has_protocol(curr_bs->backing_file)) {
+ /*
+ * If either of the filename paths is actually a protocol, then
+ * compare unmodified paths; otherwise make paths relative.
+ */
char *backing_file_full_ret;
if (strcmp(backing_file, curr_bs->backing_file) == 0) {
@@ -6820,7 +6839,7 @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
/* Note: This function may return false positives; it may return true
* even if opening the backing file specified by bs's image header
* would result in exactly bs->backing. */
-static bool bdrv_backing_overridden(BlockDriverState *bs)
+bool bdrv_backing_overridden(BlockDriverState *bs)
{
if (bs->backing) {
return strcmp(bs->auto_backing_file,
@@ -47,7 +47,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
Error **errp)
{
ImageInfo **p_image_info;
- BlockDriverState *bs0;
+ BlockDriverState *bs0, *backing;
BlockDeviceInfo *info;
if (!bs->drv) {
@@ -76,9 +76,10 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
info->node_name = g_strdup(bs->node_name);
}
- if (bs->backing_file[0]) {
+ backing = bdrv_cow_bs(bs);
+ if (backing) {
info->has_backing_file = true;
- info->backing_file = g_strdup(bs->backing_file);
+ info->backing_file = g_strdup(backing->filename);
}
if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
@@ -314,6 +315,7 @@ void bdrv_query_image_info(BlockDriverState *bs,
backing_filename = bs->backing_file;
if (backing_filename[0] != '\0') {
char *backing_filename2;
+
info->backing_filename = g_strdup(backing_filename);
info->has_backing_filename = true;
backing_filename2 = bdrv_get_full_backing_filename(bs, NULL);
@@ -36,7 +36,7 @@ def log_node_info(node):
log('bs->filename: ' + node['image']['filename'],
filters=[filter_testfiles, filter_imgfmt])
- log('bs->backing_file: ' + node['backing_file'],
+ log('bs->backing_file: ' + node['image']['full-backing-filename'],
filters=[filter_testfiles, filter_imgfmt])
if 'backing-image' in node['image']:
@@ -73,8 +73,8 @@ with iotests.FilePath('base.img') as base_img_path, \
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
- # Filename should be plain, and the backing filename should not
- # contain the "file:" prefix
+ # Filename should be plain, and the backing node filename should
+ # not contain the "file:" prefix
log_node_info(vm.node_info('node0'))
vm.qmp_log('blockdev-del', node_name='node0')
@@ -4,7 +4,7 @@
{"return": {}}
bs->filename: TEST_DIR/PID-top.img
-bs->backing_file: TEST_DIR/PID-base.img
+bs->backing_file: file:TEST_DIR/PID-base.img
bs->backing->bs->filename: TEST_DIR/PID-base.img
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
@@ -41,7 +41,7 @@ bs->backing->bs->filename: TEST_DIR/PID-base.img
{"return": {}}
bs->filename: TEST_DIR/PID-top.img
-bs->backing_file: TEST_DIR/PID-base.img
+bs->backing_file: file:TEST_DIR/PID-base.img
bs->backing->bs->filename: TEST_DIR/PID-base.img
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
@@ -55,7 +55,7 @@ bs->backing->bs->filename: TEST_DIR/PID-base.img
{"return": {}}
bs->filename: json:{"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
-bs->backing_file: null-co://
+bs->backing_file: TEST_DIR/PID-base.img
bs->backing->bs->filename: null-co://
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
@@ -725,7 +725,9 @@ class TestBlockdevReopen(iotests.QMPTestCase):
# Detach hd2 from hd0.
self.reopen(opts, {'backing': None})
- self.reopen(opts, {}, "backing is missing for 'hd0'")
+
+ # Without a backing file, we can omit 'backing' again
+ self.reopen(opts)
# Remove both hd0 and hd2
result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
@@ -32,7 +32,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
"actual-size": SIZE,
"dirty-flag": false
},
- "backing-filename-format": "file",
+ "backing-filename-format": "IMGFMT",
"virtual-size": 67108864,
"filename": "TEST_DIR/t.IMGFMT.mid",
"cluster-size": 65536,
@@ -112,7 +112,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
"actual-size": SIZE,
"dirty-flag": false
},
- "backing-filename-format": "file",
+ "backing-filename-format": "IMGFMT",
"virtual-size": 67108864,
"filename": "TEST_DIR/t.IMGFMT.mid",
"cluster-size": 65536,