]> git.proxmox.com Git - pve-qemu.git/blobdiff - debian/patches/pve/0052-vma-allow-partial-restore.patch
update submodule and patches to 7.1.0
[pve-qemu.git] / debian / patches / pve / 0052-vma-allow-partial-restore.patch
diff --git a/debian/patches/pve/0052-vma-allow-partial-restore.patch b/debian/patches/pve/0052-vma-allow-partial-restore.patch
new file mode 100644 (file)
index 0000000..f1fd7cb
--- /dev/null
@@ -0,0 +1,407 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fabian Ebner <f.ebner@proxmox.com>
+Date: Thu, 21 Apr 2022 13:26:48 +0200
+Subject: [PATCH] vma: allow partial restore
+
+Introduce a new map line for skipping a certain drive, of the form
+skip=drive-scsi0
+
+Since in PVE, most archives are compressed and piped to vma for
+restore, it's not easily possible to skip reads.
+
+For the reader, a new skip flag for VmaRestoreState is added and the
+target is allowed to be NULL if skip is specified when registering. If
+the skip flag is set, no writes will be made as well as no check for
+duplicate clusters. Therefore, the flag is not set for verify.
+
+Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
+Acked-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
+---
+ vma-reader.c |  64 ++++++++++++---------
+ vma.c        | 157 +++++++++++++++++++++++++++++----------------------
+ vma.h        |   2 +-
+ 3 files changed, 126 insertions(+), 97 deletions(-)
+
+diff --git a/vma-reader.c b/vma-reader.c
+index e65f1e8415..81a891c6b1 100644
+--- a/vma-reader.c
++++ b/vma-reader.c
+@@ -28,6 +28,7 @@ typedef struct VmaRestoreState {
+     bool write_zeroes;
+     unsigned long *bitmap;
+     int bitmap_size;
++    bool skip;
+ }  VmaRestoreState;
+ struct VmaReader {
+@@ -425,13 +426,14 @@ VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id)
+ }
+ static void allocate_rstate(VmaReader *vmar,  guint8 dev_id,
+-                            BlockBackend *target, bool write_zeroes)
++                            BlockBackend *target, bool write_zeroes, bool skip)
+ {
+     assert(vmar);
+     assert(dev_id);
+     vmar->rstate[dev_id].target = target;
+     vmar->rstate[dev_id].write_zeroes = write_zeroes;
++    vmar->rstate[dev_id].skip = skip;
+     int64_t size = vmar->devinfo[dev_id].size;
+@@ -446,28 +448,30 @@ static void allocate_rstate(VmaReader *vmar,  guint8 dev_id,
+ }
+ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockBackend *target,
+-                           bool write_zeroes, Error **errp)
++                           bool write_zeroes, bool skip, Error **errp)
+ {
+     assert(vmar);
+-    assert(target != NULL);
++    assert(target != NULL || skip);
+     assert(dev_id);
+-    assert(vmar->rstate[dev_id].target == NULL);
+-
+-    int64_t size = blk_getlength(target);
+-    int64_t size_diff = size - vmar->devinfo[dev_id].size;
+-
+-    /* storage types can have different size restrictions, so it
+-     * is not always possible to create an image with exact size.
+-     * So we tolerate a size difference up to 4MB.
+-     */
+-    if ((size_diff < 0) || (size_diff > 4*1024*1024)) {
+-        error_setg(errp, "vma_reader_register_bs for stream %s failed - "
+-                   "unexpected size %zd != %zd", vmar->devinfo[dev_id].devname,
+-                   size, vmar->devinfo[dev_id].size);
+-        return -1;
++    assert(vmar->rstate[dev_id].target == NULL && !vmar->rstate[dev_id].skip);
++
++    if (target != NULL) {
++        int64_t size = blk_getlength(target);
++        int64_t size_diff = size - vmar->devinfo[dev_id].size;
++
++        /* storage types can have different size restrictions, so it
++         * is not always possible to create an image with exact size.
++         * So we tolerate a size difference up to 4MB.
++         */
++        if ((size_diff < 0) || (size_diff > 4*1024*1024)) {
++            error_setg(errp, "vma_reader_register_bs for stream %s failed - "
++                       "unexpected size %zd != %zd", vmar->devinfo[dev_id].devname,
++                       size, vmar->devinfo[dev_id].size);
++            return -1;
++        }
+     }
+-    allocate_rstate(vmar, dev_id, target, write_zeroes);
++    allocate_rstate(vmar, dev_id, target, write_zeroes, skip);
+     return 0;
+ }
+@@ -560,19 +564,23 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
+         VmaRestoreState *rstate = &vmar->rstate[dev_id];
+         BlockBackend *target = NULL;
++        bool skip = rstate->skip;
++
+         if (dev_id != vmar->vmstate_stream) {
+             target = rstate->target;
+-            if (!verify && !target) {
++            if (!verify && !target && !skip) {
+                 error_setg(errp, "got wrong dev id %d", dev_id);
+                 return -1;
+             }
+-            if (vma_reader_get_bitmap(rstate, cluster_num)) {
+-                error_setg(errp, "found duplicated cluster %zd for stream %s",
+-                          cluster_num, vmar->devinfo[dev_id].devname);
+-                return -1;
++            if (!skip) {
++                if (vma_reader_get_bitmap(rstate, cluster_num)) {
++                    error_setg(errp, "found duplicated cluster %zd for stream %s",
++                              cluster_num, vmar->devinfo[dev_id].devname);
++                    return -1;
++                }
++                vma_reader_set_bitmap(rstate, cluster_num, 1);
+             }
+-            vma_reader_set_bitmap(rstate, cluster_num, 1);
+             max_sector = vmar->devinfo[dev_id].size/BDRV_SECTOR_SIZE;
+         } else {
+@@ -618,7 +626,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
+                 return -1;
+             }
+-            if (!verify) {
++            if (!verify && !skip) {
+                 int nb_sectors = end_sector - sector_num;
+                 if (restore_write_data(vmar, dev_id, target, vmstate_fd,
+                                        buf + start, sector_num, nb_sectors,
+@@ -654,7 +662,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
+                         return -1;
+                     }
+-                    if (!verify) {
++                    if (!verify && !skip) {
+                         int nb_sectors = end_sector - sector_num;
+                         if (restore_write_data(vmar, dev_id, target, vmstate_fd,
+                                                buf + start, sector_num,
+@@ -679,7 +687,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
+                             vmar->partial_zero_cluster_data += zero_size;
+                         }
+-                        if (rstate->write_zeroes && !verify) {
++                        if (rstate->write_zeroes && !verify && !skip) {
+                             if (restore_write_data(vmar, dev_id, target, vmstate_fd,
+                                                    zero_vma_block, sector_num,
+                                                    nb_sectors, errp) < 0) {
+@@ -850,7 +858,7 @@ int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp)
+     for (dev_id = 1; dev_id < 255; dev_id++) {
+         if (vma_reader_get_device_info(vmar, dev_id)) {
+-            allocate_rstate(vmar, dev_id, NULL, false);
++            allocate_rstate(vmar, dev_id, NULL, false, false);
+         }
+     }
+diff --git a/vma.c b/vma.c
+index e8dffb43e0..e6e9ffc7fe 100644
+--- a/vma.c
++++ b/vma.c
+@@ -138,6 +138,7 @@ typedef struct RestoreMap {
+     char *throttling_group;
+     char *cache;
+     bool write_zero;
++    bool skip;
+ } RestoreMap;
+ static bool try_parse_option(char **line, const char *optname, char **out, const char *inbuf) {
+@@ -245,47 +246,61 @@ static int extract_content(int argc, char **argv)
+             char *bps = NULL;
+             char *group = NULL;
+             char *cache = NULL;
++            char *devname = NULL;
++            bool skip = false;
++            uint64_t bps_value = 0;
++            const char *path = NULL;
++            bool write_zero = true;
++
+             if (!line || line[0] == '\0' || !strcmp(line, "done\n")) {
+                 break;
+             }
+             int len = strlen(line);
+             if (line[len - 1] == '\n') {
+                 line[len - 1] = '\0';
+-                if (len == 1) {
++                len = len - 1;
++                if (len == 0) {
+                     break;
+                 }
+             }
+-            while (1) {
+-                if (!try_parse_option(&line, "format", &format, inbuf) &&
+-                    !try_parse_option(&line, "throttling.bps", &bps, inbuf) &&
+-                    !try_parse_option(&line, "throttling.group", &group, inbuf) &&
+-                    !try_parse_option(&line, "cache", &cache, inbuf))
+-                {
+-                    break;
++            if (strncmp(line, "skip", 4) == 0) {
++                if (len < 6 || line[4] != '=') {
++                    g_error("read map failed - option 'skip' has no value ('%s')",
++                            inbuf);
++                } else {
++                    devname = line + 5;
++                    skip = true;
++                }
++            } else {
++                while (1) {
++                    if (!try_parse_option(&line, "format", &format, inbuf) &&
++                        !try_parse_option(&line, "throttling.bps", &bps, inbuf) &&
++                        !try_parse_option(&line, "throttling.group", &group, inbuf) &&
++                        !try_parse_option(&line, "cache", &cache, inbuf))
++                    {
++                        break;
++                    }
+                 }
+-            }
+-            uint64_t bps_value = 0;
+-            if (bps) {
+-                bps_value = verify_u64(bps);
+-                g_free(bps);
+-            }
++                if (bps) {
++                    bps_value = verify_u64(bps);
++                    g_free(bps);
++                }
+-            const char *path;
+-            bool write_zero;
+-            if (line[0] == '0' && line[1] == ':') {
+-                path = line + 2;
+-                write_zero = false;
+-            } else if (line[0] == '1' && line[1] == ':') {
+-                path = line + 2;
+-                write_zero = true;
+-            } else {
+-                g_error("read map failed - parse error ('%s')", inbuf);
++                if (line[0] == '0' && line[1] == ':') {
++                    path = line + 2;
++                    write_zero = false;
++                } else if (line[0] == '1' && line[1] == ':') {
++                    path = line + 2;
++                    write_zero = true;
++                } else {
++                    g_error("read map failed - parse error ('%s')", inbuf);
++                }
++
++                path = extract_devname(path, &devname, -1);
+             }
+-            char *devname = NULL;
+-            path = extract_devname(path, &devname, -1);
+             if (!devname) {
+                 g_error("read map failed - no dev name specified ('%s')",
+                         inbuf);
+@@ -299,6 +314,7 @@ static int extract_content(int argc, char **argv)
+             map->throttling_group = group;
+             map->cache = cache;
+             map->write_zero = write_zero;
++            map->skip = skip;
+             g_hash_table_insert(devmap, map->devname, map);
+@@ -328,6 +344,7 @@ static int extract_content(int argc, char **argv)
+             const char *cache = NULL;
+             int flags = BDRV_O_RDWR;
+             bool write_zero = true;
++            bool skip = false;
+             BlockBackend *blk = NULL;
+@@ -343,6 +360,7 @@ static int extract_content(int argc, char **argv)
+                 throttling_group = map->throttling_group;
+                 cache = map->cache;
+                 write_zero = map->write_zero;
++                skip = map->skip;
+             } else {
+                 devfn = g_strdup_printf("%s/tmp-disk-%s.raw",
+                                         dirname, di->devname);
+@@ -361,57 +379,60 @@ static int extract_content(int argc, char **argv)
+                 write_zero = false;
+             }
+-          size_t devlen = strlen(devfn);
+-          QDict *options = NULL;
+-            bool writethrough;
+-            if (format) {
+-                /* explicit format from commandline */
+-                options = qdict_new();
+-                qdict_put_str(options, "driver", format);
+-            } else if ((devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0) ||
+-                     strncmp(devfn, "/dev/", 5) == 0)
+-          {
+-                /* This part is now deprecated for PVE as well (just as qemu
+-                 * deprecated not specifying an explicit raw format, too.
+-                 */
+-              /* explicit raw format */
+-              options = qdict_new();
+-              qdict_put_str(options, "driver", "raw");
+-          }
+-            if (cache && bdrv_parse_cache_mode(cache, &flags, &writethrough)) {
+-                g_error("invalid cache option: %s\n", cache);
+-            }
++            if (!skip) {
++                size_t devlen = strlen(devfn);
++                QDict *options = NULL;
++                bool writethrough;
++                if (format) {
++                    /* explicit format from commandline */
++                    options = qdict_new();
++                    qdict_put_str(options, "driver", format);
++                } else if ((devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0) ||
++                    strncmp(devfn, "/dev/", 5) == 0)
++                {
++                    /* This part is now deprecated for PVE as well (just as qemu
++                     * deprecated not specifying an explicit raw format, too.
++                     */
++                    /* explicit raw format */
++                    options = qdict_new();
++                    qdict_put_str(options, "driver", "raw");
++                }
+-          if (errp || !(blk = blk_new_open(devfn, NULL, options, flags, &errp))) {
+-                g_error("can't open file %s - %s", devfn,
+-                        error_get_pretty(errp));
+-            }
++                if (cache && bdrv_parse_cache_mode(cache, &flags, &writethrough)) {
++                    g_error("invalid cache option: %s\n", cache);
++                }
+-            if (cache) {
+-                blk_set_enable_write_cache(blk, !writethrough);
+-            }
++                if (errp || !(blk = blk_new_open(devfn, NULL, options, flags, &errp))) {
++                    g_error("can't open file %s - %s", devfn,
++                            error_get_pretty(errp));
++                }
+-            if (throttling_group) {
+-                blk_io_limits_enable(blk, throttling_group);
+-            }
++                if (cache) {
++                    blk_set_enable_write_cache(blk, !writethrough);
++                }
+-            if (throttling_bps) {
+-                if (!throttling_group) {
+-                    blk_io_limits_enable(blk, devfn);
++                if (throttling_group) {
++                    blk_io_limits_enable(blk, throttling_group);
+                 }
+-                ThrottleConfig cfg;
+-                throttle_config_init(&cfg);
+-                cfg.buckets[THROTTLE_BPS_WRITE].avg = throttling_bps;
+-                Error *err = NULL;
+-                if (!throttle_is_valid(&cfg, &err)) {
+-                    error_report_err(err);
+-                    g_error("failed to apply throttling");
++                if (throttling_bps) {
++                    if (!throttling_group) {
++                        blk_io_limits_enable(blk, devfn);
++                    }
++
++                    ThrottleConfig cfg;
++                    throttle_config_init(&cfg);
++                    cfg.buckets[THROTTLE_BPS_WRITE].avg = throttling_bps;
++                    Error *err = NULL;
++                    if (!throttle_is_valid(&cfg, &err)) {
++                        error_report_err(err);
++                        g_error("failed to apply throttling");
++                    }
++                    blk_set_io_limits(blk, &cfg);
+                 }
+-                blk_set_io_limits(blk, &cfg);
+             }
+-            if (vma_reader_register_bs(vmar, i, blk, write_zero, &errp) < 0) {
++            if (vma_reader_register_bs(vmar, i, blk, write_zero, skip, &errp) < 0) {
+                 g_error("%s", error_get_pretty(errp));
+             }
+diff --git a/vma.h b/vma.h
+index c895c97f6d..1b62859165 100644
+--- a/vma.h
++++ b/vma.h
+@@ -142,7 +142,7 @@ GList *vma_reader_get_config_data(VmaReader *vmar);
+ VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id);
+ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id,
+                            BlockBackend *target, bool write_zeroes,
+-                           Error **errp);
++                           bool skip, Error **errp);
+ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
+                        Error **errp);
+ int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp);