Statistics
| Branch: | Revision:

root / block-migration.c @ a55eb92c

History | View | Annotate | Download (14.3 kB)

1 c163b5ca lirans@il.ibm.com
/*
2 c163b5ca lirans@il.ibm.com
 * QEMU live block migration
3 c163b5ca lirans@il.ibm.com
 *
4 c163b5ca lirans@il.ibm.com
 * Copyright IBM, Corp. 2009
5 c163b5ca lirans@il.ibm.com
 *
6 c163b5ca lirans@il.ibm.com
 * Authors:
7 c163b5ca lirans@il.ibm.com
 *  Liran Schour   <lirans@il.ibm.com>
8 c163b5ca lirans@il.ibm.com
 *
9 c163b5ca lirans@il.ibm.com
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10 c163b5ca lirans@il.ibm.com
 * the COPYING file in the top-level directory.
11 c163b5ca lirans@il.ibm.com
 *
12 c163b5ca lirans@il.ibm.com
 */
13 c163b5ca lirans@il.ibm.com
14 c163b5ca lirans@il.ibm.com
#include "qemu-common.h"
15 c163b5ca lirans@il.ibm.com
#include "block_int.h"
16 c163b5ca lirans@il.ibm.com
#include "hw/hw.h"
17 c163b5ca lirans@il.ibm.com
#include "block-migration.h"
18 c163b5ca lirans@il.ibm.com
#include <assert.h>
19 c163b5ca lirans@il.ibm.com
20 c163b5ca lirans@il.ibm.com
#define SECTOR_BITS 9
21 c163b5ca lirans@il.ibm.com
#define SECTOR_SIZE (1 << SECTOR_BITS)
22 c163b5ca lirans@il.ibm.com
#define SECTOR_MASK ~(SECTOR_SIZE - 1);
23 c163b5ca lirans@il.ibm.com
24 a55eb92c Jan Kiszka
#define BLOCK_SIZE (block_mig_state->sectors_per_block << SECTOR_BITS)
25 c163b5ca lirans@il.ibm.com
26 c163b5ca lirans@il.ibm.com
#define BLK_MIG_FLAG_DEVICE_BLOCK       0x01
27 c163b5ca lirans@il.ibm.com
#define BLK_MIG_FLAG_EOS                0x02
28 c163b5ca lirans@il.ibm.com
29 c163b5ca lirans@il.ibm.com
#define MAX_IS_ALLOCATED_SEARCH 65536
30 c163b5ca lirans@il.ibm.com
#define MAX_BLOCKS_READ 10000
31 c163b5ca lirans@il.ibm.com
#define BLOCKS_READ_CHANGE 100
32 c163b5ca lirans@il.ibm.com
#define INITIAL_BLOCKS_READ 100
33 c163b5ca lirans@il.ibm.com
34 c163b5ca lirans@il.ibm.com
//#define DEBUG_BLK_MIGRATION
35 c163b5ca lirans@il.ibm.com
36 c163b5ca lirans@il.ibm.com
#ifdef DEBUG_BLK_MIGRATION
37 a55eb92c Jan Kiszka
#define dprintf(fmt, ...) \
38 c163b5ca lirans@il.ibm.com
    do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0)
39 c163b5ca lirans@il.ibm.com
#else
40 a55eb92c Jan Kiszka
#define dprintf(fmt, ...) \
41 c163b5ca lirans@il.ibm.com
    do { } while (0)
42 c163b5ca lirans@il.ibm.com
#endif
43 c163b5ca lirans@il.ibm.com
44 a55eb92c Jan Kiszka
typedef struct BlkMigDevState {
45 a55eb92c Jan Kiszka
    BlockDriverState *bs;
46 a55eb92c Jan Kiszka
    int bulk_completed;
47 a55eb92c Jan Kiszka
    int shared_base;
48 a55eb92c Jan Kiszka
    struct BlkMigDevState *next;
49 a55eb92c Jan Kiszka
    int64_t cur_sector;
50 a55eb92c Jan Kiszka
    int64_t total_sectors;
51 a55eb92c Jan Kiszka
    int64_t dirty;
52 a55eb92c Jan Kiszka
} BlkMigDevState;
53 a55eb92c Jan Kiszka
54 c163b5ca lirans@il.ibm.com
typedef struct BlkMigBlock {
55 c163b5ca lirans@il.ibm.com
    uint8_t *buf;
56 c163b5ca lirans@il.ibm.com
    BlkMigDevState *bmds;
57 c163b5ca lirans@il.ibm.com
    int64_t sector;
58 c163b5ca lirans@il.ibm.com
    struct iovec iov;
59 c163b5ca lirans@il.ibm.com
    QEMUIOVector qiov;
60 c163b5ca lirans@il.ibm.com
    BlockDriverAIOCB *aiocb;
61 c163b5ca lirans@il.ibm.com
    int ret;
62 c163b5ca lirans@il.ibm.com
    struct BlkMigBlock *next;
63 c163b5ca lirans@il.ibm.com
} BlkMigBlock;
64 c163b5ca lirans@il.ibm.com
65 c163b5ca lirans@il.ibm.com
typedef struct BlkMigState {
66 c163b5ca lirans@il.ibm.com
    int bulk_completed;
67 c163b5ca lirans@il.ibm.com
    int blk_enable;
68 c163b5ca lirans@il.ibm.com
    int shared_base;
69 c163b5ca lirans@il.ibm.com
    int no_dirty;
70 c163b5ca lirans@il.ibm.com
    QEMUFile *load_file;
71 c163b5ca lirans@il.ibm.com
    BlkMigDevState *bmds_first;
72 c163b5ca lirans@il.ibm.com
    int sectors_per_block;
73 c163b5ca lirans@il.ibm.com
    BlkMigBlock *first_blk;
74 c163b5ca lirans@il.ibm.com
    BlkMigBlock *last_blk;
75 c163b5ca lirans@il.ibm.com
    int submitted;
76 c163b5ca lirans@il.ibm.com
    int read_done;
77 c163b5ca lirans@il.ibm.com
    int transferred;
78 c163b5ca lirans@il.ibm.com
    int64_t print_completion;
79 c163b5ca lirans@il.ibm.com
} BlkMigState;
80 c163b5ca lirans@il.ibm.com
81 a55eb92c Jan Kiszka
static BlkMigState *block_mig_state = NULL;
82 c163b5ca lirans@il.ibm.com
83 c163b5ca lirans@il.ibm.com
static void blk_mig_read_cb(void *opaque, int ret)
84 c163b5ca lirans@il.ibm.com
{
85 c163b5ca lirans@il.ibm.com
    BlkMigBlock *blk = opaque;
86 a55eb92c Jan Kiszka
87 c163b5ca lirans@il.ibm.com
    blk->ret = ret;
88 a55eb92c Jan Kiszka
89 c163b5ca lirans@il.ibm.com
    /* insert at the end */
90 a55eb92c Jan Kiszka
    if (block_mig_state->last_blk == NULL) {
91 c163b5ca lirans@il.ibm.com
        block_mig_state->first_blk = blk;
92 c163b5ca lirans@il.ibm.com
        block_mig_state->last_blk = blk;
93 c163b5ca lirans@il.ibm.com
    } else {
94 c163b5ca lirans@il.ibm.com
        block_mig_state->last_blk->next = blk;
95 c163b5ca lirans@il.ibm.com
        block_mig_state->last_blk = blk;
96 c163b5ca lirans@il.ibm.com
    }
97 a55eb92c Jan Kiszka
98 c163b5ca lirans@il.ibm.com
    block_mig_state->submitted--;
99 c163b5ca lirans@il.ibm.com
    block_mig_state->read_done++;
100 c163b5ca lirans@il.ibm.com
    assert(block_mig_state->submitted >= 0);
101 c163b5ca lirans@il.ibm.com
}
102 c163b5ca lirans@il.ibm.com
103 c163b5ca lirans@il.ibm.com
static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms)
104 a55eb92c Jan Kiszka
{
105 c163b5ca lirans@il.ibm.com
    int nr_sectors;
106 c163b5ca lirans@il.ibm.com
    int64_t total_sectors, cur_sector = 0;
107 c163b5ca lirans@il.ibm.com
    BlockDriverState *bs = bms->bs;
108 c163b5ca lirans@il.ibm.com
    BlkMigBlock *blk;
109 a55eb92c Jan Kiszka
110 c163b5ca lirans@il.ibm.com
    blk = qemu_malloc(sizeof(BlkMigBlock));
111 c163b5ca lirans@il.ibm.com
    blk->buf = qemu_malloc(BLOCK_SIZE);
112 a55eb92c Jan Kiszka
113 c163b5ca lirans@il.ibm.com
    cur_sector = bms->cur_sector;
114 c163b5ca lirans@il.ibm.com
    total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
115 a55eb92c Jan Kiszka
116 a55eb92c Jan Kiszka
    if (bms->shared_base) {
117 a55eb92c Jan Kiszka
        while (cur_sector < bms->total_sectors &&
118 a55eb92c Jan Kiszka
               !bdrv_is_allocated(bms->bs, cur_sector,
119 a55eb92c Jan Kiszka
                                  MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) {
120 c163b5ca lirans@il.ibm.com
            cur_sector += nr_sectors;
121 c163b5ca lirans@il.ibm.com
        }
122 c163b5ca lirans@il.ibm.com
    }
123 a55eb92c Jan Kiszka
124 a55eb92c Jan Kiszka
    if (cur_sector >= total_sectors) {
125 c163b5ca lirans@il.ibm.com
        bms->cur_sector = total_sectors;
126 c163b5ca lirans@il.ibm.com
        qemu_free(blk->buf);
127 c163b5ca lirans@il.ibm.com
        qemu_free(blk);
128 c163b5ca lirans@il.ibm.com
        return 1;
129 c163b5ca lirans@il.ibm.com
    }
130 a55eb92c Jan Kiszka
131 a55eb92c Jan Kiszka
    if (cur_sector >= block_mig_state->print_completion) {
132 c163b5ca lirans@il.ibm.com
        printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors);
133 c163b5ca lirans@il.ibm.com
        fflush(stdout);
134 a55eb92c Jan Kiszka
        block_mig_state->print_completion +=
135 c163b5ca lirans@il.ibm.com
            (block_mig_state->sectors_per_block * 10000);
136 c163b5ca lirans@il.ibm.com
    }
137 a55eb92c Jan Kiszka
138 c163b5ca lirans@il.ibm.com
    /* we going to transfder BLOCK_SIZE any way even if it is not allocated */
139 c163b5ca lirans@il.ibm.com
    nr_sectors = block_mig_state->sectors_per_block;
140 c163b5ca lirans@il.ibm.com
141 c163b5ca lirans@il.ibm.com
    cur_sector &= ~((int64_t)block_mig_state->sectors_per_block -1);
142 a55eb92c Jan Kiszka
143 a55eb92c Jan Kiszka
    if (total_sectors - cur_sector < block_mig_state->sectors_per_block) {
144 c163b5ca lirans@il.ibm.com
        nr_sectors = (total_sectors - cur_sector);
145 c163b5ca lirans@il.ibm.com
    }
146 a55eb92c Jan Kiszka
147 c163b5ca lirans@il.ibm.com
    bms->cur_sector = cur_sector + nr_sectors;
148 c163b5ca lirans@il.ibm.com
    blk->sector = cur_sector;
149 c163b5ca lirans@il.ibm.com
    blk->bmds = bms;
150 c163b5ca lirans@il.ibm.com
    blk->next = NULL;
151 a55eb92c Jan Kiszka
152 c163b5ca lirans@il.ibm.com
    blk->iov.iov_base = blk->buf;
153 c163b5ca lirans@il.ibm.com
    blk->iov.iov_len = nr_sectors * SECTOR_SIZE;
154 c163b5ca lirans@il.ibm.com
    qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
155 a55eb92c Jan Kiszka
156 c163b5ca lirans@il.ibm.com
    blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
157 c163b5ca lirans@il.ibm.com
                                nr_sectors, blk_mig_read_cb, blk);
158 a55eb92c Jan Kiszka
159 a55eb92c Jan Kiszka
    if (!blk->aiocb) {
160 c163b5ca lirans@il.ibm.com
        printf("Error reading sector %" PRId64 "\n", cur_sector);
161 c163b5ca lirans@il.ibm.com
        qemu_free(blk->buf);
162 c163b5ca lirans@il.ibm.com
        qemu_free(blk);
163 c163b5ca lirans@il.ibm.com
        return 0;
164 c163b5ca lirans@il.ibm.com
    }
165 c163b5ca lirans@il.ibm.com
166 c163b5ca lirans@il.ibm.com
    bdrv_reset_dirty(bms->bs, cur_sector, nr_sectors);
167 c163b5ca lirans@il.ibm.com
    block_mig_state->submitted++;
168 a55eb92c Jan Kiszka
169 c163b5ca lirans@il.ibm.com
    return (bms->cur_sector >= total_sectors);
170 c163b5ca lirans@il.ibm.com
}
171 c163b5ca lirans@il.ibm.com
172 c163b5ca lirans@il.ibm.com
static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
173 a55eb92c Jan Kiszka
{
174 c163b5ca lirans@il.ibm.com
    int len, nr_sectors;
175 c163b5ca lirans@il.ibm.com
    int64_t total_sectors = bmds->total_sectors, cur_sector = 0;
176 c163b5ca lirans@il.ibm.com
    uint8_t *tmp_buf = NULL;
177 c163b5ca lirans@il.ibm.com
    BlockDriverState *bs = bmds->bs;
178 c163b5ca lirans@il.ibm.com
179 c163b5ca lirans@il.ibm.com
    tmp_buf = qemu_malloc(BLOCK_SIZE);
180 a55eb92c Jan Kiszka
181 c163b5ca lirans@il.ibm.com
    cur_sector = bmds->cur_sector;
182 a55eb92c Jan Kiszka
183 a55eb92c Jan Kiszka
    if (bmds->shared_base) {
184 a55eb92c Jan Kiszka
        while (cur_sector < bmds->total_sectors &&
185 a55eb92c Jan Kiszka
               !bdrv_is_allocated(bmds->bs, cur_sector,
186 a55eb92c Jan Kiszka
                                  MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) {
187 c163b5ca lirans@il.ibm.com
            cur_sector += nr_sectors;
188 c163b5ca lirans@il.ibm.com
        }
189 c163b5ca lirans@il.ibm.com
    }
190 a55eb92c Jan Kiszka
191 a55eb92c Jan Kiszka
    if (cur_sector >= total_sectors) {
192 c163b5ca lirans@il.ibm.com
        bmds->cur_sector = total_sectors;
193 c163b5ca lirans@il.ibm.com
        qemu_free(tmp_buf);
194 c163b5ca lirans@il.ibm.com
        return 1;
195 c163b5ca lirans@il.ibm.com
    }
196 a55eb92c Jan Kiszka
197 a55eb92c Jan Kiszka
    if (cur_sector >= block_mig_state->print_completion) {
198 c163b5ca lirans@il.ibm.com
        printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors);
199 c163b5ca lirans@il.ibm.com
        fflush(stdout);
200 a55eb92c Jan Kiszka
        block_mig_state->print_completion +=
201 c163b5ca lirans@il.ibm.com
            (block_mig_state->sectors_per_block * 10000);
202 c163b5ca lirans@il.ibm.com
    }
203 a55eb92c Jan Kiszka
204 c163b5ca lirans@il.ibm.com
    cur_sector &= ~((int64_t)block_mig_state->sectors_per_block -1);
205 a55eb92c Jan Kiszka
206 a55eb92c Jan Kiszka
    /* we going to transfer BLOCK_SIZE any way even if it is not allocated */
207 c163b5ca lirans@il.ibm.com
    nr_sectors = block_mig_state->sectors_per_block;
208 a55eb92c Jan Kiszka
209 a55eb92c Jan Kiszka
    if (total_sectors - cur_sector < block_mig_state->sectors_per_block) {
210 c163b5ca lirans@il.ibm.com
        nr_sectors = (total_sectors - cur_sector);
211 c163b5ca lirans@il.ibm.com
    }
212 a55eb92c Jan Kiszka
213 a55eb92c Jan Kiszka
    if (bdrv_read(bs, cur_sector, tmp_buf, nr_sectors) < 0) {
214 c163b5ca lirans@il.ibm.com
        printf("Error reading sector %" PRId64 "\n", cur_sector);
215 c163b5ca lirans@il.ibm.com
    }
216 c163b5ca lirans@il.ibm.com
217 c163b5ca lirans@il.ibm.com
    bdrv_reset_dirty(bs, cur_sector, nr_sectors);
218 a55eb92c Jan Kiszka
219 a55eb92c Jan Kiszka
    /* sector number and flags */
220 a55eb92c Jan Kiszka
    qemu_put_be64(f, (cur_sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK);
221 a55eb92c Jan Kiszka
222 a55eb92c Jan Kiszka
    /* device name */
223 c163b5ca lirans@il.ibm.com
    len = strlen(bs->device_name);
224 c163b5ca lirans@il.ibm.com
    qemu_put_byte(f, len);
225 c163b5ca lirans@il.ibm.com
    qemu_put_buffer(f, (uint8_t *)bs->device_name, len);
226 a55eb92c Jan Kiszka
227 a55eb92c Jan Kiszka
    qemu_put_buffer(f, tmp_buf, BLOCK_SIZE);
228 a55eb92c Jan Kiszka
229 c163b5ca lirans@il.ibm.com
    bmds->cur_sector = cur_sector + block_mig_state->sectors_per_block;
230 a55eb92c Jan Kiszka
231 c163b5ca lirans@il.ibm.com
    qemu_free(tmp_buf);
232 a55eb92c Jan Kiszka
233 c163b5ca lirans@il.ibm.com
    return (bmds->cur_sector >= total_sectors);
234 c163b5ca lirans@il.ibm.com
}
235 c163b5ca lirans@il.ibm.com
236 c163b5ca lirans@il.ibm.com
static void send_blk(QEMUFile *f, BlkMigBlock * blk)
237 c163b5ca lirans@il.ibm.com
{
238 c163b5ca lirans@il.ibm.com
    int len;
239 a55eb92c Jan Kiszka
240 a55eb92c Jan Kiszka
    /* sector number and flags */
241 a55eb92c Jan Kiszka
    qemu_put_be64(f, (blk->sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK);
242 a55eb92c Jan Kiszka
243 a55eb92c Jan Kiszka
    /* device name */
244 c163b5ca lirans@il.ibm.com
    len = strlen(blk->bmds->bs->device_name);
245 c163b5ca lirans@il.ibm.com
    qemu_put_byte(f, len);
246 c163b5ca lirans@il.ibm.com
    qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len);
247 a55eb92c Jan Kiszka
248 a55eb92c Jan Kiszka
    qemu_put_buffer(f, blk->buf, BLOCK_SIZE);
249 c163b5ca lirans@il.ibm.com
}
250 c163b5ca lirans@il.ibm.com
251 c163b5ca lirans@il.ibm.com
static void blk_mig_save_dev_info(QEMUFile *f, BlkMigDevState *bmds)
252 c163b5ca lirans@il.ibm.com
{
253 c163b5ca lirans@il.ibm.com
}
254 c163b5ca lirans@il.ibm.com
255 c163b5ca lirans@il.ibm.com
static void set_dirty_tracking(int enable)
256 c163b5ca lirans@il.ibm.com
{
257 c163b5ca lirans@il.ibm.com
    BlkMigDevState *bmds;
258 a55eb92c Jan Kiszka
    for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) {
259 a55eb92c Jan Kiszka
        bdrv_set_dirty_tracking(bmds->bs, enable);
260 c163b5ca lirans@il.ibm.com
    }
261 c163b5ca lirans@il.ibm.com
}
262 c163b5ca lirans@il.ibm.com
263 c163b5ca lirans@il.ibm.com
static void init_blk_migration(QEMUFile *f)
264 c163b5ca lirans@il.ibm.com
{
265 c163b5ca lirans@il.ibm.com
    BlkMigDevState **pbmds, *bmds;
266 c163b5ca lirans@il.ibm.com
    BlockDriverState *bs;
267 a55eb92c Jan Kiszka
268 c163b5ca lirans@il.ibm.com
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
269 a55eb92c Jan Kiszka
        if (bs->type == BDRV_TYPE_HD) {
270 c163b5ca lirans@il.ibm.com
            bmds = qemu_mallocz(sizeof(BlkMigDevState));
271 c163b5ca lirans@il.ibm.com
            bmds->bs = bs;
272 c163b5ca lirans@il.ibm.com
            bmds->bulk_completed = 0;
273 c163b5ca lirans@il.ibm.com
            bmds->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
274 c163b5ca lirans@il.ibm.com
            bmds->shared_base = block_mig_state->shared_base;
275 a55eb92c Jan Kiszka
276 a55eb92c Jan Kiszka
            if (bmds->shared_base) {
277 a55eb92c Jan Kiszka
                printf("Start migration for %s with shared base image\n",
278 c163b5ca lirans@il.ibm.com
                       bs->device_name);
279 c163b5ca lirans@il.ibm.com
            } else {
280 c163b5ca lirans@il.ibm.com
                printf("Start full migration for %s\n", bs->device_name);
281 c163b5ca lirans@il.ibm.com
            }
282 a55eb92c Jan Kiszka
283 c163b5ca lirans@il.ibm.com
            /* insert at the end */
284 c163b5ca lirans@il.ibm.com
            pbmds = &block_mig_state->bmds_first;
285 a55eb92c Jan Kiszka
            while (*pbmds != NULL) {
286 c163b5ca lirans@il.ibm.com
                pbmds = &(*pbmds)->next;
287 a55eb92c Jan Kiszka
            }
288 c163b5ca lirans@il.ibm.com
            *pbmds = bmds;
289 a55eb92c Jan Kiszka
290 c163b5ca lirans@il.ibm.com
            blk_mig_save_dev_info(f, bmds);
291 c163b5ca lirans@il.ibm.com
        }
292 a55eb92c Jan Kiszka
    }
293 a55eb92c Jan Kiszka
294 c163b5ca lirans@il.ibm.com
    block_mig_state->sectors_per_block = bdrv_get_sectors_per_chunk();
295 c163b5ca lirans@il.ibm.com
}
296 c163b5ca lirans@il.ibm.com
297 c163b5ca lirans@il.ibm.com
static int blk_mig_save_bulked_block(QEMUFile *f, int is_async)
298 c163b5ca lirans@il.ibm.com
{
299 c163b5ca lirans@il.ibm.com
    BlkMigDevState *bmds;
300 c163b5ca lirans@il.ibm.com
301 c163b5ca lirans@il.ibm.com
    for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) {
302 a55eb92c Jan Kiszka
        if (bmds->bulk_completed == 0) {
303 a55eb92c Jan Kiszka
            if (is_async) {
304 a55eb92c Jan Kiszka
                if (mig_read_device_bulk(f, bmds) == 1) {
305 c163b5ca lirans@il.ibm.com
                    /* completed bulk section for this device */
306 c163b5ca lirans@il.ibm.com
                    bmds->bulk_completed = 1;
307 c163b5ca lirans@il.ibm.com
                }
308 c163b5ca lirans@il.ibm.com
            } else {
309 a55eb92c Jan Kiszka
                if (mig_save_device_bulk(f, bmds) == 1) {
310 c163b5ca lirans@il.ibm.com
                    /* completed bulk section for this device */
311 c163b5ca lirans@il.ibm.com
                    bmds->bulk_completed = 1;
312 c163b5ca lirans@il.ibm.com
                }
313 c163b5ca lirans@il.ibm.com
            }
314 c163b5ca lirans@il.ibm.com
            return 1;
315 c163b5ca lirans@il.ibm.com
        }
316 c163b5ca lirans@il.ibm.com
    }
317 a55eb92c Jan Kiszka
318 c163b5ca lirans@il.ibm.com
    /* we reached here means bulk is completed */
319 c163b5ca lirans@il.ibm.com
    block_mig_state->bulk_completed = 1;
320 a55eb92c Jan Kiszka
321 c163b5ca lirans@il.ibm.com
    return 0;
322 c163b5ca lirans@il.ibm.com
}
323 c163b5ca lirans@il.ibm.com
324 c163b5ca lirans@il.ibm.com
#define MAX_NUM_BLOCKS 4
325 c163b5ca lirans@il.ibm.com
326 c163b5ca lirans@il.ibm.com
static void blk_mig_save_dirty_blocks(QEMUFile *f)
327 c163b5ca lirans@il.ibm.com
{
328 c163b5ca lirans@il.ibm.com
    BlkMigDevState *bmds;
329 c163b5ca lirans@il.ibm.com
    uint8_t buf[BLOCK_SIZE];
330 c163b5ca lirans@il.ibm.com
    int64_t sector;
331 c163b5ca lirans@il.ibm.com
    int len;
332 a55eb92c Jan Kiszka
333 a55eb92c Jan Kiszka
    for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) {
334 a55eb92c Jan Kiszka
        for (sector = 0; sector < bmds->cur_sector;) {
335 a55eb92c Jan Kiszka
            if (bdrv_get_dirty(bmds->bs, sector)) {
336 a55eb92c Jan Kiszka
                if (bdrv_read(bmds->bs, sector, buf,
337 a55eb92c Jan Kiszka
                              block_mig_state->sectors_per_block) < 0) {
338 a55eb92c Jan Kiszka
                    /* FIXME: add error handling */
339 c163b5ca lirans@il.ibm.com
                }
340 a55eb92c Jan Kiszka
341 a55eb92c Jan Kiszka
                /* sector number and flags */
342 a55eb92c Jan Kiszka
                qemu_put_be64(f, (sector << SECTOR_BITS)
343 a55eb92c Jan Kiszka
                                 | BLK_MIG_FLAG_DEVICE_BLOCK);
344 a55eb92c Jan Kiszka
345 c163b5ca lirans@il.ibm.com
                /* device name */
346 c163b5ca lirans@il.ibm.com
                len = strlen(bmds->bs->device_name);
347 c163b5ca lirans@il.ibm.com
                qemu_put_byte(f, len);
348 c163b5ca lirans@il.ibm.com
                qemu_put_buffer(f, (uint8_t *)bmds->bs->device_name, len);
349 a55eb92c Jan Kiszka
350 a55eb92c Jan Kiszka
                qemu_put_buffer(f, buf,
351 a55eb92c Jan Kiszka
                                (block_mig_state->sectors_per_block *
352 c163b5ca lirans@il.ibm.com
                                 SECTOR_SIZE));
353 a55eb92c Jan Kiszka
354 a55eb92c Jan Kiszka
                bdrv_reset_dirty(bmds->bs, sector,
355 c163b5ca lirans@il.ibm.com
                                 block_mig_state->sectors_per_block);
356 a55eb92c Jan Kiszka
            }
357 a55eb92c Jan Kiszka
            sector += block_mig_state->sectors_per_block;
358 c163b5ca lirans@il.ibm.com
        }
359 c163b5ca lirans@il.ibm.com
    }
360 c163b5ca lirans@il.ibm.com
}
361 c163b5ca lirans@il.ibm.com
362 c163b5ca lirans@il.ibm.com
static void flush_blks(QEMUFile* f)
363 c163b5ca lirans@il.ibm.com
{
364 a55eb92c Jan Kiszka
    BlkMigBlock *blk, *next;
365 a55eb92c Jan Kiszka
366 a55eb92c Jan Kiszka
    dprintf("%s Enter submitted %d read_done %d transfered\n", __FUNCTION__,
367 c163b5ca lirans@il.ibm.com
            submitted, read_done, transfered);
368 a55eb92c Jan Kiszka
369 a55eb92c Jan Kiszka
    for (blk = block_mig_state->first_blk;
370 a55eb92c Jan Kiszka
         blk != NULL && !qemu_file_rate_limit(f);
371 a55eb92c Jan Kiszka
         blk = next) {
372 c163b5ca lirans@il.ibm.com
        send_blk(f, blk);
373 a55eb92c Jan Kiszka
374 a55eb92c Jan Kiszka
        next = blk->next;
375 c163b5ca lirans@il.ibm.com
        qemu_free(blk->buf);
376 c163b5ca lirans@il.ibm.com
        qemu_free(blk);
377 a55eb92c Jan Kiszka
378 c163b5ca lirans@il.ibm.com
        block_mig_state->read_done--;
379 c163b5ca lirans@il.ibm.com
        block_mig_state->transferred++;
380 c163b5ca lirans@il.ibm.com
        assert(block_mig_state->read_done >= 0);
381 c163b5ca lirans@il.ibm.com
    }
382 c163b5ca lirans@il.ibm.com
    block_mig_state->first_blk = blk;
383 a55eb92c Jan Kiszka
384 a55eb92c Jan Kiszka
    if (block_mig_state->first_blk == NULL) {
385 c163b5ca lirans@il.ibm.com
        block_mig_state->last_blk = NULL;
386 c163b5ca lirans@il.ibm.com
    }
387 c163b5ca lirans@il.ibm.com
388 a55eb92c Jan Kiszka
    dprintf("%s Exit submitted %d read_done %d transferred%d\n", __FUNCTION__,
389 a55eb92c Jan Kiszka
            block_mig_state->submitted, block_mig_state->read_done,
390 c163b5ca lirans@il.ibm.com
            block_mig_state->transferred);
391 c163b5ca lirans@il.ibm.com
}
392 c163b5ca lirans@il.ibm.com
393 c163b5ca lirans@il.ibm.com
static int is_stage2_completed(void)
394 c163b5ca lirans@il.ibm.com
{
395 c163b5ca lirans@il.ibm.com
    BlkMigDevState *bmds;
396 a55eb92c Jan Kiszka
397 a55eb92c Jan Kiszka
    if (block_mig_state->submitted > 0) {
398 c163b5ca lirans@il.ibm.com
        return 0;
399 c163b5ca lirans@il.ibm.com
    }
400 a55eb92c Jan Kiszka
401 c163b5ca lirans@il.ibm.com
    for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) {
402 a55eb92c Jan Kiszka
        if (bmds->bulk_completed == 0) {
403 c163b5ca lirans@il.ibm.com
            return 0;
404 c163b5ca lirans@il.ibm.com
        }
405 c163b5ca lirans@il.ibm.com
    }
406 a55eb92c Jan Kiszka
407 c163b5ca lirans@il.ibm.com
    return 1;
408 c163b5ca lirans@il.ibm.com
}
409 c163b5ca lirans@il.ibm.com
410 c163b5ca lirans@il.ibm.com
static int block_save_live(QEMUFile *f, int stage, void *opaque)
411 c163b5ca lirans@il.ibm.com
{
412 a55eb92c Jan Kiszka
    dprintf("Enter save live stage %d submitted %d transferred %d\n", stage,
413 c163b5ca lirans@il.ibm.com
            submitted, transferred);
414 a55eb92c Jan Kiszka
415 a55eb92c Jan Kiszka
    if (block_mig_state->blk_enable != 1) {
416 c163b5ca lirans@il.ibm.com
        /* no need to migrate storage */
417 a55eb92c Jan Kiszka
        qemu_put_be64(f, BLK_MIG_FLAG_EOS);
418 c163b5ca lirans@il.ibm.com
        return 1;
419 c163b5ca lirans@il.ibm.com
    }
420 a55eb92c Jan Kiszka
421 a55eb92c Jan Kiszka
    if (stage == 1) {
422 c163b5ca lirans@il.ibm.com
        init_blk_migration(f);
423 a55eb92c Jan Kiszka
424 c163b5ca lirans@il.ibm.com
        /* start track dirty blocks */
425 c163b5ca lirans@il.ibm.com
        set_dirty_tracking(1);
426 c163b5ca lirans@il.ibm.com
    }
427 c163b5ca lirans@il.ibm.com
428 c163b5ca lirans@il.ibm.com
    flush_blks(f);
429 a55eb92c Jan Kiszka
430 c163b5ca lirans@il.ibm.com
    /* control the rate of transfer */
431 a55eb92c Jan Kiszka
    while ((block_mig_state->submitted +
432 a55eb92c Jan Kiszka
            block_mig_state->read_done) * BLOCK_SIZE <
433 a55eb92c Jan Kiszka
           qemu_file_get_rate_limit(f)) {
434 a55eb92c Jan Kiszka
        if (blk_mig_save_bulked_block(f, 1) == 0) {
435 a55eb92c Jan Kiszka
            /* no more bulk blocks for now */
436 c163b5ca lirans@il.ibm.com
            break;
437 a55eb92c Jan Kiszka
        }
438 c163b5ca lirans@il.ibm.com
    }
439 a55eb92c Jan Kiszka
440 c163b5ca lirans@il.ibm.com
    flush_blks(f);
441 a55eb92c Jan Kiszka
442 a55eb92c Jan Kiszka
    if (stage == 3) {
443 a55eb92c Jan Kiszka
        while (blk_mig_save_bulked_block(f, 0) != 0) {
444 a55eb92c Jan Kiszka
            /* empty */
445 a55eb92c Jan Kiszka
        }
446 a55eb92c Jan Kiszka
447 c163b5ca lirans@il.ibm.com
        blk_mig_save_dirty_blocks(f);
448 a55eb92c Jan Kiszka
449 c163b5ca lirans@il.ibm.com
        /* stop track dirty blocks */
450 a55eb92c Jan Kiszka
        set_dirty_tracking(0);
451 a55eb92c Jan Kiszka
452 a55eb92c Jan Kiszka
        printf("\nBlock migration completed\n");
453 c163b5ca lirans@il.ibm.com
    }
454 a55eb92c Jan Kiszka
455 a55eb92c Jan Kiszka
    qemu_put_be64(f, BLK_MIG_FLAG_EOS);
456 a55eb92c Jan Kiszka
457 c163b5ca lirans@il.ibm.com
    return ((stage == 2) && is_stage2_completed());
458 c163b5ca lirans@il.ibm.com
}
459 c163b5ca lirans@il.ibm.com
460 c163b5ca lirans@il.ibm.com
static int block_load(QEMUFile *f, void *opaque, int version_id)
461 c163b5ca lirans@il.ibm.com
{
462 c163b5ca lirans@il.ibm.com
    int len, flags;
463 c163b5ca lirans@il.ibm.com
    char device_name[256];
464 c163b5ca lirans@il.ibm.com
    int64_t addr;
465 c163b5ca lirans@il.ibm.com
    BlockDriverState *bs;
466 c163b5ca lirans@il.ibm.com
    uint8_t *buf;
467 a55eb92c Jan Kiszka
468 c163b5ca lirans@il.ibm.com
    block_mig_state->sectors_per_block = bdrv_get_sectors_per_chunk();
469 c163b5ca lirans@il.ibm.com
    buf = qemu_malloc(BLOCK_SIZE);
470 a55eb92c Jan Kiszka
471 c163b5ca lirans@il.ibm.com
    do {
472 c163b5ca lirans@il.ibm.com
        addr = qemu_get_be64(f);
473 a55eb92c Jan Kiszka
474 c163b5ca lirans@il.ibm.com
        flags = addr & ~SECTOR_MASK;
475 c163b5ca lirans@il.ibm.com
        addr &= SECTOR_MASK;
476 a55eb92c Jan Kiszka
477 a55eb92c Jan Kiszka
        if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) {
478 c163b5ca lirans@il.ibm.com
            /* get device name */
479 c163b5ca lirans@il.ibm.com
            len = qemu_get_byte(f);
480 a55eb92c Jan Kiszka
481 c163b5ca lirans@il.ibm.com
            qemu_get_buffer(f, (uint8_t *)device_name, len);
482 c163b5ca lirans@il.ibm.com
            device_name[len] = '\0';
483 a55eb92c Jan Kiszka
484 c163b5ca lirans@il.ibm.com
            bs = bdrv_find(device_name);
485 a55eb92c Jan Kiszka
486 a55eb92c Jan Kiszka
            qemu_get_buffer(f, buf, BLOCK_SIZE);
487 a55eb92c Jan Kiszka
            if (bs != NULL) {
488 a55eb92c Jan Kiszka
                bdrv_write(bs, (addr >> SECTOR_BITS),
489 c163b5ca lirans@il.ibm.com
                           buf, block_mig_state->sectors_per_block);
490 c163b5ca lirans@il.ibm.com
            } else {
491 c163b5ca lirans@il.ibm.com
                printf("Error unknown block device %s\n", device_name);
492 a55eb92c Jan Kiszka
                /* FIXME: add error handling */
493 c163b5ca lirans@il.ibm.com
            }
494 a55eb92c Jan Kiszka
        } else if (!(flags & BLK_MIG_FLAG_EOS)) {
495 c163b5ca lirans@il.ibm.com
            printf("Unknown flags\n");
496 a55eb92c Jan Kiszka
            /* FIXME: add error handling */
497 c163b5ca lirans@il.ibm.com
        }
498 a55eb92c Jan Kiszka
    } while (!(flags & BLK_MIG_FLAG_EOS));
