]>
Commit | Line | Data |
---|---|---|
d592fd72 DM |
1 | Index: new/savevm-async.c |
2 | =================================================================== | |
e96de165 DM |
3 | --- new.orig/savevm-async.c 2012-11-22 10:44:32.000000000 +0100 |
4 | +++ new/savevm-async.c 2012-11-22 12:15:20.000000000 +0100 | |
5 | @@ -7,7 +7,7 @@ | |
6 | #include "buffered_file.h" | |
7 | #include "migration.h" | |
d592fd72 | 8 | |
e96de165 DM |
9 | -//#define DEBUG_SAVEVM_STATE |
10 | +/* #define DEBUG_SAVEVM_STATE */ | |
11 | ||
12 | #ifdef DEBUG_SAVEVM_STATE | |
13 | #define DPRINTF(fmt, ...) \ | |
14 | @@ -86,11 +86,11 @@ | |
15 | } | |
16 | ||
17 | if (snap_state.bs) { | |
18 | - // try to truncate, but ignore errors (will fail on block devices). | |
19 | - // note: bdrv_read() need whole blocks, so we round up | |
20 | + /* try to truncate, but ignore errors (will fail on block devices). | |
21 | + * note: bdrv_read() need whole blocks, so we round up | |
22 | + */ | |
23 | size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK; | |
24 | bdrv_truncate(snap_state.bs, size); | |
25 | - | |
26 | bdrv_delete(snap_state.bs); | |
27 | snap_state.bs = NULL; | |
28 | } | |
29 | @@ -137,11 +137,13 @@ | |
30 | return bdrv_flush(snap_state.bs); | |
31 | } | |
32 | ||
33 | -static ssize_t block_state_put_buffer(void *opaque, const void *buf, | |
34 | - size_t size) | |
35 | +static int block_state_put_buffer(void *opaque, const uint8_t *buf, | |
36 | + int64_t pos, int size) | |
d592fd72 | 37 | { |
d592fd72 DM |
38 | int ret; |
39 | ||
e96de165 DM |
40 | + assert(pos == snap_state.bs_pos); |
41 | + | |
42 | if ((ret = bdrv_pwrite(snap_state.bs, snap_state.bs_pos, buf, size)) > 0) { | |
43 | snap_state.bs_pos += ret; | |
d592fd72 | 44 | } |
e96de165 DM |
45 | @@ -149,50 +151,74 @@ |
46 | return ret; | |
47 | } | |
48 | ||
49 | -static void block_state_put_ready(void *opaque) | |
50 | +static void process_savevm_co(void *opaque) | |
51 | { | |
52 | int ret; | |
53 | + uint64_t remaining; | |
54 | + int64_t maxlen; | |
55 | + MigrationParams params = { | |
56 | + .blk = 0, | |
57 | + .shared = 0 | |
58 | + }; | |
59 | ||
60 | - if (snap_state.state != SAVE_STATE_ACTIVE) { | |
61 | - save_snapshot_error("put_ready returning because of non-active state"); | |
62 | - return; | |
63 | - } | |
64 | + snap_state.state = SAVE_STATE_ACTIVE; | |
d592fd72 DM |
65 | |
66 | - if (!runstate_check(RUN_STATE_SAVE_VM)) { | |
67 | - save_snapshot_error("put_ready returning because of wrong run state"); | |
e96de165 DM |
68 | + ret = qemu_savevm_state_begin(snap_state.file, ¶ms); |
69 | + if (ret < 0) { | |
70 | + save_snapshot_error("qemu_savevm_state_begin failed"); | |
71 | return; | |
d592fd72 DM |
72 | } |
73 | ||
74 | - ret = qemu_savevm_state_iterate(snap_state.file); | |
e96de165 DM |
75 | - if (ret < 0) { |
76 | - save_snapshot_error("qemu_savevm_state_iterate error %d", ret); | |
77 | - return; | |
78 | - } else if (ret == 1) { | |
79 | - DPRINTF("savevm inerate finished\n"); | |
80 | - if ((ret = qemu_savevm_state_complete(snap_state.file)) < 0) { | |
81 | - save_snapshot_error("qemu_savevm_state_complete error %d", ret); | |
82 | - return; | |
83 | - } else { | |
84 | - DPRINTF("save complete\n"); | |
85 | - save_snapshot_completed(); | |
86 | + while (snap_state.state == SAVE_STATE_ACTIVE) { | |
87 | + | |
88 | + ret = qemu_savevm_state_iterate(snap_state.file); | |
89 | + remaining = ram_bytes_remaining(); | |
90 | + | |
91 | + DPRINTF("savevm inerate %zd %d\n", remaining, ret); | |
92 | + | |
93 | + if (ret < 0) { | |
94 | + save_snapshot_error("qemu_savevm_state_iterate error %d", ret); | |
95 | return; | |
96 | } | |
97 | + | |
98 | + /* stop the VM if we get to the end of available space, | |
99 | + * or if remaining is just a few MB | |
100 | + */ | |
101 | + maxlen = bdrv_getlength(snap_state.bs) - 30*1024*1024; | |
102 | + if ((remaining < 100000) || | |
103 | + ((snap_state.bs_pos + remaining) >= maxlen)) { | |
104 | + if (runstate_is_running()) { | |
105 | + vm_stop(RUN_STATE_SAVE_VM); | |
106 | + } | |
d592fd72 | 107 | + } |
e96de165 DM |
108 | + |
109 | + if (ret == 1) { /* finished */ | |
110 | + if (runstate_is_running()) { | |
111 | + vm_stop(RUN_STATE_SAVE_VM); | |
112 | + } | |
113 | + DPRINTF("savevm inerate finished\n"); | |
114 | + if ((ret = qemu_savevm_state_complete(snap_state.file)) < 0) { | |
115 | + save_snapshot_error("qemu_savevm_state_complete error %d", ret); | |
116 | + return; | |
117 | + } else { | |
118 | + DPRINTF("save complete\n"); | |
119 | + save_snapshot_completed(); | |
120 | + return; | |
121 | + } | |
122 | + } | |
123 | } | |
124 | } | |
125 | ||
126 | -static void block_state_wait_for_unfreeze(void *opaque) | |
127 | -{ | |
128 | - /* do nothing here - should not be called */ | |
129 | -} | |
130 | +static const QEMUFileOps block_file_ops = { | |
131 | + .put_buffer = block_state_put_buffer, | |
132 | + .close = block_state_close, | |
133 | +}; | |
134 | + | |
135 | ||
136 | void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) | |
137 | { | |
138 | BlockDriver *drv = NULL; | |
139 | int bdrv_oflags = BDRV_O_CACHE_WB | BDRV_O_RDWR; | |
140 | - MigrationParams params = { | |
141 | - .blk = 0, | |
142 | - .shared = 0 | |
143 | - }; | |
144 | int ret; | |
145 | ||
146 | if (snap_state.state != SAVE_STATE_DONE) { | |
147 | @@ -211,10 +237,8 @@ | |
d592fd72 DM |
148 | snap_state.error = NULL; |
149 | } | |
150 | ||
151 | - /* stop the VM */ | |
152 | - vm_stop(RUN_STATE_SAVE_VM); | |
153 | - | |
154 | if (!has_statefile) { | |
155 | + vm_stop(RUN_STATE_SAVE_VM); | |
156 | snap_state.state = SAVE_STATE_COMPLETED; | |
157 | return; | |
158 | } | |
e96de165 DM |
159 | @@ -231,27 +255,15 @@ |
160 | goto restart; | |
161 | } | |
162 | ||
163 | - snap_state.file = qemu_fopen_ops_buffered(&snap_state, 1000000000, | |
164 | - block_state_put_buffer, | |
165 | - block_state_put_ready, | |
166 | - block_state_wait_for_unfreeze, | |
167 | - block_state_close); | |
168 | + snap_state.file = qemu_fopen_ops(&snap_state, &block_file_ops); | |
169 | ||
170 | if (!snap_state.file) { | |
171 | error_set(errp, QERR_OPEN_FILE_FAILED, statefile); | |
172 | goto restart; | |
173 | } | |
174 | ||
175 | - snap_state.state = SAVE_STATE_ACTIVE; | |
176 | - | |
177 | - ret = qemu_savevm_state_begin(snap_state.file, ¶ms); | |
178 | - if (ret < 0) { | |
179 | - error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
180 | - "qemu_savevm_state_begin failed\n"); | |
181 | - goto restart; | |
182 | - } | |
183 | - | |
184 | - block_state_put_ready(&snap_state); | |
185 | + Coroutine *co = qemu_coroutine_create(process_savevm_co); | |
186 | + qemu_coroutine_enter(co, NULL); | |
187 | ||
188 | return; | |
189 | ||
190 | @@ -384,7 +396,8 @@ | |
191 | } | |
192 | } | |
193 | ||
194 | -static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) | |
195 | +static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, | |
196 | + int size) | |
197 | { | |
198 | BlockDriverState *bs = (BlockDriverState *)opaque; | |
199 | int64_t maxlen = bdrv_getlength(bs); | |
200 | @@ -400,6 +413,10 @@ | |
201 | return bdrv_pread(bs, pos, buf, size); | |
202 | } | |
203 | ||
204 | +static const QEMUFileOps loadstate_file_ops = { | |
205 | + .get_buffer = loadstate_get_buffer, | |
206 | +}; | |
207 | + | |
208 | int load_state_from_blockdev(const char *filename) | |
209 | { | |
210 | BlockDriverState *bs = NULL; | |
211 | @@ -415,7 +432,7 @@ | |
212 | } | |
213 | ||
214 | /* restore the VM state */ | |
215 | - f = qemu_fopen_ops(bs, NULL, loadstate_get_buffer, NULL, NULL, NULL, NULL); | |
216 | + f = qemu_fopen_ops(bs, &loadstate_file_ops); | |
217 | if (!f) { | |
218 | error_report("Could not open VM state file"); | |
219 | ret = -EINVAL; |