]> git.proxmox.com Git - pve-qemu-kvm.git/blame - debian/patches/internal-snapshot.patch
add patch for experimental snapshot support
[pve-qemu-kvm.git] / debian / patches / internal-snapshot.patch
CommitLineData
7378b84a
DM
1Index: 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' }
16Index: 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+}
166Index: 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+ },
192Index: 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+}
227Index: 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
240Index: 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+ },