X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=block.c;h=11ab55f80b00865e9be4f49bca458bb2651984c2;hb=e3a6e0daf47f43cdb02b42c4dd3694a8f00063d5;hp=6925e57d7ca04326faaca3c2d013f0f57c577ced;hpb=add8200dd14041d059cc376eff91461fadd93ec5;p=mirror_qemu.git diff --git a/block.c b/block.c index 6925e57d7c..11ab55f80b 100644 --- a/block.c +++ b/block.c @@ -29,7 +29,7 @@ #include "block/nbd.h" #include "block/qdict.h" #include "qemu/error-report.h" -#include "module_block.h" +#include "block/module_block.h" #include "qemu/main-loop.h" #include "qemu/module.h" #include "qapi/error.h" @@ -433,9 +433,11 @@ static int bdrv_format_is_whitelisted(const char *format_name, bool read_only) { static const char *whitelist_rw[] = { CONFIG_BDRV_RW_WHITELIST + NULL }; static const char *whitelist_ro[] = { CONFIG_BDRV_RO_WHITELIST + NULL }; const char **p; @@ -710,11 +712,12 @@ int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp) int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz) { BlockDriver *drv = bs->drv; + BlockDriverState *filtered = bdrv_filter_bs(bs); if (drv && drv->bdrv_probe_blocksizes) { return drv->bdrv_probe_blocksizes(bs, bsz); - } else if (drv && drv->is_filter && bs->file) { - return bdrv_probe_blocksizes(bs->file->bs, bsz); + } else if (filtered) { + return bdrv_probe_blocksizes(filtered, bsz); } return -ENOTSUP; @@ -729,11 +732,12 @@ int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz) int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo) { BlockDriver *drv = bs->drv; + BlockDriverState *filtered = bdrv_filter_bs(bs); if (drv && drv->bdrv_probe_geometry) { return drv->bdrv_probe_geometry(bs, geo); - } else if (drv && drv->is_filter && bs->file) { - return bdrv_probe_geometry(bs->file->bs, geo); + } else if (filtered) { + return bdrv_probe_geometry(filtered, geo); } return -ENOTSUP; @@ -1151,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 */ @@ -1206,7 +1206,8 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, } ret = bdrv_change_backing_file(parent, filename, - base->drv ? base->drv->format_name : ""); + base->drv ? base->drv->format_name : "", + false); if (ret < 0) { error_setg_errno(errp, -ret, "Could not update backing file link"); } @@ -2024,6 +2025,22 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, return -EPERM; } + /* + * Unaligned requests will automatically be aligned to bl.request_alignment + * and without RESIZE we can't extend requests to write to space beyond the + * end of the image, so it's required that the image size is aligned. + */ + if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) && + !(cumulative_perms & BLK_PERM_RESIZE)) + { + if ((bs->total_sectors * BDRV_SECTOR_SIZE) % bs->bl.request_alignment) { + error_setg(errp, "Cannot get 'write' permission without 'resize': " + "Image size is not a multiple of request " + "alignment"); + return -EPERM; + } + } + /* Check this node */ if (!drv) { return 0; @@ -2585,7 +2602,7 @@ static void bdrv_replace_child_noperm(BdrvChild *child, /* * Updates @child to change its reference to point to @new_bs, including - * checking and applying the necessary permisson updates both to the old node + * checking and applying the necessary permission updates both to the old node * and to @new_bs. * * NULL is passed as @new_bs for removing the reference before freeing @child. @@ -2593,12 +2610,15 @@ static void bdrv_replace_child_noperm(BdrvChild *child, * If @new_bs is not NULL, bdrv_check_perm() must be called beforehand, as this * function uses bdrv_set_perm() to update the permissions according to the new * reference that @new_bs gets. + * + * Callers must ensure that child->frozen is false. */ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) { BlockDriverState *old_bs = child->bs; uint64_t perm, shared_perm; + /* Asserts that child->frozen == false */ bdrv_replace_child_noperm(child, new_bs); /* @@ -2759,6 +2779,7 @@ static void bdrv_detach_child(BdrvChild *child) g_free(child); } +/* Callers must ensure that child->frozen is false. */ void bdrv_root_unref_child(BdrvChild *child) { BlockDriverState *child_bs; @@ -2796,6 +2817,7 @@ static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child) } } +/* Callers must ensure that child->frozen is false. */ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) { if (child == NULL) { @@ -2844,7 +2866,7 @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs) } /* - * Sets the backing file link of a BDS. A new reference is created; callers + * Sets the bs->backing link of a BDS. A new reference is created; callers * which don't need their own reference any more must call bdrv_unref(). */ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, @@ -2853,7 +2875,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, bool update_inherits_from = bdrv_chain_contains(bs, backing_hd) && bdrv_inherits_from_recursive(backing_hd, bs); - if (bdrv_is_backing_chain_frozen(bs, backing_bs(bs), errp)) { + if (bdrv_is_backing_chain_frozen(bs, child_bs(bs->backing), errp)) { return; } @@ -2862,6 +2884,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, } if (bs->backing) { + /* Cannot be frozen, we checked that above */ bdrv_unref_child(bs, bs->backing); bs->backing = NULL; } @@ -3977,7 +4000,7 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state, Error **errp) { BlockDriverState *bs = reopen_state->bs; - BlockDriverState *overlay_bs, *new_backing_bs; + BlockDriverState *overlay_bs, *below_bs, *new_backing_bs; QObject *value; const char *str; @@ -4016,26 +4039,57 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state, } } + /* + * Ensure that @bs can really handle backing files, because we are + * about to give it one (or swap the existing one) + */ + if (bs->drv->is_filter) { + /* Filters always have a file or a backing child */ + if (!bs->backing) { + error_setg(errp, "'%s' is a %s filter node that does not support a " + "backing child", bs->node_name, bs->drv->format_name); + return -EINVAL; + } + } else if (!bs->drv->supports_backing) { + error_setg(errp, "Driver '%s' of node '%s' does not support backing " + "files", bs->drv->format_name, bs->node_name); + return -EINVAL; + } + /* * Find the "actual" backing file by skipping all links that point * to an implicit node, if any (e.g. a commit filter node). + * We cannot use any of the bdrv_skip_*() functions here because + * those return the first explicit node, while we are looking for + * its overlay here. */ overlay_bs = bs; - while (backing_bs(overlay_bs) && backing_bs(overlay_bs)->implicit) { - overlay_bs = backing_bs(overlay_bs); + for (below_bs = bdrv_filter_or_cow_bs(overlay_bs); + below_bs && below_bs->implicit; + below_bs = bdrv_filter_or_cow_bs(overlay_bs)) + { + overlay_bs = below_bs; } /* If we want to replace the backing file we need some extra checks */ - if (new_backing_bs != backing_bs(overlay_bs)) { + if (new_backing_bs != bdrv_filter_or_cow_bs(overlay_bs)) { /* Check for implicit nodes between bs and its backing file */ if (bs != overlay_bs) { error_setg(errp, "Cannot change backing link if '%s' has " "an implicit backing file", bs->node_name); return -EPERM; } - /* Check if the backing link that we want to replace is frozen */ - if (bdrv_is_backing_chain_frozen(overlay_bs, backing_bs(overlay_bs), - errp)) { + /* + * Check if the backing link that we want to replace is frozen. + * Note that + * bdrv_filter_or_cow_child(overlay_bs) == overlay_bs->backing, + * because we know that overlay_bs == bs, and that @bs + * either is a filter that uses ->backing or a COW format BDS + * with bs->drv->supports_backing == true. + */ + if (bdrv_is_backing_chain_frozen(overlay_bs, + child_bs(overlay_bs->backing), errp)) + { return -EPERM; } reopen_state->replace_backing_bs = true; @@ -4184,7 +4238,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, * its metadata. Otherwise the 'backing' option can be omitted. */ if (drv->supports_backing && reopen_state->backing_missing && - (backing_bs(reopen_state->bs) || reopen_state->bs->backing_file[0])) { + (reopen_state->bs->backing || reopen_state->bs->backing_file[0])) { error_setg(errp, "backing is missing for '%s'", reopen_state->bs->node_name); ret = -EINVAL; @@ -4325,7 +4379,7 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) * from bdrv_set_backing_hd()) has the new values. */ if (reopen_state->replace_backing_bs) { - BlockDriverState *old_backing_bs = backing_bs(bs); + BlockDriverState *old_backing_bs = child_bs(bs->backing); assert(!old_backing_bs || !old_backing_bs->implicit); /* Abort the permission update on the backing bs we're detaching */ if (old_backing_bs) { @@ -4368,6 +4422,7 @@ static void bdrv_close(BlockDriverState *bs) if (bs->drv) { if (bs->drv->bdrv_close) { + /* Must unfreeze all children, so bdrv_unref_child() works */ bs->drv->bdrv_close(bs); } bs->drv = NULL; @@ -4680,8 +4735,8 @@ int bdrv_check(BlockDriverState *bs, * image file header * -ENOTSUP - format driver doesn't support changing the backing file */ -int bdrv_change_backing_file(BlockDriverState *bs, - const char *backing_file, const char *backing_fmt) +int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, + const char *backing_fmt, bool warn) { BlockDriver *drv = bs->drv; int ret; @@ -4695,6 +4750,12 @@ int bdrv_change_backing_file(BlockDriverState *bs, return -EINVAL; } + if (warn && backing_file && !backing_fmt) { + warn_report("Deprecated use of backing file without explicit " + "backing format, use of this image requires " + "potentially unsafe format probing"); + } + if (drv->bdrv_change_backing_file != NULL) { ret = drv->bdrv_change_backing_file(bs, backing_file, backing_fmt); } else { @@ -4711,9 +4772,9 @@ int bdrv_change_backing_file(BlockDriverState *bs, } /* - * Finds the image layer in the chain that has 'bs' as its backing file. - * - * active is the current topmost image. + * Finds the first non-filter node above bs in the chain between + * active and bs. The returned node is either an immediate parent of + * bs, or there are only filter nodes between the two. * * Returns NULL if bs is not found in active's image chain, * or if active == bs. @@ -4723,11 +4784,18 @@ int bdrv_change_backing_file(BlockDriverState *bs, BlockDriverState *bdrv_find_overlay(BlockDriverState *active, BlockDriverState *bs) { - while (active && bs != backing_bs(active)) { - active = backing_bs(active); + bs = bdrv_skip_filters(bs); + active = bdrv_skip_filters(active); + + while (active) { + BlockDriverState *next = bdrv_backing_chain_next(active); + if (bs == next) { + return active; + } + active = next; } - return active; + return NULL; } /* Given a BDS, searches for the base layer. */ @@ -4737,20 +4805,22 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs) } /* - * Return true if at least one of the backing links between @bs and - * @base is frozen. @errp is set if that's the case. + * Return true if at least one of the COW (backing) and filter links + * between @bs and @base is frozen. @errp is set if that's the case. * @base must be reachable from @bs, or NULL. */ bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base, Error **errp) { BlockDriverState *i; + BdrvChild *child; + + for (i = bs; i != base; i = child_bs(child)) { + child = bdrv_filter_or_cow_child(i); - for (i = bs; i != base; i = backing_bs(i)) { - if (i->backing && i->backing->frozen) { + if (child && child->frozen) { error_setg(errp, "Cannot change '%s' link from '%s' to '%s'", - i->backing->name, i->node_name, - backing_bs(i)->node_name); + child->name, i->node_name, child->bs->node_name); return true; } } @@ -4759,7 +4829,7 @@ bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base, } /* - * Freeze all backing links between @bs and @base. + * Freeze all COW (backing) and filter links between @bs and @base. * If any of the links is already frozen the operation is aborted and * none of the links are modified. * @base must be reachable from @bs, or NULL. @@ -4769,22 +4839,25 @@ int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base, Error **errp) { BlockDriverState *i; + BdrvChild *child; if (bdrv_is_backing_chain_frozen(bs, base, errp)) { return -EPERM; } - for (i = bs; i != base; i = backing_bs(i)) { - if (i->backing && backing_bs(i)->never_freeze) { + for (i = bs; i != base; i = child_bs(child)) { + child = bdrv_filter_or_cow_child(i); + if (child && child->bs->never_freeze) { error_setg(errp, "Cannot freeze '%s' link to '%s'", - i->backing->name, backing_bs(i)->node_name); + child->name, child->bs->node_name); return -EPERM; } } - for (i = bs; i != base; i = backing_bs(i)) { - if (i->backing) { - i->backing->frozen = true; + for (i = bs; i != base; i = child_bs(child)) { + child = bdrv_filter_or_cow_child(i); + if (child) { + child->frozen = true; } } @@ -4792,18 +4865,21 @@ int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base, } /* - * Unfreeze all backing links between @bs and @base. The caller must - * ensure that all links are frozen before using this function. + * Unfreeze all COW (backing) and filter links between @bs and @base. + * The caller must ensure that all links are frozen before using this + * function. * @base must be reachable from @bs, or NULL. */ void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base) { BlockDriverState *i; + BdrvChild *child; - for (i = bs; i != base; i = backing_bs(i)) { - if (i->backing) { - assert(i->backing->frozen); - i->backing->frozen = false; + for (i = bs; i != base; i = child_bs(child)) { + child = bdrv_filter_or_cow_child(i); + if (child) { + assert(child->frozen); + child->frozen = false; } } } @@ -4871,9 +4947,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, * other intermediate nodes have been dropped. * If 'top' is an implicit node (e.g. "commit_top") we should skip * it because no one inherits from it. We use explicit_top for that. */ - while (explicit_top && explicit_top->implicit) { - explicit_top = backing_bs(explicit_top); - } + explicit_top = bdrv_skip_implicit_filters(explicit_top); update_inherits_from = bdrv_inherits_from_recursive(base, explicit_top); /* success - we can delete the intermediate states, and link top->base */ @@ -4906,8 +4980,11 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, } } - /* Do the actual switch in the in-memory graph. - * Completes bdrv_check_update_perm() transaction internally. */ + /* + * Do the actual switch in the in-memory graph. + * Completes bdrv_check_update_perm() transaction internally. + * c->frozen is false, we have checked that above. + */ bdrv_ref(base); bdrv_replace_child(c, base); bdrv_unref(top); @@ -4924,6 +5001,31 @@ exit: return ret; } +/** + * Implementation of BlockDriver.bdrv_get_allocated_file_size() that + * sums the size of all data-bearing children. (This excludes backing + * children.) + */ +static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) +{ + BdrvChild *child; + int64_t child_size, sum = 0; + + QLIST_FOREACH(child, &bs->children, next) { + if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | + BDRV_CHILD_FILTERED)) + { + child_size = bdrv_get_allocated_file_size(child->bs); + if (child_size < 0) { + return child_size; + } + sum += child_size; + } + } + + return sum; +} + /** * Length of a allocated file in bytes. Sparse files are counted by actual * allocated space. Return < 0 if error or unknown. @@ -4937,10 +5039,21 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) if (drv->bdrv_get_allocated_file_size) { return drv->bdrv_get_allocated_file_size(bs); } - if (bs->file) { - return bdrv_get_allocated_file_size(bs->file->bs); + + if (drv->bdrv_file_open) { + /* + * Protocol drivers default to -ENOTSUP (most of their data is + * not stored in any of their children (if they even have any), + * so there is no generic way to figure it out). + */ + return -ENOTSUP; + } else if (drv->is_filter) { + /* Filter drivers default to the size of their filtered child */ + return bdrv_get_allocated_file_size(bdrv_filter_bs(bs)); + } else { + /* Other drivers default to summing their children's sizes */ + return bdrv_sum_allocated_file_size(bs); } - return -ENOTSUP; } /* @@ -5022,12 +5135,27 @@ bool bdrv_is_sg(BlockDriverState *bs) return bs->sg; } -bool bdrv_is_encrypted(BlockDriverState *bs) +/** + * Return whether the given node supports compressed writes. + */ +bool bdrv_supports_compressed_writes(BlockDriverState *bs) { - if (bs->backing && bs->backing->bs->encrypted) { - return true; + BlockDriverState *filtered; + + if (!bs->drv || !block_driver_can_compress(bs->drv)) { + return false; } - return bs->encrypted; + + filtered = bdrv_filter_bs(bs); + if (filtered) { + /* + * Filters can only forward compressed writes, so we have to + * check the child. + */ + return bdrv_supports_compressed_writes(filtered); + } + + return true; } const char *bdrv_get_format_name(BlockDriverState *bs) @@ -5312,7 +5440,7 @@ BlockDriverState *bdrv_lookup_bs(const char *device, bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base) { while (top && top != base) { - top = backing_bs(top); + top = bdrv_filter_or_cow_bs(top); } return top != NULL; @@ -5384,20 +5512,24 @@ int bdrv_has_zero_init_1(BlockDriverState *bs) int bdrv_has_zero_init(BlockDriverState *bs) { + BlockDriverState *filtered; + if (!bs->drv) { return 0; } /* If BS is a copy on write image, it is initialized to the contents of the base image, which may not be zeroes. */ - if (bs->backing) { + if (bdrv_cow_child(bs)) { return 0; } if (bs->drv->bdrv_has_zero_init) { return bs->drv->bdrv_has_zero_init(bs); } - if (bs->file && bs->drv->is_filter) { - return bdrv_has_zero_init(bs->file->bs); + + filtered = bdrv_filter_bs(bs); + if (filtered) { + return bdrv_has_zero_init(filtered); } /* safe default */ @@ -5427,8 +5559,9 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return -ENOMEDIUM; } if (!drv->bdrv_get_info) { - if (bs->file && drv->is_filter) { - return bdrv_get_info(bs->file->bs, bdi); + BlockDriverState *filtered = bdrv_filter_bs(bs); + if (filtered) { + return bdrv_get_info(filtered, bdi); } return -ENOTSUP; } @@ -5467,17 +5600,7 @@ void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event) static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs) { while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) { - if (bs->file) { - bs = bs->file->bs; - continue; - } - - if (bs->drv->is_filter && bs->backing) { - bs = bs->backing->bs; - continue; - } - - break; + bs = bdrv_primary_bs(bs); } if (bs && bs->drv && bs->drv->bdrv_debug_breakpoint) { @@ -5512,7 +5635,7 @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) int bdrv_debug_resume(BlockDriverState *bs, const char *tag) { while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) { - bs = bs->file ? bs->file->bs : NULL; + bs = bdrv_primary_bs(bs); } if (bs && bs->drv && bs->drv->bdrv_debug_resume) { @@ -5525,7 +5648,7 @@ int bdrv_debug_resume(BlockDriverState *bs, const char *tag) bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag) { while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) { - bs = bs->file ? bs->file->bs : NULL; + bs = bdrv_primary_bs(bs); } if (bs && bs->drv && bs->drv->bdrv_debug_is_suspended) { @@ -5546,8 +5669,10 @@ 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; if (!bs || !bs->drv || !backing_file) { return NULL; @@ -5558,15 +5683,47 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, is_protocol = path_has_protocol(backing_file); - for (curr_bs = bs; curr_bs->backing; curr_bs = curr_bs->backing->bs) { + /* + * Being largely a legacy function, skip any filters here + * (because filters do not have normal filenames, so they cannot + * match anyway; and allowing json:{} filenames is a bit out of + * scope). + */ + for (curr_bs = bdrv_skip_filters(bs); + bdrv_cow_child(curr_bs) != NULL; + curr_bs = bs_below) + { + bs_below = bdrv_backing_chain_next(curr_bs); + + if (bdrv_backing_overridden(curr_bs)) { + /* + * If the backing file was overridden, we can only compare + * directly against the backing node's filename. + */ - /* 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 (!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) { - retval = curr_bs->backing->bs; + retval = bs_below; break; } /* Also check against the full backing filename for the image */ @@ -5576,7 +5733,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, bool equal = strcmp(backing_file, backing_file_full_ret) == 0; g_free(backing_file_full_ret); if (equal) { - retval = curr_bs->backing->bs; + retval = bs_below; break; } } @@ -5602,7 +5759,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, g_free(filename_tmp); if (strcmp(backing_file_full, filename_full) == 0) { - retval = curr_bs->backing->bs; + retval = bs_below; break; } } @@ -6094,6 +6251,10 @@ void bdrv_img_create(const char *filename, const char *fmt, "same filename as the backing file"); goto out; } + if (backing_file[0] == '\0') { + error_setg(errp, "Expected backing file name, got empty string"); + goto out; + } } backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT); @@ -6132,6 +6293,26 @@ void bdrv_img_create(const char *filename, const char *fmt, error_append_hint(&local_err, "Could not open backing image.\n"); goto out; } else { + if (!backing_fmt) { + warn_report("Deprecated use of backing file without explicit " + "backing format (detected format of %s)", + bs->drv->format_name); + if (bs->drv != &bdrv_raw) { + /* + * A probe of raw deserves the most attention: + * leaving the backing format out of the image + * will ensure bs->probed is set (ensuring we + * don't accidentally commit into the backing + * file), and allow more spots to warn the users + * to fix their toolchain when opening this image + * later. For other images, we can safely record + * the format that we probed. + */ + backing_fmt = bs->drv->format_name; + qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, backing_fmt, + NULL); + } + } if (size == -1) { /* Opened BS, have no size */ size = bdrv_getlength(bs); @@ -6145,7 +6326,12 @@ void bdrv_img_create(const char *filename, const char *fmt, } bdrv_unref(bs); } - } /* (backing_file && !(flags & BDRV_O_NO_BACKING)) */ + /* (backing_file && !(flags & BDRV_O_NO_BACKING)) */ + } else if (backing_file && !backing_fmt) { + warn_report("Deprecated use of unopened backing file without " + "explicit backing format, use of this image requires " + "potentially unsafe format probing"); + } if (size == -1) { error_setg(errp, "Image creation needs a size parameter"); @@ -6484,6 +6670,8 @@ int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts, bool bdrv_recurse_can_replace(BlockDriverState *bs, BlockDriverState *to_replace) { + BlockDriverState *filtered; + if (!bs || !bs->drv) { return false; } @@ -6498,9 +6686,9 @@ bool bdrv_recurse_can_replace(BlockDriverState *bs, } /* For filters without an own implementation, we can recurse on our own */ - if (bs->drv->is_filter) { - BdrvChild *child = bs->file ?: bs->backing; - return bdrv_recurse_can_replace(child->bs, to_replace); + filtered = bdrv_filter_bs(bs); + if (filtered) { + return bdrv_recurse_can_replace(filtered, to_replace); } /* Safe default */ @@ -6651,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, @@ -6679,6 +6867,7 @@ void bdrv_refresh_filename(BlockDriverState *bs) { BlockDriver *drv = bs->drv; BdrvChild *child; + BlockDriverState *primary_child_bs; QDict *opts; bool backing_overridden; bool generate_json_filename; /* Whether our default implementation should @@ -6748,20 +6937,30 @@ void bdrv_refresh_filename(BlockDriverState *bs) qobject_unref(bs->full_open_options); bs->full_open_options = opts; + primary_child_bs = bdrv_primary_bs(bs); + if (drv->bdrv_refresh_filename) { /* Obsolete information is of no use here, so drop the old file name * information before refreshing it */ bs->exact_filename[0] = '\0'; drv->bdrv_refresh_filename(bs); - } else if (bs->file) { - /* Try to reconstruct valid information from the underlying file */ + } else if (primary_child_bs) { + /* + * Try to reconstruct valid information from the underlying + * file -- this only works for format nodes (filter nodes + * cannot be probed and as such must be selected by the user + * either through an options dict, or through a special + * filename which the filter driver must construct in its + * .bdrv_refresh_filename() implementation). + */ bs->exact_filename[0] = '\0'; /* * We can use the underlying file's filename if: * - it has a filename, + * - the current BDS is not a filter, * - the file is a protocol BDS, and * - opening that file (as this BDS's format) will automatically create * the BDS tree we have right now, that is: @@ -6770,11 +6969,11 @@ void bdrv_refresh_filename(BlockDriverState *bs) * - no non-file child of this BDS has been overridden by the user * Both of these conditions are represented by generate_json_filename. */ - if (bs->file->bs->exact_filename[0] && - bs->file->bs->drv->bdrv_file_open && - !generate_json_filename) + if (primary_child_bs->exact_filename[0] && + primary_child_bs->drv->bdrv_file_open && + !drv->is_filter && !generate_json_filename) { - strcpy(bs->exact_filename, bs->file->bs->exact_filename); + strcpy(bs->exact_filename, primary_child_bs->exact_filename); } } @@ -6794,6 +6993,7 @@ void bdrv_refresh_filename(BlockDriverState *bs) char *bdrv_dirname(BlockDriverState *bs, Error **errp) { BlockDriver *drv = bs->drv; + BlockDriverState *child_bs; if (!drv) { error_setg(errp, "Node '%s' is ejected", bs->node_name); @@ -6804,8 +7004,9 @@ char *bdrv_dirname(BlockDriverState *bs, Error **errp) return drv->bdrv_dirname(bs, errp); } - if (bs->file) { - return bdrv_dirname(bs->file->bs, errp); + child_bs = bdrv_primary_bs(bs); + if (child_bs) { + return bdrv_dirname(child_bs, errp); } bdrv_refresh_filename(bs); @@ -6889,3 +7090,156 @@ int bdrv_make_empty(BdrvChild *c, Error **errp) return 0; } + +/* + * Return the child that @bs acts as an overlay for, and from which data may be + * copied in COW or COR operations. Usually this is the backing file. + */ +BdrvChild *bdrv_cow_child(BlockDriverState *bs) +{ + if (!bs || !bs->drv) { + return NULL; + } + + if (bs->drv->is_filter) { + return NULL; + } + + if (!bs->backing) { + return NULL; + } + + assert(bs->backing->role & BDRV_CHILD_COW); + return bs->backing; +} + +/* + * If @bs acts as a filter for exactly one of its children, return + * that child. + */ +BdrvChild *bdrv_filter_child(BlockDriverState *bs) +{ + BdrvChild *c; + + if (!bs || !bs->drv) { + return NULL; + } + + if (!bs->drv->is_filter) { + return NULL; + } + + /* Only one of @backing or @file may be used */ + assert(!(bs->backing && bs->file)); + + c = bs->backing ?: bs->file; + if (!c) { + return NULL; + } + + assert(c->role & BDRV_CHILD_FILTERED); + return c; +} + +/* + * Return either the result of bdrv_cow_child() or bdrv_filter_child(), + * whichever is non-NULL. + * + * Return NULL if both are NULL. + */ +BdrvChild *bdrv_filter_or_cow_child(BlockDriverState *bs) +{ + BdrvChild *cow_child = bdrv_cow_child(bs); + BdrvChild *filter_child = bdrv_filter_child(bs); + + /* Filter nodes cannot have COW backing files */ + assert(!(cow_child && filter_child)); + + return cow_child ?: filter_child; +} + +/* + * Return the primary child of this node: For filters, that is the + * filtered child. For other nodes, that is usually the child storing + * metadata. + * (A generally more helpful description is that this is (usually) the + * child that has the same filename as @bs.) + * + * Drivers do not necessarily have a primary child; for example quorum + * does not. + */ +BdrvChild *bdrv_primary_child(BlockDriverState *bs) +{ + BdrvChild *c, *found = NULL; + + QLIST_FOREACH(c, &bs->children, next) { + if (c->role & BDRV_CHILD_PRIMARY) { + assert(!found); + found = c; + } + } + + return found; +} + +static BlockDriverState *bdrv_do_skip_filters(BlockDriverState *bs, + bool stop_on_explicit_filter) +{ + BdrvChild *c; + + if (!bs) { + return NULL; + } + + while (!(stop_on_explicit_filter && !bs->implicit)) { + c = bdrv_filter_child(bs); + if (!c) { + /* + * A filter that is embedded in a working block graph must + * have a child. Assert this here so this function does + * not return a filter node that is not expected by the + * caller. + */ + assert(!bs->drv || !bs->drv->is_filter); + break; + } + bs = c->bs; + } + /* + * Note that this treats nodes with bs->drv == NULL as not being + * filters (bs->drv == NULL should be replaced by something else + * anyway). + * The advantage of this behavior is that this function will thus + * always return a non-NULL value (given a non-NULL @bs). + */ + + return bs; +} + +/* + * Return the first BDS that has not been added implicitly or that + * does not have a filtered child down the chain starting from @bs + * (including @bs itself). + */ +BlockDriverState *bdrv_skip_implicit_filters(BlockDriverState *bs) +{ + return bdrv_do_skip_filters(bs, true); +} + +/* + * Return the first BDS that does not have a filtered child down the + * chain starting from @bs (including @bs itself). + */ +BlockDriverState *bdrv_skip_filters(BlockDriverState *bs) +{ + return bdrv_do_skip_filters(bs, false); +} + +/* + * For a backing chain, return the first non-filter backing image of + * the first non-filter image. + */ +BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs) +{ + return bdrv_skip_filters(bdrv_cow_bs(bdrv_skip_filters(bs))); +}