[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC 01/13] postcopy/migration: Split fault related state i
From: |
zhanghailiang |
Subject: |
[Qemu-devel] [RFC 01/13] postcopy/migration: Split fault related state into struct UserfaultState |
Date: |
Thu, 7 Jan 2016 20:19:56 +0800 |
Split fault related state from MigrationIncomingState struct, and put
them all into a new struct UserfaultState. We will add this state into
struct MigrationState in later patch.
We also fix some helper functions to use the new type.
Signed-off-by: zhanghailiang <address@hidden>
---
include/migration/migration.h | 20 ++++----
include/migration/postcopy-ram.h | 2 +-
include/qemu/typedefs.h | 1 +
migration/postcopy-ram.c | 99 +++++++++++++++++++++++-----------------
migration/savevm.c | 2 +-
5 files changed, 72 insertions(+), 52 deletions(-)
diff --git a/include/migration/migration.h b/include/migration/migration.h
index d9494b8..4c80939 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -79,6 +79,16 @@ typedef enum {
POSTCOPY_INCOMING_END
} PostcopyState;
+struct UserfaultState {
+ bool have_fault_thread;
+ QemuThread fault_thread;
+ QemuSemaphore fault_thread_sem;
+ /* For the kernel to send us notifications */
+ int userfault_fd;
+ /* To tell the fault_thread to quit */
+ int userfault_quit_fd;
+};
+
/* State for the incoming migration */
struct MigrationIncomingState {
QEMUFile *from_src_file;
@@ -89,22 +99,16 @@ struct MigrationIncomingState {
*/
QemuEvent main_thread_load_event;
- bool have_fault_thread;
- QemuThread fault_thread;
- QemuSemaphore fault_thread_sem;
-
bool have_listen_thread;
QemuThread listen_thread;
QemuSemaphore listen_thread_sem;
- /* For the kernel to send us notifications */
- int userfault_fd;
- /* To tell the fault_thread to quit */
- int userfault_quit_fd;
QEMUFile *to_src_file;
QemuMutex rp_mutex; /* We send replies from multiple threads */
void *postcopy_tmp_page;
+ UserfaultState userfault_state;
+
/* See savevm.c */
LoadStateEntry_Head loadvm_handlers;
};
diff --git a/include/migration/postcopy-ram.h b/include/migration/postcopy-ram.h
index b6a7491..e30978f 100644
--- a/include/migration/postcopy-ram.h
+++ b/include/migration/postcopy-ram.h
@@ -20,7 +20,7 @@ bool postcopy_ram_supported_by_host(void);
* Make all of RAM sensitive to accesses to areas that haven't yet been written
* and wire up anything necessary to deal with it.
*/
-int postcopy_ram_enable_notify(MigrationIncomingState *mis);
+int postcopy_ram_enable_notify(UserfaultState *us);
/*
* Initialise postcopy-ram, setting the RAM to a state where we can go into
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 78fe6e8..eda3063 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -41,6 +41,7 @@ typedef struct MemoryListener MemoryListener;
typedef struct MemoryMappingList MemoryMappingList;
typedef struct MemoryRegion MemoryRegion;
typedef struct MemoryRegionSection MemoryRegionSection;
+typedef struct UserfaultState UserfaultState;
typedef struct MigrationIncomingState MigrationIncomingState;
typedef struct MigrationParams MigrationParams;
typedef struct MigrationState MigrationState;
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 3946aa9..38245d4 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -233,7 +233,7 @@ static int init_range(const char *block_name, void
*host_addr,
static int cleanup_range(const char *block_name, void *host_addr,
ram_addr_t offset, ram_addr_t length, void *opaque)
{
- MigrationIncomingState *mis = opaque;
+ UserfaultState *us = opaque;
struct uffdio_range range_struct;
trace_postcopy_cleanup_range(block_name, host_addr, offset, length);
@@ -251,7 +251,7 @@ static int cleanup_range(const char *block_name, void
*host_addr,
range_struct.start = (uintptr_t)host_addr;
range_struct.len = length;
- if (ioctl(mis->userfault_fd, UFFDIO_UNREGISTER, &range_struct)) {
+ if (ioctl(us->userfault_fd, UFFDIO_UNREGISTER, &range_struct)) {
error_report("%s: userfault unregister %s", __func__, strerror(errno));
return -1;
@@ -274,36 +274,47 @@ int postcopy_ram_incoming_init(MigrationIncomingState
*mis, size_t ram_pages)
return 0;
}
-/*
- * At the end of a migration where postcopy_ram_incoming_init was called.
- */
-int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)
+static int postcopy_ram_disable_notify(UserfaultState *us)
{
- trace_postcopy_ram_incoming_cleanup_entry();
-
- if (mis->have_fault_thread) {
+ if (us->have_fault_thread) {
uint64_t tmp64;
- if (qemu_ram_foreach_block(cleanup_range, mis)) {
+ if (qemu_ram_foreach_block(cleanup_range, us)) {
return -1;
}
+
/*
- * Tell the fault_thread to exit, it's an eventfd that should
- * currently be at 0, we're going to increment it to 1
- */
+ * Tell the fault_thread to exit, it's an eventfd that should
+ * currently be at 0, we're going to increment it to 1
+ */
tmp64 = 1;
- if (write(mis->userfault_quit_fd, &tmp64, 8) == 8) {
+
+ if (write(us->userfault_quit_fd, &tmp64, 8) == 8) {
trace_postcopy_ram_incoming_cleanup_join();
- qemu_thread_join(&mis->fault_thread);
+ qemu_thread_join(&us->fault_thread);
} else {
/* Not much we can do here, but may as well report it */
error_report("%s: incrementing userfault_quit_fd: %s", __func__,
strerror(errno));
}
+
trace_postcopy_ram_incoming_cleanup_closeuf();
- close(mis->userfault_fd);
- close(mis->userfault_quit_fd);
- mis->have_fault_thread = false;
+ close(us->userfault_fd);
+ close(us->userfault_quit_fd);
+ us->have_fault_thread = false;
+ }
+ return 0;
+}
+
+/*
+ * At the end of a migration where postcopy_ram_incoming_init was called.
+ */
+int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)
+{
+ trace_postcopy_ram_incoming_cleanup_entry();
+
+ if (postcopy_ram_disable_notify(&mis->userfault_state) < 0) {
+ return 0;
}
qemu_balloon_inhibit(false);
@@ -376,7 +387,7 @@ static int ram_block_enable_notify(const char *block_name,
void *host_addr,
ram_addr_t offset, ram_addr_t length,
void *opaque)
{
- MigrationIncomingState *mis = opaque;
+ UserfaultState *us = opaque;
struct uffdio_register reg_struct;
reg_struct.range.start = (uintptr_t)host_addr;
@@ -384,7 +395,7 @@ static int ram_block_enable_notify(const char *block_name,
void *host_addr,
reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING;
/* Now tell our userfault_fd that it's responsible for this area */
- if (ioctl(mis->userfault_fd, UFFDIO_REGISTER, ®_struct)) {
+ if (ioctl(us->userfault_fd, UFFDIO_REGISTER, ®_struct)) {
error_report("%s userfault register: %s", __func__, strerror(errno));
return -1;
}
@@ -397,15 +408,17 @@ static int ram_block_enable_notify(const char
*block_name, void *host_addr,
*/
static void *postcopy_ram_fault_thread(void *opaque)
{
- MigrationIncomingState *mis = opaque;
+ UserfaultState *us = opaque;
struct uffd_msg msg;
int ret;
size_t hostpagesize = getpagesize();
RAMBlock *rb = NULL;
RAMBlock *last_rb = NULL; /* last RAMBlock we sent part of */
+ MigrationIncomingState *mis = container_of(us, MigrationIncomingState,
+ userfault_state);
trace_postcopy_ram_fault_thread_entry();
- qemu_sem_post(&mis->fault_thread_sem);
+ qemu_sem_post(&us->fault_thread_sem);
while (true) {
ram_addr_t rb_offset;
@@ -417,10 +430,10 @@ static void *postcopy_ram_fault_thread(void *opaque)
* however we can be told to quit via userfault_quit_fd which is
* an eventfd
*/
- pfd[0].fd = mis->userfault_fd;
+ pfd[0].fd = us->userfault_fd;
pfd[0].events = POLLIN;
pfd[0].revents = 0;
- pfd[1].fd = mis->userfault_quit_fd;
+ pfd[1].fd = us->userfault_quit_fd;
pfd[1].events = POLLIN; /* Waiting for eventfd to go positive */
pfd[1].revents = 0;
@@ -434,7 +447,8 @@ static void *postcopy_ram_fault_thread(void *opaque)
break;
}
- ret = read(mis->userfault_fd, &msg, sizeof(msg));
+ ret = read(us->userfault_fd, &msg, sizeof(msg));
+
if (ret != sizeof(msg)) {
if (errno == EAGAIN) {
/*
@@ -491,11 +505,11 @@ static void *postcopy_ram_fault_thread(void *opaque)
return NULL;
}
-int postcopy_ram_enable_notify(MigrationIncomingState *mis)
+int postcopy_ram_enable_notify(UserfaultState *us)
{
/* Open the fd for the kernel to give us userfaults */
- mis->userfault_fd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
- if (mis->userfault_fd == -1) {
+ us->userfault_fd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
+ if (us->userfault_fd == -1) {
error_report("%s: Failed to open userfault fd: %s", __func__,
strerror(errno));
return -1;
@@ -505,28 +519,28 @@ int postcopy_ram_enable_notify(MigrationIncomingState
*mis)
* Although the host check already tested the API, we need to
* do the check again as an ABI handshake on the new fd.
*/
- if (!ufd_version_check(mis->userfault_fd)) {
+ if (!ufd_version_check(us->userfault_fd)) {
return -1;
}
/* Now an eventfd we use to tell the fault-thread to quit */
- mis->userfault_quit_fd = eventfd(0, EFD_CLOEXEC);
- if (mis->userfault_quit_fd == -1) {
+ us->userfault_quit_fd = eventfd(0, EFD_CLOEXEC);
+ if (us->userfault_quit_fd == -1) {
error_report("%s: Opening userfault_quit_fd: %s", __func__,
strerror(errno));
- close(mis->userfault_fd);
+ close(us->userfault_fd);
return -1;
}
- qemu_sem_init(&mis->fault_thread_sem, 0);
- qemu_thread_create(&mis->fault_thread, "postcopy/fault",
- postcopy_ram_fault_thread, mis, QEMU_THREAD_JOINABLE);
- qemu_sem_wait(&mis->fault_thread_sem);
- qemu_sem_destroy(&mis->fault_thread_sem);
- mis->have_fault_thread = true;
+ qemu_sem_init(&us->fault_thread_sem, 0);
+ qemu_thread_create(&us->fault_thread, "postcopy/fault",
+ postcopy_ram_fault_thread, us, QEMU_THREAD_JOINABLE);
+ qemu_sem_wait(&us->fault_thread_sem);
+ qemu_sem_destroy(&us->fault_thread_sem);
+ us->have_fault_thread = true;
/* Mark so that we get notified of accesses to unwritten areas */
- if (qemu_ram_foreach_block(ram_block_enable_notify, mis)) {
+ if (qemu_ram_foreach_block(ram_block_enable_notify, us)) {
return -1;
}
@@ -559,7 +573,7 @@ int postcopy_place_page(MigrationIncomingState *mis, void
*host, void *from)
* which would be slightly cheaper, but we'd have to be careful
* of the order of updating our page state.
*/
- if (ioctl(mis->userfault_fd, UFFDIO_COPY, ©_struct)) {
+ if (ioctl(mis->userfault_state.userfault_fd, UFFDIO_COPY, ©_struct)) {
int e = errno;
error_report("%s: %s copy host: %p from: %p",
__func__, strerror(e), host, from);
@@ -583,7 +597,8 @@ int postcopy_place_page_zero(MigrationIncomingState *mis,
void *host)
zero_struct.range.len = getpagesize();
zero_struct.mode = 0;
- if (ioctl(mis->userfault_fd, UFFDIO_ZEROPAGE, &zero_struct)) {
+ if (ioctl(mis->userfault_state.userfault_fd, UFFDIO_ZEROPAGE,
+ &zero_struct)) {
int e = errno;
error_report("%s: %s zero host: %p",
__func__, strerror(e), host);
@@ -651,7 +666,7 @@ int postcopy_ram_prepare_discard(MigrationIncomingState
*mis)
return -1;
}
-int postcopy_ram_enable_notify(MigrationIncomingState *mis)
+int postcopy_ram_enable_notify(UserfaultState *us, int mode)
{
assert(0);
return -1;
diff --git a/migration/savevm.c b/migration/savevm.c
index 0ad1b93..9b22498 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1467,7 +1467,7 @@ static int
loadvm_postcopy_handle_listen(MigrationIncomingState *mis)
* However, at this point the CPU shouldn't be running, and the IO
* shouldn't be doing anything yet so don't actually expect requests
*/
- if (postcopy_ram_enable_notify(mis)) {
+ if (postcopy_ram_enable_notify(&mis->userfault_state)) {
return -1;
}
--
1.8.3.1
- [Qemu-devel] [RFC 00/13] Live memory snapshot based on userfaultfd, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 10/13] snapshot: Enable the write-protect notification capability for VM's RAM, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 04/13] migration: Create a snapshot thread to realize saving memory snapshot, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 05/13] migration: implement initialization work for snapshot, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 11/13] snapshot/migration: Save VM's RAM into snapshot file, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 13/13] snapshot: Remove page's write-protect and copy the content during setup stage, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 03/13] migration: Allow -incoming to work on file: urls, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 01/13] postcopy/migration: Split fault related state into struct UserfaultState,
zhanghailiang <=
- [Qemu-devel] [RFC 09/13] migration/postcopy-ram: fix some helper functions to support userfaultfd write-protect, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 02/13] migration: Allow the migrate command to work on file: urls, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 08/13] snapshot: Save VM's device state into snapshot file, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 06/13] QEMUSizedBuffer: Introduce two help functions for qsb, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 07/13] savevm: Split qemu_savevm_state_complete_precopy() into two helper functions, zhanghailiang, 2016/01/07
- [Qemu-devel] [RFC 12/13] migration/ram: Fix some helper functions' parameter to use PageSearchStatus, zhanghailiang, 2016/01/07