Skip to contentSkip to conversation

add file: migration support (r2)

PATCH In review Charles Duffy 4 participants 9 messages Nov 13, 2008 – Nov 18, 2008 Kbuild

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 add file: migration support (r2)

This patch adds support for migration to and from file: targets, moves common helpers between exec: and file: use cases from migration-exec.c to migration.c, and adds a qemu_fdopen() helper parallel to qemu_fopen().

Compared to the previous version submitted, it removes some cruft which was accidentally included, and documents the limitations of O_NONBLOCK on Linux with local filesystem access.

Makefile +2 -2
index 3ed8b2a..a5db522 100644
@@ -78,8 +78,8 @@ OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o
 OBJS+=usb-serial.o usb-net.o
 OBJS+=sd.o ssi-sd.o
 OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
-OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
-OBJS+=qemu-char.o aio.o net-checksum.o savevm.o
+OBJS+=buffered_file.o migration.o migration-file.o migration-tcp.o net.o
+OBJS+=qemu-sockets.o qemu-char.o aio.o net-checksum.o savevm.o
 
 ifdef CONFIG_BRLAPI
 OBJS+= baum.o
hw/hw.h +1 -0
index eab7bb4..4d5ae42 100644
@@ -35,6 +35,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
                          QEMUFileRateLimit *rate_limit);
 QEMUFile *qemu_fopen(const char *filename, const char *mode);
 QEMUFile *qemu_fopen_socket(int fd);
+QEMUFile *qemu_fdopen(int fd, const char *mode);
 QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
 void qemu_fflush(QEMUFile *f);
migration-exec.c +2 -12
index caeed4b..f625689 100644
@@ -32,16 +32,6 @@
     do { } while (0)
 #endif
 
-static int file_errno(FdMigrationState *s)
-{
-    return errno;
-}
-
-static int file_write(FdMigrationState *s, const void * buf, size_t size)
-{
-    return write(s->fd, buf, size);
-}
-
 static int exec_close(FdMigrationState *s)
 {
     dprintf("exec_close\n");
@@ -86,8 +76,8 @@ MigrationState *exec_start_outgoing_migration(const char *command,
     s->opaque = qemu_popen(f, "w");
 
     s->close = exec_close;
-    s->get_error = file_errno;
-    s->write = file_write;
+    s->get_error = migrate_file_errno;
+    s->write = migrate_file_write;
     s->mig_state.cancel = migrate_fd_cancel;
     s->mig_state.get_status = migrate_fd_get_status;
     s->mig_state.release = migrate_fd_release;
migration-file.c new file +118 -0

118 lines not on this page · raw message

migration.c +19 -0
index 0ef777a..709ee49 100644
@@ -40,6 +40,8 @@ void qemu_start_incoming_migration(const char *uri)
 
     if (strstart(uri, "tcp:", &p))
         tcp_start_incoming_migration(p);
+    else if (strstart(uri, "file:", &p))
+        file_start_incoming_migration(p);
 #if !defined(WIN32)
     else if (strstart(uri, "exec:", &p))
         exec_start_incoming_migration(p);
@@ -55,6 +57,8 @@ void do_migrate(int detach, const char *uri)
 
     if (strstart(uri, "tcp:", &p))
         s = tcp_start_outgoing_migration(p, max_throttle, detach);
+    else if (strstart(uri, "file:", &p))
+        s = file_start_outgoing_migration(p, max_throttle, detach);
 #if !defined(WIN32)
     else if (strstart(uri, "exec:", &p))
         s = exec_start_outgoing_migration(p, max_throttle, detach);
@@ -279,3 +283,18 @@ int migrate_fd_close(void *opaque)
     FdMigrationState *s = opaque;
     return s->close(s);
 }
+
+int migrate_file_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+int migrate_file_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+int migrate_file_close(FdMigrationState *s)
+{
+    return close(s->fd);
+}
migration.h +12 -0
index 953ec70..dcbda39 100644
@@ -61,6 +61,12 @@ MigrationState *exec_start_outgoing_migration(const char *host_port,
 					     int64_t bandwidth_limit,
 					     int detach);
 
+int file_start_incoming_migration(const char *filename);
+
+MigrationState *file_start_outgoing_migration(const char *filename,
+                                             int64_t bandwidth_limit,
+                                             int async);
+
 int tcp_start_incoming_migration(const char *host_port);
 
 MigrationState *tcp_start_outgoing_migration(const char *host_port,
@@ -89,6 +95,12 @@ void migrate_fd_wait_for_unfreeze(void *opaque);
 
 int migrate_fd_close(void *opaque);
 
+int migrate_file_errno(FdMigrationState *s);
+
+int migrate_file_write(FdMigrationState *s, const void * buf, size_t size);
+
+int migrate_file_close(FdMigrationState *s);
+
 static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state)
 {
     return container_of(mig_state, FdMigrationState, mig_state);
savevm.c +24 -1
index 1ee5a6f..8f5fd16 100644
@@ -226,7 +226,6 @@ QEMUFile *qemu_popen(FILE *popen_file, const char *mode)
     } else {
         s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL);
     }
