From 99a526d92531d64ff0c31a83d0d55f38651a32a5 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 15:21:54 +0100 Subject: [PATCH 16/48] backup: vma: add dir format --- blockdev.c | 137 ++++++++++++++++++++++++++++++++++++++++--------------- hmp-commands.hx | 8 ++-- hmp.c | 4 +- qapi-schema.json | 2 +- vma.c | 2 +- 5 files changed, 111 insertions(+), 42 deletions(-) diff --git a/blockdev.c b/blockdev.c index 3e5c9ce..af1b9d4 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3007,6 +3007,8 @@ typedef struct PVEBackupDevInfo { uint8_t dev_id; //bool started; bool completed; + char targetfile[PATH_MAX]; + BlockDriverState *target; } PVEBackupDevInfo; static void pvebackup_run_next_job(void); @@ -3075,8 +3077,6 @@ 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) { @@ -3087,8 +3087,11 @@ static void pvebackup_complete_cb(void *opaque, int ret) BlockDriverState *bs = di->bs; di->bs = NULL; + di->target = NULL; - vma_writer_close_stream(backup_state.vmaw, di->dev_id); + if (backup_state.vmaw) { + vma_writer_close_stream(backup_state.vmaw, di->dev_id); + } block_job_cb(bs, ret); @@ -3168,6 +3171,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, { BlockBackend *blk; BlockDriverState *bs = NULL; + const char *backup_dir = NULL; Error *local_err = NULL; uuid_t uuid; VmaWriter *vmaw = NULL; @@ -3175,6 +3179,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, GList *di_list = NULL; GList *l; UuidInfo *uuid_info; + BlockJob *job; if (backup_state.di_list) { error_set(errp, ERROR_CLASS_GENERIC_ERROR, @@ -3185,11 +3190,6 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, /* 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); @@ -3258,27 +3258,62 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, uuid_generate(uuid); - vmaw = vma_writer_create(backup_file, uuid, &local_err); - if (!vmaw) { - if (local_err) { - error_propagate(errp, local_err); + if (format == BACKUP_FORMAT_VMA) { + vmaw = vma_writer_create(backup_file, uuid, &local_err); + if (!vmaw) { + if (local_err) { + error_propagate(errp, local_err); + } + goto err; } - goto err; - } - /* register all devices for vma writer */ - l = di_list; - while (l) { - PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; - l = g_list_next(l); + /* 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"); + 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; + } + } + } else if (format == BACKUP_FORMAT_DIR) { + if (mkdir(backup_file, 0640) != 0) { + error_setg_errno(errp, errno, "can't create directory '%s'\n", + backup_file); goto err; } + backup_dir = backup_file; + + l = di_list; + while (l) { + PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; + l = g_list_next(l); + + const char *devname = bdrv_get_device_name(di->bs); + snprintf(di->targetfile, PATH_MAX, "%s/%s.raw", backup_dir, devname); + + int flags = BDRV_O_RDWR; + bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL, + di->size, flags, &local_err, false); + if (local_err) { + error_propagate(errp, local_err); + goto err; + } + + di->target = bdrv_open(di->targetfile, NULL, NULL, flags, &local_err); + if (!di->target) { + error_propagate(errp, local_err); + goto err; + } + } + } else { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format"); + goto err; } /* add configuration file to archive */ @@ -3291,12 +3326,27 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, 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; + char *basename = g_path_get_basename(config_file); + + if (format == BACKUP_FORMAT_VMA) { + if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) { + error_setg(errp, "unable to add config data to vma archive"); + g_free(cdata); + g_free(basename); + goto err; + } + } else if (format == BACKUP_FORMAT_DIR) { + char config_path[PATH_MAX]; + snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename); + if (!g_file_set_contents(config_path, cdata, clen, &err)) { + error_setg(errp, "unable to write config file '%s'", config_path); + g_free(cdata); + g_free(basename); + goto err; + } } + + g_free(basename); g_free(cdata); } @@ -3335,15 +3385,16 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, while (l) { PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; l = g_list_next(l); - - backup_job_create(NULL, 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, NULL, &local_err); - if (local_err != NULL) { + job = backup_job_create(NULL, di->bs, di->target, speed, MIRROR_SYNC_MODE_FULL, NULL, + false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, + BLOCK_JOB_DEFAULT, + pvebackup_dump_cb, pvebackup_complete_cb, di, + 1, NULL, &local_err); + if (!job || local_err != NULL) { error_setg(&backup_state.error, "backup_job_create failed"); pvebackup_cancel(NULL); } + block_job_start(job); } if (!backup_state.error) { @@ -3352,14 +3403,24 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, 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); + PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; l = g_list_next(l); + + if (di->target) { + bdrv_unref(di->target); + } + + if (di->targetfile[0]) { + unlink(di->targetfile); + } + g_free(di); } g_list_free(di_list); @@ -3373,6 +3434,10 @@ err: unlink(backup_file); } + if (backup_dir) { + rmdir(backup_dir); + } + return NULL; } diff --git a/hmp-commands.hx b/hmp-commands.hx index aea39d0..7288203 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -89,9 +89,11 @@ ETEXI { .name = "backup", - .args_type = "backupfile:s,speed:o?,devlist:s?", - .params = "backupfile [speed [devlist]]", - .help = "create a VM Backup.", + .args_type = "directory:-d,backupfile:s,speed:o?,devlist:s?", + .params = "[-d] backupfile [speed [devlist]]", + .help = "create a VM Backup." + "\n\t\t\t Use -d to dump data into a directory instead" + "\n\t\t\t of using VMA format.", .cmd = hmp_backup, }, diff --git a/hmp.c b/hmp.c index c685ba5..465d7fa 100644 --- a/hmp.c +++ b/hmp.c @@ -1664,11 +1664,13 @@ void hmp_backup(Monitor *mon, const QDict *qdict) { Error *error = NULL; + int dir = qdict_get_try_bool(qdict, "directory", 0); 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, + qmp_backup(backup_file, true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA, + false, NULL, !!devlist, devlist, qdict_haskey(qdict, "speed"), speed, &error); hmp_handle_error(mon, &error); diff --git a/qapi-schema.json b/qapi-schema.json index 059cbfc..1127f2c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -609,7 +609,7 @@ # @vma: Proxmox vma backup format ## { 'enum': 'BackupFormat', - 'data': [ 'vma' ] } + 'data': [ 'vma', 'dir' ] } ## # @backup: diff --git a/vma.c b/vma.c index 8925407..1ffaced 100644 --- a/vma.c +++ b/vma.c @@ -264,7 +264,7 @@ static int extract_content(int argc, char **argv) g_free(statefn); } else if (di) { char *devfn = NULL; - int flags = BDRV_O_RDWR|BDRV_O_CACHE_WB; + int flags = BDRV_O_RDWR; bool write_zero = true; if (readmap) { -- 2.1.4