Commit 5dafc53f1fb091d242f2179ffcb43bb28af36d1e

Authored by aliguori
1 parent f5049756

Refactor QEMUFile for live migration

To support live migration, we override QEMUFile so that instead of writing to
disk, the save/restore state happens over a network connection.

This patch makes QEMUFile read/write operations function pointers so that we
can override them for live migration.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5352 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 237 additions and 56 deletions
@@ -7,9 +7,36 @@ @@ -7,9 +7,36 @@
7 7
8 /* VM Load/Save */ 8 /* VM Load/Save */
9 9
  10 +/* This function writes a chunk of data to a file at the given position.
  11 + * The pos argument can be ignored if the file is only being used for
  12 + * streaming. The handler should try to write all of the data it can.
  13 + */
  14 +typedef void (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
  15 + int64_t pos, int size);
  16 +
  17 +/* Read a chunk of data from a file at the given position. The pos argument
  18 + * can be ignored if the file is only be used for streaming. The number of
  19 + * bytes actually read should be returned.
  20 + */
  21 +typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
  22 + int64_t pos, int size);
  23 +
  24 +/* Close a file and return an error code */
  25 +typedef int (QEMUFileCloseFunc)(void *opaque);
  26 +
  27 +/* Called to determine if the file has exceeded it's bandwidth allocation. The
  28 + * bandwidth capping is a soft limit, not a hard limit.
  29 + */
  30 +typedef int (QEMUFileRateLimit)(void *opaque);
  31 +
  32 +QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
  33 + QEMUFileGetBufferFunc *get_buffer,
  34 + QEMUFileCloseFunc *close,
  35 + QEMUFileRateLimit *rate_limit);
10 QEMUFile *qemu_fopen(const char *filename, const char *mode); 36 QEMUFile *qemu_fopen(const char *filename, const char *mode);
  37 +QEMUFile *qemu_fopen_fd(int fd);
11 void qemu_fflush(QEMUFile *f); 38 void qemu_fflush(QEMUFile *f);
12 -void qemu_fclose(QEMUFile *f); 39 +int qemu_fclose(QEMUFile *f);
13 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); 40 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
14 void qemu_put_byte(QEMUFile *f, int v); 41 void qemu_put_byte(QEMUFile *f, int v);
15 void qemu_put_be16(QEMUFile *f, unsigned int v); 42 void qemu_put_be16(QEMUFile *f, unsigned int v);
@@ -20,6 +47,12 @@ int qemu_get_byte(QEMUFile *f); @@ -20,6 +47,12 @@ int qemu_get_byte(QEMUFile *f);
20 unsigned int qemu_get_be16(QEMUFile *f); 47 unsigned int qemu_get_be16(QEMUFile *f);
21 unsigned int qemu_get_be32(QEMUFile *f); 48 unsigned int qemu_get_be32(QEMUFile *f);
22 uint64_t qemu_get_be64(QEMUFile *f); 49 uint64_t qemu_get_be64(QEMUFile *f);
  50 +int qemu_file_rate_limit(QEMUFile *f);
  51 +
  52 +/* Try to send any outstanding data. This function is useful when output is
  53 + * halted due to rate limiting or EAGAIN errors occur as it can be used to
  54 + * resume output. */
  55 +void qemu_file_put_notify(QEMUFile *f);
