Print this page
PSARC 2008/290 lofi mount
6384817 Need persistent lofi based mounts and direct mount(1m) support for lofi

@@ -17,11 +17,11 @@
  * information: Portions Copyright [yyyy] [name of copyright owner]
  *
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
 /*        All Rights Reserved   */

@@ -35,11 +35,11 @@
  * software developed by the University of California, Berkeley, and its
  * contributors.
  */
 
 
-#pragma ident   "@(#)ufs_vfsops.c       2.275   07/10/25 SMI"
+#pragma ident   "@(#)ufs_vfsops.c       2.276   08/05/07 SMI"
 
 #include <sys/types.h>
 #include <sys/t_lock.h>
 #include <sys/param.h>
 #include <sys/systm.h>

@@ -264,10 +264,12 @@
 {
         char *data = uap->dataptr;
         int datalen = uap->datalen;
         dev_t dev;
         struct vnode *bvp;
+        struct vnode *lvp = NULL;
+        struct vnode *svp = NULL;
         struct pathname dpn;
         int error;
         enum whymountroot why = ROOT_INIT;
         struct ufs_args args;
         int oflag, aflag;

@@ -306,10 +308,20 @@
                         return (EFAULT);
                 datalen = sizeof (struct ufs_args);
         } else {
                 datalen = 0;
         }
+
+        if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
+            (uap->flags & MS_RDONLY) != 0) {
+                oflag = FREAD;
+                aflag = VREAD;
+        } else {
+                oflag = FREAD | FWRITE;
+                aflag = VREAD | VWRITE;
+        }
+
         /*
          * Read in the mount point pathname
          * (so we can record the directory the file system was last mounted on).
          */
         if (error = pn_get(uap->dir, fromspace, &dpn))

@@ -316,57 +328,77 @@
                 return (error);
 
         /*
          * Resolve path name of special file being mounted.
          */
-        if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &bvp)) {
+        if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &svp)) {
                 pn_free(&dpn);
                 return (error);
         }
-        if (bvp->v_type != VBLK) {
-                VN_RELE(bvp);
+
+        error = vfs_get_lofi(vfsp, &lvp);
+
+        if (error > 0) {
+                VN_RELE(svp);
                 pn_free(&dpn);
+                return (error);
+        } else if (error == 0) {
+                bvp = lvp;
+        } else {
+                bvp = svp;
+
+                if (svp->v_type != VBLK) {
+                        VN_RELE(svp);
+                        pn_free(&dpn);
                 return (ENOTBLK);
         }
+
+                if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0) {
+                        VN_RELE(svp);
+                        pn_free(&dpn);
+                        return (error);
+                }
+        }
+
         dev = bvp->v_rdev;
         if (getmajor(dev) >= devcnt) {
                 pn_free(&dpn);
-                VN_RELE(bvp);
+                if (lvp != NULL)
+                        VN_RELE(lvp);
+                if (svp != NULL)
+                        VN_RELE(svp);
                 return (ENXIO);
         }
         if (uap->flags & MS_REMOUNT)
                 why = ROOT_REMOUNT;
 
         /*
-         * In SunCluster, requests to a global device are satisfied by
-         * a local device. We substitute the global pxfs node with a
-         * local spec node here.
+         * In SunCluster, requests to a global device are satisfied by a
+         * local device. We substitute the global pxfs node with a local
+         * spec node here.
+         *
+         * Open device/file mounted on.  We need this to check whether
+         * the caller has sufficient rights to access the resource in
+         * question.  When bio is fixed for vnodes this can all be vnode
+         * operations.
          */
         if (IS_PXFSVP(bvp)) {
-                VN_RELE(bvp);
+                ASSERT(lvp == NULL);
+                VN_RELE(svp);
+                svp = NULL;
                 bvp = makespecvp(dev, VBLK);
-        }
-
-        /*
-         * Open block device mounted on.  We need this to
-         * check whether the caller has sufficient rights to
-         * access the device in question.
-         * When bio is fixed for vnodes this can all be vnode
-         * operations.
-         */
-        if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
-            (uap->flags & MS_RDONLY) != 0) {
-                oflag = FREAD;
-                aflag = VREAD;
+                error = VOP_ACCESS(bvp, aflag, 0, cr, NULL);
         } else {
-                oflag = FREAD | FWRITE;
-                aflag = VREAD | VWRITE;
+                error = VOP_ACCESS(svp, aflag, 0, cr, NULL);
         }
-        if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
-            (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
+
+        if (error != 0) {
                 pn_free(&dpn);
-                VN_RELE(bvp);
+                if (lvp != NULL)
+                        VN_RELE(lvp);
+                if (svp != NULL)
+                        VN_RELE(svp);
                 return (error);
         }
 
         /*
          * Ensure that this device isn't already mounted or in progress on a

@@ -375,17 +407,23 @@
          */
         if ((uap->flags & MS_NOCHECK) == 0) {
                 if ((uap->flags & MS_GLOBAL) == 0 &&
                     vfs_devmounting(dev, vfsp)) {
                         pn_free(&dpn);
-                        VN_RELE(bvp);
+                        if (lvp != NULL)
+                                VN_RELE(lvp);
+                        if (svp != NULL)
+                                VN_RELE(svp);
                         return (EBUSY);
                 }
                 if (vfs_devismounted(dev)) {
                         if ((uap->flags & MS_REMOUNT) == 0) {
                                 pn_free(&dpn);
-                                VN_RELE(bvp);
+                                if (lvp != NULL)
+                                        VN_RELE(lvp);
+                                if (svp != NULL)
+                                        VN_RELE(svp);
                                 return (EBUSY);
                         }
                 }
         }
 

@@ -402,13 +440,24 @@
         /*
          * Mount the filesystem, free the device vnode on error.
          */
         error = mountfs(vfsp, why, bvp, dpn.pn_path, cr, 0, &args, datalen);
         pn_free(&dpn);
+
         if (error) {
-                VN_RELE(bvp);
+                if (lvp != NULL)
+                        VN_RELE(lvp);
+                if (svp != NULL)
+                        VN_RELE(svp);
+        } else {
+                /*
+                 * If lofi, drop our reference to the original file.
+                 */
+                if (lvp != NULL)
+                        VN_RELE(svp);
         }
+
         if (error == 0)
                 vfs_set_feature(vfsp, VFSFT_XVATTR);
         return (error);
 }
 /*