X-Git-Url: https://git.proxmox.com/?p=pve-qemu-kvm.git;a=blobdiff_plain;f=debian%2Fpatches%2Fold%2Fbackup-add-pve-monitor-commands.patch;fp=debian%2Fpatches%2Fold%2Fbackup-add-pve-monitor-commands.patch;h=0000000000000000000000000000000000000000;hp=2b45b2cc360ee113909eca0dbd79a06f915c0fb0;hb=e8d0924679a5d7a3acfc128a1140ffdef0269338;hpb=dcfd9c72bc5bb92f7715f7eb52e6610bc629a1c8 diff --git a/debian/patches/old/backup-add-pve-monitor-commands.patch b/debian/patches/old/backup-add-pve-monitor-commands.patch deleted file mode 100644 index 2b45b2c..0000000 --- a/debian/patches/old/backup-add-pve-monitor-commands.patch +++ /dev/null @@ -1,752 +0,0 @@ -Index: new/blockdev.c -=================================================================== ---- new.orig/blockdev.c 2014-11-20 07:36:12.000000000 +0100 -+++ new/blockdev.c 2014-11-20 07:47:31.000000000 +0100 -@@ -49,6 +49,7 @@ - #include "qmp-commands.h" - #include "trace.h" - #include "sysemu/arch_init.h" -+#include "vma.h" - - static const char *const if_name[IF_COUNT] = { - [IF_NONE] = "none", -@@ -2276,6 +2277,443 @@ - bdrv_put_ref_bh_schedule(bs); - } - -+/* PVE backup related function */ -+ -+static struct PVEBackupState { -+ Error *error; -+ bool cancel; -+ uuid_t uuid; -+ char uuid_str[37]; -+ int64_t speed; -+ time_t start_time; -+ time_t end_time; -+ char *backup_file; -+ VmaWriter *vmaw; -+ GList *di_list; -+ size_t total; -+ size_t transferred; -+ size_t zero_bytes; -+} backup_state; -+ -+typedef struct PVEBackupDevInfo { -+ BlockDriverState *bs; -+ size_t size; -+ uint8_t dev_id; -+ //bool started; -+ bool completed; -+} PVEBackupDevInfo; -+ -+static void pvebackup_run_next_job(void); -+ -+static int pvebackup_dump_cb(void *opaque, BlockDriverState *target, -+ int64_t sector_num, int n_sectors, -+ unsigned char *buf) -+{ -+ PVEBackupDevInfo *di = opaque; -+ -+ if (sector_num & 0x7f) { -+ if (!backup_state.error) { -+ error_setg(&backup_state.error, -+ "got unaligned write inside backup dump " -+ "callback (sector %ld)", sector_num); -+ } -+ return -1; // not aligned to cluster size -+ } -+ -+ int64_t cluster_num = sector_num >> 7; -+ int size = n_sectors * BDRV_SECTOR_SIZE; -+ -+ int ret = -1; -+ -+ if (backup_state.vmaw) { -+ size_t zero_bytes = 0; -+ ret = vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num, -+ buf, &zero_bytes); -+ backup_state.zero_bytes += zero_bytes; -+ } else { -+ ret = size; -+ if (!buf) { -+ backup_state.zero_bytes += size; -+ } -+ } -+ -+ backup_state.transferred += size; -+ -+ return ret; -+} -+ -+static void pvebackup_cleanup(void) -+{ -+ backup_state.end_time = time(NULL); -+ -+ if (backup_state.vmaw) { -+ Error *local_err = NULL; -+ vma_writer_close(backup_state.vmaw, &local_err); -+ error_propagate(&backup_state.error, local_err); -+ backup_state.vmaw = NULL; -+ } -+ -+ if (backup_state.di_list) { -+ GList *l = backup_state.di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ g_free(di); -+ } -+ g_list_free(backup_state.di_list); -+ backup_state.di_list = NULL; -+ } -+} -+ -+static void pvebackup_complete_cb(void *opaque, int ret) -+{ -+ PVEBackupDevInfo *di = opaque; -+ -+ assert(backup_state.vmaw); -+ -+ di->completed = true; -+ -+ if (ret < 0 && !backup_state.error) { -+ error_setg(&backup_state.error, "job failed with err %d - %s", -+ ret, strerror(-ret)); -+ } -+ -+ BlockDriverState *bs = di->bs; -+ -+ di->bs = NULL; -+ -+ vma_writer_close_stream(backup_state.vmaw, di->dev_id); -+ -+ block_job_cb(bs, ret); -+ -+ if (!backup_state.cancel) { -+ pvebackup_run_next_job(); -+ } -+} -+ -+static void pvebackup_cancel(void *opaque) -+{ -+ backup_state.cancel = true; -+ -+ if (!backup_state.error) { -+ error_setg(&backup_state.error, "backup cancelled"); -+ } -+ -+ /* drain all i/o (awake jobs waiting for aio) */ -+ bdrv_drain_all(); -+ -+ GList *l = backup_state.di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ if (!di->completed && di->bs) { -+ BlockJob *job = di->bs->job; -+ if (job) { -+ if (!di->completed) { -+ block_job_cancel_sync(job); -+ } -+ } -+ } -+ } -+ -+ pvebackup_cleanup(); -+} -+ -+void qmp_backup_cancel(Error **errp) -+{ -+ Coroutine *co = qemu_coroutine_create(pvebackup_cancel); -+ qemu_coroutine_enter(co, NULL); -+ -+ while (backup_state.vmaw) { -+ /* vma writer use main aio context */ -+ aio_poll(qemu_get_aio_context(), true); -+ } -+} -+ -+static void pvebackup_run_next_job(void) -+{ -+ GList *l = backup_state.di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ if (!di->completed && di->bs && di->bs->job) { -+ BlockJob *job = di->bs->job; -+ if (block_job_is_paused(job)) { -+ bool cancel = backup_state.error || backup_state.cancel; -+ if (cancel) { -+ block_job_cancel(job); -+ } else { -+ block_job_resume(job); -+ } -+ } -+ return; -+ } -+ } -+ -+ pvebackup_cleanup(); -+} -+ -+UuidInfo *qmp_backup(const char *backup_file, bool has_format, -+ BackupFormat format, -+ bool has_config_file, const char *config_file, -+ bool has_devlist, const char *devlist, -+ bool has_speed, int64_t speed, Error **errp) -+{ -+ BlockBackend *blk; -+ BlockDriverState *bs = NULL; -+ Error *local_err = NULL; -+ uuid_t uuid; -+ VmaWriter *vmaw = NULL; -+ gchar **devs = NULL; -+ GList *di_list = NULL; -+ GList *l; -+ UuidInfo *uuid_info; -+ -+ if (backup_state.di_list) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, -+ "previous backup not finished"); -+ return NULL; -+ } -+ -+ /* Todo: try to auto-detect format based on file name */ -+ format = has_format ? format : BACKUP_FORMAT_VMA; -+ -+ if (format != BACKUP_FORMAT_VMA) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format"); -+ return NULL; -+ } -+ -+ if (has_devlist) { -+ devs = g_strsplit_set(devlist, ",;:", -1); -+ -+ gchar **d = devs; -+ while (d && *d) { -+ blk = blk_by_name(*d); -+ if (blk) { -+ bs = blk_bs(blk); -+ if (bdrv_is_read_only(bs)) { -+ error_setg(errp, "Node '%s' is read only", *d); -+ goto err; -+ } -+ if (!bdrv_is_inserted(bs)) { -+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, *d); -+ goto err; -+ } -+ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1); -+ di->bs = bs; -+ di_list = g_list_append(di_list, di); -+ } else { -+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, -+ "Device '%s' not found", *d); -+ goto err; -+ } -+ d++; -+ } -+ -+ } else { -+ -+ bs = NULL; -+ while ((bs = bdrv_next(bs))) { -+ -+ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { -+ continue; -+ } -+ -+ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1); -+ di->bs = bs; -+ di_list = g_list_append(di_list, di); -+ } -+ } -+ -+ if (!di_list) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "empty device list"); -+ goto err; -+ } -+ -+ size_t total = 0; -+ -+ l = di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ if (bdrv_op_is_blocked(di->bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { -+ goto err; -+ } -+ -+ ssize_t size = bdrv_getlength(di->bs); -+ if (size < 0) { -+ error_setg_errno(errp, -di->size, "bdrv_getlength failed"); -+ goto err; -+ } -+ di->size = size; -+ total += size; -+ } -+ -+ uuid_generate(uuid); -+ -+ vmaw = vma_writer_create(backup_file, uuid, &local_err); -+ if (!vmaw) { -+ if (local_err) { -+ error_propagate(errp, local_err); -+ } -+ goto err; -+ } -+ -+ /* register all devices for vma writer */ -+ l = di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ -+ const char *devname = bdrv_get_device_name(di->bs); -+ di->dev_id = vma_writer_register_stream(vmaw, devname, di->size); -+ if (di->dev_id <= 0) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, -+ "register_stream failed"); -+ goto err; -+ } -+ } -+ -+ /* add configuration file to archive */ -+ if (has_config_file) { -+ char *cdata = NULL; -+ gsize clen = 0; -+ GError *err = NULL; -+ if (!g_file_get_contents(config_file, &cdata, &clen, &err)) { -+ error_setg(errp, "unable to read file '%s'", config_file); -+ goto err; -+ } -+ -+ const char *basename = g_path_get_basename(config_file); -+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) { -+ error_setg(errp, "unable to add config data to vma archive"); -+ g_free(cdata); -+ goto err; -+ } -+ g_free(cdata); -+ } -+ -+ /* initialize global backup_state now */ -+ -+ backup_state.cancel = false; -+ -+ if (backup_state.error) { -+ error_free(backup_state.error); -+ backup_state.error = NULL; -+ } -+ -+ backup_state.speed = (has_speed && speed > 0) ? speed : 0; -+ -+ backup_state.start_time = time(NULL); -+ backup_state.end_time = 0; -+ -+ if (backup_state.backup_file) { -+ g_free(backup_state.backup_file); -+ } -+ backup_state.backup_file = g_strdup(backup_file); -+ -+ backup_state.vmaw = vmaw; -+ -+ uuid_copy(backup_state.uuid, uuid); -+ uuid_unparse_lower(uuid, backup_state.uuid_str); -+ -+ backup_state.di_list = di_list; -+ -+ backup_state.total = total; -+ backup_state.transferred = 0; -+ backup_state.zero_bytes = 0; -+ -+ /* start all jobs (paused state) */ -+ l = di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ -+ backup_start(di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL, NULL, -+ BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, -+ pvebackup_dump_cb, pvebackup_complete_cb, di, -+ 1, &local_err); -+ if (local_err != NULL) { -+ error_setg(&backup_state.error, "backup_job_create failed"); -+ pvebackup_cancel(NULL); -+ } -+ } -+ -+ if (!backup_state.error) { -+ pvebackup_run_next_job(); // run one job -+ } -+ -+ uuid_info = g_malloc0(sizeof(*uuid_info)); -+ uuid_info->UUID = g_strdup(backup_state.uuid_str); -+ return uuid_info; -+ -+err: -+ -+ l = di_list; -+ while (l) { -+ g_free(l->data); -+ l = g_list_next(l); -+ } -+ g_list_free(di_list); -+ -+ if (devs) { -+ g_strfreev(devs); -+ } -+ -+ if (vmaw) { -+ Error *err = NULL; -+ vma_writer_close(vmaw, &err); -+ unlink(backup_file); -+ } -+ -+ return NULL; -+} -+ -+BackupStatus *qmp_query_backup(Error **errp) -+{ -+ BackupStatus *info = g_malloc0(sizeof(*info)); -+ -+ if (!backup_state.start_time) { -+ /* not started, return {} */ -+ return info; -+ } -+ -+ info->has_status = true; -+ info->has_start_time = true; -+ info->start_time = backup_state.start_time; -+ -+ if (backup_state.backup_file) { -+ info->has_backup_file = true; -+ info->backup_file = g_strdup(backup_state.backup_file); -+ } -+ -+ info->has_uuid = true; -+ info->uuid = g_strdup(backup_state.uuid_str); -+ -+ if (backup_state.end_time) { -+ if (backup_state.error) { -+ info->status = g_strdup("error"); -+ info->has_errmsg = true; -+ info->errmsg = g_strdup(error_get_pretty(backup_state.error)); -+ } else { -+ info->status = g_strdup("done"); -+ } -+ info->has_end_time = true; -+ info->end_time = backup_state.end_time; -+ } else { -+ info->status = g_strdup("active"); -+ } -+ -+ info->has_total = true; -+ info->total = backup_state.total; -+ info->has_zero_bytes = true; -+ info->zero_bytes = backup_state.zero_bytes; -+ info->has_transferred = true; -+ info->transferred = backup_state.transferred; -+ -+ return info; -+} -+ - void qmp_block_stream(const char *device, - bool has_base, const char *base, - bool has_backing_file, const char *backing_file, -Index: new/hmp-commands.hx -=================================================================== ---- new.orig/hmp-commands.hx 2014-11-20 06:45:05.000000000 +0100 -+++ new/hmp-commands.hx 2014-11-20 07:47:31.000000000 +0100 -@@ -87,6 +87,35 @@ - Copy data from a backing file into a block device. - ETEXI - -+ { -+ .name = "backup", -+ .args_type = "backupfile:s,speed:o?,devlist:s?", -+ .params = "backupfile [speed [devlist]]", -+ .help = "create a VM Backup.", -+ .mhandler.cmd = hmp_backup, -+ }, -+ -+STEXI -+@item backup -+@findex backup -+Create a VM backup. -+ETEXI -+ -+ { -+ .name = "backup_cancel", -+ .args_type = "", -+ .params = "", -+ .help = "cancel the current VM backup", -+ .mhandler.cmd = hmp_backup_cancel, -+ }, -+ -+STEXI -+@item backup_cancel -+@findex backup_cancel -+Cancel the current VM backup. -+ -+ETEXI -+ - { - .name = "block_job_set_speed", - .args_type = "device:B,speed:o", -@@ -1768,6 +1797,8 @@ - show CPU statistics - @item info usernet - show user network stack connection states -+@item info backup -+show backup status - @item info migrate - show migration status - @item info migrate_capabilities -Index: new/hmp.c -=================================================================== ---- new.orig/hmp.c 2014-11-20 07:26:23.000000000 +0100 -+++ new/hmp.c 2014-11-20 07:47:31.000000000 +0100 -@@ -145,6 +145,44 @@ - qapi_free_MouseInfoList(mice_list); - } - -+void hmp_info_backup(Monitor *mon, const QDict *qdict) -+{ -+ BackupStatus *info; -+ -+ info = qmp_query_backup(NULL); -+ if (info->has_status) { -+ if (info->has_errmsg) { -+ monitor_printf(mon, "Backup status: %s - %s\n", -+ info->status, info->errmsg); -+ } else { -+ monitor_printf(mon, "Backup status: %s\n", info->status); -+ } -+ } -+ -+ if (info->has_backup_file) { -+ monitor_printf(mon, "Start time: %s", ctime(&info->start_time)); -+ if (info->end_time) { -+ monitor_printf(mon, "End time: %s", ctime(&info->end_time)); -+ } -+ -+ int per = (info->has_total && info->total && -+ info->has_transferred && info->transferred) ? -+ (info->transferred * 100)/info->total : 0; -+ int zero_per = (info->has_total && info->total && -+ info->has_zero_bytes && info->zero_bytes) ? -+ (info->zero_bytes * 100)/info->total : 0; -+ monitor_printf(mon, "Backup file: %s\n", info->backup_file); -+ monitor_printf(mon, "Backup uuid: %s\n", info->uuid); -+ monitor_printf(mon, "Total size: %zd\n", info->total); -+ monitor_printf(mon, "Transferred bytes: %zd (%d%%)\n", -+ info->transferred, per); -+ monitor_printf(mon, "Zero bytes: %zd (%d%%)\n", -+ info->zero_bytes, zero_per); -+ } -+ -+ qapi_free_BackupStatus(info); -+} -+ - void hmp_info_migrate(Monitor *mon, const QDict *qdict) - { - MigrationInfo *info; -@@ -1407,6 +1445,29 @@ - - hmp_handle_error(mon, &error); - } -+ -+void hmp_backup_cancel(Monitor *mon, const QDict *qdict) -+{ -+ Error *error = NULL; -+ -+ qmp_backup_cancel(&error); -+ -+ hmp_handle_error(mon, &error); -+} -+ -+void hmp_backup(Monitor *mon, const QDict *qdict) -+{ -+ Error *error = NULL; -+ -+ const char *backup_file = qdict_get_str(qdict, "backupfile"); -+ const char *devlist = qdict_get_try_str(qdict, "devlist"); -+ int64_t speed = qdict_get_try_int(qdict, "speed", 0); -+ -+ qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist, -+ devlist, qdict_haskey(qdict, "speed"), speed, &error); -+ -+ hmp_handle_error(mon, &error); -+} - - void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict) - { -Index: new/hmp.h -=================================================================== ---- new.orig/hmp.h 2014-11-20 06:45:05.000000000 +0100 -+++ new/hmp.h 2014-11-20 07:47:31.000000000 +0100 -@@ -30,6 +30,7 @@ - void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict); - void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict); - void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict); -+void hmp_info_backup(Monitor *mon, const QDict *qdict); - void hmp_info_cpus(Monitor *mon, const QDict *qdict); - void hmp_info_block(Monitor *mon, const QDict *qdict); - void hmp_info_blockstats(Monitor *mon, const QDict *qdict); -@@ -74,6 +75,8 @@ - void hmp_change(Monitor *mon, const QDict *qdict); - void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict); - void hmp_block_stream(Monitor *mon, const QDict *qdict); -+void hmp_backup(Monitor *mon, const QDict *qdict); -+void hmp_backup_cancel(Monitor *mon, const QDict *qdict); - void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict); - void hmp_block_job_cancel(Monitor *mon, const QDict *qdict); - void hmp_block_job_pause(Monitor *mon, const QDict *qdict); -Index: new/monitor.c -=================================================================== ---- new.orig/monitor.c 2014-11-20 06:45:06.000000000 +0100 -+++ new/monitor.c 2014-11-20 07:47:31.000000000 +0100 -@@ -2759,6 +2759,13 @@ - }, - #endif - { -+ .name = "backup", -+ .args_type = "", -+ .params = "", -+ .help = "show backup status", -+ .mhandler.cmd = hmp_info_backup, -+ }, -+ { - .name = "migrate", - .args_type = "", - .params = "", -Index: new/qapi-schema.json -=================================================================== ---- new.orig/qapi-schema.json 2014-11-20 07:26:43.000000000 +0100 -+++ new/qapi-schema.json 2014-11-20 07:47:31.000000000 +0100 -@@ -352,6 +352,95 @@ - ## - { 'command': 'query-events', 'returns': ['EventInfo'] } - -+# @BackupStatus: -+# -+# Detailed backup status. -+# -+# @status: #optional string describing the current backup status. -+# This can be 'active', 'done', 'error'. If this field is not -+# returned, no backup process has been initiated -+# -+# @errmsg: #optional error message (only returned if status is 'error') -+# -+# @total: #optional total amount of bytes involved in the backup process -+# -+# @transferred: #optional amount of bytes already backed up. -+# -+# @zero-bytes: #optional amount of 'zero' bytes detected. -+# -+# @start-time: #optional time (epoch) when backup job started. -+# -+# @end-time: #optional time (epoch) when backup job finished. -+# -+# @backupfile: #optional backup file name -+# -+# @uuid: #optional uuid for this backup job -+# -+## -+{ 'struct': 'BackupStatus', -+ 'data': {'*status': 'str', '*errmsg': 'str', '*total': 'int', -+ '*transferred': 'int', '*zero-bytes': 'int', -+ '*start-time': 'int', '*end-time': 'int', -+ '*backup-file': 'str', '*uuid': 'str' } } -+ -+## -+# @BackupFormat -+# -+# An enumeration of supported backup formats. -+# -+# @vma: Proxmox vma backup format -+## -+{ 'enum': 'BackupFormat', -+ 'data': [ 'vma' ] } -+ -+## -+# @backup: -+# -+# Starts a VM backup. -+# -+# @backup-file: the backup file name -+# -+# @format: format of the backup file -+# -+# @config-filename: #optional name of a configuration file to include into -+# the backup archive. -+# -+# @speed: #optional the maximum speed, in bytes per second -+# -+# @devlist: #optional list of block device names (separated by ',', ';' -+# or ':'). By default the backup includes all writable block devices. -+# -+# Returns: the uuid of the backup job -+# -+## -+{ 'command': 'backup', 'data': { 'backup-file': 'str', -+ '*format': 'BackupFormat', -+ '*config-file': 'str', -+ '*devlist': 'str', '*speed': 'int' }, -+ 'returns': 'UuidInfo' } -+ -+## -+# @query-backup -+# -+# Returns information about current/last backup task. -+# -+# Returns: @BackupStatus -+# -+## -+{ 'command': 'query-backup', 'returns': 'BackupStatus' } -+ -+## -+# @backup-cancel -+# -+# Cancel the current executing backup process. -+# -+# Returns: nothing on success -+# -+# Notes: This command succeeds even if there is no backup process running. -+# -+## -+{ 'command': 'backup-cancel' } -+ - ## - # @MigrationStats - # -Index: new/qmp-commands.hx -=================================================================== ---- new.orig/qmp-commands.hx 2014-11-20 07:26:23.000000000 +0100 -+++ new/qmp-commands.hx 2014-11-20 07:47:31.000000000 +0100 -@@ -1203,6 +1203,24 @@ - EQMP - - { -+ .name = "backup", -+ .args_type = "backup-file:s,format:s?,config-file:F?,speed:o?,devlist:s?", -+ .mhandler.cmd_new = qmp_marshal_input_backup, -+ }, -+ -+ { -+ .name = "backup-cancel", -+ .args_type = "", -+ .mhandler.cmd_new = qmp_marshal_input_backup_cancel, -+ }, -+ -+ { -+ .name = "query-backup", -+ .args_type = "", -+ .mhandler.cmd_new = qmp_marshal_input_query_backup, -+ }, -+ -+ { - .name = "block-job-set-speed", - .args_type = "device:B,speed:o", - .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,