]>
Commit | Line | Data |
---|---|---|
f6d40bfd FE |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Fabian Ebner <f.ebner@proxmox.com> | |
3 | Date: Mon, 7 Feb 2022 14:21:01 +0100 | |
4 | Subject: [PATCH] qemu-img: dd: add -l option for loading a snapshot | |
5 | ||
6 | Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> | |
7 | --- | |
8 | docs/tools/qemu-img.rst | 6 +++--- | |
9 | qemu-img-cmds.hx | 4 ++-- | |
10 | qemu-img.c | 33 +++++++++++++++++++++++++++++++-- | |
11 | 3 files changed, 36 insertions(+), 7 deletions(-) | |
12 | ||
13 | diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst | |
14 | index a49badb158..1039aec01c 100644 | |
15 | --- a/docs/tools/qemu-img.rst | |
16 | +++ b/docs/tools/qemu-img.rst | |
17 | @@ -492,10 +492,10 @@ Command description: | |
18 | it doesn't need to be specified separately in this case. | |
19 | ||
20 | ||
21 | -.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] if=INPUT of=OUTPUT | |
22 | +.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [-l SNAPSHOT_PARAM] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] if=INPUT of=OUTPUT | |
23 | ||
24 | - dd copies from *INPUT* file to *OUTPUT* file converting it from | |
25 | - *FMT* format to *OUTPUT_FMT* format. | |
26 | + dd copies from *INPUT* file or snapshot *SNAPSHOT_PARAM* to *OUTPUT* file | |
27 | + converting it from *FMT* format to *OUTPUT_FMT* format. | |
28 | ||
29 | The data is by default read and written using blocks of 512 bytes but can be | |
30 | modified by specifying *BLOCK_SIZE*. If count=\ *BLOCKS* is specified | |
31 | diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx | |
32 | index f3b2b1b4de..e77ed9347f 100644 | |
33 | --- a/qemu-img-cmds.hx | |
34 | +++ b/qemu-img-cmds.hx | |
35 | @@ -58,9 +58,9 @@ SRST | |
36 | ERST | |
37 | ||
38 | DEF("dd", img_dd, | |
39 | - "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [-n] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output") | |
40 | + "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [-n] [-l snapshot_param] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output") | |
41 | SRST | |
42 | -.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE] if=INPUT of=OUTPUT | |
43 | +.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [-l SNAPSHOT_PARAM] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE] if=INPUT of=OUTPUT | |
44 | ERST | |
45 | ||
46 | DEF("info", img_info, | |
47 | diff --git a/qemu-img.c b/qemu-img.c | |
48 | index 015d6d2ce4..7031195e32 100644 | |
49 | --- a/qemu-img.c | |
50 | +++ b/qemu-img.c | |
51 | @@ -4922,6 +4922,7 @@ static int img_dd(int argc, char **argv) | |
52 | BlockDriver *drv = NULL, *proto_drv = NULL; | |
53 | BlockBackend *blk1 = NULL, *blk2 = NULL; | |
54 | QemuOpts *opts = NULL; | |
55 | + QemuOpts *sn_opts = NULL; | |
56 | QemuOptsList *create_opts = NULL; | |
57 | Error *local_err = NULL; | |
58 | bool image_opts = false; | |
59 | @@ -4931,6 +4932,7 @@ static int img_dd(int argc, char **argv) | |
60 | int64_t size = 0, readsize = 0; | |
61 | int64_t block_count = 0, out_pos, in_pos; | |
62 | bool force_share = false, skip_create = false; | |
63 | + const char *snapshot_name = NULL; | |
64 | struct DdInfo dd = { | |
65 | .flags = 0, | |
66 | .count = 0, | |
67 | @@ -4968,7 +4970,7 @@ static int img_dd(int argc, char **argv) | |
68 | { 0, 0, 0, 0 } | |
69 | }; | |
70 | ||
71 | - while ((c = getopt_long(argc, argv, ":hf:O:Un", long_options, NULL))) { | |
72 | + while ((c = getopt_long(argc, argv, ":hf:O:l:Un", long_options, NULL))) { | |
73 | if (c == EOF) { | |
74 | break; | |
75 | } | |
76 | @@ -4991,6 +4993,19 @@ static int img_dd(int argc, char **argv) | |
77 | case 'n': | |
78 | skip_create = true; | |
79 | break; | |
80 | + case 'l': | |
81 | + if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { | |
82 | + sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts, | |
83 | + optarg, false); | |
84 | + if (!sn_opts) { | |
85 | + error_report("Failed in parsing snapshot param '%s'", | |
86 | + optarg); | |
87 | + goto out; | |
88 | + } | |
89 | + } else { | |
90 | + snapshot_name = optarg; | |
91 | + } | |
92 | + break; | |
93 | case 'U': | |
94 | force_share = true; | |
95 | break; | |
96 | @@ -5050,11 +5065,24 @@ static int img_dd(int argc, char **argv) | |
97 | if (dd.flags & C_IF) { | |
98 | blk1 = img_open(image_opts, in.filename, fmt, 0, false, false, | |
99 | force_share); | |
100 | - | |
101 | if (!blk1) { | |
102 | ret = -1; | |
103 | goto out; | |
104 | } | |
105 | + if (sn_opts) { | |
106 | + bdrv_snapshot_load_tmp(blk_bs(blk1), | |
107 | + qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID), | |
108 | + qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME), | |
109 | + &local_err); | |
110 | + } else if (snapshot_name != NULL) { | |
111 | + bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(blk1), snapshot_name, | |
112 | + &local_err); | |
113 | + } | |
114 | + if (local_err) { | |
115 | + error_reportf_err(local_err, "Failed to load snapshot: "); | |
116 | + ret = -1; | |
117 | + goto out; | |
118 | + } | |
119 | } | |
120 | ||
121 | if (dd.flags & C_OSIZE) { | |
122 | @@ -5203,6 +5231,7 @@ static int img_dd(int argc, char **argv) | |
123 | out: | |
124 | g_free(arg); | |
125 | qemu_opts_del(opts); | |
126 | + qemu_opts_del(sn_opts); | |
127 | qemu_opts_free(create_opts); | |
128 | blk_unref(blk1); | |
129 | blk_unref(blk2); |