Index: new/blockdev.c
===================================================================
---- new.orig/blockdev.c 2013-12-03 07:34:22.000000000 +0100
-+++ new/blockdev.c 2013-12-03 08:50:24.000000000 +0100
+--- new.orig/blockdev.c 2013-12-06 10:04:18.000000000 +0100
++++ new/blockdev.c 2013-12-06 10:27:39.000000000 +0100
@@ -45,6 +45,7 @@
#include "qmp-commands.h"
#include "trace.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
-@@ -1438,6 +1439,419 @@
+@@ -1438,7 +1439,6 @@
}
}
+-
+ static void eject_device(BlockDriverState *bs, int force, Error **errp)
+ {
+ if (bdrv_in_use(bs)) {
+@@ -1736,6 +1736,437 @@
+ bdrv_put_ref_bh_schedule(bs);
+ }
+
+/* PVE backup related function */
+
+static struct PVEBackupState {
+
+typedef struct PVEBackupDevInfo {
+ BlockDriverState *bs;
++ size_t size;
+ uint8_t dev_id;
+ //bool started;
+ bool completed;
+
+static void pvebackup_run_next_job(void);
+
-+static int pvebackup_dump_cb(void *opaque, BlockDriverState *bs,
-+ int64_t cluster_num, unsigned char *buf)
++static int pvebackup_dump_cb(void *opaque, BlockDriverState *target,
++ int64_t sector_num, int n_sectors,
++ unsigned char *buf)
+{
+ PVEBackupDevInfo *di = opaque;
+
-+ assert(backup_state.vmaw);
-+
-+ size_t zero_bytes = 0;
-+ return vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num,
-+ buf, &zero_bytes);
-+}
-+
-+static void pvebackup_update_status(void)
-+{
-+ g_assert(backup_state.vmaw);
-+
-+ VmaStatus vmastat;
++ 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
++ }
+
-+ vma_writer_get_status(backup_state.vmaw, &vmastat);
++ int64_t cluster_num = sector_num >> 7;
++ int size = n_sectors * BDRV_SECTOR_SIZE;
+
-+ uint64_t total = 0;
-+ uint64_t transferred = 0;
-+ uint64_t zero_bytes = 0;
++ int ret = -1;
+
-+ int i;
-+ for (i = 0; i < 256; i++) {
-+ if (vmastat.stream_info[i].size) {
-+ total += vmastat.stream_info[i].size;
-+ transferred += vmastat.stream_info[i].transferred;
-+ zero_bytes += vmastat.stream_info[i].zero_bytes;
++ 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.total = total;
-+ backup_state.transferred = transferred;
-+ backup_state.zero_bytes = zero_bytes;
++ backup_state.transferred += size;
++
++ return ret;
+}
+
+static void pvebackup_cleanup(void)
+{
++ backup_state.end_time = time(NULL);
++
+ if (backup_state.vmaw) {
-+ backup_state.end_time = time(NULL);
+ Error *local_err = NULL;
-+ pvebackup_update_status();
+ vma_writer_close(backup_state.vmaw, &local_err);
+ error_propagate(&backup_state.error, local_err);
+ backup_state.vmaw = NULL;
+ 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();
+ }
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
-+ if (!di->completed && di->bs) {
++ if (!di->completed && di->bs) {
+ BlockJob *job = di->bs->job;
+ if (job) {
+ if (!di->completed) {
+ goto err;
+ }
+
++ size_t total = 0;
++
+ l = di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
-+ if (di->bs->job) {
++ if (bdrv_in_use(di->bs)) {
+ error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(di->bs));
+ 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);
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+
-+ int64_t size = bdrv_getlength(di->bs);
+ const char *devname = bdrv_get_device_name(di->bs);
-+ di->dev_id = vma_writer_register_stream(vmaw, devname, size);
++ 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");
+
+ backup_state.di_list = di_list;
+
-+ pvebackup_update_status();
++ backup_state.total = total;
++ backup_state.transferred = 0;
++ backup_state.zero_bytes = 0;
+
+ /* start all jobs (paused state) */
+ l = di_list;
+ info->status = g_strdup("active");
+ }
+
-+ if (backup_state.vmaw) {
-+ pvebackup_update_status();
-+ }
-+
+ info->has_total = true;
+ info->total = backup_state.total;
+ info->has_zero_bytes = true;
+
+ return info;
+}
-
- static void eject_device(BlockDriverState *bs, int force, Error **errp)
- {
++
+ void qmp_block_stream(const char *device, bool has_base,
+ const char *base, bool has_speed, int64_t speed,
+ bool has_on_error, BlockdevOnError on_error,
Index: new/hmp-commands.hx
===================================================================
--- new.orig/hmp-commands.hx 2013-12-03 06:36:18.000000000 +0100
-+++ new/hmp-commands.hx 2013-12-03 07:34:22.000000000 +0100
++++ new/hmp-commands.hx 2013-12-06 10:26:47.000000000 +0100
@@ -83,6 +83,35 @@
Copy data from a backing file into a block device.
ETEXI
@item info migrate_capabilities
Index: new/hmp.c
===================================================================
---- new.orig/hmp.c 2013-12-03 07:34:22.000000000 +0100
-+++ new/hmp.c 2013-12-03 07:34:22.000000000 +0100
-@@ -133,6 +133,38 @@
+--- new.orig/hmp.c 2013-12-06 10:04:18.000000000 +0100
++++ new/hmp.c 2013-12-06 10:26:47.000000000 +0100
+@@ -133,6 +133,44 @@
qapi_free_MouseInfoList(mice_list);
}
+ 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;
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
{
MigrationInfo *info;
-@@ -1194,6 +1226,37 @@
+@@ -1193,6 +1231,29 @@
+
hmp_handle_error(mon, &error);
}
-
++
+void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
+{
-+ Error *errp = NULL;
++ Error *error = NULL;
+
-+ qmp_backup_cancel(&errp);
++ qmp_backup_cancel(&error);
+
-+ if (error_is_set(&errp)) {
-+ monitor_printf(mon, "%s\n", error_get_pretty(errp));
-+ error_free(errp);
-+ return;
-+ }
++ hmp_handle_error(mon, &error);
+}
+
+void hmp_backup(Monitor *mon, const QDict *qdict)
+{
-+ const char *backup_file = qdict_get_str(qdict, "backup-file");
++ 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);
+
-+ Error *errp = NULL;
-+
+ qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist,
-+ devlist, qdict_haskey(qdict, "speed"), speed, &errp);
++ devlist, qdict_haskey(qdict, "speed"), speed, &error);
+
-+ if (error_is_set(&errp)) {
-+ monitor_printf(mon, "%s\n", error_get_pretty(errp));
-+ error_free(errp);
-+ return;
-+ }
++ hmp_handle_error(mon, &error);
+}
-+
+
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
{
- Error *error = NULL;
Index: new/hmp.h
===================================================================
--- new.orig/hmp.h 2013-12-03 06:36:18.000000000 +0100
-+++ new/hmp.h 2013-12-03 07:34:22.000000000 +0100
++++ new/hmp.h 2013-12-06 10:04:22.000000000 +0100
@@ -28,6 +28,7 @@
void hmp_info_migrate(Monitor *mon, const QDict *qdict);
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
Index: new/monitor.c
===================================================================
--- new.orig/monitor.c 2013-12-03 06:36:18.000000000 +0100
-+++ new/monitor.c 2013-12-03 07:34:22.000000000 +0100
++++ new/monitor.c 2013-12-06 10:04:22.000000000 +0100
@@ -2880,6 +2880,13 @@
},
#endif
.params = "",
Index: new/qapi-schema.json
===================================================================
---- new.orig/qapi-schema.json 2013-12-03 07:34:22.000000000 +0100
-+++ new/qapi-schema.json 2013-12-03 07:34:22.000000000 +0100
+--- new.orig/qapi-schema.json 2013-12-06 10:04:18.000000000 +0100
++++ new/qapi-schema.json 2013-12-06 10:26:47.000000000 +0100
@@ -547,6 +547,95 @@
##
{ 'command': 'query-events', 'returns': ['EventInfo'] }
#
Index: new/qmp-commands.hx
===================================================================
---- new.orig/qmp-commands.hx 2013-12-03 07:34:22.000000000 +0100
-+++ new/qmp-commands.hx 2013-12-03 07:34:22.000000000 +0100
+--- new.orig/qmp-commands.hx 2013-12-06 10:04:18.000000000 +0100
++++ new/qmp-commands.hx 2013-12-06 10:04:22.000000000 +0100
@@ -966,6 +966,24 @@
EQMP