aboutsummaryrefslogtreecommitdiff
path: root/samples/client.c
diff options
context:
space:
mode:
authorWilliam Henderson <william.henderson@nutanix.com>2023-07-14 10:57:14 +0000
committerJohn Levon <john.levon@nutanix.com>2023-09-15 13:05:01 +0100
commit87d4940b1faa2f8462acbc26d6f0bcf10d928982 (patch)
tree626b223b78b125187359b47657ac32afe94d6b03 /samples/client.c
parent4b94ab928514422b631e932fc280f0d6686fba90 (diff)
downloadlibvfio-user-87d4940b1faa2f8462acbc26d6f0bcf10d928982.zip
libvfio-user-87d4940b1faa2f8462acbc26d6f0bcf10d928982.tar.gz
libvfio-user-87d4940b1faa2f8462acbc26d6f0bcf10d928982.tar.bz2
fix: changes to samples according to comments
Signed-off-by: William Henderson <william.henderson@nutanix.com>
Diffstat (limited to 'samples/client.c')
-rw-r--r--samples/client.c123
1 files changed, 54 insertions, 69 deletions
diff --git a/samples/client.c b/samples/client.c
index 6fae041..e9dd5a6 100644
--- a/samples/client.c
+++ b/samples/client.c
@@ -216,7 +216,7 @@ send_device_reset(int sock)
}
/* returns whether a VFIO migration capability is found */
-static bool
+static void
get_region_vfio_caps(struct vfio_info_cap_header *header,
struct vfio_region_info_cap_sparse_mmap **sparse)
{
@@ -243,7 +243,6 @@ get_region_vfio_caps(struct vfio_info_cap_header *header,
}
header = (struct vfio_info_cap_header*)((char*)header + header->next - sizeof(struct vfio_region_info));
}
- return false;
}
static void
@@ -259,40 +258,6 @@ do_get_device_region_info(int sock, struct vfio_region_info *region_info,
}
static void
-mmap_sparse_areas(int *fds, struct vfio_region_info *region_info,
- struct vfio_region_info_cap_sparse_mmap *sparse)
-{
- size_t i;
-
- for (i = 0; i < sparse->nr_areas; i++) {
-
- ssize_t ret;
- void *addr;
- char pathname[PATH_MAX];
- char buf[PATH_MAX] = "";
-
- ret = snprintf(pathname, sizeof(pathname), "/proc/self/fd/%d", fds[i]);
- assert(ret != -1 && (size_t)ret < sizeof(pathname));
- ret = readlink(pathname, buf, sizeof(buf) - 1);
- if (ret == -1) {
- err(EXIT_FAILURE, "failed to resolve file descriptor %d", fds[i]);
- }
- addr = mmap(NULL, sparse->areas[i].size, PROT_READ | PROT_WRITE,
- MAP_SHARED, fds[i], region_info->offset +
- sparse->areas[i].offset);
- if (addr == MAP_FAILED) {
- err(EXIT_FAILURE,
- "failed to mmap sparse region %zu in %s (%#llx-%#llx)",
- i, buf, (ull_t)sparse->areas[i].offset,
- (ull_t)sparse->areas[i].offset + sparse->areas[i].size - 1);
- }
-
- ret = munmap(addr, sparse->areas[i].size);
- assert(ret == 0);
- }
-}
-
-static void
get_device_region_info(int sock, uint32_t index)
{
struct vfio_region_info *region_info;
@@ -335,14 +300,8 @@ get_device_region_info(int sock, uint32_t index)
nr_fds);
if (cap_sz) {
struct vfio_region_info_cap_sparse_mmap *sparse = NULL;
- if (get_region_vfio_caps((struct vfio_info_cap_header*)(region_info + 1),
- &sparse)) {
- if (sparse != NULL) {
- assert((index == VFU_PCI_DEV_BAR1_REGION_IDX && nr_fds == 2));
- assert(nr_fds == sparse->nr_areas);
- mmap_sparse_areas(fds, region_info, sparse);
- }
- }
+ get_region_vfio_caps((struct vfio_info_cap_header*)(region_info + 1),
+ &sparse);
}
free(region_info);
@@ -520,12 +479,13 @@ set_migration_state(int sock, uint32_t state)
{
static int msg_id = 0xfab1;
struct vfio_user_device_feature req = {
- .argsz = 16,
+ .argsz = sizeof(struct vfio_user_device_feature)
+ + sizeof(struct vfio_user_device_feature_mig_state),
.flags = VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_MIG_DEVICE_STATE
};
struct vfio_user_device_feature_mig_state change_state = {
.device_state = state,
- .data_fd = 0
+ .data_fd = -1
};
struct iovec send_iovecs[3] = {
[1] = {
@@ -538,6 +498,10 @@ set_migration_state(int sock, uint32_t state)
}
};
void* response = malloc(sizeof(req) + sizeof(change_state));
+
+ if (response == NULL) {
+ return -1;
+ }
pthread_mutex_lock(&mutex);
int ret = tran_sock_msg_iovec(sock, msg_id--, VFIO_USER_DEVICE_FEATURE,
@@ -547,12 +511,17 @@ set_migration_state(int sock, uint32_t state)
pthread_mutex_unlock(&mutex);
if (ret < 0) {
- return -1;
+ return ret;
}
- assert(memcmp(&req, response, sizeof(req)) == 0);
- assert(memcmp(&change_state, response + sizeof(req),
- sizeof(change_state)) == 0);
+ if (memcmp(&req, response, sizeof(req)) != 0) {
+ err(EXIT_FAILURE, "invalid response to set_migration_state (header)");
+ }
+
+ if (memcmp(&change_state, response + sizeof(req),
+ sizeof(change_state)) != 0) {
+ err(EXIT_FAILURE, "invalid response to set_migration_state (payload)");
+ }
return ret;
}
@@ -562,7 +531,7 @@ read_migr_data(int sock, void *buf, size_t len)
{
static int msg_id = 0x6904;
struct vfio_user_mig_data req = {
- .argsz = 12,
+ .argsz = sizeof(struct vfio_user_mig_data),
.size = len
};
struct iovec send_iovecs[2] = {
@@ -573,6 +542,10 @@ read_migr_data(int sock, void *buf, size_t len)
};
struct vfio_user_mig_data *res = calloc(1, sizeof(req) + len);
+ if (res == NULL) {
+ return -1;
+ }
+
pthread_mutex_lock(&mutex);
int ret = tran_sock_msg_iovec(sock, msg_id--, VFIO_USER_MIG_DATA_READ,
send_iovecs, 2, NULL, 0, NULL,
@@ -581,7 +554,7 @@ read_migr_data(int sock, void *buf, size_t len)
if (ret < 0) {
free(res);
- return -1;
+ return ret;
}
memcpy(buf, res->data, res->size);
@@ -596,7 +569,7 @@ write_migr_data(int sock, void *buf, size_t len)
{
static int msg_id = 0x2023;
struct vfio_user_mig_data req = {
- .argsz = 12 + len,
+ .argsz = sizeof(struct vfio_user_mig_data) + len,
.size = len
};
struct iovec send_iovecs[3] = {
@@ -616,10 +589,6 @@ write_migr_data(int sock, void *buf, size_t len)
&req, sizeof(req), NULL, 0);
pthread_mutex_unlock(&mutex);
- if (ret < 0) {
- return -1;
- }
-
return ret;
}
@@ -832,15 +801,29 @@ usage(char *argv0)
basename(argv0));
}
+/*
+ * Normally each time the source client (QEMU) would read migration data from
+ * the device it would send them to the destination client. However, since in
+ * our sample both the source and the destination client are the same process,
+ * we simply accumulate the migration data of each iteration and apply it to
+ * the destination server at the end.
+ *
+ * Performs as many migration loops as @nr_iters or until the device has no
+ * more migration data (pending_bytes is zero), which ever comes first. The
+ * result of each migration iteration is stored in @migr_iter. @migr_iter must
+ * be at least @nr_iters.
+ *
+ * @returns the number of iterations performed
+ */
static size_t
-do_migrate(int sock, size_t max_iters, size_t max_iter_size,
+do_migrate(int sock, size_t nr_iters, size_t max_iter_size,
struct iovec *migr_iter)
{
int ret;
- size_t i;
bool is_more = true;
+ size_t i = 0;
- for (i = 0; i < max_iters && is_more; i++) {
+ for (i = 0; i < nr_iters && is_more; i++) {
migr_iter[i].iov_len = max_iter_size;
migr_iter[i].iov_base = malloc(migr_iter[i].iov_len);
@@ -855,12 +838,9 @@ do_migrate(int sock, size_t max_iters, size_t max_iter_size,
err(EXIT_FAILURE, "failed to read migration data");
}
- if (ret < (int)migr_iter[i].iov_len) {
- // FIXME is it pointless shuffling stuff around?
- void* buf = malloc(ret);
- memcpy(buf, migr_iter[i].iov_base, ret);
- free(migr_iter[i].iov_base);
- migr_iter[i].iov_base = buf;
+ // We know we've finished transferring data when less is returned
+ // than is requested.
+ if ((size_t)ret < migr_iter[i].iov_len) {
migr_iter[i].iov_len = ret;
is_more = false;
}
@@ -928,7 +908,12 @@ migrate_from(int sock, size_t *nr_iters, struct iovec **migr_iters,
err(EXIT_FAILURE, "failed to create pthread");
}
- *nr_iters = 16;
+ size_t expected_data = bar1_size + sizeof(time_t);
+
+ *nr_iters = (expected_data + max_iter_size - 1) / max_iter_size;
+
+ printf("client: calculated %ld iters needed to migrate\n", *nr_iters);
+
*migr_iters = malloc(sizeof(struct iovec) * *nr_iters);
if (*migr_iters == NULL) {
err(EXIT_FAILURE, NULL);
@@ -1008,7 +993,7 @@ migrate_to(char *old_sock_path, int *server_max_fds,
if (ret == -1) {
err(EXIT_FAILURE, "failed to fork");
}
- if (ret == 0) { /* child (destination server) */
+ if (ret > 0) { /* child (destination server) */
char *_argv[] = {
path_to_server,
(char *)"-r", // start in VFIO_DEVICE_STATE_RESUMING
@@ -1072,7 +1057,7 @@ migrate_to(char *old_sock_path, int *server_max_fds,
fprintf(stderr, "client: CRC mismatch: %u != %u\n", src_crc, dst_crc);
abort();
} else {
- fprintf(stdout, "client: CRC match, we did it! :)\n");
+ printf("client: CRC match, we did it! :)\n");
}
/* XXX set device state to running */