From a1f0676733467957c47b2a18c0c9929fd71b613d Mon Sep 17 00:00:00 2001 From: Manuel Bentele Date: Wed, 7 Oct 2020 10:51:06 +0200 Subject: block: Add driver callback to get cluster information Signed-off-by: Manuel Bentele --- block.c | 17 +++++++++++++++++ block/qcow2.c | 40 ++++++++++++++++++++++++++++++++++++++++ block/qcow2.h | 22 ++++++++++++++++++++++ include/block/block-io.h | 3 +++ include/block/block_int-common.h | 8 ++++++++ meson.build | 2 ++ meson_options.txt | 2 ++ qemu-io-cmds.c | 31 +++++++++++++++++++++++++++++++ scripts/meson-buildoptions.sh | 4 ++++ 9 files changed, 129 insertions(+) diff --git a/block.c b/block.c index a18f052374..e73b262871 100644 --- a/block.c +++ b/block.c @@ -6304,6 +6304,23 @@ BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs) return drv->bdrv_get_specific_stats(bs); } +#ifdef CONFIG_BDRV_CLUSTER_INFO +int bdrv_get_cluster_info(BlockDriverState *bs, uint64_t offset) +{ + BlockDriver *drv = bs->drv; + + if (!drv) { + return -ENOMEDIUM; + } + + if (drv->bdrv_get_cluster_info) { + return drv->bdrv_get_cluster_info(bs, offset); + } + + return -ENOTSUP; +} +#endif + void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event) { IO_CODE(); diff --git a/block/qcow2.c b/block/qcow2.c index 4d6666d3ff..a97f7b431a 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5925,6 +5925,42 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, s->signaled_corruption = true; } +#ifdef CONFIG_BDRV_CLUSTER_INFO +int qcow2_get_cluster_info(BlockDriverState *bs, uint64_t offset) +{ + BDRVQcow2State *s = bs->opaque; + uint64_t host_offset; + uint64_t coffset; + unsigned int bytes; + QCow2SubclusterType type; + int ret = 0, csize, nb_csectors; + + /* only get information for one byte */ + bytes = 1; + + ret = qcow2_get_host_offset(bs, offset, &bytes, &host_offset, &type); + if (ret < 0) { + return ret; + } + + printf("cluster type: %s\n", qcow2_get_subcluster_name(type)); + printf("cluster offset host: %ld\n", host_offset); + printf("cluster offset guest: %ld\n", offset); + printf("cluster offset in-cluster: %ld\n", offset_into_cluster(s, offset)); + + if (type == QCOW2_SUBCLUSTER_COMPRESSED) { + qcow2_parse_compressed_l2_entry(bs, host_offset, &coffset, &csize); + nb_csectors = ((host_offset >> s->csize_shift) & s->csize_mask) + 1; + + printf("cluster compressed offset: %ld\n", coffset); + printf("cluster compressed sectors: %d\n", nb_csectors); + printf("cluster compressed size: %d\n", csize); + } + + return ret; +} +#endif + #define QCOW_COMMON_OPTIONS \ { \ .name = BLOCK_OPT_SIZE, \ @@ -6108,6 +6144,10 @@ BlockDriver bdrv_qcow2 = { .bdrv_co_can_store_new_dirty_bitmap = qcow2_co_can_store_new_dirty_bitmap, .bdrv_co_remove_persistent_dirty_bitmap = qcow2_co_remove_persistent_dirty_bitmap, + +#ifdef CONFIG_BDRV_CLUSTER_INFO + .bdrv_get_cluster_info = qcow2_get_cluster_info, +#endif }; static void bdrv_qcow2_init(void) diff --git a/block/qcow2.h b/block/qcow2.h index 2285f18a73..ac30e48ee6 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -793,6 +793,24 @@ QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs, } } +#ifdef CONFIG_BDRV_CLUSTER_INFO +static inline const char *qcow2_get_subcluster_name( + const QCow2SubclusterType type) +{ + static const char *subcluster_names[] = { + "QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN", + "QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC", + "QCOW2_SUBCLUSTER_ZERO_PLAIN", + "QCOW2_SUBCLUSTER_ZERO_ALLOC", + "QCOW2_SUBCLUSTER_NORMAL", + "QCOW2_SUBCLUSTER_COMPRESSED", + "QCOW2_SUBCLUSTER_INVALID" + }; + + return subcluster_names[type]; +} +#endif + static inline bool qcow2_cluster_is_allocated(QCow2ClusterType type) { return (type == QCOW2_CLUSTER_COMPRESSED || type == QCOW2_CLUSTER_NORMAL || @@ -840,6 +858,10 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, int64_t size, const char *message_format, ...) G_GNUC_PRINTF(5, 6); +#ifdef CONFIG_BDRV_CLUSTER_INFO +int qcow2_get_cluster_info(BlockDriverState *bs, uint64_t offset); +#endif + int qcow2_validate_table(BlockDriverState *bs, uint64_t offset, uint64_t entries, size_t entry_len, int64_t max_size_bytes, const char *table_name, diff --git a/include/block/block-io.h b/include/block/block-io.h index b099d7db45..8866258282 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -126,6 +126,9 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, Error **errp); BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs); +#ifdef CONFIG_BDRV_CLUSTER_INFO + int bdrv_get_cluster_info(BlockDriverState *bs, uint64_t offset); +#endif void bdrv_round_to_clusters(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *cluster_offset, diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 31ae91e56e..2546500ab0 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -638,6 +638,14 @@ struct BlockDriver { int coroutine_fn (*bdrv_co_pdiscard_snapshot)(BlockDriverState *bs, int64_t offset, int64_t bytes); +#ifdef CONFIG_BDRV_CLUSTER_INFO + /* + * Returns information about the mapping between the guest cluster + * and the host cluster for a specific guest block address. + */ + int (*bdrv_get_cluster_info)(BlockDriverState *bs, uint64_t offset); +#endif + /* * Invalidate any cached meta-data. */ diff --git a/meson.build b/meson.build index 5c6b5a1c75..1b671e04ff 100644 --- a/meson.build +++ b/meson.build @@ -1821,6 +1821,7 @@ endif config_host_data.set('CONFIG_MODULE_UPGRADES', get_option('module_upgrades')) config_host_data.set('CONFIG_ATTR', libattr.found()) +config_host_data.set('CONFIG_BDRV_CLUSTER_INFO', get_option('block_drv_cluster_info')) config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools')) config_host_data.set('CONFIG_BRLAPI', brlapi.found()) config_host_data.set('CONFIG_COCOA', cocoa.found()) @@ -3854,6 +3855,7 @@ summary_info += {'coroutine pool': have_coroutine_pool} if have_block summary_info += {'Block whitelist (rw)': get_option('block_drv_rw_whitelist')} summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')} + summary_info += {'Block cluster info support': get_option('block_drv_cluster_info')} summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')} summary_info += {'VirtFS support': have_virtfs} summary_info += {'build virtiofs daemon': have_virtiofsd} diff --git a/meson_options.txt b/meson_options.txt index 4b749ca549..ea5b11c596 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -27,6 +27,8 @@ option('block_drv_rw_whitelist', type : 'string', value : '', description: 'set block driver read-write whitelist (by default affects only QEMU, not tools like qemu-img)') option('block_drv_ro_whitelist', type : 'string', value : '', description: 'set block driver read-only whitelist (by default affects only QEMU, not tools like qemu-img)') +option('block_drv_cluster_info', type: 'boolean', value: false, + description: 'block driver cluster info support') option('interp_prefix', type : 'string', value : '/usr/gnemul/qemu-%M', description: 'where to find shared libraries etc., use %M for cpu name') option('fuzzing_engine', type : 'string', value : '', diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 952dc940f1..c288c2ab30 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -2405,6 +2405,34 @@ static const cmdinfo_t sleep_cmd = { .oneline = "waits for the given value in milliseconds", }; +#ifdef CONFIG_BDRV_CLUSTER_INFO +static int cluster_info_f(BlockBackend *blk, int argc, char **argv) +{ + BlockDriverState *bs = blk_bs(blk); + char *endptr; + long offset; + + offset = strtol(argv[1], &endptr, 0); + if (offset < 0 || *endptr != '\0' || + offset > (bs->total_sectors * BDRV_SECTOR_SIZE)) { + printf("%s is not a valid number\n", argv[1]); + return -EINVAL; + } + + return bdrv_get_cluster_info(bs, offset); +} + +static const cmdinfo_t cluster_info_cmd = { + .name = "cluster_info", + .argmin = 1, + .argmax = 1, + .cfunc = cluster_info_f, + .args = "offset", + .oneline = "returns information about the mapping between guest \ + and host cluster type for a specific guest address", +}; +#endif + static void help_oneline(const char *cmd, const cmdinfo_t *ct) { printf("%s ", cmd); @@ -2517,5 +2545,8 @@ static void __attribute((constructor)) init_qemuio_commands(void) qemuio_add_command(&wait_break_cmd); qemuio_add_command(&abort_cmd); qemuio_add_command(&sleep_cmd); +#ifdef CONFIG_BDRV_CLUSTER_INFO + qemuio_add_command(&cluster_info_cmd); +#endif qemuio_add_command(&sigraise_cmd); } diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index aa6e30ea91..ff0764b866 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -13,6 +13,8 @@ meson_options_help() { printf "%s\n" ' --disable-install-blobs install provided firmware blobs' printf "%s\n" ' --docdir=VALUE Base directory for documentation installation' printf "%s\n" ' (can be empty) [share/doc]' + printf "%s\n" ' --enable-block-drv-cluster-info' + printf "%s\n" ' block driver cluster info support' printf "%s\n" ' --enable-block-drv-whitelist-in-tools' printf "%s\n" ' use block whitelist also in tools instead of only' printf "%s\n" ' QEMU' @@ -204,6 +206,8 @@ _meson_option_parse() { --disable-blkio) printf "%s" -Dblkio=disabled ;; --block-drv-ro-whitelist=*) quote_sh "-Dblock_drv_ro_whitelist=$2" ;; --block-drv-rw-whitelist=*) quote_sh "-Dblock_drv_rw_whitelist=$2" ;; + --enable-block-drv-cluster-info) printf "%s" -Dblock_drv_cluster_info=true ;; + --disable-block-drv-cluster-info) printf "%s" -Dblock_drv_cluster_info=false ;; --enable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=true ;; --disable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=false ;; --enable-bochs) printf "%s" -Dbochs=enabled ;; -- cgit v1.2.3-55-g7522