Go to sshfs' directory. First prepare the mount:
- You have to use forced unmount for a Fuse filesystem. The reason for this as follows:
+ You have to use forced unmount for a Fuse filesystem. The reason for this is as follows:
With traditional filesystems, relations between fs entities are permanently stored in some background storage; but when one uses the filesystem, the fs hierarchy is built up and maintained by the kernel, and this what's transported to the userspace so that we get the usual "filesystem feeling".
==== //depot/projects/soc2005/fuse4bsd2/fuse_module/Makefile#3 (text+ko) ====
@@ -6,11 +6,11 @@
.endif
.if defined(DEBUG)
-CFLAGS+= -D_DEBUG -g
+DEBUG_FLAGS+= -D_DEBUG -g
.endif
.if defined(DEBUG2G)
-CFLAGS+= -D_DEBUG2G -g
+DEBUG_FLAGS+= -D_DEBUG2G -g
.endif
.if defined(DEBUG_MSGING)
@@ -27,7 +27,7 @@
KMOD=fuse
-CLEANFILES+= fuse_kernel.h fuse_opnames.c fuse_opnames.o fmaster.o vnode_if.h vnode_if_typedef.h vnode_if_newproto.h
+CLEANFILES+= fuse_kernel.h fuse_opnames.c fuse_opnames.o fmaster.o vnode_if.h vnode_if_typedef.h vnode_if_newproto.h fuse.ko.debug
fuse.ko: fuse_kernel.h vnode_if.h vnode_if_typedef.h vnode_if_newproto.h
@@ -47,7 +47,4 @@
vnode_if_newproto.h:
awk -f /sys/tools/vnode_if.awk /sys/kern/vnode_if.src -p
-nonstripped: fuse.ko
- ld -Bshareable -d -warn-common -o fuse.ko fuse.kld
-
.include
==== //depot/projects/soc2005/fuse4bsd2/fuse_module/fuse.c#5 (text+ko) ====
@@ -47,6 +47,10 @@
#define __static static
#endif
+#ifndef ROOTLESS_SHARES
+#define ROOTLESS_SHARES 1
+#endif
+
MALLOC_DEFINE(M_FUSEMSG, "fuse messaging",
"buffer for fuse messaging related things");
@@ -137,17 +141,30 @@
static __inline int fuse_ohead_audit(struct fuse_out_header *ohead, struct uio *uio);
__static int fuse_body_audit(struct fuse_callback_node *caliban, size_t blen);
-static __inline void fuse_setup_ihead(struct fuse_in_header *ihead, struct fuse_ticket *tick, uint64_t nid, enum fuse_opcode op, struct thread* td, struct ucred *cred);
+static __inline void fuse_setup_ihead(struct fuse_in_header *ihead,
+ struct fuse_ticket *tick, uint64_t nid,
+ enum fuse_opcode op, size_t blen,
+ struct thread* td, struct ucred *cred);
__static __inline struct sx *fusedev_get_lock(struct cdev *fdev);
__static __inline struct fuse_data *fusedev_get_data(struct cdev *fdev);
static int fdisp_get_vopdata(struct fuse_dispatcher *fdip, struct mount *mp);
-static void fdisp_prepare_msg(struct fuse_dispatcher *fdip, enum fuse_opcode op, uint64_t nid, struct thread *td, struct ucred *cred);
-static __inline int fdisp_prepare_all(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct vnode *vp, struct thread *td, struct ucred *cred);
+static void fdisp_prepare_msg(struct fuse_dispatcher *fdip,
+ enum fuse_opcode op, uint64_t nid,
+ struct thread *td, struct ucred *cred);
+static __inline int fdisp_prepare_all(struct fuse_dispatcher *fdip,
+ enum fuse_opcode op, struct vnode *vp,
+ struct thread *td, struct ucred *cred);
__static int fdisp_wait_answ(struct fuse_dispatcher *fdip);
-static __inline int fdisp_simple_putget(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct vnode *vp, struct thread *td, struct ucred *cred);
+static __inline int fdisp_simple_putget(struct fuse_dispatcher *fdip,
+ enum fuse_opcode op, struct vnode *vp,
+ struct thread *td, struct ucred *cred);
static __inline int fuse_send_init(struct fuse_data *data, struct thread *td);
-static __inline int fuse_send_forget(struct mount *mp, struct thread *td, struct ucred *cred, uint64_t nodeid, uint64_t nlookup, struct fuse_dispatcher *fdip);
+static __inline int fuse_send_forget(struct mount *mp, struct thread *td,
+ struct ucred *cred, uint64_t nodeid,
+ uint64_t nlookup,
+
+ struct fuse_dispatcher *fdip);
/***************************************
@@ -462,6 +479,9 @@
data->freeticket_counter = 0;
data->daemoncred = crhold(cred);
+ /* sx_init(&data->shareslock, "lock for fuse shares consistency"); */
+ LIST_INIT(&data->fuse_shares_head);
+
return (data);
}
@@ -484,6 +504,8 @@
crfree(data->daemoncred);
+ /* sx_destroy(&data->shareslock); */
+
FREE(data,M_FUSEMSG);
}
@@ -491,7 +513,7 @@
fdata_kick_set(struct fuse_data *data)
{
mtx_lock(&data->msg_mtx);
- data->dataflag |= FU_KICK;
+ data->dataflag |= FDAT_KICK;
cv_signal(&data->msg_cv);
mtx_unlock(&data->msg_mtx);
}
@@ -499,7 +521,7 @@
static __inline int
fdata_kick_get(struct fuse_data *data)
{
- return (data->dataflag & FU_KICK);
+ return (data->dataflag & FDAT_KICK);
}
/* <== fuse_data methods */
@@ -702,7 +724,7 @@
err = blen == sizeof(struct fuse_entry_out) ? 0 : EINVAL;
break;
case FUSE_FORGET:
- KASSERT(0, ("a handler has been intalled for FUSE_FORGET"));
+ panic("a handler has been intalled for FUSE_FORGET");
break;
case FUSE_GETATTR:
err = blen == sizeof(struct fuse_attr_out) ? 0 : EINVAL;
@@ -764,16 +786,16 @@
err = blen == 0 ? 0 : EINVAL;
break;
case FUSE_SETXATTR:
- KASSERT(0, ("FUSE_SETXATTR implementor has forgotten to define a response body format check"));
+ panic("FUSE_SETXATTR implementor has forgotten to define a response body format check");
break;
case FUSE_GETXATTR:
- KASSERT(0, ("FUSE_GETXATTR implementor has forgotten to define a response body format check"));
+ panic("FUSE_GETXATTR implementor has forgotten to define a response body format check");
break;
case FUSE_LISTXATTR:
- KASSERT(0, ("FUSE_LISTXATTR implementor has forgotten to define a response body format check"));
+ panic("FUSE_LISTXATTR implementor has forgotten to define a response body format check");
break;
case FUSE_REMOVEXATTR:
- KASSERT(0, ("FUSE_REMOVEXATTR implementor has forgotten to define a response body format check"));
+ panic("FUSE_REMOVEXATTR implementor has forgotten to define a response body format check");
break;
case FUSE_INIT:
err = blen == sizeof(struct fuse_init_in_out) ? 0 : EINVAL;
@@ -793,20 +815,28 @@
case FUSE_FSYNCDIR:
err = blen == 0 ? 0 : EINVAL;
break;
+#ifdef FUSE_GETLK
case FUSE_GETLK:
- KASSERT(0, ("FUSE_GETLK implementor has forgotten to define a response body format check"));
+ panic("FUSE_GETLK implementor has forgotten to define a response body format check");
break;
+#endif
+#ifdef FUSE_SETLK
case FUSE_SETLK:
- KASSERT(0, ("FUSE_SETLK implementor has forgotten to define a response body format check"));
+ panic("FUSE_SETLK implementor has forgotten to define a response body format check");
break;
+#endif
+#ifdef FUSE_SETLKW
case FUSE_SETLKW:
- KASSERT(0, ("FUSE_SETLKW implementor has forgotten to define a response body format check"));
+ panic("FUSE_SETLKW implementor has forgotten to define a response body format check");
break;
+#endif
+#ifdef FUSE_ACCESS
case FUSE_ACCESS:
- KASSERT(0, ("FUSE_ACCESS implementor has forgotten to define a response body format check"));
+ panic("FUSE_ACCESS implementor has forgotten to define a response body format check");
break;
+#endif
default:
- KASSERT(0, ("fuse opcodes out of sync"));
+ panic("fuse opcodes out of sync");
}
if (err)
@@ -824,10 +854,10 @@
static __inline void
fuse_setup_ihead(struct fuse_in_header *ihead, struct fuse_ticket *tick,
- uint64_t nid, enum fuse_opcode op, struct thread* td,
- struct ucred *cred)
+ uint64_t nid, enum fuse_opcode op, size_t blen,
+ struct thread* td, struct ucred *cred)
{
- ihead->len = 0; /* actually not used by lib */
+ ihead->len = sizeof(ihead) + blen; /* actually not used by lib */
ihead->unique = tick->unique;
ihead->nodeid = nid;
ihead->opcode = op;
@@ -905,6 +935,18 @@
*
****************************/
+#define FUSEREF \
+do { \
+ mtx_lock(&fuse_useco_mtx); \
+ if (fuse_useco < 0) { \
+ /* Module unload is going on */ \
+ mtx_unlock(&fuse_useco_mtx); \
+ return (ENOENT); \
+ } else \
+ fuse_useco++; \
+ mtx_unlock(&fuse_useco_mtx); \
+} while (0)
+
/*
* Resources are set up on a per-open basis
*/
@@ -917,14 +959,7 @@
if (dev->si_usecount > 1)
return (EBUSY);
- mtx_lock(&fuse_useco_mtx);
- if (fuse_useco < 0) {
- /* Module unload is going on */
- mtx_unlock(&fuse_useco_mtx);
- return (ENOENT);
- } else
- fuse_useco++;
- mtx_unlock(&fuse_useco_mtx);
+ FUSEREF;
data = fdata_alloc(td->td_ucred);
@@ -1023,7 +1058,7 @@
* (There is no much use of a partial read here...)
*/
if (uio->uio_resid < fmsgn->msg.len) {
- data->dataflag |= FU_KICK;
+ data->dataflag |= FDAT_KICK;
err = ENODEV;
}
@@ -1194,7 +1229,7 @@
FUSE_DIMALLOC(&fdip->tick->msgn.msg, fdip->finh,
fdip->indata, fdip->iosize);
- fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, td, cred);
+ fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, td, cred);
}
/* prev. two in one */
@@ -1565,7 +1600,8 @@
fuse_mount(struct mount *mp, struct thread *td)
{
int err = 0;
- int len;
+ int len, sharecount = 0;
+ int sharing = 0;
char *fspec;
struct vnode *devvp;
struct vfsoptlist *opts;
@@ -1577,6 +1613,10 @@
struct vnode *rvp;
struct fuse_vnode_data *fvdat;
+#define SHAREDMOUNT 0x1
+#define PRIVMOUNT 0x2
+#define IS_SHARED(sh) (!((sh) & PRIVMOUNT))
+
if (mp->mnt_flag & MNT_UPDATE) {
uprintf("fuse: updating mounts is not supported\n");
return (EOPNOTSUPP);
@@ -1606,6 +1646,14 @@
return (err);
if (!fspec || fspec[len - 1] != '\0')
return (EINVAL);
+
+/*
+ vfs_flagopt(opts, "shared", sharing, SHAREDMOUNT);
+ */
+ vfs_flagopt(opts, "private", &sharing, PRIVMOUNT);
+
+ FUSEREF;
+
/*
* Not an update, or updating the name: look up the name
* and verify that it refers to a sensible disk device.
@@ -1613,13 +1661,14 @@
NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td);
if ((err = namei(ndp)) != 0)
- return (err);
+ goto out;
NDFREE(ndp, NDF_ONLY_PNBUF);
devvp = ndp->ni_vp;
if (devvp->v_type != VCHR) {
vrele(devvp);
- return (ENXIO);
+ err = ENXIO;
+ goto out;
}
fdev = devvp->v_rdev;
@@ -1632,7 +1681,8 @@
if (! fdev->si_devsw ||
strcmp("fuse", fdev->si_devsw->d_name) ||
! (slock = fusedev_get_lock(fdev))) {
- return (ENXIO);
+ err = ENXIO;
+ goto out;
}
MALLOC(fmnt, struct fuse_mnt_data *, sizeof(*fmnt), M_FUSEFS,
@@ -1643,17 +1693,13 @@
if (fmnt->mntopts & FUSEFS_DAEMON_CAN_SPY && suser(td)) {
uprintf("only root can use \"allow_other\"\n");
free(fmnt, M_FUSEFS);
- return (EPERM);
+ err = EPERM;
+ goto out;
}
-#if ! REALTIME_TRACK_UNPRIVPROCDBG
- fmnt->mntopts &= ~FUSEFS_UNPRIVPROCDBG;
- fmnt->mntopts |= get_unprivileged_proc_debug(td) ? FUSEFS_UNPRIVPROCDBG : 0;
-#endif
-
DEBUG2G("mntopts 0x%x\n", fmnt->mntopts);
- sx_slock(slock);
+ sx_xlock(slock);
/* Sanity + permission checks */
@@ -1670,42 +1716,80 @@
uprintf("fuse daemon found, but has been backlisted\n");
}
- if ((! err) && suser(td)) {
- if (td->td_ucred->cr_uid != data->daemoncred->cr_uid) {
- err = EPERM;
- uprintf("attempt to mount other user's daemon\n");
+ if (!err) {
+ if (data->mp) {
+ if (! (data->dataflag & FDAT_SHARED &&
+ IS_SHARED(sharing)))
+ /*
+ * device is owned and either us or owner
+ * insits on a private mount
+ */
+ goto deny;
+ } else {
+ if (suser(td) &&
+ td->td_ucred->cr_uid != data->daemoncred->cr_uid)
+ /* we are not allowed to do the first mount */
+ goto deny;
}
+ goto allow;
+deny:
+ err = EPERM;
}
+allow:
if (err) {
- sx_sunlock(slock);
+ sx_xunlock(slock);
FREE(fmnt, M_FUSEFS);
- return (err);
+ goto out;
}
- /* Now handshaking with daemon */
+ if (data->mp) {
+ struct fuse_share *fsh;
+ MALLOC(fsh, struct fuse_share *, sizeof(*fsh),
+ M_FUSEFS, M_WAITOK);
+ fsh->uid = td->td_ucred->cr_uid;
+ fsh->master = data->mp;
+ LIST_INSERT_HEAD(&data->fuse_shares_head, fsh,
+ fuse_shares_link);
+ fmnt->share = fsh;
+ LIST_FOREACH(fsh, &data->fuse_shares_head,
+ fuse_shares_link)
+ sharecount++;
+ } else {
+ /* Now handshaking with daemon */
- if ((err = fuse_send_init(data, td))) {
- /*
- * Something went wrong with sending init --
- * eg., bad version number
- * Thus we tell the daemon it's time to get off
- */
- fdata_kick_set(data);
-
- sx_sunlock(slock);
- FREE(fmnt, M_FUSEFS);
- return (err);
+ if ((err = fuse_send_init(data, td))) {
+ /*
+ * Something went wrong with sending init --
+ * eg., bad version number
+ * Thus we tell the daemon it's time to get off
+ */
+ fdata_kick_set(data);
+
+ sx_xunlock(slock);
+ FREE(fmnt, M_FUSEFS);
+ goto out;
+ }
+ if (IS_SHARED(sharing))
+ data->dataflag |= FDAT_SHARED;
}
- sx_sunlock(slock);
/* We need this here as this slot is used by getnewvnode() */
mp->mnt_stat.f_iosize = PAGE_SIZE;
+ mp->mnt_data = fmnt;
+#if ROOTLESS_SHARES
+ if (fmnt->share)
+ goto rootdone;
+#endif
+
/* code stolen from portalfs */
- MALLOC(fvdat, struct fuse_vnode_data *, sizeof(*fvdat), M_FUSEFS,
- M_WAITOK | M_ZERO);
+ if (data->mp)
+ fvdat = ((struct fuse_mnt_data *)data->mp->mnt_data)->rvp->v_data;
+ else
+ MALLOC(fvdat, struct fuse_vnode_data *, sizeof(*fvdat),
+ M_FUSEFS, M_WAITOK | M_ZERO);
#if __FreeBSD_version >= 600000
err = getnewvnode("fuse", mp, &fuse_vnops, &rvp);
#else
@@ -1713,29 +1797,77 @@
#endif
if (err) {
- FREE(fmnt, M_FUSEFS);
- FREE(fvdat, M_FUSEFS);
- return (err);
+ if (data->mp) {
+ fdata_kick_set(data);
+ FREE(fmnt, M_FUSEFS);
+ FREE(fvdat, M_FUSEFS);
+ }
+ sx_xunlock(slock);
+ goto out;
}
/*
* FUSE_ROOT_INODE as an inode number will be resolved directly.
- * without resorting to the vfs hashing mechanism, thus it also can
- * be inserted directly to the v_hash slot.
+ * without resorting to the vfs hashing mechanism, thus it also
+ * can be inserted directly to the v_hash slot.
*/
rvp->v_hash = FUSE_ROOT_INODE;
+ fmnt->rvp = rvp;
fuse_vnode_init(rvp, fvdat, VDIR);
rvp->v_vflag |= VV_ROOT;
- fmnt->rvp = rvp;
+#if ROOTLESS_SHARES
+rootdone:
+#endif
+
+ if (! data->mp) {
+ data->mp = mp;
+#if ! REALTIME_TRACK_UNPRIVPROCDBG
+ fmnt->mntopts &= ~FUSEFS_UNPRIVPROCDBG;
+ fmnt->mntopts |= get_unprivileged_proc_debug(td) ? FUSEFS_UNPRIVPROCDBG : 0;
+#endif
+ }
+
+ sx_xunlock(slock);
+
vfs_getnewfsid(mp);
- mp->mnt_data = fmnt;
mp->mnt_flag |= MNT_LOCAL;
copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &len);
+ if (fmnt->share && len >= 1) {
+ /*
+ * I've considered using s1, s2,... for shares, instead
+ * #1, #2,... as s* is more conventional...
+ * Finally I chose #* as I feel it's more expressive
+ * and s* can be misleading (slices are strung up
+ * serially, shares exist in parallell)
+ */
+ mp->mnt_stat.f_mntfromname[len-1] = '#';
+ if (len < MNAMELEN - 1) {
+ /* Duhh, ain't there a better way of doing this? */
+ int log = 0, lim = 1;
+ while (sharecount >= lim) {
+ lim *= 10;
+ log++;
+ }
+ if (log >= MNAMELEN - len) {
+ mp->mnt_stat.f_mntfromname[len] = '?';
+ len++;
+ } else {
+ sprintf(mp->mnt_stat.f_mntfromname + len, "%d",
+ sharecount);
+ len += log;
+ }
+ }
+ }
bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len);
+ DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
- return (0);
+out:
+ if (err)
+ fuse_useco--;
+
+ return (err);
}
/*
@@ -1744,34 +1876,57 @@
static int
fuse_unmount(struct mount *mp, int mntflags, struct thread *td)
{
- int err, flags = 0;
+ int flags = 0, err = 0;
struct sx *slock;
struct fuse_data *data;
struct fuse_mnt_data *fmnt;
+ DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
/* Flag handling */
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- /* Flush files -> vflush */
- /* There is 1 extra root vnode reference (mp->mnt_data). */
- if ((err = vflush(mp, 1, flags, td)))
- return (err);
-
fmnt = mp->mnt_data;
slock = fusedev_get_lock(fmnt->fdev);
- sx_slock(slock);
- if ((data = fusedev_get_data(fmnt->fdev)))
+ sx_xlock(slock);
+ if (! (data = fusedev_get_data(fmnt->fdev)))
+ goto out;
+ if (fmnt->share)
+ LIST_REMOVE(fmnt->share, fuse_shares_link);
+ else {
+ if (! LIST_EMPTY(&data->fuse_shares_head)) {
+ sx_xunlock(slock);
+ return (EBUSY);
+ }
fdata_kick_set(data);
- sx_sunlock(slock);
+ }
+
+out:
+ sx_xunlock(slock);
+
+
+ if (
+#if ROOTLESS_SHARES
+ ! fmnt->share
+#else
+ 1
+#endif
+ ) {
+ /* Flush files -> vflush */
+ /* There is 1 extra root vnode reference (mp->mnt_data). */
+ if ((err = vflush(mp, 1, flags, td)))
+ return (err);
+ }
mp->mnt_data = NULL;
+ FREE(fmnt->share, M_FUSEFS);
FREE(fmnt, M_FUSEFS);
- /* Other guys do this, I don't know what is it good for... */
+ /* Other guys do this, I don't know what it is good for... */
mp->mnt_flag &= ~MNT_LOCAL;
+ fuse_useco--;
return (0);
}
@@ -1787,9 +1942,17 @@
/*
* Return locked reference to root.
*/
+ struct fuse_mnt_data *fmnt = mp->mnt_data;
struct vnode *vp;
- vp = ((struct fuse_mnt_data *)mp->mnt_data)->rvp;
+ DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
+
+#if ROOTLESS_SHARES
+ if (fmnt->share)
+ return fuse_root(fmnt->share->master, flags, vpp, td);
+#endif
+
+ vp = fmnt->rvp;
vref(vp);
VOP_UNLOCK(vp, 0, td);
vn_lock(vp, flags | LK_RETRY, td);
@@ -1802,10 +1965,18 @@
{
struct fuse_dispatcher fdi;
struct fuse_statfs_out *fsfo;
+ struct fuse_mnt_data *fmnt;
int err = 0;
- if ((err = fdisp_simple_putget(&fdi, FUSE_STATFS,
- ((struct fuse_mnt_data *)mp->mnt_data)->rvp, td, NULL)))
+ DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
+ fmnt = mp->mnt_data;
+
+#if ROOTLESS_SHARES
+ if (fmnt->share)
+ fmnt = (struct fuse_mnt_data *)fmnt->share->master->mnt_data;
+#endif
+
+ if ((err = fdisp_simple_putget(&fdi, FUSE_STATFS, fmnt->rvp, td, NULL)))
return (err);
fsfo = fdi.answ;
@@ -1834,10 +2005,12 @@
enum vtype vtyp, struct vnode **vpp)
{
int err = 0;
+ struct fuse_mnt_data *fmnt;
struct fuse_vnode_data *fvdat;
struct vnode *vp2;
int myflags = LK_EXCLUSIVE;
+ DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
DEBUG("been asked for vno #%llu\n", nodeid);
if (nodeid == FUSE_ROOT_INODE) {
@@ -1845,6 +2018,13 @@
return (err);
}
+ fmnt = mp->mnt_data;
+#if ! ROOTLESS_SHARES
+ if (fmnt->share)
+ mp = fmnt->share->master;
+#endif
+ DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
+
/* XXX nodeid: cast from 64 bytes to 32 */
if ((err = vfs_hash_get(mp, nodeid, /*flags*/ myflags, td, vpp, NULL, NULL)))
return (err);
@@ -1921,8 +2101,17 @@
vp->v_data = fvdat;
SETPARENT(vp, (VTOI(vp) == FUSE_ROOT_INODE) ? vp : NULL);
vp->v_type = vtyp;
- sx_init(&fvdat->fh_lock, "lock for fuse filehandles");
- LIST_INIT(&fvdat->fh_head);
+ if (
+#if ROOTLESS_SHARES
+ 1
+#else
+ ! ((struct fuse_mnt_data *)vp->v_mount->mnt_data)->share
+#endif
+ ) {
+
+ sx_init(&fvdat->fh_lock, "lock for fuse filehandles");
+ LIST_INIT(&fvdat->fh_head);
+ }
vp->v_bufobj.bo_ops = &fuse_bufops;
vp->v_bufobj.bo_private = vp;
@@ -1967,7 +2156,11 @@
* Taking down fuse_vnode_data structures is just hooked in here...
* no separate destructor.
*/
- if (fvdat) {
+ if (
+#if ! ROOTLESS_SHARES
+ ! ((struct fuse_mnt_data *)vp->v_mount->mnt_data)->share &&
+#endif
+ fvdat) {
sx_destroy(&fvdat->fh_lock);
FREE(fvdat, M_FUSEFS);
}
@@ -2143,6 +2336,15 @@
struct fuse_dispatcher fdi;
int err = 0;
+#if ! ROOTLESS_SHARES
+ if (VTOI(vp) == FUSE_ROOT_INODE) {
+ if (fmnt->share) {
+ fmnt = fmnt->share->master->mnt_data;
+ vp = fmnt->rvp;
+ }
+ }
+#endif
+
if ((err = fdisp_simple_putget(&fdi, FUSE_GETATTR, vp, td, cred)))
return (err);
@@ -2160,26 +2362,34 @@
* if she is *more* privileged than the daemon. This is to
* protect the power user from the daemon spying on her I/O
* operations.
- * Yes, it is a crude and blunt protection...
- * XXX there should be a sysctl interface to this.
- * Ideally not just a "daemon can spy bit", but some clever
- * data which determines in a compact but flexible way whose
- * daemon can spy on whom.
- * (Though controlling it via a mount option seems to be good
- * enough...)
+ *
+ * If a user wouldn't mind this, she can relax this check
+ * by doing a shared mount.
*/
- if (cr_candebug(
+ int denied;
+
+ if ((denied = cr_candebug(
#if REALTIME_TRACK_UNPRIVPROCDBG
get_unprivileged_proc_debug(td),
#else
((struct fuse_mnt_data *)vp->v_mount->mnt_data)->mntopts & FUSEFS_UNPRIVPROCDBG,
#endif
- fusedev_get_data(fdi.fdev)->daemoncred, cred))
+ fusedev_get_data(fdi.fdev)->daemoncred, cred)))
{
- sx_sunlock(fdi.slock);
- uprintf("Your access is blocked in order to prevent the fuse daemon spying on you\n (consider mounting with \"allow_other\")\n");
- return (EPERM);
+ struct fuse_share *fsh;
+
+ LIST_FOREACH(fsh, &fdi.data->fuse_shares_head, fuse_shares_link) {
+ if (! (denied = (fsh->uid != cred->cr_uid)))
+ break;
+ }
+
+ if (denied) {
+ sx_sunlock(fdi.slock);
+ uprintf("Your access is blocked in order to prevent the Fuse daemon spying on you.\n"
+ "To get further, you can do a shared mount, cf. mount_fusefs(8).\n");
+ return (EPERM);
+ }
}
}
sx_sunlock(fdi.slock);
@@ -2751,6 +2961,23 @@
struct file *fp = NULL;
>>> TRUNCATED FOR MAIL (1000 lines) <<<