Il 21/11/2013 10:11, Lei Li ha scritto: > This patch implements save_page callback for the outside > of page flipping. It will write the address of the page > on the Unix socket and flip the page data on pipe by > vmsplice(). Every page address would have a header flag > RAM_SAVE_FLAG_HOOK, which will trigger the load hook to > receive it in incoming side as well. > > Signed-off-by: Lei Li <li...@linux.vnet.ibm.com> > --- > migration-local.c | 54 > +++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 54 insertions(+), 0 deletions(-) > > diff --git a/migration-local.c b/migration-local.c > index 0f0896b..14207e9 100644 > --- a/migration-local.c > +++ b/migration-local.c > @@ -200,6 +200,59 @@ static int qemu_local_send_pipefd(QEMUFile *f, void > *opaque, > return 0; > } > > +static size_t qemu_local_save_ram(QEMUFile *f, void *opaque, > + MemoryRegion *mr, ram_addr_t offset, > + size_t size, int *bytes_sent) > +{ > + QEMUFileLocal *s = opaque; > + ram_addr_t current_addr = mr->ram_addr + offset; > + void *ram_addr; > + ssize_t ret; > + > + if (s->unix_page_flipping) { > + qemu_fflush(s->file); > + qemu_put_be64(s->file, RAM_SAVE_FLAG_HOOK); > + > + /* Write page address to unix socket */ > + qemu_put_be64(s->file, current_addr); > +
You can write current_addr | RAM_SAVE_FLAG_HOOK. The value will be in the flags argument of the hook_ram_load, you can extract it with "flags & ~RAM_SAVE_FLAG_HOOK". This cuts by half the data written to the Unix socket. Paolo > + ram_addr = memory_region_get_ram_ptr(mr) + offset; > + > + /* vmsplice page data to pipe */ > + struct iovec iov = { > + .iov_base = ram_addr, > + .iov_len = size, > + }; > + > + /* > + * The flag SPLICE_F_MOVE is introduced in kernel for the page > + * flipping feature in QEMU, which will movie pages rather than > + * copying, previously unused. > + * > + * If a move is not possible the kernel will transparently falls > + * back to copying data. > + * > + * For older kernels the SPLICE_F_MOVE would be ignored and a copy > + * would occur. > + */ > + ret = vmsplice(s->pipefd[1], &iov, 1, SPLICE_F_GIFT | SPLICE_F_MOVE); > + if (ret == -1) { > + if (errno != EAGAIN && errno != EINTR) { > + fprintf(stderr, "vmsplice save error: %s\n", > strerror(errno)); > + return ret; > + } > + } else { > + if (bytes_sent) { > + *bytes_sent = 1; > + } > + DPRINTF("block_offset: %lu, offset: %lu\n", block_offset, > offset); > + return 0; > + } > + } > + > + return RAM_SAVE_CONTROL_NOT_SUPP; > +} > + > static const QEMUFileOps pipe_read_ops = { > .get_fd = qemu_local_get_sockfd, > .get_buffer = qemu_local_get_buffer, > @@ -211,6 +264,7 @@ static const QEMUFileOps pipe_write_ops = { > .writev_buffer = qemu_local_writev_buffer, > .close = qemu_local_close, > .before_ram_iterate = qemu_local_send_pipefd, > + .save_page = qemu_local_save_ram > }; > > QEMUFile *qemu_fopen_socket_local(int sockfd, const char *mode) >