From d4cbff6f5eced7371e96e620a45e59b11ada51e9 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: <5e4659718c6d6ee9ab11b269d929a292a71b3ab0.1334770230.git.minovotn@redhat.com> References: <5e4659718c6d6ee9ab11b269d929a292a71b3ab0.1334770230.git.minovotn@redhat.com> From: Paolo Bonzini Date: Fri, 13 Apr 2012 16:27:22 +0200 Subject: [PATCH 14/18] block: add witness argument to drive-reopen RH-Author: Paolo Bonzini Message-id: <1334334446-31987-13-git-send-email-pbonzini@redhat.com> Patchwork-id: 39224 O-Subject: [RHEL 6.3 qemu-kvm PATCH 12/16] block: add witness argument to drive-reopen Bugzilla: 806432 RH-Acked-by: Kevin Wolf RH-Acked-by: Laszlo Ersek RH-Acked-by: Jeffrey Cody Management needs a way for QEMU to confirm that no I/O has been sent to the target and not to the source. To provide this guarantee we rely on a file in local persistent storage. QEMU receives a file descriptor via SCM_RIGHTS and writes a single byte to it. If it fails, it will fail the drive-reopen command too and management knows that no I/O request has been issued to the new destination. Likewise, if management finds the file to have nonzero size it knows that the target is valid and that indeed I/O requests could have been submitted to it. --- blockdev.c | 20 +++++++++++++++++++- hmp.c | 2 +- qapi-schema.json | 10 +++++++++- qemu-monitor.hx | 12 +++++++++++- 4 files changed, 40 insertions(+), 4 deletions(-) Signed-off-by: Michal Novotny --- blockdev.c | 23 ++++++++++++++++++++++- hmp.c | 2 +- qapi-schema.json | 10 +++++++++- qemu-monitor.hx | 12 +++++++++++- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/blockdev.c b/blockdev.c index a29416e..9fd29d7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -680,14 +680,25 @@ void do_commit(Monitor *mon, const QDict *qdict) #ifdef CONFIG_LIVE_SNAPSHOTS void qmp___com_redhat_drive_reopen(const char *device, const char *new_image_file, - bool has_format, const char *format, Error **errp) + bool has_format, const char *format, + bool has_witness, const char *witness, + Error **errp) { BlockDriverState *bs; BlockDriver *drv, *old_drv, *proto_drv; + int fd = -1; int ret = 0; int flags; char old_filename[1024]; + if (has_witness) { + fd = monitor_get_fd(cur_mon, witness); + if (fd == -1) { + error_set(errp, QERR_FD_NOT_FOUND, witness); + return; + } + } + bs = bdrv_find(device); if (!bs) { error_set(errp, QERR_DEVICE_NOT_FOUND, device); @@ -732,6 +743,16 @@ void qmp___com_redhat_drive_reopen(const char *device, const char *new_image_fil bdrv_close(bs); ret = bdrv_open(bs, new_image_file, flags, drv); + + if (ret == 0 && fd != -1) { + ret = write(fd, "", 1) == 1 ? 0 : -1; + qemu_fdatasync(fd); + close(fd); + if (ret < 0) { + bdrv_close(bs); + } + } + /* * If reopening the image file we just created fails, fall back * and try to re-open the original image. If that fails too, we diff --git a/hmp.c b/hmp.c index a500123..b9e0ad3 100644 --- a/hmp.c +++ b/hmp.c @@ -81,7 +81,7 @@ void hmp_drive_reopen(Monitor *mon, const QDict *qdict) const char *format = qdict_get_try_str(qdict, "format"); Error *errp = NULL; - qmp___com_redhat_drive_reopen(device, filename, !!format, format, &errp); + qmp___com_redhat_drive_reopen(device, filename, !!format, format, false, NULL, &errp); hmp_handle_error(mon, &errp); } #endif diff --git a/qapi-schema.json b/qapi-schema.json index 9c9700e..5e939dd 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -132,6 +132,13 @@ # # @format: #optional the format of the new image, default is 'qcow2'. # +# @witness: A file descriptor name that was passed via getfd. QEMU will write +# a single byte to this file descriptor before completing the command +# successfully. If the byte is not written to the file, it is +# guaranteed that the guest has not issued any I/O to the new image. +# Failure to write the byte is fatal just like failure to open the new +# image, and will cause the guest to revert to the currently open file. +# # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound # If @new-image-file can't be opened, OpenFileFailed @@ -140,7 +147,8 @@ # Since 1.1 ## { 'command': '__com.redhat_drive-reopen', - 'data': { 'device': 'str', 'new-image-file': 'str', '*format': 'str' } } + 'data': { 'device': 'str', 'new-image-file': 'str', '*format': 'str', + '*witness': 'str' } } ## # @__com.redhat_drive-mirror diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 52b92ed..bafd0ae 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -1629,7 +1629,7 @@ EQMP #ifdef CONFIG_LIVE_SNAPSHOTS { .name = "__com.redhat_drive-reopen", - .args_type = "device:B,new-image-file:s,format:s?", + .args_type = "device:B,new-image-file:s,format:s?,witness:s?", .user_print = monitor_user_noop, .mhandler.cmd_new = qmp_marshal_input___com_redhat_drive_reopen, }, @@ -1644,11 +1644,21 @@ guest is expecting the drive to change its content, the new image should contain the same data of the current one. One use case is to terminate a __com.redhat-drive-mirror command. +The command can optionally write a single byte to a file descriptor name +that was passed via SCM rights (getfd). QEMU will write a single byte +to this file descriptor before completing the command successfully. +If the byte is not written to the file, it is guaranteed that the +guest has not issued any I/O to the new image. Failure to write the +byte is fatal just like failure to open the new image, and will cause +the guest to revert to the currently open file. + + Arguments: - "device": device name to operate on (json-string) - "new-image-file": name of new image file (json-string) - "format": format of new image (json-string, optional) +- "witness": file descriptor previously passed via SCM rights (json-string, optional) Example: -- 1.7.7.6