23 56
24 static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) 57 static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
25 { 58 {
@@ -6198,11 +6198,12 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) @@ -6198,11 +6198,12 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
6198 #define IO_BUF_SIZE 32768 6198 #define IO_BUF_SIZE 32768
6199 6199
6200 struct QEMUFile { 6200 struct QEMUFile {
6201 - FILE *outfile;  
6202 - BlockDriverState *bs;  
6203 - int is_file;  
6204 - int is_writable;  
6205 - int64_t base_offset; 6201 + QEMUFilePutBufferFunc *put_buffer;
  6202 + QEMUFileGetBufferFunc *get_buffer;
  6203 + QEMUFileCloseFunc *close;
  6204 + QEMUFileRateLimit *rate_limit;
  6205 + void *opaque;
  6206 +
6206 int64_t buf_offset; /* start of buffer when writing, end of buffer 6207 int64_t buf_offset; /* start of buffer when writing, end of buffer
6207 when reading */ 6208 when reading */
6208 int buf_index; 6209 int buf_index;
@@ -6210,58 +6211,198 @@ struct QEMUFile { @@ -6210,58 +6211,198 @@ struct QEMUFile {
6210 uint8_t buf[IO_BUF_SIZE]; 6211 uint8_t buf[IO_BUF_SIZE];
6211 }; 6212 };
6212 6213
  6214 +typedef struct QEMUFileFD
  6215 +{
  6216 + int fd;
  6217 + QEMUFile *file;
  6218 +} QEMUFileFD;
  6219 +
  6220 +static void fd_put_notify(void *opaque)
  6221 +{
  6222 + QEMUFileFD *s = opaque;
  6223 +
  6224 + /* Remove writable callback and do a put notify */
  6225 + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
  6226 + qemu_file_put_notify(s->file);
  6227 +}
  6228 +
  6229 +static int fd_put_buffer(void *opaque, const uint8_t *buf,
  6230 + int64_t pos, int size)
  6231 +{
  6232 + QEMUFileFD *s = opaque;
  6233 + ssize_t len;
  6234 +
  6235 + do {
  6236 + len = write(s->fd, buf, size);
  6237 + } while (len == -1 && errno == EINTR);
  6238 +
  6239 + if (len == -1)
  6240 + len = -errno;
  6241 +
  6242 + /* When the fd becomes writable again, register a callback to do
  6243 + * a put notify */
  6244 + if (len == -EAGAIN)
  6245 + qemu_set_fd_handler2(s->fd, NULL, NULL, fd_put_notify, s);
  6246 +
  6247 + return len;
  6248 +}
  6249 +
  6250 +static int fd_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
  6251 +{
  6252 + QEMUFileFD *s = opaque;
  6253 + ssize_t len;
  6254 +
  6255 + do {
  6256 + len = read(s->fd, buf, size);
  6257 + } while (len == -1 && errno == EINTR);
  6258 +
  6259 + if (len == -1)
  6260 + len = -errno;
  6261 +
  6262 + return len;
  6263 +}
  6264 +
  6265 +static int fd_close(void *opaque)
  6266 +{
  6267 + QEMUFileFD *s = opaque;
  6268 + qemu_free(s);
  6269 + return 0;
  6270 +}
  6271 +
  6272 +QEMUFile *qemu_fopen_fd(int fd)
  6273 +{
  6274 + QEMUFileFD *s = qemu_mallocz(sizeof(QEMUFileFD));
  6275 +
  6276 + if (s == NULL)
  6277 + return NULL;
  6278 +
  6279 + s->fd = fd;
  6280 + s->file = qemu_fopen_ops(s, fd_put_buffer, fd_get_buffer, fd_close, NULL);
  6281 + return s->file;
  6282 +}
  6283 +
  6284 +typedef struct QEMUFileStdio
  6285 +{
  6286 + FILE *outfile;
  6287 +} QEMUFileStdio;
  6288 +
  6289 +static void file_put_buffer(void *opaque, const uint8_t *buf,
  6290 + int64_t pos, int size)
  6291 +{
  6292 + QEMUFileStdio *s = opaque;
  6293 + fseek(s->outfile, pos, SEEK_SET);
  6294 + fwrite(buf, 1, size, s->outfile);
  6295 +}
  6296 +
  6297 +static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
  6298 +{
  6299 + QEMUFileStdio *s = opaque;
  6300 + fseek(s->outfile, pos, SEEK_SET);
  6301 + return fread(buf, 1, size, s->outfile);
  6302 +}
  6303 +
  6304 +static int file_close(void *opaque)
  6305 +{
  6306 + QEMUFileStdio *s = opaque;
  6307 + fclose(s->outfile);
  6308 + qemu_free(s);
  6309 + return 0;
  6310 +}
  6311 +
6213 QEMUFile *qemu_fopen(const char *filename, const char *mode) 6312 QEMUFile *qemu_fopen(const char *filename, const char *mode)
6214 { 6313 {
6215 - QEMUFile *f; 6314 + QEMUFileStdio *s;
6216 6315
6217 - f = qemu_mallocz(sizeof(QEMUFile));  
6218 - if (!f) 6316 + s = qemu_mallocz(sizeof(QEMUFileStdio));
  6317 + if (!s)
6219 return NULL; 6318 return NULL;
6220 - if (!strcmp(mode, "wb")) {  
6221 - f->is_writable = 1;  
6222 - } else if (!strcmp(mode, "rb")) {  
6223 - f->is_writable = 0;  
6224 - } else {  
6225 - goto fail;  
6226 - }  
6227 - f->outfile = fopen(filename, mode);  
6228 - if (!f->outfile) 6319 +
  6320 + s->outfile = fopen(filename, mode);
  6321 + if (!s->outfile)
6229 goto fail; 6322 goto fail;
6230 - f->is_file = 1;  
6231 - return f;  
6232 - fail:  
6233 - if (f->outfile)  
6234 - fclose(f->outfile);  
6235 - qemu_free(f); 6323 +
  6324 + if (!strcmp(mode, "wb"))
  6325 + return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL);
  6326 + else if (!strcmp(mode, "rb"))
  6327 + return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL);
  6328 +
  6329 +fail:
  6330 + if (s->outfile)
  6331 + fclose(s->outfile);
  6332 + qemu_free(s);
6236 return NULL; 6333 return NULL;
6237 } 6334 }
6238 6335
6239 -static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) 6336 +typedef struct QEMUFileBdrv
  6337 +{
  6338 + BlockDriverState *bs;
  6339 + int64_t base_offset;
  6340 +} QEMUFileBdrv;
  6341 +
  6342 +static void bdrv_put_buffer(void *opaque, const uint8_t *buf,
  6343 + int64_t pos, int size)
  6344 +{
  6345 + QEMUFileBdrv *s = opaque;
  6346 + bdrv_pwrite(s->bs, s->base_offset + pos, buf, size);
  6347 +}
  6348 +
  6349 +static int bdrv_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
  6350 +{
  6351 + QEMUFileBdrv *s = opaque;
  6352 + return bdrv_pread(s->bs, s->base_offset + pos, buf, size);
  6353 +}
  6354 +
  6355 +static int bdrv_fclose(void *opaque)
  6356 +{
  6357 + QEMUFileBdrv *s = opaque;
  6358 + qemu_free(s);
  6359 + return 0;
  6360 +}
  6361 +
  6362 +QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
  6363 +{
  6364 + QEMUFileBdrv *s;
  6365 +
  6366 + s = qemu_mallocz(sizeof(QEMUFileBdrv));
  6367 + if (!s)
  6368 + return NULL;
  6369 +
  6370 + s->bs = bs;
  6371 + s->base_offset = offset;
  6372 +
  6373 + if (is_writable)
  6374 + return qemu_fopen_ops(s, bdrv_put_buffer, NULL, bdrv_fclose, NULL);
  6375 +
  6376 + return qemu_fopen_ops(s, NULL, bdrv_get_buffer, bdrv_fclose, NULL);
  6377 +}
  6378 +
  6379 +QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
  6380 + QEMUFileGetBufferFunc *get_buffer,
  6381 + QEMUFileCloseFunc *close,
  6382 + QEMUFileRateLimit *rate_limit)
