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 7  
8 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 36 QEMUFile *qemu_fopen(const char *filename, const char *mode);
  37 +QEMUFile *qemu_fopen_fd(int fd);
11 38 void qemu_fflush(QEMUFile *f);
12   -void qemu_fclose(QEMUFile *f);
  39 +int qemu_fclose(QEMUFile *f);
13 40 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
14 41 void qemu_put_byte(QEMUFile *f, int v);
15 42 void qemu_put_be16(QEMUFile *f, unsigned int v);
... ... @@ -20,6 +47,12 @@ int qemu_get_byte(QEMUFile *f);
20 47 unsigned int qemu_get_be16(QEMUFile *f);
21 48 unsigned int qemu_get_be32(QEMUFile *f);
22 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 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 6198 #define IO_BUF_SIZE 32768
6199 6199  
6200 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 6207 int64_t buf_offset; /* start of buffer when writing, end of buffer
6207 6208 when reading */
6208 6209 int buf_index;
... ... @@ -6210,58 +6211,198 @@ struct QEMUFile {
6210 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 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 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 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 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 6384 QEMUFile *f;
6242 6385  
6243 6386 f = qemu_mallocz(sizeof(QEMUFile));
6244 6387 if (!f)
6245 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 6396 return f;
6251 6397 }
6252 6398  
6253 6399 void qemu_fflush(QEMUFile *f)
6254 6400 {
6255   - if (!f->is_writable)
  6401 + if (!f->put_buffer)
6256 6402 return;
  6403 +
6257 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 6406 f->buf_offset += f->buf_index;
6266 6407 f->buf_index = 0;
6267 6408 }
... ... @@ -6271,32 +6412,31 @@ static void qemu_fill_buffer(QEMUFile *f)
6271 6412 {
6272 6413 int len;
6273 6414  
6274   - if (f->is_writable)
  6415 + if (!f->get_buffer)
6275 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 6422 f->buf_index = 0;
6288 6423 f->buf_size = len;
6289 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 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 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 6510 /* SEEK_END not supported */
6371 6511 return -1;
6372 6512 }
6373   - if (f->is_writable) {
  6513 + if (f->put_buffer) {
6374 6514 qemu_fflush(f);
6375 6515 f->buf_offset = pos;
6376 6516 } else {
... ... @@ -6381,6 +6521,14 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
6381 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 6532 void qemu_put_be16(QEMUFile *f, unsigned int v)
6385 6533 {
6386 6534 qemu_put_byte(f, v >> 8);
... ...