]> git.proxmox.com Git - pve-qemu-kvm.git/blob - debian/patches/internal-snapshot.patch
add patch for experimental snapshot support
[pve-qemu-kvm.git] / debian / patches / internal-snapshot.patch
1 Index: new/qapi-schema.json
2 ===================================================================
3 --- new.orig/qapi-schema.json 2012-09-04 12:52:21.000000000 +0200
4 +++ new/qapi-schema.json 2012-09-04 12:53:35.000000000 +0200
5 @@ -2493,3 +2493,10 @@
6 # Since: 1.2.0
7 ##
8 { 'command': 'query-target', 'returns': 'TargetInfo' }
9 +
10 +
11 +{ 'command': 'snapshot-start' 'data': { 'statefile': 'str' } }
12 +
13 +{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
14 +
15 +{ 'command': 'snapshot-end' }
16 Index: new/qmp.c
17 ===================================================================
18 --- new.orig/qmp.c 2012-09-04 12:52:21.000000000 +0200
19 +++ new/qmp.c 2012-09-04 12:53:35.000000000 +0200
20 @@ -479,3 +479,145 @@
21 return arch_query_cpu_definitions(errp);
22 }
23
24 +static struct SnapshotState {
25 + int in_progress;
26 + int saved_vm_running;
27 +} snap_state;
28 +
29 +void qmp_snapshot_start(const char *statefile, Error **errp)
30 +{
31 + QEMUFile *f;
32 + int ret;
33 +
34 + if (snap_state.in_progress) {
35 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
36 + "VM snapshot already started\n");
37 + return;
38 + }
39 + snap_state.in_progress = 1;
40 +
41 + snap_state.saved_vm_running = runstate_is_running();
42 +
43 + vm_stop(RUN_STATE_SAVE_VM);
44 +
45 + f = qemu_fopen(statefile, "wb");
46 + if (!f) {
47 + error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
48 + return;
49 + }
50 +
51 + /* todo: does that save complete state? */
52 + ret = qemu_savevm_state_complete(f);
53 + qemu_fclose(f);
54 + if (ret < 0) {
55 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
56 + "Error %d while writing VM state\n", ret);
57 + return;
58 + }
59 +}
60 +
61 +void qmp_snapshot_end(Error **errp)
62 +{
63 + if (!snap_state.in_progress) {
64 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
65 + "VM snapshot not started\n");
66 + return;
67 + }
68 + snap_state.in_progress = 0;
69 +
70 + if (snap_state.saved_vm_running) {
71 + vm_start();
72 + }
73 +}
74 +
75 +/* Fixme: Copied from savevm */
76 +static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
77 + const char *name)
78 +{
79 + QEMUSnapshotInfo *sn_tab, *sn;
80 + int nb_sns, i, ret;
81 +
82 + ret = -ENOENT;
83 + nb_sns = bdrv_snapshot_list(bs, &sn_tab);
84 + if (nb_sns < 0)
85 + return ret;
86 + for(i = 0; i < nb_sns; i++) {
87 + sn = &sn_tab[i];
88 + if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
89 + *sn_info = *sn;
90 + ret = 0;
91 + break;
92 + }
93 + }
94 + g_free(sn_tab);
95 + return ret;
96 +}
97 +
98 +void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
99 +{
100 + BlockDriverState *bs;
101 + QEMUSnapshotInfo sn1, *sn = &sn1;
102 + int ret;
103 +#ifdef _WIN32
104 + struct _timeb tb;
105 +#else
106 + struct timeval tv;
107 +#endif
108 +
109 + if (!snap_state.in_progress) {
110 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
111 + "VM snapshot not started\n");
112 + return;
113 + }
114 +
115 + bs = bdrv_find(device);
116 + if (!bs) {
117 + error_set(errp, QERR_DEVICE_NOT_FOUND, device);
118 + return;
119 + }
120 +
121 + if (!bdrv_is_inserted(bs)) {
122 + error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
123 + return;
124 + }
125 +
126 + if (bdrv_is_read_only(bs)) {
127 + error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
128 + return;
129 + }
130 +
131 + if (!bdrv_can_snapshot(bs)) {
132 + error_set(errp, QERR_NOT_SUPPORTED);
133 + return;
134 + }
135 +
136 + if (bdrv_snapshot_find(bs, sn, name) >= 0) {
137 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
138 + "snapshot '%s' already exists", name);
139 + return;
140 + }
141 +
142 + sn = &sn1;
143 + memset(sn, 0, sizeof(*sn));
144 +
145 +#ifdef _WIN32
146 + _ftime(&tb);
147 + sn->date_sec = tb.time;
148 + sn->date_nsec = tb.millitm * 1000000;
149 +#else
150 + gettimeofday(&tv, NULL);
151 + sn->date_sec = tv.tv_sec;
152 + sn->date_nsec = tv.tv_usec * 1000;
153 +#endif
154 + sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
155 +
156 + pstrcpy(sn->name, sizeof(sn->name), name);
157 +
158 + sn->vm_state_size = 0; /* do not save state */
159 +
160 + ret = bdrv_snapshot_create(bs, sn);
161 + if (ret < 0) {
162 + error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Error while creating snapshot on '%s'\n", device);
163 + return;
164 + }
165 +}
166 Index: new/qmp-commands.hx
167 ===================================================================
168 --- new.orig/qmp-commands.hx 2012-09-04 12:52:21.000000000 +0200
169 +++ new/qmp-commands.hx 2012-09-04 12:53:35.000000000 +0200
170 @@ -2514,3 +2514,21 @@
171 .args_type = "",
172 .mhandler.cmd_new = qmp_marshal_input_query_target,
173 },
174 +
175 + {
176 + .name = "snapshot-start",
177 + .args_type = "statefile:s",
178 + .mhandler.cmd_new = qmp_marshal_input_snapshot_start,
179 + },
180 +
181 + {
182 + .name = "snapshot-drive",
183 + .args_type = "device:s,name:s",
184 + .mhandler.cmd_new = qmp_marshal_input_snapshot_drive,
185 + },
186 +
187 + {
188 + .name = "snapshot-end",
189 + .args_type = "",
190 + .mhandler.cmd_new = qmp_marshal_input_snapshot_end,
191 + },
192 Index: new/hmp.c
193 ===================================================================
194 --- new.orig/hmp.c 2012-09-04 12:52:21.000000000 +0200
195 +++ new/hmp.c 2012-09-04 12:53:35.000000000 +0200
196 @@ -1102,3 +1102,30 @@
197 qmp_closefd(fdname, &errp);
198 hmp_handle_error(mon, &errp);
199 }
200 +
201 +void hmp_snapshot_start(Monitor *mon, const QDict *qdict)
202 +{
203 + Error *errp = NULL;
204 + const char *statefile = qdict_get_str(qdict, "statefile");
205 +
206 + qmp_snapshot_start(statefile, &errp);
207 + hmp_handle_error(mon, &errp);
208 +}
209 +
210 +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict)
211 +{
212 + Error *errp = NULL;
213 + const char *name = qdict_get_str(qdict, "name");
214 + const char *device = qdict_get_str(qdict, "device");
215 +
216 + qmp_snapshot_drive(device, name, &errp);
217 + hmp_handle_error(mon, &errp);
218 +}
219 +
220 +void hmp_snapshot_end(Monitor *mon, const QDict *qdict)
221 +{
222 + Error *errp = NULL;
223 +
224 + qmp_snapshot_end(&errp);
225 + hmp_handle_error(mon, &errp);
226 +}
227 Index: new/hmp.h
228 ===================================================================
229 --- new.orig/hmp.h 2012-09-04 12:52:21.000000000 +0200
230 +++ new/hmp.h 2012-09-04 12:53:35.000000000 +0200
231 @@ -71,5 +71,8 @@
232 void hmp_netdev_del(Monitor *mon, const QDict *qdict);
233 void hmp_getfd(Monitor *mon, const QDict *qdict);
234 void hmp_closefd(Monitor *mon, const QDict *qdict);
235 +void hmp_snapshot_start(Monitor *mon, const QDict *qdict);
236 +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
237 +void hmp_snapshot_end(Monitor *mon, const QDict *qdict);
238
239 #endif
240 Index: new/hmp-commands.hx
241 ===================================================================
242 --- new.orig/hmp-commands.hx 2012-09-04 12:52:21.000000000 +0200
243 +++ new/hmp-commands.hx 2012-09-04 12:53:35.000000000 +0200
244 @@ -1494,3 +1494,28 @@
245 STEXI
246 @end table
247 ETEXI
248 +
249 + {
250 + .name = "snapshot-start",
251 + .args_type = "statefile:s",
252 + .params = "statefile",
253 + .help = "Prepare for snapshot and halt VM. Save VM state to statefile.",
254 + .mhandler.cmd = hmp_snapshot_start,
255 + },
256 +
257 +
258 + {
259 + .name = "snapshot-drive",
260 + .args_type = "device:s,name:s",
261 + .params = "device name",
262 + .help = "Create internal snapshot.",
263 + .mhandler.cmd = hmp_snapshot_drive,
264 + },
265 +
266 + {
267 + .name = "snapshot-end",
268 + .args_type = "",
269 + .params = "",
270 + .help = "Resume VM after snaphot.",
271 + .mhandler.cmd = hmp_snapshot_end,
272 + },