diff options
author | syl <syl@cvs.openbsd.org> | 2013-06-21 21:30:39 +0000 |
---|---|---|
committer | syl <syl@cvs.openbsd.org> | 2013-06-21 21:30:39 +0000 |
commit | 7c9f46e214219ed351634e9a7b91b5c3e5883787 (patch) | |
tree | 964ad9e5e1b3950dd77f8cda2ee0f0a30f588198 /sys/miscfs | |
parent | fc6c87c0c1329a7cd41957048b7c5e6e663dd563 (diff) |
Make fuse device clonable.
ok tedu@
Diffstat (limited to 'sys/miscfs')
-rw-r--r-- | sys/miscfs/fuse/fuse_device.c | 234 | ||||
-rw-r--r-- | sys/miscfs/fuse/fuse_vfsops.c | 20 |
2 files changed, 132 insertions, 122 deletions
diff --git a/sys/miscfs/fuse/fuse_device.c b/sys/miscfs/fuse/fuse_device.c index 2962488549e..ee2ad9c860c 100644 --- a/sys/miscfs/fuse/fuse_device.c +++ b/sys/miscfs/fuse/fuse_device.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fuse_device.c,v 1.2 2013/06/12 22:55:02 tedu Exp $ */ +/* $OpenBSD: fuse_device.c,v 1.3 2013/06/21 21:30:38 syl Exp $ */ /* * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com> * @@ -27,40 +27,36 @@ #include "fusefs_node.h" #include "fusefs.h" -#define FUSE_UNIT(dev) (minor(dev)) -#define FUSE_DEV2SC(a) (&fuse_softc[FUSE_UNIT(a)]) -#define DEVNAME(_s) ((_s)->sc_dev.dv_xname) - #ifdef FUSE_DEBUG -#define DPRINTF(fmt, arg...) printf("%s: " fmt, DEVNAME(sc), ##arg) +#define DPRINTF(fmt, arg...) printf("%s: " fmt, "fuse", ##arg) #else #define DPRINTF(fmt, arg...) #endif SIMPLEQ_HEAD(fusebuf_head, fusebuf); -struct fuse_softc { - struct fusefs_mnt *sc_fmp; - struct device sc_dev; - int sc_opened; +struct fuse_d { + struct fusefs_mnt *fd_fmp; + int fd_unit; - struct fusebuf_head sc_fbufs_in; - struct fusebuf_head sc_fbufs_wait; + /*fusebufs queues*/ + struct fusebuf_head fd_fbufs_in; + struct fusebuf_head fd_fbufs_wait; /* kq fields */ - struct selinfo sc_rsel; + struct selinfo fd_rsel; + LIST_ENTRY(fuse_d) fd_list; }; -#define FUSE_OPEN 1 -#define FUSE_CLOSE 0 -#define FUSE_DONE 2 - -struct fuse_softc *fuse_softc; -static int numfuse = 0; int stat_fbufs_in = 0; int stat_fbufs_wait = 0; int stat_opened_fusedev = 0; +LIST_HEAD(, fuse_d) fuse_d_list; +struct fuse_d *fuse_create(int); +struct fuse_d *fuse_lookup(int); +void fuse_destroy(dev_t dev, struct fuse_d *fd); + void fuseattach(int); int fuseopen(dev_t, int, int, struct proc *); int fuseclose(dev_t, int, int, struct proc *); @@ -118,6 +114,41 @@ fuse_dump_buff(char *buff, int len) } #endif +struct fuse_d * +fuse_lookup(int unit) +{ + struct fuse_d *fd; + + LIST_FOREACH(fd, &fuse_d_list, fd_list) + if (fd->fd_unit == unit) + return (fd); + return (NULL); +} + +struct fuse_d * +fuse_create(int unit) +{ + struct fuse_d *fd; + + if ((fd = fuse_lookup(unit)) != NULL) + return (NULL); + + fd = malloc(sizeof(*fd), M_DEVBUF, M_WAITOK | M_ZERO); + fd->fd_unit = unit; + SIMPLEQ_INIT(&fd->fd_fbufs_in); + SIMPLEQ_INIT(&fd->fd_fbufs_wait); + LIST_INSERT_HEAD(&fuse_d_list, fd, fd_list); + return (fd); +} + +void +fuse_destroy(dev_t dev, struct fuse_d *fd) +{ + LIST_REMOVE(fd, fd_list); + fuse_device_cleanup(dev, NULL); + free(fd, M_DEVBUF); +} + /* * if fbuf == NULL cleanup all msgs else remove fbuf from * sc_fbufs_in and sc_fbufs_wait. @@ -125,20 +156,19 @@ fuse_dump_buff(char *buff, int len) void fuse_device_cleanup(dev_t dev, struct fusebuf *fbuf) { - struct fuse_softc *sc; + struct fuse_d *fd; struct fusebuf *f; - if (FUSE_UNIT(dev) >= numfuse) + fd = fuse_lookup(minor(dev)); + if (fd == NULL) return; - sc = FUSE_DEV2SC(dev); - sc->sc_fmp = NULL; - + fd->fd_fmp = NULL; /* clear FIFO IN*/ - while ((f = SIMPLEQ_FIRST(&sc->sc_fbufs_in))) { + while ((f = SIMPLEQ_FIRST(&fd->fd_fbufs_in))) { if (fbuf == f || fbuf == NULL) { DPRINTF("cleanup unprocessed msg in sc_fbufs_in\n"); - SIMPLEQ_REMOVE_HEAD(&sc->sc_fbufs_in, fb_next); + SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_in, fb_next); stat_fbufs_in--; if (fbuf == NULL) pool_put(&fusefs_fbuf_pool, f); @@ -146,10 +176,10 @@ fuse_device_cleanup(dev_t dev, struct fusebuf *fbuf) } /* clear FIFO WAIT*/ - while ((f = SIMPLEQ_FIRST(&sc->sc_fbufs_wait))) { + while ((f = SIMPLEQ_FIRST(&fd->fd_fbufs_wait))) { if (fbuf == f || fbuf == NULL) { DPRINTF("umount unprocessed msg in sc_fbufs_wait\n"); - SIMPLEQ_REMOVE_HEAD(&sc->sc_fbufs_wait, fb_next); + SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_wait, fb_next); stat_fbufs_wait--; if (fbuf == NULL) pool_put(&fusefs_fbuf_pool, f); @@ -160,94 +190,66 @@ fuse_device_cleanup(dev_t dev, struct fusebuf *fbuf) void fuse_device_queue_fbuf(dev_t dev, struct fusebuf *fbuf) { - struct fuse_softc *sc; + struct fuse_d *fd; - if (FUSE_UNIT(dev) >= numfuse) + fd = fuse_lookup(minor(dev)); + if (fd == NULL) return; - sc = FUSE_DEV2SC(dev); - SIMPLEQ_INSERT_TAIL(&sc->sc_fbufs_in, fbuf, fb_next); + SIMPLEQ_INSERT_TAIL(&fd->fd_fbufs_in, fbuf, fb_next); stat_fbufs_in++; - selwakeup(&sc->sc_rsel); + selwakeup(&fd->fd_rsel); } void fuse_device_set_fmp(struct fusefs_mnt *fmp) { - struct fuse_softc *sc; + struct fuse_d *fd; - if (FUSE_UNIT(fmp->dev) >= numfuse) + fd = fuse_lookup(minor(fmp->dev)); + if (fd == NULL) return; - sc = FUSE_DEV2SC(fmp->dev); - sc->sc_fmp = fmp; + fd->fd_fmp = fmp; } void fuseattach(int num) { - char *mem; - u_long size; - int i; - - if (num <= 0) - return; - size = num * sizeof(struct fuse_softc); - mem = malloc(size, M_FUSEFS, M_NOWAIT | M_ZERO); - - if (mem == NULL) { - printf("fuse: WARNING no memory for fuse device\n"); - return; - } - fuse_softc = (struct fuse_softc *)mem; - for (i = 0; i < num; i++) { - struct fuse_softc *sc = &fuse_softc[i]; - - SIMPLEQ_INIT(&sc->sc_fbufs_in); - SIMPLEQ_INIT(&sc->sc_fbufs_wait); - sc->sc_dev.dv_unit = i; - snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname), - "fuse%d", i); - device_ref(&sc->sc_dev); - } - numfuse = num; + LIST_INIT(&fuse_d_list); } int fuseopen(dev_t dev, int flags, int fmt, struct proc * p) { - struct fuse_softc *sc; + struct fuse_d *fd; - if (FUSE_UNIT(dev) >= numfuse) - return (ENXIO); - - sc = FUSE_DEV2SC(dev); + if (flags & O_EXCL) + return (EBUSY); /* No exclusive opens */ - if (sc->sc_opened != FUSE_CLOSE || sc->sc_fmp) + if ((fd = fuse_create(minor(dev))) == NULL) return (EBUSY); - sc->sc_opened = FUSE_OPEN; stat_opened_fusedev++; - return (0); } int fuseclose(dev_t dev, int flags, int fmt, struct proc *p) { - struct fuse_softc *sc; + struct fuse_d *fd; - if (FUSE_UNIT(dev) >= numfuse) - return (ENXIO); + fd = fuse_lookup(minor(dev)); + if (fd == NULL) + return (EINVAL); - sc = FUSE_DEV2SC(dev); - if (sc->sc_fmp) { + if (fd->fd_fmp) { printf("libfuse close the device without umount\n"); - sc->sc_fmp->sess_init = 0; - sc->sc_fmp = NULL; + fd->fd_fmp->sess_init = 0; + fd->fd_fmp = NULL; } - sc->sc_opened = FUSE_CLOSE; + fuse_destroy(dev, fd); stat_opened_fusedev--; return (0); } @@ -255,13 +257,8 @@ fuseclose(dev_t dev, int flags, int fmt, struct proc *p) int fuseioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) { - struct fuse_softc *sc; int error = 0; - if (FUSE_UNIT(dev) >= numfuse) - return (ENXIO); - - sc = FUSE_DEV2SC(dev); switch (cmd) { default: DPRINTF("bad ioctl number %d\n", cmd); @@ -274,7 +271,7 @@ fuseioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) int fuseread(dev_t dev, struct uio *uio, int ioflag) { - struct fuse_softc *sc; + struct fuse_d *fd; struct fusebuf *fbuf; int error = 0; char *F_dat; @@ -282,20 +279,17 @@ fuseread(dev_t dev, struct uio *uio, int ioflag) int size; size_t len; - if (FUSE_UNIT(dev) >= numfuse) + fd = fuse_lookup(minor(dev)); + if (fd == NULL) return (ENXIO); - sc = FUSE_DEV2SC(dev); - if (sc->sc_opened != FUSE_OPEN) - return (ENODEV); - - if (SIMPLEQ_EMPTY(&sc->sc_fbufs_in)) { + if (SIMPLEQ_EMPTY(&fd->fd_fbufs_in)) { if (ioflag & O_NONBLOCK) return (EAGAIN); goto end; } - fbuf = SIMPLEQ_FIRST(&sc->sc_fbufs_in); + fbuf = SIMPLEQ_FIRST(&fd->fd_fbufs_in); /* * If it was not taken by last read @@ -339,9 +333,9 @@ fuseread(dev_t dev, struct uio *uio, int ioflag) * fbuf moves from a simpleq to another */ if (remain == 0) { - SIMPLEQ_REMOVE_HEAD(&sc->sc_fbufs_in, fb_next); + SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_in, fb_next); stat_fbufs_in--; - SIMPLEQ_INSERT_TAIL(&sc->sc_fbufs_wait, fbuf, fb_next); + SIMPLEQ_INSERT_TAIL(&fd->fd_fbufs_wait, fbuf, fb_next); stat_fbufs_wait++; } @@ -353,15 +347,15 @@ int fusewrite(dev_t dev, struct uio *uio, int ioflag) { struct fusebuf *lastfbuf; - struct fuse_softc *sc; + struct fuse_d *fd; struct fusebuf *fbuf; struct fb_hdr hdr; int error = 0; - if (FUSE_UNIT(dev) >= numfuse) + fd = fuse_lookup(minor(dev)); + if (fd == NULL) return (ENXIO); - sc = FUSE_DEV2SC(dev); if (uio->uio_resid < sizeof(hdr)) { return (EINVAL); } @@ -372,7 +366,7 @@ fusewrite(dev_t dev, struct uio *uio, int ioflag) if ((error = uiomove(&hdr, sizeof(hdr), uio)) != 0) return (error); - SIMPLEQ_FOREACH(fbuf, &sc->sc_fbufs_wait, fb_next) { + SIMPLEQ_FOREACH(fbuf, &fd->fd_fbufs_wait, fb_next) { if (fbuf->fb_uuid == hdr.fh_uuid) { DPRINTF("catch unique %lu\n", fbuf->fb_uuid); break; @@ -390,7 +384,7 @@ fusewrite(dev_t dev, struct uio *uio, int ioflag) if (uio->uio_resid != hdr.fh_len || (uio->uio_resid != 0 && hdr.fh_err) || - SIMPLEQ_EMPTY(&sc->sc_fbufs_wait)) { + SIMPLEQ_EMPTY(&fd->fd_fbufs_wait)) { printf("corrupted fuse header or queue empty\n"); return (EINVAL); } @@ -407,10 +401,10 @@ fusewrite(dev_t dev, struct uio *uio, int ioflag) if (!error) { switch (fbuf->fb_type) { case FBT_INIT: - sc->sc_fmp->sess_init = 1; + fd->fd_fmp->sess_init = 1; break ; case FBT_DESTROY: - sc->sc_fmp = NULL; + fd->fd_fmp = NULL; break ; } @@ -418,10 +412,10 @@ fusewrite(dev_t dev, struct uio *uio, int ioflag) } /* the fbuf could not be the HEAD fbuf */ - if (fbuf == SIMPLEQ_FIRST(&sc->sc_fbufs_wait)) - SIMPLEQ_REMOVE_HEAD(&sc->sc_fbufs_wait, fb_next); + if (fbuf == SIMPLEQ_FIRST(&fd->fd_fbufs_wait)) + SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_wait, fb_next); else - SIMPLEQ_REMOVE_AFTER(&sc->sc_fbufs_wait, lastfbuf, + SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_wait, lastfbuf, fb_next); stat_fbufs_wait--; @@ -437,15 +431,15 @@ fusewrite(dev_t dev, struct uio *uio, int ioflag) int fusepoll(dev_t dev, int events, struct proc *p) { - struct fuse_softc *sc; + struct fuse_d *fd; int revents = 0; - if (FUSE_UNIT(dev) >= numfuse) - return (ENXIO); + fd = fuse_lookup(minor(dev)); + if (fd == NULL) + return (EINVAL); - sc = FUSE_DEV2SC(dev); if (events & (POLLIN | POLLRDNORM)) - if (!SIMPLEQ_EMPTY(&sc->sc_fbufs_in)) + if (!SIMPLEQ_EMPTY(&fd->fd_fbufs_in)) revents |= events & (POLLIN | POLLRDNORM); if (events & (POLLOUT | POLLWRNORM)) @@ -453,7 +447,7 @@ fusepoll(dev_t dev, int events, struct proc *p) if (revents == 0) if (events & (POLLIN | POLLRDNORM)) - selrecord(p, &sc->sc_rsel); + selrecord(p, &fd->fd_rsel); return (revents); } @@ -461,27 +455,27 @@ fusepoll(dev_t dev, int events, struct proc *p) int fusekqfilter(dev_t dev, struct knote *kn) { - struct fuse_softc *sc; + struct fuse_d *fd; struct klist *klist; - if (FUSE_UNIT(dev) >= numfuse) - return (ENXIO); + fd = fuse_lookup(minor(dev)); + if (fd == NULL) + return (EINVAL); - sc = FUSE_DEV2SC(dev); switch (kn->kn_filter) { case EVFILT_READ: - klist = &sc->sc_rsel.si_note; + klist = &fd->fd_rsel.si_note; kn->kn_fop = &fuse_rd_filtops; break; case EVFILT_WRITE: - klist = &sc->sc_rsel.si_note; + klist = &fd->fd_rsel.si_note; kn->kn_fop = &fuse_seltrue_filtops; break; default: return (EINVAL); } - kn->kn_hook = sc; + kn->kn_hook = fd; SLIST_INSERT_HEAD(klist, kn, kn_selnext); @@ -491,8 +485,8 @@ fusekqfilter(dev_t dev, struct knote *kn) void filt_fuse_rdetach(struct knote *kn) { - struct fuse_softc *sc = kn->kn_hook; - struct klist *klist = &sc->sc_rsel.si_note; + struct fuse_d *fd = kn->kn_hook; + struct klist *klist = &fd->fd_rsel.si_note; SLIST_REMOVE(klist, kn, knote, kn_selnext); } @@ -500,10 +494,10 @@ filt_fuse_rdetach(struct knote *kn) int filt_fuse_read(struct knote *kn, long hint) { - struct fuse_softc *sc = kn->kn_hook; + struct fuse_d *fd = kn->kn_hook; int event = 0; - if (!SIMPLEQ_EMPTY(&sc->sc_fbufs_in)) + if (!SIMPLEQ_EMPTY(&fd->fd_fbufs_in)) event = 1; return (event); diff --git a/sys/miscfs/fuse/fuse_vfsops.c b/sys/miscfs/fuse/fuse_vfsops.c index fd6059c5780..2a1317395b4 100644 --- a/sys/miscfs/fuse/fuse_vfsops.c +++ b/sys/miscfs/fuse/fuse_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fuse_vfsops.c,v 1.4 2013/06/12 22:55:02 tedu Exp $ */ +/* $OpenBSD: fuse_vfsops.c,v 1.5 2013/06/21 21:30:38 syl Exp $ */ /* * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com> * @@ -16,9 +16,13 @@ */ #include <sys/param.h> +#include <sys/file.h> +#include <sys/filedesc.h> #include <sys/malloc.h> #include <sys/mount.h> #include <sys/pool.h> +#include <sys/proc.h> +#include <sys/specdev.h> #include <sys/statvfs.h> #include <sys/sysctl.h> #include <sys/vnode.h> @@ -69,6 +73,8 @@ fusefs_mount(struct mount *mp, const char *path, void *data, struct fusefs_mnt *fmp; struct fusebuf *fbuf; struct fusefs_args args; + struct vnode *vp; + struct file *fp; int error; if (mp->mnt_flag & MNT_UPDATE) @@ -78,10 +84,20 @@ fusefs_mount(struct mount *mp, const char *path, void *data, if (error) return (error); + if ((fp = fd_getfile(p->p_fd, args.fd)) == NULL) + return (EBADF); + + if (fp->f_type != DTYPE_VNODE) + return (EINVAL); + + vp = fp->f_data; + if (vp->v_type != VCHR) + return (EBADF); + fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO); fmp->mp = mp; fmp->sess_init = 0; - fmp->dev = args.dev; + fmp->dev = vp->v_rdev; mp->mnt_data = fmp; mp->mnt_flag |= MNT_LOCAL; |