2 * virtio-fs glue for FUSE
3 * Copyright (C) 2018 Red Hat, Inc. and/or its affiliates
6 * Dave Gilbert <dgilbert@redhat.com>
8 * Implements the glue between libfuse and libvhost-user
10 * This program can be distributed under the terms of the GNU LGPLv2.
11 * See the file COPYING.LIB
14 #include "fuse_virtio.h"
16 #include "standard-headers/linux/fuse.h"
17 #include "fuse_misc.h"
26 #include <sys/socket.h>
27 #include <sys/types.h>
31 #include "contrib/libvhost-user/libvhost-user.h"
34 * We pass the dev element into libvhost-user
35 * and then use it to get back to the outer
36 * container for other data.
40 struct fuse_session
*se
;
44 struct virtio_fs_config
{
50 * Callback from libvhost-user if there's a new fd we're supposed to listen
51 * to, typically a queue kick?
53 static void fv_set_watch(VuDev
*dev
, int fd
, int condition
, vu_watch_cb cb
,
56 fuse_log(FUSE_LOG_WARNING
, "%s: TODO! fd=%d\n", __func__
, fd
);
60 * Callback from libvhost-user if we're no longer supposed to listen on an fd
62 static void fv_remove_watch(VuDev
*dev
, int fd
)
64 fuse_log(FUSE_LOG_WARNING
, "%s: TODO! fd=%d\n", __func__
, fd
);
67 /* Callback from libvhost-user to panic */
68 static void fv_panic(VuDev
*dev
, const char *err
)
70 fuse_log(FUSE_LOG_ERR
, "%s: libvhost-user: %s\n", __func__
, err
);
71 /* TODO: Allow reconnects?? */
75 static bool fv_queue_order(VuDev
*dev
, int qidx
)
80 static const VuDevIface fv_iface
= {
81 /* TODO: Add other callbacks */
82 .queue_is_processed_in_order
= fv_queue_order
,
86 * Main loop; this mostly deals with events on the vhost-user
87 * socket itself, and not actual fuse data.
89 int virtio_loop(struct fuse_session
*se
)
91 fuse_log(FUSE_LOG_INFO
, "%s: Entry\n", __func__
);
93 while (!fuse_session_exited(se
)) {
95 pf
[0].fd
= se
->vu_socketfd
;
96 pf
[0].events
= POLLIN
;
99 fuse_log(FUSE_LOG_DEBUG
, "%s: Waiting for VU event\n", __func__
);
100 int poll_res
= ppoll(pf
, 1, NULL
, NULL
);
102 if (poll_res
== -1) {
103 if (errno
== EINTR
) {
104 fuse_log(FUSE_LOG_INFO
, "%s: ppoll interrupted, going around\n",
108 fuse_log(FUSE_LOG_ERR
, "virtio_loop ppoll: %m\n");
111 assert(poll_res
== 1);
112 if (pf
[0].revents
& (POLLERR
| POLLHUP
| POLLNVAL
)) {
113 fuse_log(FUSE_LOG_ERR
, "%s: Unexpected poll revents %x\n", __func__
,
117 assert(pf
[0].revents
& POLLIN
);
118 fuse_log(FUSE_LOG_DEBUG
, "%s: Got VU event\n", __func__
);
119 if (!vu_dispatch(&se
->virtio_dev
->dev
)) {
120 fuse_log(FUSE_LOG_ERR
, "%s: vu_dispatch failed\n", __func__
);
125 fuse_log(FUSE_LOG_INFO
, "%s: Exit\n", __func__
);
130 int virtio_session_mount(struct fuse_session
*se
)
132 struct sockaddr_un un
;
135 if (strlen(se
->vu_socket_path
) >= sizeof(un
.sun_path
)) {
136 fuse_log(FUSE_LOG_ERR
, "Socket path too long\n");
143 * Create the Unix socket to communicate with qemu
144 * based on QEMU's vhost-user-bridge
146 unlink(se
->vu_socket_path
);
147 strcpy(un
.sun_path
, se
->vu_socket_path
);
148 size_t addr_len
= sizeof(un
);
150 int listen_sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
151 if (listen_sock
== -1) {
152 fuse_log(FUSE_LOG_ERR
, "vhost socket creation: %m\n");
155 un
.sun_family
= AF_UNIX
;
158 * Unfortunately bind doesn't let you set the mask on the socket,
159 * so set umask to 077 and restore it later.
161 old_umask
= umask(0077);
162 if (bind(listen_sock
, (struct sockaddr
*)&un
, addr_len
) == -1) {
163 fuse_log(FUSE_LOG_ERR
, "vhost socket bind: %m\n");
169 if (listen(listen_sock
, 1) == -1) {
170 fuse_log(FUSE_LOG_ERR
, "vhost socket listen: %m\n");
174 fuse_log(FUSE_LOG_INFO
, "%s: Waiting for vhost-user socket connection...\n",
176 int data_sock
= accept(listen_sock
, NULL
, NULL
);
177 if (data_sock
== -1) {
178 fuse_log(FUSE_LOG_ERR
, "vhost socket accept: %m\n");
183 fuse_log(FUSE_LOG_INFO
, "%s: Received vhost-user socket connection\n",
186 /* TODO: Some cleanup/deallocation! */
187 se
->virtio_dev
= calloc(sizeof(struct fv_VuDev
), 1);
188 if (!se
->virtio_dev
) {
189 fuse_log(FUSE_LOG_ERR
, "%s: virtio_dev calloc failed\n", __func__
);
194 se
->vu_socketfd
= data_sock
;
195 se
->virtio_dev
->se
= se
;
196 vu_init(&se
->virtio_dev
->dev
, 2, se
->vu_socketfd
, fv_panic
, fv_set_watch
,
197 fv_remove_watch
, &fv_iface
);