-    fprintf(stderr, "qemu_popen: returning result of qemu_fopen_ops\n");
     return s->file;
 }
 
@@ -283,6 +282,30 @@ static int file_close(void *opaque)
     return 0;
 }
 
+QEMUFile *qemu_fdopen(int fd, const char *mode)
+{
+    QEMUFileStdio *s;
+
+    s = qemu_mallocz(sizeof(QEMUFileStdio));
+    if (!s)
+        return NULL;
+
+    s->outfile = fdopen(fd, mode);
+    if (!s->outfile)
+        goto fail;
+
+    if (!strcmp(mode, "wb"))
+        return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL);
+    else if (!strcmp(mode, "rb"))
+        return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL);
+
+fail:
+    if (s->outfile)
+        fclose(s->outfile);
+    qemu_free(s);
+    return NULL;
+}
+
 QEMUFile *qemu_fopen(const char *filename, const char *mode)
 {
     QEMUFileStdio *s;
#1 lore raw
Quoted 2 lines · Charles Duffy

documents the limitations of O_NONBLOCK on Linux with local filesystem access.

That's not a Linux limitation.

All OSes ignore O_NONBLOCK for filesystem accesses, including remote filesystems. This is a POSIX thing.

The reason is that there's no way to select() on a file. (You'd need to select() on readiness to read/write a specific byte range anyway, so the interface doesn't work.)

The nearest equivalent to select() on file I/O is AIO, which is probably what should be used if migration file I/O is blocking QEMU.

-- Jamie

#2 lore raw
In reply to Charles Duffy
Quoted 7 lines · Charles Duffy

This patch adds support for migration to and from file: targets, moves common helpers between exec: and file: use cases from migration-exec.c to migration.c, and adds a qemu_fdopen() helper parallel to qemu_fopen().

Compared to the previous version submitted, it removes some cruft which was accidentally included, and documents the limitations of O_NONBLOCK on Linux with local filesystem access.

I don't see any documentation.

The documentation should make it clear that this is not intended as a substitute for savvm/loadvm. A "live" migration doesn't make sense if you're writing to an actual file (rather than a FIFO) as you'll end up with unecessarily large files.

Paul

#3 lore raw
Quoted 6 lines · Paul Brook
Quoted 4 lines · Charles Duffy

This patch adds support for migration to and from file: targets, moves common helpers between exec: and file: use cases from migration-exec.c to migration.c, and adds a qemu_fdopen() helper parallel to qemu_fopen().

Quoted 9 lines
Quoted 4 lines

Compared to the previous version submitted, it removes some cruft which was accidentally included, and documents the limitations of O_NONBLOCK on Linux with local filesystem access.

I don't see any documentation.

The documentation should make it clear that this is not intended as a substitute for savvm/loadvm. A "live" migration doesn't make sense if you're writing to an actual file (rather than a FIFO) as you'll end up with unecessarily large files.

Forget the large file, it's not "live" which makes it not useful compared with savevm/loadvm. Using rate limiting as a crutch to avoid this is wrong because it requires the user to know how much bandwidth QEMU can use before blocking.

To do live migration to a file, you need to tie into something like posix-aio. You could actually use a bdrv_raw and expand it like we do for a qcow file although that's sort of an abuse of the block driver API.

Regards,

Anthony Liguori

Quoted 4 lines

Paul

#4 lore raw
In reply to Paul Brook
Quoted 9 lines · Paul Brook
Quoted 7 lines · Charles Duffy

This patch adds support for migration to and from file: targets, moves common helpers between exec: and file: use cases from migration-exec.c to migration.c, and adds a qemu_fdopen() helper parallel to qemu_fopen().

Compared to the previous version submitted, it removes some cruft which was accidentally included, and documents the limitations of O_NONBLOCK on Linux with local filesystem access.

Quoted 8 lines

I don't see any documentation.

The documentation should make it clear that this is not intended as a substitute for savvm/loadvm.

A "live" migration doesn't make sense if you're writing to an actual file (rather than a FIFO) as you'll end up with unecessarily large files.

That's true. It would be better to use a slightly different format when writing to a file, which lays out the RAM linearly and overwrites re-dirtied pages during the migration.

I'm not sure if "live" migration to a file is really useful. "Dead" migration is useful for suspending a VM to disk.

-- Jamie

#5 lore raw
Quoted 2 lines

I'm not sure if "live" migration to a file is really useful. "Dead" migration is useful for suspending a VM to disk.

Right. That's the point I was trying to make.

Paul

#6 lore raw
Quoted 4 lines · Paul Brook
Quoted 2 lines

I'm not sure if "live" migration to a file is really useful. "Dead" migration is useful for suspending a VM to disk.

Right. That's the point I was trying to make.

I thought of a use for live migration to and from a file. It's when you have to restart a host while minimising downtime of all its guests. The liveness reduces that downtime. That could be rebooting, or simply replacing QEMU/KVM by a newer version. It would require a lot of guest memory (collectively), to be worth it.

-- Jamie

#7 lore raw
Quoted 9 lines · Jamie Lokier
Quoted 4 lines · Paul Brook
Quoted 2 lines

I'm not sure if "live" migration to a file is really useful. "Dead" migration is useful for suspending a VM to disk.

Right. That's the point I was trying to make.

I thought of a use for live migration to and from a file. It's when you have to restart a host while minimising downtime of all its guests. The liveness reduces that downtime.

I wouldn't be surprised if this actually took longer, because you have to read more data in when you do the restore.

Paul

#8 lore raw
Quoted 7 lines · Paul Brook
Quoted 5 lines · Jamie Lokier
Quoted 3 lines · Paul Brook
Quoted 3 lines

I'm not sure if "live" migration to a file is really useful. "Dead" migration is useful for suspending a VM to disk.

Quoted 9 lines
Quoted 6 lines
Quoted 2 lines

Right. That's the point I was trying to make.

I thought of a use for live migration to and from a file. It's when you have to restart a host while minimising downtime of all its guests. The liveness reduces that downtime.

I wouldn't be surprised if this actually took longer, because you have to read more data in when you do the restore.

file: migration is essentially live checkpointing. It takes longer to save but the key is that you do the checkpointing without incurring down time.

The real use case would be live migrating to a file (or BDRV) and then immediately resuming the source VM after the migration has completed. The effect would be live checkpointing.

But without an implementation of file: or bdrv: that are actually live, it really is just an academic conversation :-)

Regards,

Anthony Liguori

Quoted 4 lines

Paul