From 6270aec1271880bb5f12db46d40f51671c548f59 Mon Sep 17 00:00:00 2001 From: Jeff Cody <jcody@redhat.com> Date: Thu, 7 Nov 2013 07:28:56 +0100 Subject: [PATCH 57/81] block: optionally disable live block jobs RH-Author: Jeff Cody <jcody@redhat.com> Message-id: <5b15ff37a1f28a76e2b66c07df996d3a7c37d6e9.1383712781.git.jcody@redhat.com> Patchwork-id: 55478 O-Subject: [RHEL7 qemu-kvm PATCH 1/3] block: optionally disable live block jobs Bugzilla: 987582 RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com> RH-Acked-by: Eric Blake <eblake@redhat.com> RH-Acked-by: Kevin Wolf <kwolf@redhat.com> This disables all block job operations that are part of the virt differentiation features. This includes: * live snapshots (single and group) * block stream * block commit * block mirror * block transactions All of these are disabled via the CONFIG_LIVE_BLOCK_OPS config option. In RHEL6, block job differentiation grew from live snapshot disablement, which was used to encompass many operations that were not live snapshots. CONFIG_LIVE_SNAPSHOTS was used for disablement of multiple features. For RHEL7, let's use naming that is more accurate: CONFIG_LIVE_BLOCK_OPS, to denote live block operations. RHEL and RHEV have different binaries, where RHEV qemu-kvm binaries support live snapshots. The JSON files qapi-schema-rhel.json and qapi-schema-rhev.json are automatically generated from the qapi-schema.json, by looking for '_rhev_only' comments in the 'master' JSON file. For RHEL6, the JSON file had makeshift 'ifdef' statements. This was changed to '_rhev_only' and '_end_rhev-only' blocks, because calling them 'ifdef' was misleading - it did not depend on the actual state of that variable itself. The Makefile variable RHEV_CONFIGS can be appended with additional config items that may appear in the qapi-schema.json file. For instance, to have features CONFIG_LIVE_BLOCK_OPS and CONFIG_SOME_FEATURE both be RHEV only, set the variable like so: RHEV_CONFIGS = CONFIG_LIVE_BLOCK_OPS CONFIG_SOME_FEATURE RHEV_CONFIGS is then turned into a regex. For the example above, the following pattern is matched when generating the RHEL/RHEV JSON files: ^#_rhev-only +(\bCONFIG_LIVE_BLOCK_OPS\b|\bCONFIG_SOME_FEATURE\b) Unlike the RHEL6 counterpart, this one uses original qmp-commands.h, qapi-types.h, qapi-visit.c, etc.. filenames, simplifying the Makefile a bit. BZ: 987582 The Makefile changes were derived from RHEL6 commit bb5bd75dd86a6d05c9df4c2d271f98744d6c90b7, but this was not a cherry-pick as the actual changes differed significantly. Signed-off-by: Jeff Cody <jcody@redhat.com> Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com> --- Makefile | 48 ++++++++++++++++++++++++++++++++++++++++++------ block/Makefile.objs | 2 ++ blockdev.c | 7 +++++++ configure | 14 +++++++++++++- hmp-commands.hx | 5 ++++- hmp.c | 4 ++++ qapi-schema.json | 6 ++++++ qmp-commands.hx | 4 ++++ 8 files changed, 82 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index dcd31c6..45048a3 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,11 @@ # Always point to the root of the build tree (needs GNU make). BUILD_DIR=$(CURDIR) +# useful for passing ' ' and ',' into Makefile functional calls, +# as these characters cannot be passed otherwise +_empty := +_space := $(_empty) $(_empty) +_comma := , # All following code might depend on configuration variables ifneq ($(wildcard config-host.mak),) @@ -213,15 +218,45 @@ qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@") +# if there are multiple config items to be RHEV-only, simply add it to +# RHEV_CONFIGS, like so: RHEV_CONFIGS = CONFIG_LIVE_BLOCK_OPS CONFIG_SOME_FEATURE +RHEV_CONFIGS = CONFIG_LIVE_BLOCK_OPS +# Turn $(RHEV_CONFIGS) into a regex with logical OR, and whole word matching +RHEV_ONLY_CONFIG_ITEMS = (\b$(subst $(_space),\b|\b,$(strip $(RHEV_CONFIGS)))\b) + +GENERATED_JSON_FILES = $(addprefix $(SRC_PATH)/, qapi-schema-rhel.json qapi-schema-rhev.json) + +$(SRC_PATH)/qapi-schema-rhev.json: $(SRC_PATH)/qapi-schema.json + -@echo "# THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY" > $@ + -@echo "#" >> $@ + $(call quiet-command,sed -r "/^#_rhev-only +$(RHEV_ONLY_CONFIG_ITEMS)/d;/^#_end-rhev-only/d" $< >> $@, " GEN $@") + +$(SRC_PATH)/qapi-schema-rhel.json: $(SRC_PATH)/qapi-schema.json + -@echo "# THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY" > $@ + -@echo "#" >> $@ + $(call quiet-command,sed -r "/^#_rhev-only +$(RHEV_ONLY_CONFIG_ITEMS)/$(_comma)/^#_end-rhev-only/d" $< >> $@, " GEN $@") + +ifeq ($(CONFIG_LIVE_BLOCK_OPS),y) qapi-types.c qapi-types.h :\ -$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, " GEN $@") +$(SRC_PATH)/qapi-schema-rhev.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, " GEN $@") qapi-visit.c qapi-visit.h :\ -$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." < $<, " GEN $@") +$(SRC_PATH)/qapi-schema-rhev.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." < $<, " GEN $@") qmp-commands.h qmp-marshal.c :\ -$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@") +$(SRC_PATH)/qapi-schema-rhev.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@") +else +qapi-types.c qapi-types.h :\ +$(SRC_PATH)/qapi-schema-rhel.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, " GEN $@") +qapi-visit.c qapi-visit.h :\ +$(SRC_PATH)/qapi-schema-rhel.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." < $<, " GEN $@") +qmp-commands.h qmp-marshal.c :\ +$(SRC_PATH)/qapi-schema-rhel.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) + $(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@") +endif QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) @@ -243,6 +278,7 @@ clean: rm -f trace/generated-tracers-dtrace.h* rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp) rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp) + rm -f $(foreach f,$(GENERATED_JSON_FILES),$(f) $(f)-timestamp) rm -rf qapi-generated rm -rf qga/qapi-generated $(MAKE) -C tests/tcg clean diff --git a/block/Makefile.objs b/block/Makefile.objs index 6b8d5ec..f355271 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -17,8 +17,10 @@ block-obj-$(CONFIG_GLUSTERFS) += gluster.o block-obj-$(CONFIG_LIBSSH2) += ssh.o endif +ifeq ($(CONFIG_LIVE_BLOCK_OPS),y) common-obj-y += stream.o common-obj-y += commit.o common-obj-y += mirror.o +endif $(obj)/curl.o: QEMU_CFLAGS+=$(CURL_CFLAGS) diff --git a/blockdev.c b/blockdev.c index f65aff4..6710f61 100644 --- a/blockdev.c +++ b/blockdev.c @@ -237,6 +237,8 @@ typedef struct { DriveInfo *dinfo; } DrivePutRefBH; +/* right now, this is only used from block_job_cb() */ +#ifdef CONFIG_LIVE_BLOCK_OPS static void drive_put_ref_bh(void *opaque) { DrivePutRefBH *s = opaque; @@ -262,6 +264,7 @@ static void drive_put_ref_bh_schedule(DriveInfo *dinfo) s->dinfo = dinfo; qemu_bh_schedule(s->bh); } +#endif static int parse_block_error_action(const char *buf, bool is_read) { @@ -806,6 +809,7 @@ void do_commit(Monitor *mon, const QDict *qdict) } } +#ifdef CONFIG_LIVE_BLOCK_OPS static void blockdev_do_action(int kind, void *data, Error **errp) { BlockdevAction action; @@ -1051,6 +1055,7 @@ exit: g_free(states); } } +#endif static void eject_device(BlockDriverState *bs, int force, Error **errp) @@ -1286,6 +1291,7 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp) } } +#ifdef CONFIG_LIVE_BLOCK_OPS static void block_job_cb(void *opaque, int ret) { BlockDriverState *bs = opaque; @@ -1547,6 +1553,7 @@ void qmp_drive_mirror(const char *device, const char *target, */ drive_get_ref(drive_get_by_blockdev(bs)); } +#endif static BlockJob *find_block_job(const char *device) { diff --git a/configure b/configure index 4830f7e..9260d3c 100755 --- a/configure +++ b/configure @@ -240,6 +240,7 @@ gtk="" gtkabi="2.0" tpm="no" libssh2="" +live_block_ops="yes" # parse CC options first for opt do @@ -927,7 +928,11 @@ for opt do ;; --enable-libssh2) libssh2="yes" ;; - *) echo "ERROR: unknown option $opt"; show_help="yes" + --disable-live-block-ops) live_block_ops="no" + ;; + --enable-live-block-ops) live_block_ops="yes" + ;; +*) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac done @@ -1195,6 +1200,8 @@ echo " --gcov=GCOV use specified gcov [$gcov_tool]" echo " --enable-tpm enable TPM support" echo " --disable-libssh2 disable ssh block device support" echo " --enable-libssh2 enable ssh block device support" +echo " --disable-live-block-ops disable live block operations support" +echo " --enable-live-block-ops enable live block operations support" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -3556,6 +3563,7 @@ echo "TPM support $tpm" echo "libssh2 support $libssh2" echo "TPM passthrough $tpm_passthrough" echo "QOM debugging $qom_cast_debug" +echo "Live block operations $live_block_ops" if test "$sdl_too_old" = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -3940,6 +3948,10 @@ if test "$virtio_blk_data_plane" = "yes" ; then echo 'CONFIG_VIRTIO_BLK_DATA_PLANE=$(CONFIG_VIRTIO)' >> $config_host_mak fi +if test "$live_block_ops" = "yes" ; then + echo "CONFIG_LIVE_BLOCK_OPS=y" >> $config_host_mak +fi + # USB host support if test "$libusb" = "yes"; then echo "HOST_USB=libusb legacy" >> $config_host_mak diff --git a/hmp-commands.hx b/hmp-commands.hx index 5cd6368..2fc2c0b 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -68,7 +68,7 @@ action to see the updated size. Resize to a lower size is supported, but should be used with extreme caution. Note that this command only resizes image files, it can not resize block devices like LVM volumes. ETEXI - +#ifdef CONFIG_LIVE_BLOCK_OPS { .name = "block_stream", .args_type = "device:B,speed:o?,base:s?", @@ -76,6 +76,7 @@ ETEXI .help = "copy data from a backing file into a block device", .mhandler.cmd = hmp_block_stream, }, +#endif STEXI @item block_stream @@ -1024,6 +1025,7 @@ gdb. ETEXI #endif +#ifdef CONFIG_LIVE_BLOCK_OPS { .name = "snapshot_blkdev", .args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?", @@ -1066,6 +1068,7 @@ STEXI Start mirroring a block device's writes to a new destination, using the specified target. ETEXI +#endif { .name = "drive_add", diff --git a/hmp.c b/hmp.c index 3b3e7c7..29990d2 100644 --- a/hmp.c +++ b/hmp.c @@ -838,6 +838,7 @@ void hmp_block_resize(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &errp); } +#ifdef CONFIG_LIVE_BLOCK_OPS void hmp_drive_mirror(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); @@ -889,6 +890,7 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) true, mode, &errp); hmp_handle_error(mon, &errp); } +#endif void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) { @@ -1030,6 +1032,7 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &err); } +#ifdef CONFIG_LIVE_BLOCK_OPS void hmp_block_stream(Monitor *mon, const QDict *qdict) { Error *error = NULL; @@ -1043,6 +1046,7 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &error); } +#endif void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict) { diff --git a/qapi-schema.json b/qapi-schema.json index b779458..12a360a 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1617,6 +1617,7 @@ ## { 'command': 'block_resize', 'data': { 'device': 'str', 'size': 'int' }} +#_rhev-only CONFIG_LIVE_BLOCK_OPS ## # @NewImageMode # @@ -1697,6 +1698,7 @@ ## { 'command': 'blockdev-snapshot-sync', 'data': 'BlockdevSnapshot' } +#_end-rhev-only ## # @human-monitor-command: @@ -1726,6 +1728,7 @@ 'data': {'command-line': 'str', '*cpu-index': 'int'}, 'returns': 'str' } +#_rhev-only CONFIG_LIVE_BLOCK_OPS ## # @block-commit # @@ -1811,6 +1814,7 @@ '*speed': 'int', '*granularity': 'uint32', '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } +#_end-rhev-only ## # @migrate_cancel @@ -2123,6 +2127,7 @@ 'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } } +#_rhev-only CONFIG_LIVE_BLOCK_OPS ## # @block-stream: # @@ -2160,6 +2165,7 @@ { 'command': 'block-stream', 'data': { 'device': 'str', '*base': 'str', '*speed': 'int', '*on-error': 'BlockdevOnError' } } +#_end-rhev-only ## # @block-job-set-speed: diff --git a/qmp-commands.hx b/qmp-commands.hx index de5f394..e40d54d 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -904,6 +904,7 @@ Example: EQMP +#ifdef CONFIG_LIVE_BLOCK_OPS { .name = "block-stream", .args_type = "device:B,base:s?,speed:o?,on-error:s?", @@ -915,6 +916,7 @@ EQMP .args_type = "device:B,base:s?,top:s,speed:o?", .mhandler.cmd_new = qmp_marshal_input_block_commit, }, +#endif { .name = "block-job-set-speed", @@ -942,6 +944,7 @@ EQMP .args_type = "device:B", .mhandler.cmd_new = qmp_marshal_input_block_job_complete, }, +#ifdef CONFIG_LIVE_BLOCK_OPS { .name = "transaction", .args_type = "actions:q", @@ -1085,6 +1088,7 @@ Example: <- { "return": {} } EQMP +#endif { .name = "balloon", -- 1.7.1