]>
Commit | Line | Data |
---|---|---|
7b2e5c65 MAL |
1 | /* |
2 | * Vhost User library | |
3 | * | |
4 | * Copyright (c) 2016 Red Hat, Inc. | |
5 | * | |
6 | * Authors: | |
7 | * Victor Kaplansky <victork@redhat.com> | |
8 | * Marc-André Lureau <mlureau@redhat.com> | |
9 | * | |
10 | * This work is licensed under the terms of the GNU GPL, version 2 or | |
11 | * later. See the COPYING file in the top-level directory. | |
12 | */ | |
13 | ||
14 | #ifndef LIBVHOST_USER_H | |
15 | #define LIBVHOST_USER_H | |
16 | ||
17 | #include <stdint.h> | |
18 | #include <stdbool.h> | |
19 | #include <stddef.h> | |
49cc0340 | 20 | #include <sys/poll.h> |
7b2e5c65 MAL |
21 | #include <linux/vhost.h> |
22 | #include "standard-headers/linux/virtio_ring.h" | |
23 | ||
24 | /* Based on qemu/hw/virtio/vhost-user.c */ | |
25 | #define VHOST_USER_F_PROTOCOL_FEATURES 30 | |
26 | #define VHOST_LOG_PAGE 4096 | |
27 | ||
28 | #define VHOST_MAX_NR_VIRTQUEUE 8 | |
29 | #define VIRTQUEUE_MAX_SIZE 1024 | |
30 | ||
31 | #define VHOST_MEMORY_MAX_NREGIONS 8 | |
32 | ||
0bc24d83 CL |
33 | typedef enum VhostSetConfigType { |
34 | VHOST_SET_CONFIG_TYPE_MASTER = 0, | |
35 | VHOST_SET_CONFIG_TYPE_MIGRATION = 1, | |
36 | } VhostSetConfigType; | |
37 | ||
38 | /* | |
39 | * Maximum size of virtio device config space | |
40 | */ | |
41 | #define VHOST_USER_MAX_CONFIG_SIZE 256 | |
42 | ||
7b2e5c65 MAL |
43 | enum VhostUserProtocolFeature { |
44 | VHOST_USER_PROTOCOL_F_MQ = 0, | |
45 | VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, | |
46 | VHOST_USER_PROTOCOL_F_RARP = 2, | |
ea642e22 DDAG |
47 | VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, |
48 | VHOST_USER_PROTOCOL_F_NET_MTU = 4, | |
49 | VHOST_USER_PROTOCOL_F_SLAVE_REQ = 5, | |
50 | VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, | |
9ccbfe14 DDAG |
51 | VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, |
52 | VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, | |
ea3e6f5a | 53 | VHOST_USER_PROTOCOL_F_CONFIG = 9, |
d84599f5 TB |
54 | VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10, |
55 | VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, | |
7b2e5c65 MAL |
56 | |
57 | VHOST_USER_PROTOCOL_F_MAX | |
58 | }; | |
59 | ||
60 | #define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1) | |
61 | ||
62 | typedef enum VhostUserRequest { | |
63 | VHOST_USER_NONE = 0, | |
64 | VHOST_USER_GET_FEATURES = 1, | |
65 | VHOST_USER_SET_FEATURES = 2, | |
66 | VHOST_USER_SET_OWNER = 3, | |
67 | VHOST_USER_RESET_OWNER = 4, | |
68 | VHOST_USER_SET_MEM_TABLE = 5, | |
69 | VHOST_USER_SET_LOG_BASE = 6, | |
70 | VHOST_USER_SET_LOG_FD = 7, | |
71 | VHOST_USER_SET_VRING_NUM = 8, | |
72 | VHOST_USER_SET_VRING_ADDR = 9, | |
73 | VHOST_USER_SET_VRING_BASE = 10, | |
74 | VHOST_USER_GET_VRING_BASE = 11, | |
75 | VHOST_USER_SET_VRING_KICK = 12, | |
76 | VHOST_USER_SET_VRING_CALL = 13, | |
77 | VHOST_USER_SET_VRING_ERR = 14, | |
78 | VHOST_USER_GET_PROTOCOL_FEATURES = 15, | |
79 | VHOST_USER_SET_PROTOCOL_FEATURES = 16, | |
80 | VHOST_USER_GET_QUEUE_NUM = 17, | |
81 | VHOST_USER_SET_VRING_ENABLE = 18, | |
82 | VHOST_USER_SEND_RARP = 19, | |
ea642e22 DDAG |
83 | VHOST_USER_NET_SET_MTU = 20, |
84 | VHOST_USER_SET_SLAVE_REQ_FD = 21, | |
85 | VHOST_USER_IOTLB_MSG = 22, | |
86 | VHOST_USER_SET_VRING_ENDIAN = 23, | |
0bc24d83 CL |
87 | VHOST_USER_GET_CONFIG = 24, |
88 | VHOST_USER_SET_CONFIG = 25, | |
d3dff7a5 DDAG |
89 | VHOST_USER_CREATE_CRYPTO_SESSION = 26, |
90 | VHOST_USER_CLOSE_CRYPTO_SESSION = 27, | |
91 | VHOST_USER_POSTCOPY_ADVISE = 28, | |
6864a7b5 | 92 | VHOST_USER_POSTCOPY_LISTEN = 29, |
c639187e | 93 | VHOST_USER_POSTCOPY_END = 30, |
7b2e5c65 MAL |
94 | VHOST_USER_MAX |
95 | } VhostUserRequest; | |
96 | ||
d84599f5 TB |
97 | typedef enum VhostUserSlaveRequest { |
98 | VHOST_USER_SLAVE_NONE = 0, | |
99 | VHOST_USER_SLAVE_IOTLB_MSG = 1, | |
100 | VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2, | |
101 | VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3, | |
102 | VHOST_USER_SLAVE_MAX | |
103 | } VhostUserSlaveRequest; | |
104 | ||
7b2e5c65 MAL |
105 | typedef struct VhostUserMemoryRegion { |
106 | uint64_t guest_phys_addr; | |
107 | uint64_t memory_size; | |
108 | uint64_t userspace_addr; | |
109 | uint64_t mmap_offset; | |
110 | } VhostUserMemoryRegion; | |
111 | ||
112 | typedef struct VhostUserMemory { | |
113 | uint32_t nregions; | |
114 | uint32_t padding; | |
115 | VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; | |
116 | } VhostUserMemory; | |
117 | ||
118 | typedef struct VhostUserLog { | |
119 | uint64_t mmap_size; | |
120 | uint64_t mmap_offset; | |
121 | } VhostUserLog; | |
122 | ||
0bc24d83 CL |
123 | typedef struct VhostUserConfig { |
124 | uint32_t offset; | |
125 | uint32_t size; | |
126 | uint32_t flags; | |
127 | uint8_t region[VHOST_USER_MAX_CONFIG_SIZE]; | |
128 | } VhostUserConfig; | |
129 | ||
130 | static VhostUserConfig c __attribute__ ((unused)); | |
131 | #define VHOST_USER_CONFIG_HDR_SIZE (sizeof(c.offset) \ | |
132 | + sizeof(c.size) \ | |
133 | + sizeof(c.flags)) | |
134 | ||
d84599f5 TB |
135 | typedef struct VhostUserVringArea { |
136 | uint64_t u64; | |
137 | uint64_t size; | |
138 | uint64_t offset; | |
139 | } VhostUserVringArea; | |
140 | ||
7b2e5c65 MAL |
141 | #if defined(_WIN32) |
142 | # define VU_PACKED __attribute__((gcc_struct, packed)) | |
143 | #else | |
144 | # define VU_PACKED __attribute__((packed)) | |
145 | #endif | |
146 | ||
147 | typedef struct VhostUserMsg { | |
ba275e9d | 148 | int request; |
7b2e5c65 MAL |
149 | |
150 | #define VHOST_USER_VERSION_MASK (0x3) | |
151 | #define VHOST_USER_REPLY_MASK (0x1 << 2) | |
d84599f5 | 152 | #define VHOST_USER_NEED_REPLY_MASK (0x1 << 3) |
7b2e5c65 MAL |
153 | uint32_t flags; |
154 | uint32_t size; /* the following payload size */ | |
155 | ||
156 | union { | |
157 | #define VHOST_USER_VRING_IDX_MASK (0xff) | |
158 | #define VHOST_USER_VRING_NOFD_MASK (0x1 << 8) | |
159 | uint64_t u64; | |
160 | struct vhost_vring_state state; | |
161 | struct vhost_vring_addr addr; | |
162 | VhostUserMemory memory; | |
163 | VhostUserLog log; | |
0bc24d83 | 164 | VhostUserConfig config; |
d84599f5 | 165 | VhostUserVringArea area; |
7b2e5c65 MAL |
166 | } payload; |
167 | ||
168 | int fds[VHOST_MEMORY_MAX_NREGIONS]; | |
169 | int fd_num; | |
170 | uint8_t *data; | |
171 | } VU_PACKED VhostUserMsg; | |
172 | ||
173 | typedef struct VuDevRegion { | |
174 | /* Guest Physical address. */ | |
175 | uint64_t gpa; | |
176 | /* Memory region size. */ | |
177 | uint64_t size; | |
178 | /* QEMU virtual address (userspace). */ | |
179 | uint64_t qva; | |
180 | /* Starting offset in our mmaped space. */ | |
181 | uint64_t mmap_offset; | |
182 | /* Start address of mmaped space. */ | |
183 | uint64_t mmap_addr; | |
184 | } VuDevRegion; | |
185 | ||
186 | typedef struct VuDev VuDev; | |
187 | ||
188 | typedef uint64_t (*vu_get_features_cb) (VuDev *dev); | |
189 | typedef void (*vu_set_features_cb) (VuDev *dev, uint64_t features); | |
190 | typedef int (*vu_process_msg_cb) (VuDev *dev, VhostUserMsg *vmsg, | |
191 | int *do_reply); | |
192 | typedef void (*vu_queue_set_started_cb) (VuDev *dev, int qidx, bool started); | |
35480cbf | 193 | typedef bool (*vu_queue_is_processed_in_order_cb) (VuDev *dev, int qidx); |
0bc24d83 CL |
194 | typedef int (*vu_get_config_cb) (VuDev *dev, uint8_t *config, uint32_t len); |
195 | typedef int (*vu_set_config_cb) (VuDev *dev, const uint8_t *data, | |
196 | uint32_t offset, uint32_t size, | |
197 | uint32_t flags); | |
7b2e5c65 MAL |
198 | |
199 | typedef struct VuDevIface { | |
200 | /* called by VHOST_USER_GET_FEATURES to get the features bitmask */ | |
201 | vu_get_features_cb get_features; | |
202 | /* enable vhost implementation features */ | |
203 | vu_set_features_cb set_features; | |
204 | /* get the protocol feature bitmask from the underlying vhost | |
205 | * implementation */ | |
206 | vu_get_features_cb get_protocol_features; | |
207 | /* enable protocol features in the underlying vhost implementation. */ | |
208 | vu_set_features_cb set_protocol_features; | |
209 | /* process_msg is called for each vhost-user message received */ | |
210 | /* skip libvhost-user processing if return value != 0 */ | |
211 | vu_process_msg_cb process_msg; | |
212 | /* tells when queues can be processed */ | |
213 | vu_queue_set_started_cb queue_set_started; | |
35480cbf MAL |
214 | /* |
215 | * If the queue is processed in order, in which case it will be | |
216 | * resumed to vring.used->idx. This can help to support resuming | |
217 | * on unmanaged exit/crash. | |
218 | */ | |
219 | vu_queue_is_processed_in_order_cb queue_is_processed_in_order; | |
0bc24d83 CL |
220 | /* get the config space of the device */ |
221 | vu_get_config_cb get_config; | |
222 | /* set the config space of the device */ | |
223 | vu_set_config_cb set_config; | |
7b2e5c65 MAL |
224 | } VuDevIface; |
225 | ||
226 | typedef void (*vu_queue_handler_cb) (VuDev *dev, int qidx); | |
227 | ||
228 | typedef struct VuRing { | |
229 | unsigned int num; | |
230 | struct vring_desc *desc; | |
231 | struct vring_avail *avail; | |
232 | struct vring_used *used; | |
233 | uint64_t log_guest_addr; | |
234 | uint32_t flags; | |
235 | } VuRing; | |
236 | ||
237 | typedef struct VuVirtq { | |
238 | VuRing vring; | |
239 | ||
240 | /* Next head to pop */ | |
241 | uint16_t last_avail_idx; | |
242 | ||
243 | /* Last avail_idx read from VQ. */ | |
244 | uint16_t shadow_avail_idx; | |
245 | ||
246 | uint16_t used_idx; | |
247 | ||
248 | /* Last used index value we have signalled on */ | |
249 | uint16_t signalled_used; | |
250 | ||
251 | /* Last used index value we have signalled on */ | |
252 | bool signalled_used_valid; | |
253 | ||
254 | /* Notification enabled? */ | |
255 | bool notification; | |
256 | ||
257 | int inuse; | |
258 | ||
259 | vu_queue_handler_cb handler; | |
260 | ||
261 | int call_fd; | |
262 | int kick_fd; | |
263 | int err_fd; | |
264 | unsigned int enable; | |
265 | bool started; | |
266 | } VuVirtq; | |
267 | ||
268 | enum VuWatchCondtion { | |
49cc0340 FF |
269 | VU_WATCH_IN = POLLIN, |
270 | VU_WATCH_OUT = POLLOUT, | |
271 | VU_WATCH_PRI = POLLPRI, | |
272 | VU_WATCH_ERR = POLLERR, | |
273 | VU_WATCH_HUP = POLLHUP, | |
7b2e5c65 MAL |
274 | }; |
275 | ||
276 | typedef void (*vu_panic_cb) (VuDev *dev, const char *err); | |
277 | typedef void (*vu_watch_cb) (VuDev *dev, int condition, void *data); | |
278 | typedef void (*vu_set_watch_cb) (VuDev *dev, int fd, int condition, | |
279 | vu_watch_cb cb, void *data); | |
280 | typedef void (*vu_remove_watch_cb) (VuDev *dev, int fd); | |
281 | ||
282 | struct VuDev { | |
283 | int sock; | |
284 | uint32_t nregions; | |
285 | VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS]; | |
286 | VuVirtq vq[VHOST_MAX_NR_VIRTQUEUE]; | |
287 | int log_call_fd; | |
13384f15 | 288 | int slave_fd; |
7b2e5c65 MAL |
289 | uint64_t log_size; |
290 | uint8_t *log_table; | |
291 | uint64_t features; | |
292 | uint64_t protocol_features; | |
293 | bool broken; | |
294 | ||
295 | /* @set_watch: add or update the given fd to the watch set, | |
296 | * call cb when condition is met */ | |
297 | vu_set_watch_cb set_watch; | |
298 | ||
299 | /* @remove_watch: remove the given fd from the watch set */ | |
300 | vu_remove_watch_cb remove_watch; | |
301 | ||
302 | /* @panic: encountered an unrecoverable error, you may try to | |
303 | * re-initialize */ | |
304 | vu_panic_cb panic; | |
305 | const VuDevIface *iface; | |
2a84ffc0 DDAG |
306 | |
307 | /* Postcopy data */ | |
308 | int postcopy_ufd; | |
6864a7b5 | 309 | bool postcopy_listening; |
7b2e5c65 MAL |
310 | }; |
311 | ||
312 | typedef struct VuVirtqElement { | |
313 | unsigned int index; | |
314 | unsigned int out_num; | |
315 | unsigned int in_num; | |
316 | struct iovec *in_sg; | |
317 | struct iovec *out_sg; | |
318 | } VuVirtqElement; | |
319 | ||
320 | /** | |
321 | * vu_init: | |
322 | * @dev: a VuDev context | |
323 | * @socket: the socket connected to vhost-user master | |
324 | * @panic: a panic callback | |
325 | * @set_watch: a set_watch callback | |
326 | * @remove_watch: a remove_watch callback | |
327 | * @iface: a VuDevIface structure with vhost-user device callbacks | |
328 | * | |
329 | * Intializes a VuDev vhost-user context. | |
330 | **/ | |
331 | void vu_init(VuDev *dev, | |
332 | int socket, | |
333 | vu_panic_cb panic, | |
334 | vu_set_watch_cb set_watch, | |
335 | vu_remove_watch_cb remove_watch, | |
336 | const VuDevIface *iface); | |
337 | ||
338 | ||
339 | /** | |
340 | * vu_deinit: | |
341 | * @dev: a VuDev context | |
342 | * | |
343 | * Cleans up the VuDev context | |
344 | */ | |
345 | void vu_deinit(VuDev *dev); | |
346 | ||
347 | /** | |
348 | * vu_dispatch: | |
349 | * @dev: a VuDev context | |
350 | * | |
351 | * Process one vhost-user message. | |
352 | * | |
353 | * Returns: TRUE on success, FALSE on failure. | |
354 | */ | |
355 | bool vu_dispatch(VuDev *dev); | |
356 | ||
357 | /** | |
358 | * vu_gpa_to_va: | |
359 | * @dev: a VuDev context | |
293084a7 | 360 | * @plen: guest memory size |
7b2e5c65 MAL |
361 | * @guest_addr: guest address |
362 | * | |
363 | * Translate a guest address to a pointer. Returns NULL on failure. | |
364 | */ | |
293084a7 | 365 | void *vu_gpa_to_va(VuDev *dev, uint64_t *plen, uint64_t guest_addr); |
7b2e5c65 MAL |
366 | |
367 | /** | |
368 | * vu_get_queue: | |
369 | * @dev: a VuDev context | |
370 | * @qidx: queue index | |
371 | * | |
372 | * Returns the queue number @qidx. | |
373 | */ | |
374 | VuVirtq *vu_get_queue(VuDev *dev, int qidx); | |
375 | ||
376 | /** | |
377 | * vu_set_queue_handler: | |
378 | * @dev: a VuDev context | |
379 | * @vq: a VuVirtq queue | |
380 | * @handler: the queue handler callback | |
381 | * | |
382 | * Set the queue handler. This function may be called several times | |
383 | * for the same queue. If called with NULL @handler, the handler is | |
384 | * removed. | |
385 | */ | |
386 | void vu_set_queue_handler(VuDev *dev, VuVirtq *vq, | |
387 | vu_queue_handler_cb handler); | |
388 | ||
d84599f5 TB |
389 | /** |
390 | * vu_set_queue_host_notifier: | |
391 | * @dev: a VuDev context | |
392 | * @vq: a VuVirtq queue | |
393 | * @fd: a file descriptor | |
394 | * @size: host page size | |
395 | * @offset: notifier offset in @fd file | |
396 | * | |
397 | * Set queue's host notifier. This function may be called several | |
398 | * times for the same queue. If called with -1 @fd, the notifier | |
399 | * is removed. | |
400 | */ | |
401 | bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, | |
402 | int size, int offset); | |
7b2e5c65 MAL |
403 | |
404 | /** | |
405 | * vu_queue_set_notification: | |
406 | * @dev: a VuDev context | |
407 | * @vq: a VuVirtq queue | |
408 | * @enable: state | |
409 | * | |
410 | * Set whether the queue notifies (via event index or interrupt) | |
411 | */ | |
412 | void vu_queue_set_notification(VuDev *dev, VuVirtq *vq, int enable); | |
413 | ||
414 | /** | |
415 | * vu_queue_enabled: | |
416 | * @dev: a VuDev context | |
417 | * @vq: a VuVirtq queue | |
418 | * | |
419 | * Returns: whether the queue is enabled. | |
420 | */ | |
421 | bool vu_queue_enabled(VuDev *dev, VuVirtq *vq); | |
422 | ||
bcf0836d DDAG |
423 | /** |
424 | * vu_queue_started: | |
425 | * @dev: a VuDev context | |
426 | * @vq: a VuVirtq queue | |
427 | * | |
428 | * Returns: whether the queue is started. | |
429 | */ | |
430 | bool vu_queue_started(const VuDev *dev, const VuVirtq *vq); | |
431 | ||
7b2e5c65 | 432 | /** |
640601c7 | 433 | * vu_queue_empty: |
7b2e5c65 MAL |
434 | * @dev: a VuDev context |
435 | * @vq: a VuVirtq queue | |
436 | * | |
640601c7 | 437 | * Returns: true if the queue is empty or not ready. |
7b2e5c65 | 438 | */ |
640601c7 | 439 | bool vu_queue_empty(VuDev *dev, VuVirtq *vq); |
7b2e5c65 MAL |
440 | |
441 | /** | |
442 | * vu_queue_notify: | |
443 | * @dev: a VuDev context | |
444 | * @vq: a VuVirtq queue | |
445 | * | |
446 | * Request to notify the queue via callfd (skipped if unnecessary) | |
447 | */ | |
448 | void vu_queue_notify(VuDev *dev, VuVirtq *vq); | |
449 | ||
450 | /** | |
451 | * vu_queue_pop: | |
452 | * @dev: a VuDev context | |
453 | * @vq: a VuVirtq queue | |
454 | * @sz: the size of struct to return (must be >= VuVirtqElement) | |
455 | * | |
19409df8 MAL |
456 | * Returns: a VuVirtqElement filled from the queue or NULL. The |
457 | * returned element must be free()-d by the caller. | |
7b2e5c65 MAL |
458 | */ |
459 | void *vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz); | |
460 | ||
b13919ab MAL |
461 | |
462 | /** | |
463 | * vu_queue_unpop: | |
464 | * @dev: a VuDev context | |
465 | * @vq: a VuVirtq queue | |
466 | * @elem: The #VuVirtqElement | |
467 | * @len: number of bytes written | |
468 | * | |
469 | * Pretend the most recent element wasn't popped from the virtqueue. The next | |
470 | * call to vu_queue_pop() will refetch the element. | |
471 | */ | |
472 | void vu_queue_unpop(VuDev *dev, VuVirtq *vq, VuVirtqElement *elem, | |
473 | size_t len); | |
474 | ||
7b2e5c65 MAL |
475 | /** |
476 | * vu_queue_rewind: | |
477 | * @dev: a VuDev context | |
478 | * @vq: a VuVirtq queue | |
479 | * @num: number of elements to push back | |
480 | * | |
481 | * Pretend that elements weren't popped from the virtqueue. The next | |
482 | * virtqueue_pop() will refetch the oldest element. | |
483 | * | |
484 | * Returns: true on success, false if @num is greater than the number of in use | |
485 | * elements. | |
486 | */ | |
487 | bool vu_queue_rewind(VuDev *dev, VuVirtq *vq, unsigned int num); | |
488 | ||
489 | /** | |
490 | * vu_queue_fill: | |
491 | * @dev: a VuDev context | |
492 | * @vq: a VuVirtq queue | |
493 | * @elem: a VuVirtqElement | |
494 | * @len: length in bytes to write | |
495 | * @idx: optional offset for the used ring index (0 in general) | |
496 | * | |
497 | * Fill the used ring with @elem element. | |
498 | */ | |
499 | void vu_queue_fill(VuDev *dev, VuVirtq *vq, | |
500 | const VuVirtqElement *elem, | |
501 | unsigned int len, unsigned int idx); | |
502 | ||
503 | /** | |
504 | * vu_queue_push: | |
505 | * @dev: a VuDev context | |
506 | * @vq: a VuVirtq queue | |
507 | * @elem: a VuVirtqElement | |
508 | * @len: length in bytes to write | |
509 | * | |
510 | * Helper that combines vu_queue_fill() with a vu_queue_flush(). | |
511 | */ | |
512 | void vu_queue_push(VuDev *dev, VuVirtq *vq, | |
513 | const VuVirtqElement *elem, unsigned int len); | |
514 | ||
515 | /** | |
516 | * vu_queue_flush: | |
517 | * @dev: a VuDev context | |
518 | * @vq: a VuVirtq queue | |
519 | * @num: number of elements to flush | |
520 | * | |
521 | * Mark the last number of elements as done (used.idx is updated by | |
522 | * num elements). | |
523 | */ | |
524 | void vu_queue_flush(VuDev *dev, VuVirtq *vq, unsigned int num); | |
525 | ||
526 | /** | |
527 | * vu_queue_get_avail_bytes: | |
528 | * @dev: a VuDev context | |
529 | * @vq: a VuVirtq queue | |
530 | * @in_bytes: in bytes | |
531 | * @out_bytes: out bytes | |
532 | * @max_in_bytes: stop counting after max_in_bytes | |
533 | * @max_out_bytes: stop counting after max_out_bytes | |
534 | * | |
535 | * Count the number of available bytes, up to max_in_bytes/max_out_bytes. | |
536 | */ | |
537 | void vu_queue_get_avail_bytes(VuDev *vdev, VuVirtq *vq, unsigned int *in_bytes, | |
538 | unsigned int *out_bytes, | |
539 | unsigned max_in_bytes, unsigned max_out_bytes); | |
540 | ||
541 | /** | |
542 | * vu_queue_avail_bytes: | |
543 | * @dev: a VuDev context | |
544 | * @vq: a VuVirtq queue | |
545 | * @in_bytes: expected in bytes | |
546 | * @out_bytes: expected out bytes | |
547 | * | |
548 | * Returns: true if in_bytes <= in_total && out_bytes <= out_total | |
549 | */ | |
550 | bool vu_queue_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int in_bytes, | |
551 | unsigned int out_bytes); | |
552 | ||
553 | #endif /* LIBVHOST_USER_H */ |