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 | } |