Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Jun 2011 15:39:12 GMT
From:      Ilya Putsikau <ilya@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 194686 for review
Message-ID:  <201106131539.p5DFdCTY074674@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@194686?ac=10

Change 194686 by ilya@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);
 }        



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106131539.p5DFdCTY074674>