aboutsummaryrefslogtreecommitdiff
path: root/samples/client.c
diff options
context:
space:
mode:
authorThanos Makatos <thanos.makatos@nutanix.com>2020-12-14 15:50:37 +0000
committerGitHub <noreply@github.com>2020-12-14 15:50:37 +0000
commitf240c889171ab22e7b8b0b460792b0df94c335c1 (patch)
treec0a60b0dbd7f32ffac3b8caf8d1bbcfa8bfed491 /samples/client.c
parentd7157efb22c9fc06f85e40f0e6b6c5e16dc5e8e2 (diff)
downloadlibvfio-user-f240c889171ab22e7b8b0b460792b0df94c335c1.zip
libvfio-user-f240c889171ab22e7b8b0b460792b0df94c335c1.tar.gz
libvfio-user-f240c889171ab22e7b8b0b460792b0df94c335c1.tar.bz2
return region capabilities a la VFIO (#187)
This patch returns region capabilities the same way VFIO does: if argsz is not large enough then it returns only region info and sets argsz to what it should be in order to fit the capabilities, the client then retries with a large enough argsz. The protocol specification has been updated as well. Plus unit tests. Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
Diffstat (limited to 'samples/client.c')
-rw-r--r--samples/client.c103
1 files changed, 59 insertions, 44 deletions
diff --git a/samples/client.c b/samples/client.c
index 99289cb..3e3ba54 100644
--- a/samples/client.c
+++ b/samples/client.c
@@ -207,26 +207,13 @@ send_device_reset(int sock)
/* returns whether a VFIO migration capability is found */
static bool
-get_region_vfio_caps(int sock, size_t cap_sz)
+get_region_vfio_caps(struct vfio_info_cap_header *header)
{
- struct vfio_info_cap_header *header, *_header;
struct vfio_region_info_cap_type *type;
struct vfio_region_info_cap_sparse_mmap *sparse;
unsigned int i;
- ssize_t ret;
bool migr = false;
- header = _header = calloc(cap_sz, 1);
- if (header == NULL) {
- err(EXIT_FAILURE, NULL);
- }
-
- ret = recv(sock, header, cap_sz, 0);
- if (ret < 0) {
- err(EXIT_FAILURE, "failed to receive VFIO cap info");
- }
- assert((size_t)ret == cap_sz);
-
while (true) {
switch (header->id) {
case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
@@ -256,47 +243,70 @@ get_region_vfio_caps(int sock, size_t cap_sz)
}
header = (struct vfio_info_cap_header*)((char*)header + header->next - sizeof(struct vfio_region_info));
}
- free(_header);
return migr;
}
+static void
+do_get_device_region_info(int sock, struct vfio_region_info *region_info)
+{
+ int ret = vfu_msg(sock, 0,
+ VFIO_USER_DEVICE_GET_REGION_INFO,
+ region_info, region_info->argsz,
+ NULL,
+ region_info, region_info->argsz);
+ if (ret < 0) {
+ errx(EXIT_FAILURE, "failed to get device region info: %s",
+ strerror(-ret));
+ }
+}
+
+static bool
+get_device_region_info(int sock, uint32_t index)
+{
+ struct vfio_region_info *region_info;
+ size_t cap_sz;
+ size_t size = sizeof(struct vfio_region_info);
+
+ region_info = alloca(size);
+ region_info->argsz = size;
+ region_info->index = index;
+
+ do_get_device_region_info(sock, region_info);
+ if (region_info->argsz > size) {
+ size = region_info->size;
+ region_info = alloca(size);
+ region_info->argsz = size;
+ region_info->index = index;
+ do_get_device_region_info(sock, region_info);
+ assert(region_info->size == size);
+ }
+
+ cap_sz = region_info->argsz - sizeof(struct vfio_region_info);
+ printf("%s: region_info[%d] offset %#llx flags %#x size %llu "
+ "cap_sz %lu\n", __func__, index, region_info->offset,
+ region_info->flags, region_info->size, cap_sz);
+ if (cap_sz) {
+ if (get_region_vfio_caps((struct vfio_info_cap_header*)(region_info + 1))) {
+ return true;
+ }
+ }
+ return false;
+}
+
/*
* Returns the index of the migration region if found, -1 otherwise.
*/
static int
-get_device_region_info(int sock, struct vfio_device_info *client_dev_info)
+get_device_regions_info(int sock, struct vfio_device_info *client_dev_info)
{
- struct vfio_region_info region_info;
- uint16_t msg_id = 1;
- size_t cap_sz;
- int ret, migr_reg_index = -1;
+ int migr_reg_index = -1;
unsigned int i;
for (i = 0; i < client_dev_info->num_regions; i++) {
- memset(&region_info, 0, sizeof(region_info));
- region_info.argsz = sizeof(region_info);
- region_info.index = i;
- msg_id++;
- ret = vfu_msg(sock, msg_id,
- VFIO_USER_DEVICE_GET_REGION_INFO,
- &region_info, sizeof region_info,
- NULL,
- &region_info, sizeof(region_info));
- if (ret < 0) {
- errx(EXIT_FAILURE, "failed to get device region info: %s",
- strerror(-ret));
+ if (get_device_region_info(sock, i)) {
+ assert(migr_reg_index == -1);
+ migr_reg_index = i;
}
-
- cap_sz = region_info.argsz - sizeof(struct vfio_region_info);
- printf("%s: region_info[%d] offset %#llx flags %#x size %llu "
- "cap_sz %lu\n", __func__, i, region_info.offset,
- region_info.flags, region_info.size, cap_sz);
- if (cap_sz) {
- if (get_region_vfio_caps(sock, cap_sz)) {
- assert(migr_reg_index == -1);
- migr_reg_index = i;
- }
- }
}
return migr_reg_index;
}
@@ -319,6 +329,11 @@ get_device_info(int sock, struct vfio_device_info *dev_info)
errx(EXIT_FAILURE, "failed to get device info: %s", strerror(-ret));
}
+ if (dev_info->num_regions != 10) {
+ errx(EXIT_FAILURE, "bad number of device regions %d",
+ dev_info->num_regions);
+ }
+
printf("devinfo: flags %#x, num_regions %d, num_irqs %d\n",
dev_info->flags, dev_info->num_regions, dev_info->num_irqs);
}
@@ -952,7 +967,7 @@ int main(int argc, char *argv[])
get_device_info(sock, &client_dev_info);
/* XXX VFIO_USER_DEVICE_GET_REGION_INFO */
- migr_reg_index = get_device_region_info(sock, &client_dev_info);
+ migr_reg_index = get_device_regions_info(sock, &client_dev_info);
if (migr_reg_index == -1) {
errx(EXIT_FAILURE, "could not find migration region");
}