PERFORCE change 194686 for review
Ilya Putsikau
ilya at FreeBSD.org
Mon Jun 13 15:39:13 UTC 2011
http://p4web.freebsd.org/@@194686?ac=10
Change 194686 by ilya at ilya_triton2011 on 2011/06/13 15:38:33
Fix mount and unmount, remove secondary mounts support
Affected files ...
.. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vfsops.c#11 edit
Differences ...
==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vfsops.c#11 (text+ko) ====
@@ -64,322 +64,209 @@
MALLOC_DEFINE(M_FUSEVFS, "fuse_filesystem", "buffer for fuse vfs layer");
-extern struct vop_vector fuse_vnops;
+#define FUSE_FLAGOPT(fnam, fval) do { \
+ vfs_flagopt(opts, #fnam, &mntopts, fval); \
+ vfs_flagopt(opts, "__" #fnam, &__mntopts, fval); \
+} while (0)
-/*************
- *
- * >>> VFS ops
- *
- *************/
-
-/*
- * Mount system call
- */
static int
fuse_vfs_mount(struct mount *mp)
{
- struct thread *td = curthread;
- int err = 0;
- size_t len;
- char *fspec, *subtype = NULL;
- struct vnode *devvp;
- struct vfsoptlist *opts;
- struct nameidata nd, *ndp = &nd;
- struct cdev *fdev;
- struct sx *slock;
- struct fuse_data *data;
- int mntopts = 0, __mntopts = 0, max_read_set = 0, secondary = 0;
- unsigned max_read = ~0;
- struct vnode *rvp;
- struct fuse_vnode_data *fvdat;
+ size_t len;
+ int err = 0;
+ int mntopts = 0;
+ int __mntopts = 0;
+ int max_read_set = 0;
+ unsigned int max_read = ~0;
+
+ struct cdev *fdev;
+ struct fuse_data *data;
+ struct thread *td = curthread;
+ char *fspec, *subtype = NULL;
+ struct vnode *devvp;
+ struct vfsoptlist *opts;
+ struct nameidata nd, *ndp = &nd;
+
+ fuse_trace_printf_vfsop();
- GIANT_REQUIRED;
- KASSERT(fuse_useco >= 0,
- ("negative fuse usecount despite Giant"));
+ GIANT_REQUIRED;
+ KASSERT(fuse_useco >= 0,
+ ("negative fuse usecount despite Giant"));
- if (mp->mnt_flag & MNT_UPDATE)
- return (EOPNOTSUPP);
+ if (mp->mnt_flag & MNT_UPDATE)
+ return (EOPNOTSUPP);
- mp->mnt_flag |= MNT_SYNCHRONOUS;
- /* Get the new options passed to mount */
- opts = mp->mnt_optnew;
+ mp->mnt_flag |= MNT_SYNCHRONOUS;
+ /* Get the new options passed to mount */
+ opts = mp->mnt_optnew;
- if (!opts)
- return (EINVAL);
+ if (!opts)
+ return (EINVAL);
- /* `fspath' contains the mount point (eg. /mnt/fuse/sshfs); REQUIRED */
- if (!vfs_getopts(opts, "fspath", &err))
- return (err);
+ /* `fspath' contains the mount point (eg. /mnt/fuse/sshfs); REQUIRED */
+ if (!vfs_getopts(opts, "fspath", &err))
+ return (err);
- /* `from' contains the device name (eg. /dev/fuse0); REQUIRED */
- fspec = vfs_getopts(opts, "from", &err);
- if (!fspec)
- return (err);
+ /* `from' contains the device name (eg. /dev/fuse0); REQUIRED */
+ fspec = vfs_getopts(opts, "from", &err);
+ if (!fspec)
+ return (err);
- mp->mnt_data = NULL;
+ mp->mnt_data = NULL;
- /*
- * Not an update, or updating the name: look up the name
- * and verify that it refers to a sensible disk device.
- */
+ /*
+ * Not an update, or updating the name: look up the name
+ * and verify that it refers to a sensible disk device.
+ */
- NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td);
- if ((err = namei(ndp)) != 0)
- return (err);
- NDFREE(ndp, NDF_ONLY_PNBUF);
- devvp = ndp->ni_vp;
+ NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td);
+ if ((err = namei(ndp)) != 0)
+ return (err);
+ NDFREE(ndp, NDF_ONLY_PNBUF);
+ devvp = ndp->ni_vp;
- if (devvp->v_type != VCHR) {
- vrele(devvp);
- return (ENXIO);
- }
+ if (devvp->v_type != VCHR) {
+ vrele(devvp);
+ return (ENXIO);
+ }
- fdev = devvp->v_rdev;
- dev_ref(fdev);
+ fdev = devvp->v_rdev;
+ dev_ref(fdev);
- if (fuse_enforce_dev_perms) {
- /*
- * Check if mounter can open the fuse device.
- *
- * This has significance only if we are doing a secondary mount
- * which doesn't involve actually opening fuse devices, but we
- * still want to enforce the permissions of the device (in
- * order to keep control over the circle of fuse users).
- *
- * (In case of primary mounts, we are either the superuser so
- * we can do anything anyway, or we can mount only if the
- * device is already opened by us, ie. we are permitted to open
- * the device.)
- */
+ if (fuse_enforce_dev_perms) {
+ /*
+ * Check if mounter can open the fuse device.
+ *
+ * This has significance only if we are doing a secondary mount
+ * which doesn't involve actually opening fuse devices, but we
+ * still want to enforce the permissions of the device (in
+ * order to keep control over the circle of fuse users).
+ *
+ * (In case of primary mounts, we are either the superuser so
+ * we can do anything anyway, or we can mount only if the
+ * device is already opened by us, ie. we are permitted to open
+ * the device.)
+ */
#ifdef MAC
- err = mac_check_vnode_open(td->td_ucred, devvp, VREAD|VWRITE);
- if (! err)
+ err = mac_check_vnode_open(td->td_ucred, devvp, VREAD|VWRITE);
+ if (! err)
#endif
- err = VOP_ACCESS(devvp, VREAD|VWRITE, td->td_ucred, td);
- if (err) {
- vrele(devvp);
- return (err);
- }
- }
+ err = VOP_ACCESS(devvp, VREAD|VWRITE, td->td_ucred, td);
+ if (err) {
+ vrele(devvp);
+ return (err);
+ }
+ }
- /*
- * according to coda code, no extra lock is needed --
- * although in sys/vnode.h this field is marked "v"
- */
- vrele(devvp);
+ /*
+ * according to coda code, no extra lock is needed --
+ * although in sys/vnode.h this field is marked "v"
+ */
+ vrele(devvp);
- FUSE_LOCK;
- if (! fdev->si_devsw ||
- strcmp("fuse", fdev->si_devsw->d_name)) {
- FUSE_UNLOCK;
- return (ENXIO);
- }
+ FUSE_LOCK();
+ if (!fdev->si_devsw ||
+ strcmp("fuse", fdev->si_devsw->d_name)) {
+ FUSE_UNLOCK();
+ return (ENXIO);
+ }
- if ((data = fusedev_get_data(fdev)) &&
- data->dataflag & FSESS_OPENED)
- data->mntco++;
- else {
- FUSE_UNLOCK;
- dev_rel(fdev);
- return (ENXIO);
- }
- FUSE_UNLOCK;
+ data = fusedev_get_data(fdev);
+ if (data && data->dataflag & FSESS_OPENED) {
+ data->mntco++;
+ debug_printf("a.inc:mntco = %d\n", data->mntco);
+ } else {
+ FUSE_UNLOCK();
+ dev_rel(fdev);
+ return (ENXIO);
+ }
+ FUSE_UNLOCK();
- /*
- * With the help of underscored options the mount program
- * can inform us from the flags it sets by default
- */
-#define FUSE_FLAGOPT(fnam, fval) do { \
- vfs_flagopt(opts, #fnam, &mntopts, fval); \
- vfs_flagopt(opts, "__" #fnam, &__mntopts, fval); \
-} while (0)
- FUSE_FLAGOPT(private, FSESS_PRIVATE);
- FUSE_FLAGOPT(neglect_shares, FSESS_NEGLECT_SHARES);
- FUSE_FLAGOPT(allow_other, FSESS_DAEMON_CAN_SPY);
- FUSE_FLAGOPT(push_symlinks_in, FSESS_PUSH_SYMLINKS_IN);
- FUSE_FLAGOPT(default_permissions, FSESS_DEFAULT_PERMISSIONS);
+ /*
+ * With the help of underscored options the mount program
+ * can inform us from the flags it sets by default
+ */
+ FUSE_FLAGOPT(private, FSESS_PRIVATE);
+ FUSE_FLAGOPT(neglect_shares, FSESS_NEGLECT_SHARES);
+ FUSE_FLAGOPT(allow_other, FSESS_DAEMON_CAN_SPY);
+ FUSE_FLAGOPT(push_symlinks_in, FSESS_PUSH_SYMLINKS_IN);
+ FUSE_FLAGOPT(default_permissions, FSESS_DEFAULT_PERMISSIONS);
+#ifdef XXXIP
#if FUSE_HAS_DESTROY
- FUSE_FLAGOPT(sync_unmount, FSESS_SYNC_UNMOUNT);
+ FUSE_FLAGOPT(sync_unmount, FSESS_SYNC_UNMOUNT);
+#endif
#endif
-#undef FUSE_FLAGOPT
- if (vfs_scanopt(opts, "max_read=", "%u", &max_read) == 1)
- max_read_set = 1;
- subtype = vfs_getopts(opts, "subtype=", &err);
- err = 0;
+ if (vfs_scanopt(opts, "max_read=", "%u", &max_read) == 1)
+ max_read_set = 1;
+ subtype = vfs_getopts(opts, "subtype=", &err);
+ err = 0;
- if (fdata_kick_get(data))
- err = ENOTCONN;
- if (mntopts & FSESS_DAEMON_CAN_SPY)
- err = priv_check(td, PRIV_VFS_FUSE_ALLOWOTHER);
+ if (fdata_kick_get(data))
+ err = ENOTCONN;
+ if (mntopts & FSESS_DAEMON_CAN_SPY)
+ err = priv_check(td, PRIV_VFS_FUSE_ALLOWOTHER);
- slock = &data->mhierlock;
- /* Note that sx_try_xlock returns 0 on _failure_ */
- if (! err && sx_try_xlock(slock) == 0) {
- err = EBUSY;
- DEBUG2G("lock contested\n");
- }
+ DEBUG2G("mntopts 0x%x\n", mntopts);
- if (err)
- goto out;
+ /* Sanity + permission checks */
- DEBUG2G("mntopts 0x%x\n", mntopts);
+ if (!data->daemoncred)
+ panic("fuse daemon found, but identity unknown");
- /* Sanity + permission checks */
+ MPASS(data->mpri != FM_PRIMARY);
+ if (td->td_ucred->cr_uid != data->daemoncred->cr_uid)
+ /* are we allowed to do the first mount? */
+ err = priv_check(td, PRIV_VFS_FUSE_MOUNT_NONUSER);
- if (! data->daemoncred)
- panic("fuse daemon found, but identity unknown");
+ if (err) {
+ goto out;
+ }
- if (data->mpri == FM_PRIMARY) {
- secondary = 1;
- if (data->dataflag & FSESS_PRIVATE)
- /*
- * device is owned and owner doesn't
- * wanna share it with us
- */
- err = EPERM;
- if (/* actual option set differs from default */
- mntopts != __mntopts ||
- max_read_set || subtype)
- /*
- * Secondary mounts not allowed to have
- * options (basicly, that would be
- * useless though harmless, just let's
- * be explicit about it)
- */
- err = EINVAL;
- } else {
- if (td->td_ucred->cr_uid != data->daemoncred->cr_uid)
- /* are we allowed to do the first mount? */
- err = priv_check(td, PRIV_VFS_FUSE_MOUNT_NONUSER);
- }
+ /* We need this here as this slot is used by getnewvnode() */
+ mp->mnt_stat.f_iosize = MAXBSIZE;
- if (err) {
- sx_xunlock(slock);
- goto out;
- }
+ mp->mnt_data = data;
- /* We need this here as this slot is used by getnewvnode() */
- mp->mnt_stat.f_iosize = MAXBSIZE;
+ data->mp = mp;
+ data->mpri = FM_PRIMARY;
+ data->dataflag |= mntopts;
+ data->max_read = max_read;
+#ifdef XXXIP
+ if (!priv_check(td, PRIV_VFS_FUSE_SYNC_UNMOUNT))
+ data->dataflag |= FSESS_CAN_SYNC_UNMOUNT;
+#endif
- if (secondary) {
- struct fuse_secondary_data *fsdat;
-
- fsdat = malloc(sizeof(*fsdat), M_FUSEVFS, M_WAITOK| M_ZERO);
- fsdat->mpri = FM_SECONDARY;
- mp->mnt_data = fsdat;
- fsdat->mp = mp;
- fsdat->master = data;
-
- LIST_INSERT_HEAD(&data->slaves_head, fsdat, slaves_link);
-
- goto rootdone;
- }
-
- mp->mnt_data = data;
-
- /* code stolen from portalfs */
-
- fvdat = malloc(sizeof(*fvdat), M_FUSEVN, M_WAITOK | M_ZERO);
-
- err = getnewvnode("fuse", mp, &fuse_vnops, &rvp);
- if (! err) {
- err = vn_lock(rvp, LK_EXCLUSIVE | LK_RETRY);
- if (err)
- printf("fuse4bsd: leaking vnode %p\n", rvp);
- }
-
- if (! err) {
- /*
- * FUSE_ROOT_ID 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.
- */
- rvp->v_hash = FUSE_ROOT_ID;
- data->rvp = rvp;
- fuse_vnode_init(rvp, fvdat, FUSE_ROOT_ID, VNON, 0);
- rvp->v_vflag |= VV_ROOT;
- err = insmntque(rvp, mp);
- }
-
- if (err) {
- fdata_kick_set(data);
- sx_xunlock(slock);
- free(fvdat, M_FUSEVN);
- goto out;
- } else
- VOP_UNLOCK(rvp, 0);
- data->mp = mp;
- data->mpri = FM_PRIMARY;
- data->dataflag |= mntopts;
- data->max_read = max_read;
- if (! priv_check(td, PRIV_VFS_FUSE_SYNC_UNMOUNT))
- data->dataflag |= FSESS_CAN_SYNC_UNMOUNT;
-
-rootdone:
-
- sx_xunlock(slock);
-
- vfs_getnewfsid(mp);
- mp->mnt_flag |= MNT_LOCAL;
-#ifdef MNTK_MPSAFE
- mp->mnt_kern_flag |= MNTK_MPSAFE;
+ vfs_getnewfsid(mp);
+ mp->mnt_flag |= MNT_LOCAL;
+#ifdef XXXIP
+ mp->mnt_kern_flag |= MNTK_MPSAFE;
#endif
- if (subtype) {
- strlcat(mp->mnt_stat.f_fstypename, ".", MFSNAMELEN);
- strlcat(mp->mnt_stat.f_fstypename, subtype, MFSNAMELEN);
- }
- copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &len);
- if (secondary && 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 (data->mntco > lim) {
- lim *= 10;
- log++;
- }
- if (log >= MNAMELEN - len) {
- mp->mnt_stat.f_mntfromname[len] = '?';
- len++;
- } else {
- sprintf(mp->mnt_stat.f_mntfromname + len, "%d",
- data->mntco - 1);
- len += log;
- }
- }
- }
- bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len);
- DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
+ if (subtype) {
+ strlcat(mp->mnt_stat.f_fstypename, ".", MFSNAMELEN);
+ strlcat(mp->mnt_stat.f_fstypename, subtype, MFSNAMELEN);
+ }
+ copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &len);
+ bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len);
+ DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);
- if (! secondary)
- /* Now handshaking with daemon */
- fuse_internal_send_init(data, td);
+ /* Now handshaking with daemon */
+ fuse_internal_send_init(data, td);
out:
- if (err ) {
- data->mntco--;
- FUSE_LOCK;
- if (data->mntco == 0 && ! (data->dataflag & FSESS_OPENED)) {
- fdev->si_drv1 = NULL;
- fdata_destroy(data);
- }
- FUSE_UNLOCK;
- dev_rel(fdev);
- }
- return (err);
+ if (err) {
+ data->mntco--;
+ FUSE_LOCK();
+ if (data->mntco == 0 && ! (data->dataflag & FSESS_OPENED)) {
+ fdev->si_drv1 = NULL;
+ fdata_destroy(data);
+ }
+ FUSE_UNLOCK();
+ dev_rel(fdev);
+ }
+ return (err);
}
-/*
- * Unmount system call
- */
static int
fuse_vfs_unmount(struct mount *mp, int mntflags)
{
@@ -388,101 +275,60 @@
struct fuse_data *data;
struct cdev *fdev;
- struct fuse_secondary_data *fsdat = NULL;
- struct thread *td = curthread;
+ struct fuse_dispatcher fdi;
+ struct thread *td = curthread;
fuse_trace_printf_vfsop();
GIANT_REQUIRED;
- /* Flag handling */
if (mntflags & MNT_FORCE) {
flags |= FORCECLOSE;
}
data = fusefs_get_data(mp);
if (!data) {
- fsdat = fusefs_get_secdata(mp);
- data = fsdat->master;
+ panic("no private data for mount point?");
}
- if (sx_try_xlock(&data->mhierlock) == 0) {
- DEBUG2G("lock contested\n");
- return (EBUSY);
+ /* There is 1 extra root vnode reference (mp->mnt_data). */
+ err = vflush(mp, 1, flags, td);
+ if (err) {
+ debug_printf("vflush failed");
+ return (err);
}
- if (! fsdat) {
-#if _DEBUG
- struct vnode *vp, *nvp;
-#endif
- if (! (mntflags & MNT_FORCE ||
- data->dataflag & FSESS_NEGLECT_SHARES ||
- LIST_EMPTY(&data->slaves_head))) {
- err = EBUSY;
- goto unlock;
- }
-
-#if _DEBUG
- MNT_ILOCK(mp);
- DEBUG2G("vnodes:\n");
- MNT_VNODE_FOREACH(vp, mp, nvp) {
- DEBUG2G("\n");
- vn_printf(vp, "...");
- }
- MNT_IUNLOCK(mp);
-#endif
-
- /* Flush files -> vflush */
- /* There is 1 extra root vnode reference (mp->mnt_data). */
- if ((err = vflush(mp, 1, flags, td))) {
- DEBUG2G("err %d\n", err);
- goto unlock;
- }
+ if (fdata_kick_get(data)) {
+ goto alreadydead;
}
- if (fsdat) {
- LIST_REMOVE(fsdat, slaves_link);
- free(fsdat, M_FUSEVFS);
- } else {
-#if FUSE_HAS_DESTROY
- if (data->dataflag & FSESS_SYNC_UNMOUNT &&
- ((sync_unmount == 1 &&
- data->dataflag & FSESS_CAN_SYNC_UNMOUNT) ||
- sync_unmount == 2) &&
- !(mntflags & MNT_FORCE)) {
- struct fuse_dispatcher fdi;
-
- fdisp_init(&fdi, 0);
- fdisp_make(&fdi, mp, FUSE_DESTROY, FUSE_ROOT_ID, td,
- NULL);
- fdisp_wait_answ(&fdi);
- /* ignore return value */
- }
-#endif
- fdata_kick_set(data);
-
- data->mpri = FM_NOMOUNTED;
+ fdisp_init(&fdi, 0);
+ fdisp_make(&fdi, mp, FUSE_DESTROY, 0, td, NULL);
+ err = fdisp_wait_answ(&fdi);
+ if (!err) {
+ fuse_ticket_drop(fdi.tick);
}
-unlock:
- sx_xunlock(&data->mhierlock);
- if (err)
- return (err);
+ fdata_kick_set(data);
+alreadydead:
+ data->mpri = FM_NOMOUNTED;
data->mntco--;
- FUSE_LOCK;
+ FUSE_LOCK();
fdev = data->fdev;
if (data->mntco == 0 && !(data->dataflag & FSESS_OPENED)) {
data->fdev->si_drv1 = NULL;
fdata_destroy(data);
}
- FUSE_UNLOCK;
- dev_rel(fdev);
+ FUSE_UNLOCK();
+
+ MNT_ILOCK(mp);
mp->mnt_data = NULL;
+ mp->mnt_flag &= ~MNT_LOCAL;
+ MNT_IUNLOCK(mp);
- /* Other guys do this, I don't know what it is good for... */
- mp->mnt_flag &= ~MNT_LOCAL;
+ dev_rel(fdev);
return (0);
}
More information about the p4-projects
mailing list