Statistics
| Branch: | Revision:

root / block-migration.c @ 658788c5

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