1 Index: new/qapi-schema.json
2 ===================================================================
3 --- new.orig/qapi-schema.json 2014-11-20 08:59:29.000000000 +0100
4 +++ new/qapi-schema.json 2014-11-20 09:03:23.000000000 +0100
6 # @vma: Proxmox vma backup format
8 { 'enum': 'BackupFormat',
10 + 'data': [ 'vma', 'dir' ] }
15 ===================================================================
16 --- new.orig/blockdev.c 2014-11-20 08:59:29.000000000 +0100
17 +++ new/blockdev.c 2014-11-20 09:04:05.000000000 +0100
22 + char targetfile[PATH_MAX];
23 + BlockDriverState *target;
26 static void pvebackup_run_next_job(void);
29 PVEBackupDevInfo *di = opaque;
31 - assert(backup_state.vmaw);
35 if (ret < 0 && !backup_state.error) {
36 @@ -2381,8 +2381,11 @@
37 BlockDriverState *bs = di->bs;
42 - vma_writer_close_stream(backup_state.vmaw, di->dev_id);
43 + if (backup_state.vmaw) {
44 + vma_writer_close_stream(backup_state.vmaw, di->dev_id);
47 block_job_cb(bs, ret);
52 BlockDriverState *bs = NULL;
53 + const char *backup_dir = NULL;
54 Error *local_err = NULL;
56 VmaWriter *vmaw = NULL;
57 @@ -2478,11 +2482,6 @@
58 /* Todo: try to auto-detect format based on file name */
59 format = has_format ? format : BACKUP_FORMAT_VMA;
61 - if (format != BACKUP_FORMAT_VMA) {
62 - error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
67 devs = g_strsplit_set(devlist, ",;:", -1);
69 @@ -2551,27 +2550,63 @@
73 - vmaw = vma_writer_create(backup_file, uuid, &local_err);
76 - error_propagate(errp, local_err);
77 + if (format == BACKUP_FORMAT_VMA) {
78 + vmaw = vma_writer_create(backup_file, uuid, &local_err);
81 + error_propagate(errp, local_err);
88 - /* register all devices for vma writer */
91 - PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
93 + /* register all devices for vma writer */
96 + PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
99 - const char *devname = bdrv_get_device_name(di->bs);
100 - di->dev_id = vma_writer_register_stream(vmaw, devname, di->size);
101 - if (di->dev_id <= 0) {
102 - error_set(errp, ERROR_CLASS_GENERIC_ERROR,
103 - "register_stream failed");
104 + const char *devname = bdrv_get_device_name(di->bs);
105 + di->dev_id = vma_writer_register_stream(vmaw, devname, di->size);
106 + if (di->dev_id <= 0) {
107 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
108 + "register_stream failed");
112 + } else if (format == BACKUP_FORMAT_DIR) {
113 + if (mkdir(backup_file, 0640) != 0) {
114 + error_setg_errno(errp, errno, "can't create directory '%s'\n",
118 + backup_dir = backup_file;
122 + PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
123 + l = g_list_next(l);
125 + const char *devname = bdrv_get_device_name(di->bs);
126 + snprintf(di->targetfile, PATH_MAX, "%s/%s.raw", backup_dir, devname);
128 + int flags = BDRV_O_RDWR|BDRV_O_CACHE_WB;
129 + bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL,
130 + di->size, flags, &local_err, false);
132 + error_propagate(errp, local_err);
136 + di->target = bdrv_new();
137 + if (bdrv_open(&di->target, di->targetfile, NULL, NULL, flags, NULL, &local_err) < 0) {
138 + bdrv_unref(di->target);
139 + error_propagate(errp, local_err);
144 + error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
148 /* add configuration file to archive */
149 @@ -2584,12 +2619,27 @@
153 - const char *basename = g_path_get_basename(config_file);
154 - if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
155 - error_setg(errp, "unable to add config data to vma archive");
158 + char *basename = g_path_get_basename(config_file);
160 + if (format == BACKUP_FORMAT_VMA) {
161 + if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
162 + error_setg(errp, "unable to add config data to vma archive");
167 + } else if (format == BACKUP_FORMAT_DIR) {
168 + char config_path[PATH_MAX];
169 + snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename);
170 + if (!g_file_set_contents(config_path, cdata, clen, &err)) {
171 + error_setg(errp, "unable to write config file '%s'", config_path);
182 @@ -2629,10 +2679,11 @@
183 PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
186 - backup_start(di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL, NULL,
187 + backup_start(di->bs, di->target, speed, MIRROR_SYNC_MODE_FULL, NULL,
188 BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
189 pvebackup_dump_cb, pvebackup_complete_cb, di,
192 if (local_err != NULL) {
193 error_setg(&backup_state.error, "backup_job_create failed");
194 pvebackup_cancel(NULL);
195 @@ -2651,8 +2702,17 @@
200 + PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
204 + bdrv_unref(di->target);
207 + if (di->targetfile[0]) {
208 + unlink(di->targetfile);
212 g_list_free(di_list);
214 @@ -2666,6 +2726,10 @@
225 Index: new/hmp-commands.hx
226 ===================================================================
227 --- new.orig/hmp-commands.hx 2014-11-20 08:59:29.000000000 +0100
228 +++ new/hmp-commands.hx 2014-11-20 09:03:23.000000000 +0100
233 - .args_type = "backupfile:s,speed:o?,devlist:s?",
234 - .params = "backupfile [speed [devlist]]",
235 - .help = "create a VM Backup.",
236 + .args_type = "directory:-d,backupfile:s,speed:o?,devlist:s?",
237 + .params = "[-d] backupfile [speed [devlist]]",
238 + .help = "create a VM Backup."
239 + "\n\t\t\t Use -d to dump data into a directory instead"
240 + "\n\t\t\t of using VMA format.",
241 .mhandler.cmd = hmp_backup,
245 ===================================================================
246 --- new.orig/hmp.c 2014-11-20 08:59:29.000000000 +0100
247 +++ new/hmp.c 2014-11-20 09:03:23.000000000 +0100
248 @@ -1459,11 +1459,13 @@
252 + int dir = qdict_get_try_bool(qdict, "directory", 0);
253 const char *backup_file = qdict_get_str(qdict, "backupfile");
254 const char *devlist = qdict_get_try_str(qdict, "devlist");
255 int64_t speed = qdict_get_try_int(qdict, "speed", 0);
257 - qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist,
258 + qmp_backup(backup_file, true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA,
259 + false, NULL, !!devlist,
260 devlist, qdict_haskey(qdict, "speed"), speed, &error);
262 hmp_handle_error(mon, &error);