499 a55eb92c Jan Kiszka
500 c163b5ca lirans@il.ibm.com
    qemu_free(buf);
501 c163b5ca lirans@il.ibm.com
502 c163b5ca lirans@il.ibm.com
    return 0;
503 c163b5ca lirans@il.ibm.com
}
504 c163b5ca lirans@il.ibm.com
505 c163b5ca lirans@il.ibm.com
static void block_set_params(int blk_enable, int shared_base, void *opaque)
506 c163b5ca lirans@il.ibm.com
{
507 c163b5ca lirans@il.ibm.com
    assert(opaque == block_mig_state);
508 c163b5ca lirans@il.ibm.com
509 c163b5ca lirans@il.ibm.com
    block_mig_state->blk_enable = blk_enable;
510 c163b5ca lirans@il.ibm.com
    block_mig_state->shared_base = shared_base;
511 a55eb92c Jan Kiszka
512 c163b5ca lirans@il.ibm.com
    /* shared base means that blk_enable = 1 */
513 c163b5ca lirans@il.ibm.com
    block_mig_state->blk_enable |= shared_base;
514 c163b5ca lirans@il.ibm.com
}
515 c163b5ca lirans@il.ibm.com
516 c163b5ca lirans@il.ibm.com
void blk_mig_info(void)
517 c163b5ca lirans@il.ibm.com
{
518 c163b5ca lirans@il.ibm.com
    BlockDriverState *bs;
519 a55eb92c Jan Kiszka
520 c163b5ca lirans@il.ibm.com
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
521 c163b5ca lirans@il.ibm.com
        printf("Device %s\n", bs->device_name);
522 a55eb92c Jan Kiszka
        if (bs->type == BDRV_TYPE_HD) {
523 a55eb92c Jan Kiszka
            printf("device %s format %s\n",
524 c163b5ca lirans@il.ibm.com
                   bs->device_name, bs->drv->format_name);
525 c163b5ca lirans@il.ibm.com
        }
526 c163b5ca lirans@il.ibm.com
    }
527 c163b5ca lirans@il.ibm.com
}
528 c163b5ca lirans@il.ibm.com
529 c163b5ca lirans@il.ibm.com
void blk_mig_init(void)
530 a55eb92c Jan Kiszka
{
531 c163b5ca lirans@il.ibm.com
    block_mig_state = qemu_mallocz(sizeof(BlkMigState));
532 c163b5ca lirans@il.ibm.com
533 a55eb92c Jan Kiszka
    register_savevm_live("block", 0, 1, block_set_params, block_save_live,
534 a55eb92c Jan Kiszka
                         NULL, block_load, block_mig_state);
535 c163b5ca lirans@il.ibm.com
}