Revision 5e5328be
b/block-migration.c | ||
---|---|---|
14 | 14 |
#include "qemu-common.h" |
15 | 15 |
#include "block_int.h" |
16 | 16 |
#include "hw/hw.h" |
17 |
#include "qemu-queue.h" |
|
17 | 18 |
#include "block-migration.h" |
18 | 19 |
#include <assert.h> |
19 | 20 |
|
... | ... | |
41 | 42 |
BlockDriverState *bs; |
42 | 43 |
int bulk_completed; |
43 | 44 |
int shared_base; |
44 |
struct BlkMigDevState *next; |
|
45 | 45 |
int64_t cur_sector; |
46 | 46 |
int64_t total_sectors; |
47 | 47 |
int64_t dirty; |
48 |
QSIMPLEQ_ENTRY(BlkMigDevState) entry; |
|
48 | 49 |
} BlkMigDevState; |
49 | 50 |
|
50 | 51 |
typedef struct BlkMigBlock { |
... | ... | |
55 | 56 |
QEMUIOVector qiov; |
56 | 57 |
BlockDriverAIOCB *aiocb; |
57 | 58 |
int ret; |
58 |
struct BlkMigBlock *next;
|
|
59 |
QSIMPLEQ_ENTRY(BlkMigBlock) entry;
|
|
59 | 60 |
} BlkMigBlock; |
60 | 61 |
|
61 | 62 |
typedef struct BlkMigState { |
62 | 63 |
int blk_enable; |
63 | 64 |
int shared_base; |
64 |
BlkMigDevState *bmds_first; |
|
65 |
BlkMigBlock *first_blk; |
|
66 |
BlkMigBlock *last_blk; |
|
65 |
QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list; |
|
66 |
QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list; |
|
67 | 67 |
int submitted; |
68 | 68 |
int read_done; |
69 | 69 |
int transferred; |
... | ... | |
78 | 78 |
|
79 | 79 |
blk->ret = ret; |
80 | 80 |
|
81 |
/* insert at the end */ |
|
82 |
if (block_mig_state.last_blk == NULL) { |
|
83 |
block_mig_state.first_blk = blk; |
|
84 |
block_mig_state.last_blk = blk; |
|
85 |
} else { |
|
86 |
block_mig_state.last_blk->next = blk; |
|
87 |
block_mig_state.last_blk = blk; |
|
88 |
} |
|
81 |
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); |
|
89 | 82 |
|
90 | 83 |
block_mig_state.submitted--; |
91 | 84 |
block_mig_state.read_done++; |
... | ... | |
139 | 132 |
bms->cur_sector = cur_sector + nr_sectors; |
140 | 133 |
blk->sector = cur_sector; |
141 | 134 |
blk->bmds = bms; |
142 |
blk->next = NULL; |
|
143 | 135 |
|
144 | 136 |
blk->iov.iov_base = blk->buf; |
145 | 137 |
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; |
... | ... | |
245 | 237 |
static void set_dirty_tracking(int enable) |
246 | 238 |
{ |
247 | 239 |
BlkMigDevState *bmds; |
248 |
for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) { |
|
240 |
|
|
241 |
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { |
|
249 | 242 |
bdrv_set_dirty_tracking(bmds->bs, enable); |
250 | 243 |
} |
251 | 244 |
} |
252 | 245 |
|
253 | 246 |
static void init_blk_migration(QEMUFile *f) |
254 | 247 |
{ |
255 |
BlkMigDevState **pbmds, *bmds;
|
|
248 |
BlkMigDevState *bmds; |
|
256 | 249 |
BlockDriverState *bs; |
257 | 250 |
|
258 | 251 |
for (bs = bdrv_first; bs != NULL; bs = bs->next) { |
... | ... | |
270 | 263 |
printf("Start full migration for %s\n", bs->device_name); |
271 | 264 |
} |
272 | 265 |
|
273 |
/* insert at the end */ |
|
274 |
pbmds = &block_mig_state.bmds_first; |
|
275 |
while (*pbmds != NULL) { |
|
276 |
pbmds = &(*pbmds)->next; |
|
277 |
} |
|
278 |
*pbmds = bmds; |
|
266 |
QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry); |
|
279 | 267 |
} |
280 | 268 |
} |
281 | 269 |
} |
... | ... | |
284 | 272 |
{ |
285 | 273 |
BlkMigDevState *bmds; |
286 | 274 |
|
287 |
for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) {
|
|
275 |
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
|
288 | 276 |
if (bmds->bulk_completed == 0) { |
289 | 277 |
if (is_async) { |
290 | 278 |
if (mig_read_device_bulk(f, bmds) == 1) { |
... | ... | |
316 | 304 |
|
317 | 305 |
buf = qemu_malloc(BLOCK_SIZE); |
318 | 306 |
|
319 |
for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) {
|
|
307 |
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
|
320 | 308 |
for (sector = 0; sector < bmds->cur_sector;) { |
321 | 309 |
if (bdrv_get_dirty(bmds->bs, sector)) { |
322 | 310 |
if (bdrv_read(bmds->bs, sector, buf, |
... | ... | |
347 | 335 |
|
348 | 336 |
static void flush_blks(QEMUFile* f) |
349 | 337 |
{ |
350 |
BlkMigBlock *blk, *next;
|
|
338 |
BlkMigBlock *blk; |
|
351 | 339 |
|
352 | 340 |
dprintf("%s Enter submitted %d read_done %d transferred %d\n", |
353 | 341 |
__FUNCTION__, block_mig_state.submitted, block_mig_state.read_done, |
354 | 342 |
block_mig_state.transferred); |
355 | 343 |
|
356 |
for (blk = block_mig_state.first_blk; |
|
357 |
blk != NULL && !qemu_file_rate_limit(f); |
|
358 |
blk = next) { |
|
344 |
while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) { |
|
345 |
if (qemu_file_rate_limit(f)) { |
|
346 |
break; |
|
347 |
} |
|
359 | 348 |
send_blk(f, blk); |
360 | 349 |
|
361 |
next = blk->next;
|
|
350 |
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
|
|
362 | 351 |
qemu_free(blk->buf); |
363 | 352 |
qemu_free(blk); |
364 | 353 |
|
... | ... | |
366 | 355 |
block_mig_state.transferred++; |
367 | 356 |
assert(block_mig_state.read_done >= 0); |
368 | 357 |
} |
369 |
block_mig_state.first_blk = blk; |
|
370 |
|
|
371 |
if (block_mig_state.first_blk == NULL) { |
|
372 |
block_mig_state.last_blk = NULL; |
|
373 |
} |
|
374 | 358 |
|
375 | 359 |
dprintf("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__, |
376 | 360 |
block_mig_state.submitted, block_mig_state.read_done, |
... | ... | |
385 | 369 |
return 0; |
386 | 370 |
} |
387 | 371 |
|
388 |
for (bmds = block_mig_state.bmds_first; bmds != NULL; bmds = bmds->next) {
|
|
372 |
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
|
389 | 373 |
if (bmds->bulk_completed == 0) { |
390 | 374 |
return 0; |
391 | 375 |
} |
... | ... | |
498 | 482 |
|
499 | 483 |
void blk_mig_init(void) |
500 | 484 |
{ |
485 |
QSIMPLEQ_INIT(&block_mig_state.bmds_list); |
|
486 |
QSIMPLEQ_INIT(&block_mig_state.blk_list); |
|
487 |
|
|
501 | 488 |
register_savevm_live("block", 0, 1, block_set_params, block_save_live, |
502 | 489 |
NULL, block_load, &block_mig_state); |
503 | 490 |
} |
Also available in: Unified diff