Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2010-2016 Intel Corporation. All rights reserved.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include <sys/eventfd.h>
9 : :
10 : : #include "spdk/string.h"
11 : : #include "spdk/config.h"
12 : : #include "spdk/util.h"
13 : :
14 : : #include "spdk_internal/virtio.h"
15 : : #include "spdk_internal/vhost_user.h"
16 : :
17 : : /* The version of the protocol we support */
18 : : #define VHOST_USER_VERSION 0x1
19 : :
20 : : #define VIRTIO_USER_SUPPORTED_PROTOCOL_FEATURES \
21 : : ((1ULL << VHOST_USER_PROTOCOL_F_MQ) | \
22 : : (1ULL << VHOST_USER_PROTOCOL_F_CONFIG))
23 : :
24 : : struct virtio_user_dev {
25 : : int vhostfd;
26 : :
27 : : int callfds[SPDK_VIRTIO_MAX_VIRTQUEUES];
28 : : int kickfds[SPDK_VIRTIO_MAX_VIRTQUEUES];
29 : : uint32_t queue_size;
30 : :
31 : : uint8_t status;
32 : : bool is_stopping;
33 : : char path[PATH_MAX];
34 : : uint64_t protocol_features;
35 : : struct vring vrings[SPDK_VIRTIO_MAX_VIRTQUEUES];
36 : : struct spdk_mem_map *mem_map;
37 : : };
38 : :
39 : : static int
40 : 1549 : vhost_user_write(int fd, void *buf, int len, int *fds, int fd_num)
41 : 1549 : {
42 : : int r;
43 : 0 : struct msghdr msgh;
44 : 0 : struct iovec iov;
45 : 1549 : size_t fd_size = fd_num * sizeof(int);
46 [ - + ]: 1549 : char control[CMSG_SPACE(fd_size)];
47 : : struct cmsghdr *cmsg;
48 : :
49 : 1549 : memset(&msgh, 0, sizeof(msgh));
50 [ - + ]: 1549 : memset(control, 0, sizeof(control));
51 : :
52 : 1549 : iov.iov_base = (uint8_t *)buf;
53 : 1549 : iov.iov_len = len;
54 : :
55 : 1549 : msgh.msg_iov = &iov;
56 : 1549 : msgh.msg_iovlen = 1;
57 : :
58 [ + - + + ]: 1549 : if (fds && fd_num > 0) {
59 : 402 : msgh.msg_control = control;
60 : 402 : msgh.msg_controllen = sizeof(control);
61 [ + - ]: 402 : cmsg = CMSG_FIRSTHDR(&msgh);
62 [ - + ]: 402 : if (!cmsg) {
63 : 0 : SPDK_WARNLOG("First HDR is NULL\n");
64 : 0 : return -EIO;
65 : : }
66 : 402 : cmsg->cmsg_len = CMSG_LEN(fd_size);
67 : 402 : cmsg->cmsg_level = SOL_SOCKET;
68 : 402 : cmsg->cmsg_type = SCM_RIGHTS;
69 [ - + - + ]: 402 : memcpy(CMSG_DATA(cmsg), fds, fd_size);
70 : : } else {
71 : 1147 : msgh.msg_control = NULL;
72 : 1147 : msgh.msg_controllen = 0;
73 : : }
74 : :
75 : : do {
76 : 1549 : r = sendmsg(fd, &msgh, 0);
77 [ - + - - ]: 1549 : } while (r < 0 && errno == EINTR);
78 : :
79 [ - + ]: 1549 : if (r == -1) {
80 : 0 : return -errno;
81 : : }
82 : :
83 : 1549 : return 0;
84 : : }
85 : :
86 : : static int
87 : 372 : vhost_user_read(int fd, struct vhost_user_msg *msg)
88 : : {
89 : 372 : uint32_t valid_flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION;
90 : : ssize_t ret;
91 : 372 : size_t sz_hdr = VHOST_USER_HDR_SIZE, sz_payload;
92 : :
93 : 372 : ret = recv(fd, (void *)msg, sz_hdr, 0);
94 [ - + ]: 372 : if ((size_t)ret != sz_hdr) {
95 : 0 : SPDK_WARNLOG("Failed to recv msg hdr: %zd instead of %zu.\n",
96 : : ret, sz_hdr);
97 [ # # ]: 0 : if (ret == -1) {
98 : 0 : return -errno;
99 : : } else {
100 : 0 : return -EBUSY;
101 : : }
102 : : }
103 : :
104 : : /* validate msg flags */
105 [ - + ]: 372 : if (msg->flags != (valid_flags)) {
106 : 0 : SPDK_WARNLOG("Failed to recv msg: flags %"PRIx32" instead of %"PRIx32".\n",
107 : : msg->flags, valid_flags);
108 : 0 : return -EIO;
109 : : }
110 : :
111 : 372 : sz_payload = msg->size;
112 : :
113 [ - + ]: 372 : if (sz_payload > VHOST_USER_PAYLOAD_SIZE) {
114 : 0 : SPDK_WARNLOG("Received oversized msg: payload size %zu > available space %zu\n",
115 : : sz_payload, VHOST_USER_PAYLOAD_SIZE);
116 : 0 : return -EIO;
117 : : }
118 : :
119 [ + - ]: 372 : if (sz_payload) {
120 : 372 : ret = recv(fd, (void *)((char *)msg + sz_hdr), sz_payload, 0);
121 [ - + ]: 372 : if ((size_t)ret != sz_payload) {
122 : 0 : SPDK_WARNLOG("Failed to recv msg payload: %zd instead of %"PRIu32".\n",
123 : : ret, msg->size);
124 [ # # ]: 0 : if (ret == -1) {
125 : 0 : return -errno;
126 : : } else {
127 : 0 : return -EBUSY;
128 : : }
129 : : }
130 : : }
131 : :
132 : 372 : return 0;
133 : : }
134 : :
135 : : struct hugepage_file_info {
136 : : uint64_t addr; /**< virtual addr */
137 : : size_t size; /**< the file size */
138 : : char path[PATH_MAX]; /**< path to backing file */
139 : : };
140 : :
141 : : /* Two possible options:
142 : : * 1. Match HUGEPAGE_INFO_FMT to find the file storing struct hugepage_file
143 : : * array. This is simple but cannot be used in secondary process because
144 : : * secondary process will close and munmap that file.
145 : : * 2. Match HUGEFILE_FMT to find hugepage files directly.
146 : : *
147 : : * We choose option 2.
148 : : */
149 : : static int
150 : 58 : get_hugepage_file_info(struct hugepage_file_info hugepages[], int max)
151 : : {
152 : : int idx, rc;
153 : : FILE *f;
154 : 0 : char buf[BUFSIZ], *tmp, *tail;
155 : : char *str_underline, *str_start;
156 : 0 : int huge_index;
157 : 0 : uint64_t v_start, v_end;
158 : :
159 : 58 : f = fopen("/proc/self/maps", "r");
160 [ - + ]: 58 : if (!f) {
161 : 0 : SPDK_ERRLOG("cannot open /proc/self/maps\n");
162 : 0 : rc = -errno;
163 [ # # ]: 0 : assert(rc < 0); /* scan-build hack */
164 : 0 : return rc;
165 : : }
166 : :
167 : 58 : idx = 0;
168 [ + + ]: 66541 : while (fgets(buf, sizeof(buf), f) != NULL) {
169 [ - + ]: 66483 : if (sscanf(buf, "%" PRIx64 "-%" PRIx64, &v_start, &v_end) < 2) {
170 : 0 : SPDK_ERRLOG("Failed to parse address\n");
171 : 0 : rc = -EIO;
172 : 0 : goto out;
173 : : }
174 : :
175 : 66483 : tmp = strchr(buf, ' ') + 1; /** skip address */
176 [ - + ]: 66483 : tmp = strchr(tmp, ' ') + 1; /** skip perm */
177 [ - + ]: 66483 : tmp = strchr(tmp, ' ') + 1; /** skip offset */
178 [ - + ]: 66483 : tmp = strchr(tmp, ' ') + 1; /** skip dev */
179 [ - + ]: 66483 : tmp = strchr(tmp, ' ') + 1; /** skip inode */
180 [ + + ]: 1344363 : while (*tmp == ' ') { /** skip spaces */
181 : 1277880 : tmp++;
182 : : }
183 [ - + ]: 66483 : tail = strrchr(tmp, '\n'); /** remove newline if exists */
184 [ + - ]: 66483 : if (tail) {
185 : 66483 : *tail = '\0';
186 : : }
187 : :
188 : : /* Match HUGEFILE_FMT, aka "%s/%smap_%d",
189 : : * which is defined in eal_filesystem.h
190 : : */
191 [ - + ]: 66483 : str_underline = strrchr(tmp, '_');
192 [ + + ]: 66483 : if (!str_underline) {
193 : 13825 : continue;
194 : : }
195 : :
196 : 52658 : str_start = str_underline - strlen("map");
197 [ - + ]: 52658 : if (str_start < tmp) {
198 : 0 : continue;
199 : : }
200 : :
201 [ + + ]: 52658 : if (sscanf(str_start, "map_%d", &huge_index) != 1) {
202 : 22450 : continue;
203 : : }
204 : :
205 [ - + ]: 30208 : if (idx >= max) {
206 : 0 : SPDK_ERRLOG("Exceed maximum of %d\n", max);
207 : 0 : rc = -ENOSPC;
208 : 0 : goto out;
209 : : }
210 : :
211 [ + + ]: 30208 : if (idx > 0 &&
212 [ - + - + : 30150 : strncmp(tmp, hugepages[idx - 1].path, PATH_MAX) == 0 &&
+ - ]
213 [ + - ]: 30150 : v_start == hugepages[idx - 1].addr + hugepages[idx - 1].size) {
214 : 30150 : hugepages[idx - 1].size += (v_end - v_start);
215 : 30150 : continue;
216 : : }
217 : :
218 : 58 : hugepages[idx].addr = v_start;
219 : 58 : hugepages[idx].size = v_end - v_start;
220 : 58 : snprintf(hugepages[idx].path, PATH_MAX, "%s", tmp);
221 : 58 : idx++;
222 : : }
223 : :
224 : 58 : rc = idx;
225 : 58 : out:
226 : 58 : fclose(f);
227 : 58 : return rc;
228 : : }
229 : :
230 : : static int
231 : 58 : prepare_vhost_memory_user(struct vhost_user_msg *msg, int fds[])
232 : : {
233 : : int i, num;
234 : 0 : struct hugepage_file_info hugepages[VHOST_USER_MEMORY_MAX_NREGIONS];
235 : :
236 : 58 : num = get_hugepage_file_info(hugepages, VHOST_USER_MEMORY_MAX_NREGIONS);
237 [ - + ]: 58 : if (num < 0) {
238 : 0 : SPDK_ERRLOG("Failed to prepare memory for vhost-user\n");
239 : 0 : return num;
240 : : }
241 : :
242 [ + + ]: 116 : for (i = 0; i < num; ++i) {
243 : : /* the memory regions are unaligned */
244 : 58 : msg->payload.memory.regions[i].guest_phys_addr = hugepages[i].addr; /* use vaddr! */
245 : 58 : msg->payload.memory.regions[i].userspace_addr = hugepages[i].addr;
246 : 58 : msg->payload.memory.regions[i].memory_size = hugepages[i].size;
247 : 58 : msg->payload.memory.regions[i].flags_padding = 0;
248 [ - + ]: 58 : fds[i] = open(hugepages[i].path, O_RDWR);
249 : : }
250 : :
251 : 58 : msg->payload.memory.nregions = num;
252 : 58 : msg->payload.memory.padding = 0;
253 : :
254 : 58 : return 0;
255 : : }
256 : :
257 : : static const char *const vhost_msg_strings[VHOST_USER_MAX] = {
258 : : [VHOST_USER_SET_OWNER] = "VHOST_SET_OWNER",
259 : : [VHOST_USER_RESET_OWNER] = "VHOST_RESET_OWNER",
260 : : [VHOST_USER_SET_FEATURES] = "VHOST_SET_FEATURES",
261 : : [VHOST_USER_GET_FEATURES] = "VHOST_GET_FEATURES",
262 : : [VHOST_USER_SET_VRING_CALL] = "VHOST_SET_VRING_CALL",
263 : : [VHOST_USER_GET_PROTOCOL_FEATURES] = "VHOST_USER_GET_PROTOCOL_FEATURES",
264 : : [VHOST_USER_SET_PROTOCOL_FEATURES] = "VHOST_USER_SET_PROTOCOL_FEATURES",
265 : : [VHOST_USER_SET_VRING_NUM] = "VHOST_SET_VRING_NUM",
266 : : [VHOST_USER_SET_VRING_BASE] = "VHOST_SET_VRING_BASE",
267 : : [VHOST_USER_GET_VRING_BASE] = "VHOST_GET_VRING_BASE",
268 : : [VHOST_USER_SET_VRING_ADDR] = "VHOST_SET_VRING_ADDR",
269 : : [VHOST_USER_SET_VRING_KICK] = "VHOST_SET_VRING_KICK",
270 : : [VHOST_USER_SET_MEM_TABLE] = "VHOST_SET_MEM_TABLE",
271 : : [VHOST_USER_SET_VRING_ENABLE] = "VHOST_SET_VRING_ENABLE",
272 : : [VHOST_USER_GET_QUEUE_NUM] = "VHOST_USER_GET_QUEUE_NUM",
273 : : [VHOST_USER_GET_CONFIG] = "VHOST_USER_GET_CONFIG",
274 : : [VHOST_USER_SET_CONFIG] = "VHOST_USER_SET_CONFIG",
275 : : };
276 : :
277 : : static int
278 : 1549 : vhost_user_sock(struct virtio_user_dev *dev,
279 : : enum vhost_user_request req,
280 : : void *arg)
281 : : {
282 : 0 : struct vhost_user_msg msg;
283 : 1549 : struct vhost_vring_file *file = 0;
284 : 1549 : int need_reply = 0;
285 : 0 : int fds[VHOST_USER_MEMORY_MAX_NREGIONS];
286 : 1549 : int fd_num = 0;
287 : : int i, len, rc;
288 : 1549 : int vhostfd = dev->vhostfd;
289 : :
290 [ - + - + ]: 1549 : SPDK_DEBUGLOG(virtio_user, "sent message %d = %s\n", req, vhost_msg_strings[req]);
291 : :
292 : 1549 : msg.request = req;
293 : 1549 : msg.flags = VHOST_USER_VERSION;
294 : 1549 : msg.size = 0;
295 : :
296 [ + + + + : 1549 : switch (req) {
- + + + +
+ - - ]
297 : 145 : case VHOST_USER_GET_FEATURES:
298 : : case VHOST_USER_GET_PROTOCOL_FEATURES:
299 : : case VHOST_USER_GET_QUEUE_NUM:
300 : 145 : need_reply = 1;
301 : 145 : break;
302 : :
303 : 58 : case VHOST_USER_SET_FEATURES:
304 : : case VHOST_USER_SET_LOG_BASE:
305 : : case VHOST_USER_SET_PROTOCOL_FEATURES:
306 : 58 : msg.payload.u64 = *((__u64 *)arg);
307 : 58 : msg.size = sizeof(msg.payload.u64);
308 : 58 : break;
309 : :
310 : 29 : case VHOST_USER_SET_OWNER:
311 : : case VHOST_USER_RESET_OWNER:
312 : 29 : break;
313 : :
314 : 58 : case VHOST_USER_SET_MEM_TABLE:
315 : 58 : rc = prepare_vhost_memory_user(&msg, fds);
316 [ - + ]: 58 : if (rc < 0) {
317 : 0 : return rc;
318 : : }
319 : 58 : fd_num = msg.payload.memory.nregions;
320 : 58 : msg.size = sizeof(msg.payload.memory.nregions);
321 : 58 : msg.size += sizeof(msg.payload.memory.padding);
322 : 58 : msg.size += fd_num * sizeof(struct vhost_memory_region);
323 : 58 : break;
324 : :
325 : 0 : case VHOST_USER_SET_LOG_FD:
326 : 0 : fds[fd_num++] = *((int *)arg);
327 : 0 : break;
328 : :
329 : 516 : case VHOST_USER_SET_VRING_NUM:
330 : : case VHOST_USER_SET_VRING_BASE:
331 : : case VHOST_USER_SET_VRING_ENABLE:
332 : 516 : memcpy(&msg.payload.state, arg, sizeof(msg.payload.state));
333 : 516 : msg.size = sizeof(msg.payload.state);
334 : 516 : break;
335 : :
336 : 172 : case VHOST_USER_GET_VRING_BASE:
337 : 172 : memcpy(&msg.payload.state, arg, sizeof(msg.payload.state));
338 : 172 : msg.size = sizeof(msg.payload.state);
339 : 172 : need_reply = 1;
340 : 172 : break;
341 : :
342 : 172 : case VHOST_USER_SET_VRING_ADDR:
343 [ - + - + ]: 172 : memcpy(&msg.payload.addr, arg, sizeof(msg.payload.addr));
344 : 172 : msg.size = sizeof(msg.payload.addr);
345 : 172 : break;
346 : :
347 : 344 : case VHOST_USER_SET_VRING_KICK:
348 : : case VHOST_USER_SET_VRING_CALL:
349 : : case VHOST_USER_SET_VRING_ERR:
350 : 344 : file = arg;
351 : 344 : msg.payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK;
352 : 344 : msg.size = sizeof(msg.payload.u64);
353 [ + - ]: 344 : if (file->fd > 0) {
354 : 344 : fds[fd_num++] = file->fd;
355 : : } else {
356 : 0 : msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
357 : : }
358 : 344 : break;
359 : :
360 : 55 : case VHOST_USER_GET_CONFIG:
361 [ - + - + ]: 55 : memcpy(&msg.payload.cfg, arg, sizeof(msg.payload.cfg));
362 : 55 : msg.size = sizeof(msg.payload.cfg);
363 : 55 : need_reply = 1;
364 : 55 : break;
365 : :
366 : 0 : case VHOST_USER_SET_CONFIG:
367 [ # # # # ]: 0 : memcpy(&msg.payload.cfg, arg, sizeof(msg.payload.cfg));
368 : 0 : msg.size = sizeof(msg.payload.cfg);
369 : 0 : break;
370 : :
371 : 0 : default:
372 : 0 : SPDK_ERRLOG("trying to send unknown msg\n");
373 : 0 : return -EINVAL;
374 : : }
375 : :
376 : 1549 : len = VHOST_USER_HDR_SIZE + msg.size;
377 : 1549 : rc = vhost_user_write(vhostfd, &msg, len, fds, fd_num);
378 [ - + ]: 1549 : if (rc < 0) {
379 : 0 : SPDK_ERRLOG("%s failed: %s\n",
380 : : vhost_msg_strings[req], spdk_strerror(-rc));
381 : 0 : return rc;
382 : : }
383 : :
384 [ + + ]: 1549 : if (req == VHOST_USER_SET_MEM_TABLE)
385 [ + + ]: 116 : for (i = 0; i < fd_num; ++i) {
386 : 58 : close(fds[i]);
387 : : }
388 : :
389 [ + + ]: 1549 : if (need_reply) {
390 : 372 : rc = vhost_user_read(vhostfd, &msg);
391 [ - + ]: 372 : if (rc < 0) {
392 : 0 : SPDK_WARNLOG("Received msg failed: %s\n", spdk_strerror(-rc));
393 : 0 : return rc;
394 : : }
395 : :
396 [ - + ]: 372 : if (req != msg.request) {
397 : 0 : SPDK_WARNLOG("Received unexpected msg type\n");
398 : 0 : return -EIO;
399 : : }
400 : :
401 [ + + + - ]: 372 : switch (req) {
402 : 145 : case VHOST_USER_GET_FEATURES:
403 : : case VHOST_USER_GET_PROTOCOL_FEATURES:
404 : : case VHOST_USER_GET_QUEUE_NUM:
405 [ - + ]: 145 : if (msg.size != sizeof(msg.payload.u64)) {
406 : 0 : SPDK_WARNLOG("Received bad msg size\n");
407 : 0 : return -EIO;
408 : : }
409 : 145 : *((__u64 *)arg) = msg.payload.u64;
410 : 145 : break;
411 : 172 : case VHOST_USER_GET_VRING_BASE:
412 [ - + ]: 172 : if (msg.size != sizeof(msg.payload.state)) {
413 : 0 : SPDK_WARNLOG("Received bad msg size\n");
414 : 0 : return -EIO;
415 : : }
416 : 172 : memcpy(arg, &msg.payload.state,
417 : : sizeof(struct vhost_vring_state));
418 : 172 : break;
419 : 55 : case VHOST_USER_GET_CONFIG:
420 [ - + ]: 55 : if (msg.size != sizeof(msg.payload.cfg)) {
421 : 0 : SPDK_WARNLOG("Received bad msg size\n");
422 : 0 : return -EIO;
423 : : }
424 [ - + - + ]: 55 : memcpy(arg, &msg.payload.cfg, sizeof(msg.payload.cfg));
425 : 55 : break;
426 : 0 : default:
427 : 0 : SPDK_WARNLOG("Received unexpected msg type\n");
428 : 0 : return -EBADMSG;
429 : : }
430 : 0 : }
431 : :
432 : 1549 : return 0;
433 : : }
434 : :
435 : : /**
436 : : * Set up environment to talk with a vhost user backend.
437 : : *
438 : : * @return
439 : : * - (-1) if fail;
440 : : * - (0) if succeed.
441 : : */
442 : : static int
443 : 29 : vhost_user_setup(struct virtio_user_dev *dev)
444 : : {
445 : : int fd;
446 : : int flag;
447 : 0 : struct sockaddr_un un;
448 : : ssize_t rc;
449 : :
450 : 29 : fd = socket(AF_UNIX, SOCK_STREAM, 0);
451 [ - + ]: 29 : if (fd < 0) {
452 : 0 : SPDK_ERRLOG("socket() error, %s\n", spdk_strerror(errno));
453 : 0 : return -errno;
454 : : }
455 : :
456 : 29 : flag = fcntl(fd, F_GETFD);
457 [ - + ]: 29 : if (fcntl(fd, F_SETFD, flag | FD_CLOEXEC) < 0) {
458 : 0 : SPDK_ERRLOG("fcntl failed, %s\n", spdk_strerror(errno));
459 : : }
460 : :
461 : 29 : memset(&un, 0, sizeof(un));
462 : 29 : un.sun_family = AF_UNIX;
463 : 29 : rc = snprintf(un.sun_path, sizeof(un.sun_path), "%s", dev->path);
464 [ + - - + ]: 29 : if (rc < 0 || (size_t)rc >= sizeof(un.sun_path)) {
465 : 0 : SPDK_ERRLOG("socket path too long\n");
466 : 0 : close(fd);
467 [ # # ]: 0 : if (rc < 0) {
468 : 0 : return -errno;
469 : : } else {
470 : 0 : return -EINVAL;
471 : : }
472 : : }
473 [ - + ]: 29 : if (connect(fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
474 : 0 : SPDK_ERRLOG("connect error, %s\n", spdk_strerror(errno));
475 : 0 : close(fd);
476 : 0 : return -errno;
477 : : }
478 : :
479 : 29 : dev->vhostfd = fd;
480 : 29 : return 0;
481 : : }
482 : :
483 : : static int
484 : 172 : virtio_user_create_queue(struct virtio_dev *vdev, uint32_t queue_sel)
485 : : {
486 : 172 : struct virtio_user_dev *dev = vdev->ctx;
487 : :
488 : : /* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come
489 : : * firstly because vhost depends on this msg to allocate virtqueue
490 : : * pair.
491 : : */
492 : 0 : struct vhost_vring_file file;
493 : :
494 : 172 : file.index = queue_sel;
495 : 172 : file.fd = dev->callfds[queue_sel];
496 : 172 : return vhost_user_sock(dev, VHOST_USER_SET_VRING_CALL, &file);
497 : : }
498 : :
499 : : static int
500 : 172 : virtio_user_set_vring_addr(struct virtio_dev *vdev, uint32_t queue_sel)
501 : : {
502 : 172 : struct virtio_user_dev *dev = vdev->ctx;
503 : 172 : struct vring *vring = &dev->vrings[queue_sel];
504 : 688 : struct vhost_vring_addr addr = {
505 : : .index = queue_sel,
506 : 172 : .desc_user_addr = (uint64_t)(uintptr_t)vring->desc,
507 : 172 : .avail_user_addr = (uint64_t)(uintptr_t)vring->avail,
508 : 172 : .used_user_addr = (uint64_t)(uintptr_t)vring->used,
509 : : .log_guest_addr = 0,
510 : : .flags = 0, /* disable log */
511 : : };
512 : :
513 : 172 : return vhost_user_sock(dev, VHOST_USER_SET_VRING_ADDR, &addr);
514 : : }
515 : :
516 : : static int
517 : 172 : virtio_user_kick_queue(struct virtio_dev *vdev, uint32_t queue_sel)
518 : : {
519 : 172 : struct virtio_user_dev *dev = vdev->ctx;
520 : 0 : struct vhost_vring_file file;
521 : 0 : struct vhost_vring_state state;
522 : 172 : struct vring *vring = &dev->vrings[queue_sel];
523 : : int rc;
524 : :
525 : 172 : state.index = queue_sel;
526 : 172 : state.num = vring->num;
527 : 172 : rc = vhost_user_sock(dev, VHOST_USER_SET_VRING_NUM, &state);
528 [ - + ]: 172 : if (rc < 0) {
529 : 0 : return rc;
530 : : }
531 : :
532 : 172 : state.index = queue_sel;
533 : 172 : state.num = 0; /* no reservation */
534 : 172 : rc = vhost_user_sock(dev, VHOST_USER_SET_VRING_BASE, &state);
535 [ - + ]: 172 : if (rc < 0) {
536 : 0 : return rc;
537 : : }
538 : :
539 : 172 : virtio_user_set_vring_addr(vdev, queue_sel);
540 : :
541 : : /* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes
542 : : * lastly because vhost depends on this msg to judge if
543 : : * virtio is ready.
544 : : */
545 : 172 : file.index = queue_sel;
546 : 172 : file.fd = dev->kickfds[queue_sel];
547 : 172 : return vhost_user_sock(dev, VHOST_USER_SET_VRING_KICK, &file);
548 : : }
549 : :
550 : : static int
551 : 172 : virtio_user_stop_queue(struct virtio_dev *vdev, uint32_t queue_sel)
552 : : {
553 : 172 : struct virtio_user_dev *dev = vdev->ctx;
554 : 0 : struct vhost_vring_state state;
555 : :
556 : 172 : state.index = queue_sel;
557 : 172 : state.num = 0;
558 : :
559 : 172 : return vhost_user_sock(dev, VHOST_USER_GET_VRING_BASE, &state);
560 : : }
561 : :
562 : : static int
563 : 87 : virtio_user_queue_setup(struct virtio_dev *vdev,
564 : : int (*fn)(struct virtio_dev *, uint32_t))
565 : : {
566 : : uint32_t i;
567 : : int rc;
568 : :
569 [ + + ]: 603 : for (i = 0; i < vdev->max_queues; ++i) {
570 : 516 : rc = fn(vdev, i);
571 [ - + ]: 516 : if (rc < 0) {
572 : 0 : SPDK_ERRLOG("setup tx vq fails: %"PRIu32".\n", i);
573 : 0 : return rc;
574 : : }
575 : : }
576 : :
577 : 87 : return 0;
578 : : }
579 : :
580 : : static int
581 : 58 : virtio_user_map_notify(void *cb_ctx, struct spdk_mem_map *map,
582 : : enum spdk_mem_map_notify_action action,
583 : : void *vaddr, size_t size)
584 : : {
585 : 58 : struct virtio_dev *vdev = cb_ctx;
586 : 58 : struct virtio_user_dev *dev = vdev->ctx;
587 : 0 : uint64_t features;
588 : : int ret;
589 : :
590 : : /* We do not support dynamic memory allocation with virtio-user. If this is the
591 : : * initial notification when the device is started, dev->mem_map will be NULL. If
592 : : * this is the final notification when the device is stopped, dev->is_stopping will
593 : : * be true. All other cases are unsupported.
594 : : */
595 [ + + - + : 58 : if (dev->mem_map != NULL && !dev->is_stopping) {
- + ]
596 : 0 : assert(false);
597 : : SPDK_ERRLOG("Memory map change with active virtio_user_devs not allowed.\n");
598 : : SPDK_ERRLOG("Pre-allocate memory for application using -s (mem_size) option.\n");
599 : : return -1;
600 : : }
601 : :
602 : : /* We have to resend all mappings anyway, so don't bother with any
603 : : * page tracking.
604 : : */
605 : 58 : ret = vhost_user_sock(dev, VHOST_USER_SET_MEM_TABLE, NULL);
606 [ - + ]: 58 : if (ret < 0) {
607 : 0 : return ret;
608 : : }
609 : :
610 : : /* Since we might want to use that mapping straight away, we have to
611 : : * make sure the guest has already processed our SET_MEM_TABLE message.
612 : : * F_REPLY_ACK is just a feature and the host is not obliged to
613 : : * support it, so we send a simple message that always has a response
614 : : * and we wait for that response. Messages are always processed in order.
615 : : */
616 : 58 : return vhost_user_sock(dev, VHOST_USER_GET_FEATURES, &features);
617 : : }
618 : :
619 : : static int
620 : 29 : virtio_user_register_mem(struct virtio_dev *vdev)
621 : : {
622 : 29 : struct virtio_user_dev *dev = vdev->ctx;
623 : 29 : const struct spdk_mem_map_ops virtio_user_map_ops = {
624 : : .notify_cb = virtio_user_map_notify,
625 : : .are_contiguous = NULL
626 : : };
627 : :
628 : 29 : dev->mem_map = spdk_mem_map_alloc(0, &virtio_user_map_ops, vdev);
629 [ - + ]: 29 : if (dev->mem_map == NULL) {
630 : 0 : SPDK_ERRLOG("spdk_mem_map_alloc() failed\n");
631 : 0 : return -1;
632 : : }
633 : :
634 : 29 : return 0;
635 : : }
636 : :
637 : : static void
638 : 29 : virtio_user_unregister_mem(struct virtio_dev *vdev)
639 : : {
640 : 29 : struct virtio_user_dev *dev = vdev->ctx;
641 : :
642 : 29 : dev->is_stopping = true;
643 : 29 : spdk_mem_map_free(&dev->mem_map);
644 : 29 : }
645 : :
646 : : static int
647 : 29 : virtio_user_start_device(struct virtio_dev *vdev)
648 : : {
649 : 29 : struct virtio_user_dev *dev = vdev->ctx;
650 : 0 : uint64_t host_max_queues;
651 : : int ret;
652 : :
653 [ - + ]: 29 : if ((dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) == 0 &&
654 [ # # ]: 0 : vdev->max_queues > 1 + vdev->fixed_queues_num) {
655 : 0 : SPDK_WARNLOG("%s: requested %"PRIu16" request queues, but the "
656 : : "host doesn't support VHOST_USER_PROTOCOL_F_MQ. "
657 : : "Only one request queue will be used.\n",
658 : : vdev->name, vdev->max_queues - vdev->fixed_queues_num);
659 : 0 : vdev->max_queues = 1 + vdev->fixed_queues_num;
660 : : }
661 : :
662 : : /* negotiate the number of I/O queues. */
663 : 29 : ret = vhost_user_sock(dev, VHOST_USER_GET_QUEUE_NUM, &host_max_queues);
664 [ - + ]: 29 : if (ret < 0) {
665 : 0 : return ret;
666 : : }
667 : :
668 [ - + ]: 29 : if (vdev->max_queues > host_max_queues + vdev->fixed_queues_num) {
669 : 0 : SPDK_WARNLOG("%s: requested %"PRIu16" request queues"
670 : : "but only %"PRIu64" available\n",
671 : : vdev->name, vdev->max_queues - vdev->fixed_queues_num,
672 : : host_max_queues);
673 : 0 : vdev->max_queues = host_max_queues;
674 : : }
675 : :
676 : : /* tell vhost to create queues */
677 : 29 : ret = virtio_user_queue_setup(vdev, virtio_user_create_queue);
678 [ - + ]: 29 : if (ret < 0) {
679 : 0 : return ret;
680 : : }
681 : :
682 : 29 : ret = virtio_user_register_mem(vdev);
683 [ - + ]: 29 : if (ret < 0) {
684 : 0 : return ret;
685 : : }
686 : :
687 : 29 : return virtio_user_queue_setup(vdev, virtio_user_kick_queue);
688 : : }
689 : :
690 : : static int
691 : 29 : virtio_user_stop_device(struct virtio_dev *vdev)
692 : : {
693 : : int ret;
694 : :
695 : 29 : ret = virtio_user_queue_setup(vdev, virtio_user_stop_queue);
696 : : /* a queue might fail to stop for various reasons, e.g. socket
697 : : * connection going down, but this mustn't prevent us from freeing
698 : : * the mem map.
699 : : */
700 : 29 : virtio_user_unregister_mem(vdev);
701 : 29 : return ret;
702 : : }
703 : :
704 : : static int
705 : 29 : virtio_user_dev_setup(struct virtio_dev *vdev)
706 : : {
707 : 29 : struct virtio_user_dev *dev = vdev->ctx;
708 : : uint16_t i;
709 : :
710 : 29 : dev->vhostfd = -1;
711 : :
712 [ + + ]: 7453 : for (i = 0; i < SPDK_VIRTIO_MAX_VIRTQUEUES; ++i) {
713 : 7424 : dev->callfds[i] = -1;
714 : 7424 : dev->kickfds[i] = -1;
715 : : }
716 : :
717 : 29 : return vhost_user_setup(dev);
718 : : }
719 : :
720 : : static int
721 : 55 : virtio_user_read_dev_config(struct virtio_dev *vdev, size_t offset,
722 : : void *dst, int length)
723 : : {
724 : 55 : struct virtio_user_dev *dev = vdev->ctx;
725 : 55 : struct vhost_user_config cfg = {0};
726 : : int rc;
727 : :
728 [ - + ]: 55 : if ((dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_CONFIG)) == 0) {
729 : 0 : return -ENOTSUP;
730 : : }
731 : :
732 : 55 : cfg.offset = 0;
733 : 55 : cfg.size = VHOST_USER_MAX_CONFIG_SIZE;
734 : :
735 : 55 : rc = vhost_user_sock(dev, VHOST_USER_GET_CONFIG, &cfg);
736 [ - + ]: 55 : if (rc < 0) {
737 : 0 : SPDK_ERRLOG("get_config failed: %s\n", spdk_strerror(-rc));
738 : 0 : return rc;
739 : : }
740 : :
741 [ - + - + ]: 55 : memcpy(dst, cfg.region + offset, length);
742 : 55 : return 0;
743 : : }
744 : :
745 : : static int
746 : 0 : virtio_user_write_dev_config(struct virtio_dev *vdev, size_t offset,
747 : : const void *src, int length)
748 : : {
749 : 0 : struct virtio_user_dev *dev = vdev->ctx;
750 : 0 : struct vhost_user_config cfg = {0};
751 : : int rc;
752 : :
753 [ # # ]: 0 : if ((dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_CONFIG)) == 0) {
754 : 0 : return -ENOTSUP;
755 : : }
756 : :
757 : 0 : cfg.offset = offset;
758 : 0 : cfg.size = length;
759 [ # # # # ]: 0 : memcpy(cfg.region, src, length);
760 : :
761 : 0 : rc = vhost_user_sock(dev, VHOST_USER_SET_CONFIG, &cfg);
762 [ # # ]: 0 : if (rc < 0) {
763 : 0 : SPDK_ERRLOG("set_config failed: %s\n", spdk_strerror(-rc));
764 : 0 : return rc;
765 : : }
766 : :
767 : 0 : return 0;
768 : : }
769 : :
770 : : static void
771 : 174 : virtio_user_set_status(struct virtio_dev *vdev, uint8_t status)
772 : : {
773 : 174 : struct virtio_user_dev *dev = vdev->ctx;
774 : 174 : int rc = 0;
775 : :
776 [ - + - - ]: 174 : if ((dev->status & VIRTIO_CONFIG_S_NEEDS_RESET) &&
777 : : status != VIRTIO_CONFIG_S_RESET) {
778 : 0 : rc = -1;
779 [ + + ]: 174 : } else if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
780 : 29 : rc = virtio_user_start_device(vdev);
781 [ + + ]: 145 : } else if (status == VIRTIO_CONFIG_S_RESET &&
782 [ + + ]: 58 : (dev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
783 : 29 : rc = virtio_user_stop_device(vdev);
784 : : }
785 : :
786 [ - + ]: 174 : if (rc != 0) {
787 : 0 : dev->status |= VIRTIO_CONFIG_S_NEEDS_RESET;
788 : : } else {
789 : 174 : dev->status = status;
790 : : }
791 : 174 : }
792 : :
793 : : static uint8_t
794 : 290 : virtio_user_get_status(struct virtio_dev *vdev)
795 : : {
796 : 290 : struct virtio_user_dev *dev = vdev->ctx;
797 : :
798 : 290 : return dev->status;
799 : : }
800 : :
801 : : static uint64_t
802 : 29 : virtio_user_get_features(struct virtio_dev *vdev)
803 : : {
804 : 29 : struct virtio_user_dev *dev = vdev->ctx;
805 : 0 : uint64_t features;
806 : : int rc;
807 : :
808 : 29 : rc = vhost_user_sock(dev, VHOST_USER_GET_FEATURES, &features);
809 [ - + ]: 29 : if (rc < 0) {
810 : 0 : SPDK_ERRLOG("get_features failed: %s\n", spdk_strerror(-rc));
811 : 0 : return 0;
812 : : }
813 : :
814 : 29 : return features;
815 : : }
816 : :
817 : : static int
818 : 29 : virtio_user_set_features(struct virtio_dev *vdev, uint64_t features)
819 : : {
820 : 29 : struct virtio_user_dev *dev = vdev->ctx;
821 : 0 : uint64_t protocol_features;
822 : : int ret;
823 : :
824 : 29 : ret = vhost_user_sock(dev, VHOST_USER_SET_FEATURES, &features);
825 [ - + ]: 29 : if (ret < 0) {
826 : 0 : return ret;
827 : : }
828 : :
829 : 29 : vdev->negotiated_features = features;
830 : 29 : vdev->modern = virtio_dev_has_feature(vdev, VIRTIO_F_VERSION_1);
831 : :
832 [ - + ]: 29 : if (!virtio_dev_has_feature(vdev, VHOST_USER_F_PROTOCOL_FEATURES)) {
833 : : /* nothing else to do */
834 : 0 : return 0;
835 : : }
836 : :
837 : 29 : ret = vhost_user_sock(dev, VHOST_USER_GET_PROTOCOL_FEATURES, &protocol_features);
838 [ - + ]: 29 : if (ret < 0) {
839 : 0 : return ret;
840 : : }
841 : :
842 : 29 : protocol_features &= VIRTIO_USER_SUPPORTED_PROTOCOL_FEATURES;
843 : 29 : ret = vhost_user_sock(dev, VHOST_USER_SET_PROTOCOL_FEATURES, &protocol_features);
844 [ - + ]: 29 : if (ret < 0) {
845 : 0 : return ret;
846 : : }
847 : :
848 : 29 : dev->protocol_features = protocol_features;
849 : 29 : return 0;
850 : : }
851 : :
852 : : static uint16_t
853 : 268 : virtio_user_get_queue_size(struct virtio_dev *vdev, uint16_t queue_id)
854 : : {
855 : 268 : struct virtio_user_dev *dev = vdev->ctx;
856 : :
857 : : /* Currently each queue has same queue size */
858 : 268 : return dev->queue_size;
859 : : }
860 : :
861 : : static int
862 : 172 : virtio_user_setup_queue(struct virtio_dev *vdev, struct virtqueue *vq)
863 : : {
864 : 172 : struct virtio_user_dev *dev = vdev->ctx;
865 : 0 : struct vhost_vring_state state;
866 : 172 : uint16_t queue_idx = vq->vq_queue_index;
867 : : void *queue_mem;
868 : : uint64_t desc_addr, avail_addr, used_addr;
869 : : int callfd, kickfd, rc;
870 : :
871 [ + - - + ]: 172 : if (dev->callfds[queue_idx] != -1 || dev->kickfds[queue_idx] != -1) {
872 : 0 : SPDK_ERRLOG("queue %"PRIu16" already exists\n", queue_idx);
873 : 0 : return -EEXIST;
874 : : }
875 : :
876 : : /* May use invalid flag, but some backend uses kickfd and
877 : : * callfd as criteria to judge if dev is alive. so finally we
878 : : * use real event_fd.
879 : : */
880 : 172 : callfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
881 [ - + ]: 172 : if (callfd < 0) {
882 : 0 : SPDK_ERRLOG("callfd error, %s\n", spdk_strerror(errno));
883 : 0 : return -errno;
884 : : }
885 : :
886 : 172 : kickfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
887 [ - + ]: 172 : if (kickfd < 0) {
888 : 0 : SPDK_ERRLOG("kickfd error, %s\n", spdk_strerror(errno));
889 : 0 : close(callfd);
890 : 0 : return -errno;
891 : : }
892 : :
893 : 172 : queue_mem = spdk_zmalloc(vq->vq_ring_size, VIRTIO_PCI_VRING_ALIGN, NULL,
894 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
895 [ - + ]: 172 : if (queue_mem == NULL) {
896 : 0 : close(kickfd);
897 : 0 : close(callfd);
898 : 0 : return -ENOMEM;
899 : : }
900 : :
901 : 172 : vq->vq_ring_mem = SPDK_VTOPHYS_ERROR;
902 : 172 : vq->vq_ring_virt_mem = queue_mem;
903 : :
904 : 172 : state.index = vq->vq_queue_index;
905 : 172 : state.num = 1;
906 : :
907 [ + - ]: 172 : if (virtio_dev_has_feature(vdev, VHOST_USER_F_PROTOCOL_FEATURES)) {
908 : 172 : rc = vhost_user_sock(dev, VHOST_USER_SET_VRING_ENABLE, &state);
909 [ - + ]: 172 : if (rc < 0) {
910 : 0 : SPDK_ERRLOG("failed to send VHOST_USER_SET_VRING_ENABLE: %s\n",
911 : : spdk_strerror(-rc));
912 : 0 : close(kickfd);
913 : 0 : close(callfd);
914 : 0 : spdk_free(queue_mem);
915 : 0 : return -rc;
916 : : }
917 : : }
918 : :
919 : 172 : dev->callfds[queue_idx] = callfd;
920 : 172 : dev->kickfds[queue_idx] = kickfd;
921 : :
922 : 172 : desc_addr = (uintptr_t)vq->vq_ring_virt_mem;
923 : 172 : avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
924 : 172 : used_addr = SPDK_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
925 : : ring[vq->vq_nentries]),
926 : : VIRTIO_PCI_VRING_ALIGN);
927 : :
928 : 172 : dev->vrings[queue_idx].num = vq->vq_nentries;
929 : 172 : dev->vrings[queue_idx].desc = (void *)(uintptr_t)desc_addr;
930 : 172 : dev->vrings[queue_idx].avail = (void *)(uintptr_t)avail_addr;
931 : 172 : dev->vrings[queue_idx].used = (void *)(uintptr_t)used_addr;
932 : :
933 : 172 : return 0;
934 : : }
935 : :
936 : : static void
937 : 172 : virtio_user_del_queue(struct virtio_dev *vdev, struct virtqueue *vq)
938 : : {
939 : : /* For legacy devices, write 0 to VIRTIO_PCI_QUEUE_PFN port, QEMU
940 : : * correspondingly stops the ioeventfds, and reset the status of
941 : : * the device.
942 : : * For modern devices, set queue desc, avail, used in PCI bar to 0,
943 : : * not see any more behavior in QEMU.
944 : : *
945 : : * Here we just care about what information to deliver to vhost-user.
946 : : * So we just close ioeventfd for now.
947 : : */
948 : 172 : struct virtio_user_dev *dev = vdev->ctx;
949 : :
950 : 172 : close(dev->callfds[vq->vq_queue_index]);
951 : 172 : close(dev->kickfds[vq->vq_queue_index]);
952 : 172 : dev->callfds[vq->vq_queue_index] = -1;
953 : 172 : dev->kickfds[vq->vq_queue_index] = -1;
954 : :
955 : 172 : spdk_free(vq->vq_ring_virt_mem);
956 : 172 : }
957 : :
958 : : static void
959 : 199 : virtio_user_notify_queue(struct virtio_dev *vdev, struct virtqueue *vq)
960 : : {
961 : 199 : uint64_t buf = 1;
962 : 199 : struct virtio_user_dev *dev = vdev->ctx;
963 : :
964 [ - + ]: 199 : if (write(dev->kickfds[vq->vq_queue_index], &buf, sizeof(buf)) < 0) {
965 : 0 : SPDK_ERRLOG("failed to kick backend: %s.\n", spdk_strerror(errno));
966 : : }
967 : 199 : }
968 : :
969 : : static void
970 : 29 : virtio_user_destroy(struct virtio_dev *vdev)
971 : : {
972 : 29 : struct virtio_user_dev *dev = vdev->ctx;
973 : :
974 [ + - ]: 29 : if (dev) {
975 : 29 : close(dev->vhostfd);
976 : 29 : free(dev);
977 : : }
978 : 29 : }
979 : :
980 : : static void
981 : 85 : virtio_user_dump_json_info(struct virtio_dev *vdev, struct spdk_json_write_ctx *w)
982 : : {
983 : 85 : struct virtio_user_dev *dev = vdev->ctx;
984 : :
985 : 85 : spdk_json_write_named_string(w, "type", "user");
986 : 85 : spdk_json_write_named_string(w, "socket", dev->path);
987 : 85 : }
988 : :
989 : : static void
990 : 11 : virtio_user_write_json_config(struct virtio_dev *vdev, struct spdk_json_write_ctx *w)
991 : : {
992 : 11 : struct virtio_user_dev *dev = vdev->ctx;
993 : :
994 : 11 : spdk_json_write_named_string(w, "trtype", "user");
995 : 11 : spdk_json_write_named_string(w, "traddr", dev->path);
996 : 11 : spdk_json_write_named_uint32(w, "vq_count", vdev->max_queues - vdev->fixed_queues_num);
997 : 11 : spdk_json_write_named_uint32(w, "vq_size", virtio_dev_backend_ops(vdev)->get_queue_size(vdev, 0));
998 : 11 : }
999 : :
1000 : : static const struct virtio_dev_ops virtio_user_ops = {
1001 : : .read_dev_cfg = virtio_user_read_dev_config,
1002 : : .write_dev_cfg = virtio_user_write_dev_config,
1003 : : .get_status = virtio_user_get_status,
1004 : : .set_status = virtio_user_set_status,
1005 : : .get_features = virtio_user_get_features,
1006 : : .set_features = virtio_user_set_features,
1007 : : .destruct_dev = virtio_user_destroy,
1008 : : .get_queue_size = virtio_user_get_queue_size,
1009 : : .setup_queue = virtio_user_setup_queue,
1010 : : .del_queue = virtio_user_del_queue,
1011 : : .notify_queue = virtio_user_notify_queue,
1012 : : .dump_json_info = virtio_user_dump_json_info,
1013 : : .write_json_config = virtio_user_write_json_config,
1014 : : };
1015 : :
1016 : : int
1017 : 29 : virtio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *path,
1018 : : uint32_t queue_size)
1019 : : {
1020 : : struct virtio_user_dev *dev;
1021 : : int rc;
1022 : :
1023 [ - + ]: 29 : if (name == NULL) {
1024 : 0 : SPDK_ERRLOG("No name gived for controller: %s\n", path);
1025 : 0 : return -EINVAL;
1026 : : }
1027 : :
1028 : 29 : dev = calloc(1, sizeof(*dev));
1029 [ - + ]: 29 : if (dev == NULL) {
1030 : 0 : return -ENOMEM;
1031 : : }
1032 : :
1033 : 29 : rc = virtio_dev_construct(vdev, name, &virtio_user_ops, dev);
1034 [ - + ]: 29 : if (rc != 0) {
1035 : 0 : SPDK_ERRLOG("Failed to init device: %s\n", path);
1036 : 0 : free(dev);
1037 : 0 : return rc;
1038 : : }
1039 : :
1040 : 29 : vdev->is_hw = 0;
1041 : :
1042 [ - + ]: 29 : snprintf(dev->path, PATH_MAX, "%s", path);
1043 : 29 : dev->queue_size = queue_size;
1044 : :
1045 : 29 : rc = virtio_user_dev_setup(vdev);
1046 [ - + ]: 29 : if (rc < 0) {
1047 : 0 : SPDK_ERRLOG("backend set up fails\n");
1048 : 0 : goto err;
1049 : : }
1050 : :
1051 : 29 : rc = vhost_user_sock(dev, VHOST_USER_SET_OWNER, NULL);
1052 [ - + ]: 29 : if (rc < 0) {
1053 : 0 : SPDK_ERRLOG("set_owner fails: %s\n", spdk_strerror(-rc));
1054 : 0 : goto err;
1055 : : }
1056 : :
1057 : 29 : return 0;
1058 : :
1059 : 0 : err:
1060 : 0 : virtio_dev_destruct(vdev);
1061 : 0 : return rc;
1062 : : }
1063 : 2079 : SPDK_LOG_REGISTER_COMPONENT(virtio_user)
|