From: Feng S. <ste...@gm...> - 2017-10-16 13:49:18
|
Hi, I also made a quick & dirty example code by modifying the passthrough_ll.c for both unix domain socket client&server, which is at: https://github.com/openunix/hsfs2/blob/master/hsfs/hsfs_main.c Compile it with gcc -Wall hsfs_main.c `pkg-config fuse3 --cflags --libs` -o example. I will try to add VSOCK/VMCI later. Thanks. -- Feng Shuo 2017-10-16 21:39 GMT+08:00 Feng Shuo <ste...@gm...>: > This patch introduces a new fuse low level function fuse_session_socket() > to enable using a socket fd as the fuse device. This helps to implement > separated fuse daemon with its mount points, especially by unix domain > socket in one system, or VSOCK/VMCI socket between VM and Host. > > Currently only single-thread mode is supported in this "socket" mode. > > Signed-off-by: Feng Shuo <ste...@gm...> > --- > include/fuse_lowlevel.h | 10 +++++ > lib/fuse_i.h | 1 + > lib/fuse_loop_mt.c | 5 +++ > lib/fuse_lowlevel.c | 117 ++++++++++++++++++++++++++++++ > ++++++++++++++++-- > lib/fuse_versionscript | 1 + > 5 files changed, 131 insertions(+), 3 deletions(-) > > diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h > index efe4edb..8bf281f 100644 > --- a/include/fuse_lowlevel.h > +++ b/include/fuse_lowlevel.h > @@ -1955,6 +1955,16 @@ void fuse_session_process_buf(struct fuse_session > *se, > */ > int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf > *buf); > > +/** > + * Set FUSE file system to run on a socket. > + * > + * @param se session object > + * @param socket the socket fd to run with > + * > + * @return 0 on success, -1 on failure. > + **/ > +int fuse_session_socket(struct fuse_session *se, int sock); > + > #ifdef __cplusplus > } > #endif > diff --git a/lib/fuse_i.h b/lib/fuse_i.h > index 54466f6..978d610 100644 > --- a/lib/fuse_i.h > +++ b/lib/fuse_i.h > @@ -64,6 +64,7 @@ struct fuse_session { > struct fuse_notify_req notify_list; > size_t bufsize; > int error; > + int use_socket; > }; > > struct fuse_chan { > diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c > index 42d3e03..0adacc3 100644 > --- a/lib/fuse_loop_mt.c > +++ b/lib/fuse_loop_mt.c > @@ -306,6 +306,11 @@ int fuse_session_loop_mt(struct fuse_session *se, int > clone_fd) > struct fuse_mt mt; > struct fuse_worker *w; > > + /* Multi-thread not supported for socket mode */ > + if (se->use_socket) { > + fprintf(stderr, "fuse: multi-threaded not supported on > socket mode.\n"); > + return -ENOTSUP; > + } > memset(&mt, 0, sizeof(struct fuse_mt)); > mt.se = se; > mt.clone_fd = clone_fd; > diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c > index ccdb5a5..8392195 100644 > --- a/lib/fuse_lowlevel.c > +++ b/lib/fuse_lowlevel.c > @@ -26,6 +26,7 @@ > #include <errno.h> > #include <assert.h> > #include <sys/file.h> > +#include <sys/socket.h> > > #ifndef F_LINUX_SPECIFIC_BASE > #define F_LINUX_SPECIFIC_BASE 1024 > @@ -2617,6 +2618,92 @@ int fuse_session_receive_buf(struct fuse_session > *se, struct fuse_buf *buf) > return fuse_session_receive_buf_int(se, buf, NULL); > } > > +static int fuse_sock_recv(int fd, void *data, int len, int flags) > +{ > + int saved = len; > + > + while (len > 0) { > + int res; > + > + res = recv(fd, data, len, flags); > + if ((res == -1) && (errno == EAGAIN)) > + continue; > + if ((res == -1) || (res == 0)) > + return res; > + > + /* Re-do the entire read if reading header */ > + if ((res != len) && (flags & MSG_PEEK)) > + continue; > + > + len -= res; > + } > + > + return saved; > +} > + > +static int fuse_sock_read_req(int fd, void *data, int maxlen) > +{ > + struct fuse_in_header header; > + int res; > + > + res = fuse_sock_recv(fd, &header, sizeof(header), MSG_PEEK); > + if (res < sizeof(header)) > + goto out; /* -1 or 0 */ > + > + if (maxlen < header.len) { > + fprintf(stderr, > + "fuse: fuse_sock_read_req: buffer size too small: " > + "%d, required %d\n", > + maxlen, header.len); > + res = -1; > + errno = -EIO; > + goto out; > + } > + > + res = fuse_sock_recv(fd, data, header.len, 0); > +out: > + return res; > +} > + > +#ifdef HAVE_SPLICE > +static int fuse_sock_splice_req(int from, int to, int maxlen, int flags) > +{ > + struct fuse_in_header header; > + int res, len; > + > + res = fuse_sock_recv(from, &header, sizeof(header), MSG_PEEK); > + if (res < sizeof(header)) > + goto out; /* -1 or 0 */ > + > + if (maxlen < header.len) { > + fprintf(stderr, > + "fuse: fuse_sock_splice_req: buffer size too > small: " > + "%d, required %d\n", > + maxlen, header.len); > + res = -1; > + errno = -EIO; > + goto out; > + } > + > + len = header.len; > + while (len > 0) { > + res = splice(from, NULL, to, NULL, len, flags); > + if ((res == -1) && (errno == EAGAIN)) > + continue; > + if ((res == -1) || (res == 0)) > + goto out; > + len -= res; > + } > + > + return header.len; > + > +out: > + return res; > +} > +#endif > + > + > + > int fuse_session_receive_buf_int(struct fuse_session *se, struct > fuse_buf *buf, > struct fuse_chan *ch) > { > @@ -2647,8 +2734,16 @@ int fuse_session_receive_buf_int(struct > fuse_session *se, struct fuse_buf *buf, > goto fallback; > } > > - res = splice(ch ? ch->fd : se->fd, > - NULL, llp->pipe[1], NULL, bufsize, 0); > + if (se->use_socket){ > + res = fuse_sock_splice_req(ch ? ch->fd : se->fd, > + llp->pipe[1], bufsize, 0); > + if (res == 0) > + fuse_session_exit(se); > + } > + else { > + res = splice(ch ? ch->fd : se->fd, > + NULL, llp->pipe[1], NULL, bufsize, 0); > + } > err = errno; > > if (fuse_session_exited(se)) > @@ -2734,7 +2829,14 @@ fallback: > } > > restart: > - res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize); > + if (se->use_socket){ > + res = fuse_sock_read_req(ch ? ch->fd : se->fd, buf->mem, > se->bufsize); > + if (res == 0) > + fuse_session_exit(se); > + } > + else{ > + res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize); > + } > err = errno; > > if (fuse_session_exited(se)) > @@ -2851,6 +2953,7 @@ struct fuse_session *fuse_session_new(struct > fuse_args *args, > memcpy(&se->op, op, op_size); > se->owner = getuid(); > se->userdata = userdata; > + se->use_socket = 0; > > se->mo = mo; > return se; > @@ -2899,6 +3002,14 @@ error_out: > return -1; > } > > +int fuse_session_socket(struct fuse_session *se, int sock) > +{ > + se->fd = sock; > + se->mountpoint = NULL; > + se->use_socket = 1; > + return 0; > +} > + > int fuse_session_fd(struct fuse_session *se) > { > return se->fd; > diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript > index 5fa3264..ceb5c1c 100644 > --- a/lib/fuse_versionscript > +++ b/lib/fuse_versionscript > @@ -136,6 +136,7 @@ FUSE_3.1 { > global: > fuse_lib_help; > fuse_new_30; > + fuse_session_socket; > } FUSE_3.0; > > # Local Variables: > -- > 1.8.3.1 > > |