Revision 6cc2a415
b/blockdev.c | ||
---|---|---|
649 | 649 |
} |
650 | 650 |
} |
651 | 651 |
|
652 |
static void blockdev_do_action(int kind, void *data, Error **errp) |
|
653 |
{ |
|
654 |
BlockdevAction action; |
|
655 |
BlockdevActionList list; |
|
656 |
|
|
657 |
action.kind = kind; |
|
658 |
action.data = data; |
|
659 |
list.value = &action; |
|
660 |
list.next = NULL; |
|
661 |
qmp_transaction(&list, errp); |
|
662 |
} |
|
663 |
|
|
652 | 664 |
void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file, |
653 | 665 |
bool has_format, const char *format, |
666 |
bool has_mode, enum NewImageMode mode, |
|
654 | 667 |
Error **errp) |
655 | 668 |
{ |
656 |
BlockDriverState *bs; |
|
657 |
BlockDriver *drv, *old_drv, *proto_drv; |
|
658 |
int ret = 0; |
|
659 |
int flags; |
|
660 |
char old_filename[1024]; |
|
661 |
|
|
662 |
bs = bdrv_find(device); |
|
663 |
if (!bs) { |
|
664 |
error_set(errp, QERR_DEVICE_NOT_FOUND, device); |
|
665 |
return; |
|
666 |
} |
|
667 |
if (bdrv_in_use(bs)) { |
|
668 |
error_set(errp, QERR_DEVICE_IN_USE, device); |
|
669 |
return; |
|
670 |
} |
|
671 |
|
|
672 |
pstrcpy(old_filename, sizeof(old_filename), bs->filename); |
|
673 |
|
|
674 |
old_drv = bs->drv; |
|
675 |
flags = bs->open_flags; |
|
676 |
|
|
677 |
if (!has_format) { |
|
678 |
format = "qcow2"; |
|
679 |
} |
|
680 |
|
|
681 |
drv = bdrv_find_format(format); |
|
682 |
if (!drv) { |
|
683 |
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); |
|
684 |
return; |
|
685 |
} |
|
686 |
|
|
687 |
proto_drv = bdrv_find_protocol(snapshot_file); |
|
688 |
if (!proto_drv) { |
|
689 |
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); |
|
690 |
return; |
|
691 |
} |
|
692 |
|
|
693 |
ret = bdrv_img_create(snapshot_file, format, bs->filename, |
|
694 |
bs->drv->format_name, NULL, -1, flags); |
|
695 |
if (ret) { |
|
696 |
error_set(errp, QERR_UNDEFINED_ERROR); |
|
697 |
return; |
|
698 |
} |
|
699 |
|
|
700 |
bdrv_drain_all(); |
|
701 |
bdrv_flush(bs); |
|
702 |
|
|
703 |
bdrv_close(bs); |
|
704 |
ret = bdrv_open(bs, snapshot_file, flags, drv); |
|
705 |
/* |
|
706 |
* If reopening the image file we just created fails, fall back |
|
707 |
* and try to re-open the original image. If that fails too, we |
|
708 |
* are in serious trouble. |
|
709 |
*/ |
|
710 |
if (ret != 0) { |
|
711 |
ret = bdrv_open(bs, old_filename, flags, old_drv); |
|
712 |
if (ret != 0) { |
|
713 |
error_set(errp, QERR_OPEN_FILE_FAILED, old_filename); |
|
714 |
} else { |
|
715 |
error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file); |
|
716 |
} |
|
717 |
} |
|
669 |
BlockdevSnapshot snapshot = { |
|
670 |
.device = (char *) device, |
|
671 |
.snapshot_file = (char *) snapshot_file, |
|
672 |
.has_format = has_format, |
|
673 |
.format = (char *) format, |
|
674 |
.has_mode = has_mode, |
|
675 |
.mode = mode, |
|
676 |
}; |
|
677 |
blockdev_do_action(BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC, &snapshot, |
|
678 |
errp); |
|
718 | 679 |
} |
719 | 680 |
|
720 | 681 |
|
b/hmp-commands.hx | ||
---|---|---|
882 | 882 |
|
883 | 883 |
{ |
884 | 884 |
.name = "snapshot_blkdev", |
885 |
.args_type = "device:B,snapshot-file:s?,format:s?", |
|
886 |
.params = "device [new-image-file] [format]", |
|
885 |
.args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?",
|
|
886 |
.params = "[-n] device [new-image-file] [format]",
|
|
887 | 887 |
.help = "initiates a live snapshot\n\t\t\t" |
888 | 888 |
"of device. If a new image file is specified, the\n\t\t\t" |
889 | 889 |
"new image file will become the new root image.\n\t\t\t" |
890 | 890 |
"If format is specified, the snapshot file will\n\t\t\t" |
891 | 891 |
"be created in that format. Otherwise the\n\t\t\t" |
892 |
"snapshot will be internal! (currently unsupported)", |
|
892 |
"snapshot will be internal! (currently unsupported).\n\t\t\t" |
|
893 |
"The default format is qcow2. The -n flag requests QEMU\n\t\t\t" |
|
894 |
"to reuse the image found in new-image-file, instead of\n\t\t\t" |
|
895 |
"recreating it from scratch.", |
|
893 | 896 |
.mhandler.cmd = hmp_snapshot_blkdev, |
894 | 897 |
}, |
895 | 898 |
|
b/hmp.c | ||
---|---|---|
692 | 692 |
const char *device = qdict_get_str(qdict, "device"); |
693 | 693 |
const char *filename = qdict_get_try_str(qdict, "snapshot-file"); |
694 | 694 |
const char *format = qdict_get_try_str(qdict, "format"); |
695 |
int reuse = qdict_get_try_bool(qdict, "reuse", 0); |
|
696 |
enum NewImageMode mode; |
|
695 | 697 |
Error *errp = NULL; |
696 | 698 |
|
697 | 699 |
if (!filename) { |
... | ... | |
702 | 704 |
return; |
703 | 705 |
} |
704 | 706 |
|
705 |
qmp_blockdev_snapshot_sync(device, filename, !!format, format, &errp); |
|
707 |
mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS; |
|
708 |
qmp_blockdev_snapshot_sync(device, filename, !!format, format, |
|
709 |
true, mode, &errp); |
|
706 | 710 |
hmp_handle_error(mon, &errp); |
707 | 711 |
} |
708 | 712 |
|
b/qapi-schema.json | ||
---|---|---|
1141 | 1141 |
# @snapshot-file: the target of the new image. A new file will be created. |
1142 | 1142 |
# |
1143 | 1143 |
# @format: #optional the format of the snapshot image, default is 'qcow2'. |
1144 |
# |
|
1145 |
# @mode: #optional whether and how QEMU should create a new image, default is |
|
1146 |
# 'absolute-paths'. |
|
1144 | 1147 |
## |
1145 | 1148 |
{ 'type': 'BlockdevSnapshot', |
1146 | 1149 |
'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str', |
... | ... | |
1197 | 1200 |
# |
1198 | 1201 |
# @format: #optional the format of the snapshot image, default is 'qcow2'. |
1199 | 1202 |
# |
1203 |
# @mode: #optional whether and how QEMU should create a new image, default is |
|
1204 |
# 'absolute-paths'. |
|
1205 |
# |
|
1200 | 1206 |
# Returns: nothing on success |
1201 | 1207 |
# If @device is not a valid block device, DeviceNotFound |
1202 | 1208 |
# If @snapshot-file can't be opened, OpenFileFailed |
1203 | 1209 |
# If @format is invalid, InvalidBlockFormat |
1204 | 1210 |
# |
1205 |
# Notes: One of the last steps taken by this command is to close the current |
|
1206 |
# image being used by @device and open the @snapshot-file one. If that |
|
1207 |
# fails, the command will try to reopen the original image file. If |
|
1208 |
# that also fails OpenFileFailed will be returned and the guest may get |
|
1209 |
# unexpected errors. |
|
1210 |
# |
|
1211 | 1211 |
# Since 0.14.0 |
1212 | 1212 |
## |
1213 | 1213 |
{ 'command': 'blockdev-snapshot-sync', |
1214 |
'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str' } } |
|
1214 |
'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str', |
|
1215 |
'*mode': 'NewImageMode'} } |
|
1215 | 1216 |
|
1216 | 1217 |
## |
1217 | 1218 |
# @human-monitor-command: |
b/qmp-commands.hx | ||
---|---|---|
760 | 760 |
|
761 | 761 |
- "device": device name to snapshot (json-string) |
762 | 762 |
- "snapshot-file": name of new image file (json-string) |
763 |
- "mode": whether and how QEMU should create the snapshot file |
|
764 |
(NewImageMode, optional, default "absolute-paths") |
|
763 | 765 |
- "format": format of new image (json-string, optional) |
764 | 766 |
|
765 | 767 |
Example: |
Also available in: Unified diff