Skip to content

Commit 9d3619e

Browse files
committed
support VFIO_USER_REGION_WRITE_MULTI
FIXME: needs work Signed-off-by: John Levon <[email protected]>
1 parent 4953810 commit 9d3619e

File tree

4 files changed

+111
-5
lines changed

4 files changed

+111
-5
lines changed

include/vfio-user.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ enum vfio_user_command {
6767
VFIO_USER_DMA_WRITE = 12,
6868
VFIO_USER_DEVICE_RESET = 13,
6969
VFIO_USER_DIRTY_PAGES = 14,
70+
VFIO_USER_REGION_WRITE_MULTI = 15,
7071
VFIO_USER_MAX,
7172
};
7273

@@ -227,6 +228,21 @@ struct vfio_user_bitmap_range {
227228

228229
#endif /* VFIO_REGION_TYPE_MIGRATION */
229230

231+
#define VFIO_USER_MULTI_DATA 8
232+
#define VFIO_USER_MULTI_MAX 200
233+
234+
struct vfio_user_write_multi_data {
235+
uint64_t offset;
236+
uint32_t region;
237+
uint32_t count;
238+
char data[VFIO_USER_MULTI_DATA];
239+
} __attribute__((packed));
240+
241+
struct vfio_user_write_multi {
242+
uint64_t wr_cnt;
243+
struct vfio_user_write_multi_data wrs[VFIO_USER_MULTI_MAX];
244+
} __attribute__((packed));
245+
230246
#ifdef __cplusplus
231247
}
232248
#endif

lib/libvfio-user.c

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,27 @@ is_valid_region_access(vfu_ctx_t *vfu_ctx, size_t size, uint16_t cmd,
264264
return false;
265265
}
266266

267-
if (cmd == VFIO_USER_REGION_WRITE && size - sizeof(*ra) != ra->count) {
268-
vfu_log(vfu_ctx, LOG_ERR, "region write count too small: "
269-
"expected %lu, got %u", size - sizeof(*ra), ra->count);
270-
return false;
267+
switch (cmd) {
268+
case VFIO_USER_REGION_WRITE:
269+
if (size - sizeof(*ra) != ra->count) {
270+
vfu_log(vfu_ctx, LOG_ERR, "region write count too small: "
271+
"expected %lu, got %u", size - sizeof(*ra), ra->count);
272+
return false;
273+
}
274+
275+
break;
276+
277+
case VFIO_USER_REGION_WRITE_MULTI:
278+
if (ra->count > VFIO_USER_MULTI_DATA) {
279+
vfu_log(vfu_ctx, LOG_ERR, "region write count too large: "
280+
"expected %lu, got %u", size - sizeof(*ra), ra->count);
281+
return false;
282+
}
283+
284+
break;
285+
286+
default:
287+
break;
271288
}
272289

273290
index = ra->region;
@@ -350,6 +367,67 @@ handle_region_access(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
350367
return 0;
351368
}
352369

370+
static int
371+
handle_region_write_multi(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
372+
{
373+
struct vfio_user_write_multi *wm = msg->in.iov.iov_base;
374+
ssize_t ret;
375+
char *buf;
376+
377+
assert(vfu_ctx != NULL);
378+
assert(msg != NULL);
379+
380+
// FIXME: validate properly (?) - need tests
381+
382+
if (msg->in.iov.iov_len < sizeof(wm->wr_cnt)) {
383+
return ERROR_INT(EINVAL);
384+
}
385+
386+
if (wm->wr_cnt > VFIO_USER_MULTI_MAX) {
387+
return ERROR_INT(EINVAL);
388+
}
389+
390+
if (msg->in.iov.iov_len !=
391+
(offsetof(struct vfio_user_write_multi, wrs) +
392+
wm->wr_cnt * sizeof(struct vfio_user_write_multi_data))) {
393+
return ERROR_INT(EINVAL);
394+
}
395+
396+
for (size_t i = 0; i < wm->wr_cnt; i++) {
397+
struct vfio_user_region_access *in_ra;
398+
399+
/* Re-use the very similar type. */
400+
in_ra = (struct vfio_user_region_access *)&wm->wrs[i];
401+
402+
/*
403+
* We already checked total length so can be sure each entry is at least
404+
* big enough.
405+
*/
406+
if (!is_valid_region_access(vfu_ctx, sizeof(wm->wrs[i]),
407+
msg->hdr.cmd, in_ra)) {
408+
return ERROR_INT(EINVAL);
409+
}
410+
411+
if (in_ra->count == 0) {
412+
continue;
413+
}
414+
415+
buf = (char *)(&in_ra->data);
416+
417+
ret = region_access(vfu_ctx, in_ra->region, buf, in_ra->count,
418+
in_ra->offset, true);
419+
if (ret != in_ra->count) {
420+
/* FIXME we should return whatever has been accessed, not an error */
421+
if (ret >= 0) {
422+
ret = ERROR_INT(EINVAL);
423+
}
424+
return ret;
425+
}
426+
}
427+
428+
return 0;
429+
}
430+
353431
static int
354432
handle_device_get_info(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
355433
{
@@ -1164,6 +1242,11 @@ handle_request(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
11641242
ret = handle_region_access(vfu_ctx, msg);
11651243
break;
11661244

1245+
case VFIO_USER_REGION_WRITE_MULTI:
1246+
ret = handle_region_write_multi(vfu_ctx, msg);
1247+
break;
1248+
1249+
11671250
case VFIO_USER_DEVICE_RESET:
11681251
vfu_log(vfu_ctx, LOG_INFO, "device reset by client");
11691252
ret = handle_device_reset(vfu_ctx, VFU_RESET_DEVICE);
@@ -1352,6 +1435,10 @@ command_needs_quiesce(vfu_ctx_t *vfu_ctx, const vfu_msg_t *msg)
13521435
return true;
13531436
}
13541437
break;
1438+
1439+
case VFIO_USER_REGION_WRITE_MULTI:
1440+
/* FIXME */
1441+
return false;
13551442
}
13561443

13571444
return false;

samples/client.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ send_version(int sock)
107107
slen = snprintf(client_caps, sizeof(client_caps),
108108
"{"
109109
"\"capabilities\":{"
110+
"\"write_multiple\": true,"
110111
"\"max_msg_fds\":%u,"
111112
"\"max_data_xfer_size\":%u,"
112113
"\"migration\":{"

test/py/libvfio_user.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@
158158
VFIO_USER_DMA_WRITE = 12
159159
VFIO_USER_DEVICE_RESET = 13
160160
VFIO_USER_DIRTY_PAGES = 14
161-
VFIO_USER_MAX = 15
161+
# FIXME: need tests
162+
VFIO_USER_REGION_WRITE_MULTI = 15
163+
VFIO_USER_MAX = 16
162164

163165
VFIO_USER_F_TYPE_COMMAND = 0
164166
VFIO_USER_F_TYPE_REPLY = 1

0 commit comments

Comments
 (0)