Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support VFIO_USER_REGION_WRITE_MULTI #704

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions include/vfio-user.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum vfio_user_command {
VFIO_USER_DMA_WRITE = 12,
VFIO_USER_DEVICE_RESET = 13,
VFIO_USER_DIRTY_PAGES = 14,
VFIO_USER_REGION_WRITE_MULTI = 15,
VFIO_USER_MAX,
};

Expand Down Expand Up @@ -227,6 +228,21 @@ struct vfio_user_bitmap_range {

#endif /* VFIO_REGION_TYPE_MIGRATION */

#define VFIO_USER_MULTI_DATA 8
#define VFIO_USER_MULTI_MAX 200

struct vfio_user_write_multi_data {
uint64_t offset;
uint32_t region;
uint32_t count;
char data[VFIO_USER_MULTI_DATA];
} __attribute__((packed));

struct vfio_user_write_multi {
uint64_t wr_cnt;
struct vfio_user_write_multi_data wrs[VFIO_USER_MULTI_MAX];
} __attribute__((packed));

#ifdef __cplusplus
}
#endif
Expand Down
95 changes: 91 additions & 4 deletions lib/libvfio-user.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,27 @@ is_valid_region_access(vfu_ctx_t *vfu_ctx, size_t size, uint16_t cmd,
return false;
}

if (cmd == VFIO_USER_REGION_WRITE && size - sizeof(*ra) != ra->count) {
vfu_log(vfu_ctx, LOG_ERR, "region write count too small: "
"expected %lu, got %u", size - sizeof(*ra), ra->count);
return false;
switch (cmd) {
case VFIO_USER_REGION_WRITE:
if (size - sizeof(*ra) != ra->count) {
vfu_log(vfu_ctx, LOG_ERR, "region write count too small: "
"expected %lu, got %u", size - sizeof(*ra), ra->count);
return false;
}

break;

case VFIO_USER_REGION_WRITE_MULTI:
if (ra->count > VFIO_USER_MULTI_DATA) {
vfu_log(vfu_ctx, LOG_ERR, "region write count too large: "
"expected %lu, got %u", size - sizeof(*ra), ra->count);
return false;
}

break;

default:
break;
}

index = ra->region;
Expand Down Expand Up @@ -350,6 +367,67 @@ handle_region_access(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
return 0;
}

static int
handle_region_write_multi(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
{
struct vfio_user_write_multi *wm = msg->in.iov.iov_base;
ssize_t ret;
char *buf;

assert(vfu_ctx != NULL);
assert(msg != NULL);

// FIXME: validate properly (?) - need tests

if (msg->in.iov.iov_len < sizeof(wm->wr_cnt)) {
return ERROR_INT(EINVAL);
}

if (wm->wr_cnt > VFIO_USER_MULTI_MAX) {
return ERROR_INT(EINVAL);
}

if (msg->in.iov.iov_len !=
(offsetof(struct vfio_user_write_multi, wrs) +
wm->wr_cnt * sizeof(struct vfio_user_write_multi_data))) {
return ERROR_INT(EINVAL);
}

for (size_t i = 0; i < wm->wr_cnt; i++) {
struct vfio_user_region_access *in_ra;

/* Re-use the very similar type. */
in_ra = (struct vfio_user_region_access *)&wm->wrs[i];

/*
* We already checked total length so can be sure each entry is at least
* big enough.
*/
if (!is_valid_region_access(vfu_ctx, sizeof(wm->wrs[i]),
msg->hdr.cmd, in_ra)) {
return ERROR_INT(EINVAL);
}

if (in_ra->count == 0) {
continue;
}

buf = (char *)(&in_ra->data);

ret = region_access(vfu_ctx, in_ra->region, buf, in_ra->count,
in_ra->offset, true);
if (ret != in_ra->count) {
/* FIXME we should return whatever has been accessed, not an error */
if (ret >= 0) {
ret = ERROR_INT(EINVAL);
}
return ret;
}
}

return 0;
}

static int
handle_device_get_info(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
{
Expand Down Expand Up @@ -1164,6 +1242,11 @@ handle_request(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
ret = handle_region_access(vfu_ctx, msg);
break;

case VFIO_USER_REGION_WRITE_MULTI:
ret = handle_region_write_multi(vfu_ctx, msg);
break;


case VFIO_USER_DEVICE_RESET:
vfu_log(vfu_ctx, LOG_INFO, "device reset by client");
ret = handle_device_reset(vfu_ctx, VFU_RESET_DEVICE);
Expand Down Expand Up @@ -1352,6 +1435,10 @@ command_needs_quiesce(vfu_ctx_t *vfu_ctx, const vfu_msg_t *msg)
return true;
}
break;

case VFIO_USER_REGION_WRITE_MULTI:
/* FIXME */
return false;
}

return false;
Expand Down
1 change: 1 addition & 0 deletions samples/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ send_version(int sock)
slen = snprintf(client_caps, sizeof(client_caps),
"{"
"\"capabilities\":{"
"\"write_multiple\": true,"
"\"max_msg_fds\":%u,"
"\"max_data_xfer_size\":%u,"
"\"migration\":{"
Expand Down
4 changes: 3 additions & 1 deletion test/py/libvfio_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@
VFIO_USER_DMA_WRITE = 12
VFIO_USER_DEVICE_RESET = 13
VFIO_USER_DIRTY_PAGES = 14
VFIO_USER_MAX = 15
# FIXME: need tests
VFIO_USER_REGION_WRITE_MULTI = 15
VFIO_USER_MAX = 16

VFIO_USER_F_TYPE_COMMAND = 0
VFIO_USER_F_TYPE_REPLY = 1
Expand Down