6240 { 6383 {
6241 QEMUFile *f; 6384 QEMUFile *f;
6242 6385
6243 f = qemu_mallocz(sizeof(QEMUFile)); 6386 f = qemu_mallocz(sizeof(QEMUFile));
6244 if (!f) 6387 if (!f)
6245 return NULL; 6388 return NULL;
6246 - f->is_file = 0;  
6247 - f->bs = bs;  
6248 - f->is_writable = is_writable;  
6249 - f->base_offset = offset; 6389 +
  6390 + f->opaque = opaque;
  6391 + f->put_buffer = put_buffer;
  6392 + f->get_buffer = get_buffer;
  6393 + f->close = close;
  6394 + f->rate_limit = rate_limit;
  6395 +
6250 return f; 6396 return f;
6251 } 6397 }
6252 6398
6253 void qemu_fflush(QEMUFile *f) 6399 void qemu_fflush(QEMUFile *f)
6254 { 6400 {
6255 - if (!f->is_writable) 6401 + if (!f->put_buffer)
6256 return; 6402 return;
  6403 +
6257 if (f->buf_index > 0) { 6404 if (f->buf_index > 0) {
6258 - if (f->is_file) {  
6259 - fseek(f->outfile, f->buf_offset, SEEK_SET);  
6260 - fwrite(f->buf, 1, f->buf_index, f->outfile);  
6261 - } else {  
6262 - bdrv_pwrite(f->bs, f->base_offset + f->buf_offset,  
6263 - f->buf, f->buf_index);  
6264 - } 6405 + f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
6265 f->buf_offset += f->buf_index; 6406 f->buf_offset += f->buf_index;
6266 f->buf_index = 0; 6407 f->buf_index = 0;
6267 } 6408 }
@@ -6271,32 +6412,31 @@ static void qemu_fill_buffer(QEMUFile *f) @@ -6271,32 +6412,31 @@ static void qemu_fill_buffer(QEMUFile *f)
6271 { 6412 {
6272 int len; 6413 int len;
6273 6414
6274 - if (f->is_writable) 6415 + if (!f->get_buffer)
6275 return; 6416 return;
6276 - if (f->is_file) {  
6277 - fseek(f->outfile, f->buf_offset, SEEK_SET);  
6278 - len = fread(f->buf, 1, IO_BUF_SIZE, f->outfile);  
6279 - if (len < 0)  
6280 - len = 0;  
6281 - } else {  
6282 - len = bdrv_pread(f->bs, f->base_offset + f->buf_offset,  
6283 - f->buf, IO_BUF_SIZE);  
6284 - if (len < 0)  
6285 - len = 0;  
6286 - } 6417 +
  6418 + len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
  6419 + if (len < 0)
  6420 + len = 0;
  6421 +
6287 f->buf_index = 0; 6422 f->buf_index = 0;
6288 f->buf_size = len; 6423 f->buf_size = len;
6289 f->buf_offset += len; 6424 f->buf_offset += len;
6290 } 6425 }
6291 6426
6292 -void qemu_fclose(QEMUFile *f) 6427 +int qemu_fclose(QEMUFile *f)
6293 { 6428 {
6294 - if (f->is_writable)  
6295 - qemu_fflush(f);  
6296 - if (f->is_file) {  
6297 - fclose(f->outfile);  
6298 - } 6429 + int ret = 0;
  6430 + qemu_fflush(f);
  6431 + if (f->close)
  6432 + ret = f->close(f->opaque);
6299 qemu_free(f); 6433 qemu_free(f);
  6434 + return ret;
  6435 +}
  6436 +
  6437 +void qemu_file_put_notify(QEMUFile *f)
  6438 +{
  6439 + f->put_buffer(f->opaque, NULL, 0, 0);
6300 } 6440 }
6301 6441
6302 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) 6442 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
@@ -6370,7 +6510,7 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) @@ -6370,7 +6510,7 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
6370 /* SEEK_END not supported */ 6510 /* SEEK_END not supported */
6371 return -1; 6511 return -1;
6372 } 6512 }
6373 - if (f->is_writable) { 6513 + if (f->put_buffer) {
6374 qemu_fflush(f); 6514 qemu_fflush(f);
6375 f->buf_offset = pos; 6515 f->buf_offset = pos;
6376 } else { 6516 } else {
@@ -6381,6 +6521,14 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) @@ -6381,6 +6521,14 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
6381 return pos; 6521 return pos;
6382 } 6522 }
6383 6523
  6524 +int qemu_file_rate_limit(QEMUFile *f)
  6525 +{
  6526 + if (f->rate_limit)
  6527 + return f->rate_limit(f->opaque);
  6528 +
  6529 + return 0;
  6530 +}
  6531 +
6384 void qemu_put_be16(QEMUFile *f, unsigned int v) 6532 void qemu_put_be16(QEMUFile *f, unsigned int v)
6385 { 6533 {
6386 qemu_put_byte(f, v >> 8); 6534 qemu_put_byte(f, v >> 8);