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


   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  27 /*        All Rights Reserved   */
  28 
  29 /*
  30  * University Copyright- Copyright (c) 1982, 1986, 1988
  31  * The Regents of the University of California
  32  * All Rights Reserved
  33  *
  34  * University Acknowledgment- Portions of this document are derived from
  35  * software developed by the University of California, Berkeley, and its
  36  * contributors.
  37  */
  38 
  39 
  40 #pragma ident   "@(#)ufs_vfsops.c       2.275   07/10/25 SMI"
  41 
  42 #include <sys/types.h>
  43 #include <sys/t_lock.h>
  44 #include <sys/param.h>
  45 #include <sys/systm.h>
  46 #include <sys/bitmap.h>
  47 #include <sys/sysmacros.h>
  48 #include <sys/kmem.h>
  49 #include <sys/signal.h>
  50 #include <sys/user.h>
  51 #include <sys/proc.h>
  52 #include <sys/disp.h>
  53 #include <sys/buf.h>
  54 #include <sys/pathname.h>
  55 #include <sys/vfs.h>
  56 #include <sys/vfs_opreg.h>
  57 #include <sys/vnode.h>
  58 #include <sys/file.h>
  59 #include <sys/atomic.h>
  60 #include <sys/uio.h>


 249         return (mod_info(&modlinkage, modinfop));
 250 }
 251 
 252 extern struct vnode *makespecvp(dev_t dev, vtype_t type);
 253 
 254 extern kmutex_t ufs_scan_lock;
 255 
 256 static int mountfs(struct vfs *, enum whymountroot, struct vnode *, char *,
 257                 struct cred *, int, void *, int);
 258 
 259 
 260 static int
 261 ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
 262         struct cred *cr)
 263 
 264 {
 265         char *data = uap->dataptr;
 266         int datalen = uap->datalen;
 267         dev_t dev;
 268         struct vnode *bvp;


 269         struct pathname dpn;
 270         int error;
 271         enum whymountroot why = ROOT_INIT;
 272         struct ufs_args args;
 273         int oflag, aflag;
 274         int fromspace = (uap->flags & MS_SYSSPACE) ?
 275             UIO_SYSSPACE : UIO_USERSPACE;
 276 
 277         if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
 278                 return (error);
 279 
 280         if (mvp->v_type != VDIR)
 281                 return (ENOTDIR);
 282 
 283         mutex_enter(&mvp->v_lock);
 284         if ((uap->flags & MS_REMOUNT) == 0 &&
 285             (uap->flags & MS_OVERLAY) == 0 &&
 286             (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
 287                 mutex_exit(&mvp->v_lock);
 288                 return (EBUSY);


 291 
 292         /*
 293          * Get arguments
 294          */
 295         bzero(&args, sizeof (args));
 296         if ((uap->flags & MS_DATA) && data != NULL && datalen != 0) {
 297                 int copy_result = 0;
 298 
 299                 if (datalen > sizeof (args))
 300                         return (EINVAL);
 301                 if (uap->flags & MS_SYSSPACE)
 302                         bcopy(data, &args, datalen);
 303                 else
 304                         copy_result = copyin(data, &args, datalen);
 305                 if (copy_result)
 306                         return (EFAULT);
 307                 datalen = sizeof (struct ufs_args);
 308         } else {
 309                 datalen = 0;
 310         }










 311         /*
 312          * Read in the mount point pathname
 313          * (so we can record the directory the file system was last mounted on).
 314          */
 315         if (error = pn_get(uap->dir, fromspace, &dpn))
 316                 return (error);
 317 
 318         /*
 319          * Resolve path name of special file being mounted.
 320          */
 321         if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &bvp)) {
 322                 pn_free(&dpn);
 323                 return (error);
 324         }
 325         if (bvp->v_type != VBLK) {
 326                 VN_RELE(bvp);



 327                 pn_free(&dpn);









 328                 return (ENOTBLK);
 329         }








 330         dev = bvp->v_rdev;
 331         if (getmajor(dev) >= devcnt) {
 332                 pn_free(&dpn);
 333                 VN_RELE(bvp);



 334                 return (ENXIO);
 335         }
 336         if (uap->flags & MS_REMOUNT)
 337                 why = ROOT_REMOUNT;
 338 
 339         /*
 340          * In SunCluster, requests to a global device are satisfied by
 341          * a local device. We substitute the global pxfs node with a
 342          * local spec node here.





 343          */
 344         if (IS_PXFSVP(bvp)) {
 345                 VN_RELE(bvp);


 346                 bvp = makespecvp(dev, VBLK);
 347         }
 348 
 349         /*
 350          * Open block device mounted on.  We need this to
 351          * check whether the caller has sufficient rights to
 352          * access the device in question.
 353          * When bio is fixed for vnodes this can all be vnode
 354          * operations.
 355          */
 356         if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
 357             (uap->flags & MS_RDONLY) != 0) {
 358                 oflag = FREAD;
 359                 aflag = VREAD;
 360         } else {
 361                 oflag = FREAD | FWRITE;
 362                 aflag = VREAD | VWRITE;
 363         }
 364         if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
 365             (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
 366                 pn_free(&dpn);
 367                 VN_RELE(bvp);



 368                 return (error);
 369         }
 370 
 371         /*
 372          * Ensure that this device isn't already mounted or in progress on a
 373          * mount unless this is a REMOUNT request or we are told to suppress
 374          * mount checks. Global mounts require special handling.
 375          */
 376         if ((uap->flags & MS_NOCHECK) == 0) {
 377                 if ((uap->flags & MS_GLOBAL) == 0 &&
 378                     vfs_devmounting(dev, vfsp)) {
 379                         pn_free(&dpn);
 380                         VN_RELE(bvp);



 381                         return (EBUSY);
 382                 }
 383                 if (vfs_devismounted(dev)) {
 384                         if ((uap->flags & MS_REMOUNT) == 0) {
 385                                 pn_free(&dpn);
 386                                 VN_RELE(bvp);



 387                                 return (EBUSY);
 388                         }
 389                 }
 390         }
 391 
 392         /*
 393          * If the device is a tape, mount it read only
 394          */
 395         if (devopsp[getmajor(dev)]->devo_cb_ops->cb_flag & D_TAPE) {
 396                 vfsp->vfs_flag |= VFS_RDONLY;
 397                 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
 398         }
 399         if (uap->flags & MS_RDONLY)
 400                 vfsp->vfs_flag |= VFS_RDONLY;
 401 
 402         /*
 403          * Mount the filesystem, free the device vnode on error.
 404          */
 405         error = mountfs(vfsp, why, bvp, dpn.pn_path, cr, 0, &args, datalen);
 406         pn_free(&dpn);

 407         if (error) {
 408                 VN_RELE(bvp);









 409         }

 410         if (error == 0)
 411                 vfs_set_feature(vfsp, VFSFT_XVATTR);
 412         return (error);
 413 }
 414 /*
 415  * Mount root file system.
 416  * "why" is ROOT_INIT on initial call ROOT_REMOUNT if called to
 417  * remount the root file system, and ROOT_UNMOUNT if called to
 418  * unmount the root (e.g., as part of a system shutdown).
 419  *
 420  * XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP
 421  * operation, goes along with auto-configuration.  A mechanism should be
 422  * provided by which machine-INdependent code in the kernel can say "get me the
 423  * right root file system" and "get me the right initial swap area", and have
 424  * that done in what may well be a machine-dependent fashion.
 425  * Unfortunately, it is also file-system-type dependent (NFS gets it via
 426  * bootparams calls, UFS gets it from various and sundry machine-dependent
 427  * mechanisms, as SPECFS does for swap).
 428  */
 429 static int




   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  27 /*        All Rights Reserved   */
  28 
  29 /*
  30  * University Copyright- Copyright (c) 1982, 1986, 1988
  31  * The Regents of the University of California
  32  * All Rights Reserved
  33  *
  34  * University Acknowledgment- Portions of this document are derived from
  35  * software developed by the University of California, Berkeley, and its
  36  * contributors.
  37  */
  38 
  39 
  40 #pragma ident   "@(#)ufs_vfsops.c       2.276   08/05/07 SMI"
  41 
  42 #include <sys/types.h>
  43 #include <sys/t_lock.h>
  44 #include <sys/param.h>
  45 #include <sys/systm.h>
  46 #include <sys/bitmap.h>
  47 #include <sys/sysmacros.h>
  48 #include <sys/kmem.h>
  49 #include <sys/signal.h>
  50 #include <sys/user.h>
  51 #include <sys/proc.h>
  52 #include <sys/disp.h>
  53 #include <sys/buf.h>
  54 #include <sys/pathname.h>
  55 #include <sys/vfs.h>
  56 #include <sys/vfs_opreg.h>
  57 #include <sys/vnode.h>
  58 #include <sys/file.h>
  59 #include <sys/atomic.h>
  60 #include <sys/uio.h>


 249         return (mod_info(&modlinkage, modinfop));
 250 }
 251 
 252 extern struct vnode *makespecvp(dev_t dev, vtype_t type);
 253 
 254 extern kmutex_t ufs_scan_lock;
 255 
 256 static int mountfs(struct vfs *, enum whymountroot, struct vnode *, char *,
 257                 struct cred *, int, void *, int);
 258 
 259 
 260 static int
 261 ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
 262         struct cred *cr)
 263 
 264 {
 265         char *data = uap->dataptr;
 266         int datalen = uap->datalen;
 267         dev_t dev;
 268         struct vnode *bvp;
 269         struct vnode *lvp = NULL;
 270         struct vnode *svp = NULL;
 271         struct pathname dpn;
 272         int error;
 273         enum whymountroot why = ROOT_INIT;
 274         struct ufs_args args;
 275         int oflag, aflag;
 276         int fromspace = (uap->flags & MS_SYSSPACE) ?
 277             UIO_SYSSPACE : UIO_USERSPACE;
 278 
 279         if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
 280                 return (error);
 281 
 282         if (mvp->v_type != VDIR)
 283                 return (ENOTDIR);
 284 
 285         mutex_enter(&mvp->v_lock);
 286         if ((uap->flags & MS_REMOUNT) == 0 &&
 287             (uap->flags & MS_OVERLAY) == 0 &&
 288             (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
 289                 mutex_exit(&mvp->v_lock);
 290                 return (EBUSY);


 293 
 294         /*
 295          * Get arguments
 296          */
 297         bzero(&args, sizeof (args));
 298         if ((uap->flags & MS_DATA) && data != NULL && datalen != 0) {
 299                 int copy_result = 0;
 300 
 301                 if (datalen > sizeof (args))
 302                         return (EINVAL);
 303                 if (uap->flags & MS_SYSSPACE)
 304                         bcopy(data, &args, datalen);
 305                 else
 306                         copy_result = copyin(data, &args, datalen);
 307                 if (copy_result)
 308                         return (EFAULT);
 309                 datalen = sizeof (struct ufs_args);
 310         } else {
 311                 datalen = 0;
 312         }
 313 
 314         if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
 315             (uap->flags & MS_RDONLY) != 0) {
 316                 oflag = FREAD;
 317                 aflag = VREAD;
 318         } else {
 319                 oflag = FREAD | FWRITE;
 320                 aflag = VREAD | VWRITE;
 321         }
 322 
 323         /*
 324          * Read in the mount point pathname
 325          * (so we can record the directory the file system was last mounted on).
 326          */
 327         if (error = pn_get(uap->dir, fromspace, &dpn))
 328                 return (error);
 329 
 330         /*
 331          * Resolve path name of special file being mounted.
 332          */
 333         if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &svp)) {
 334                 pn_free(&dpn);
 335                 return (error);
 336         }
 337 
 338         error = vfs_get_lofi(vfsp, &lvp);
 339 
 340         if (error > 0) {
 341                 VN_RELE(svp);
 342                 pn_free(&dpn);
 343                 return (error);
 344         } else if (error == 0) {
 345                 bvp = lvp;
 346         } else {
 347                 bvp = svp;
 348 
 349                 if (svp->v_type != VBLK) {
 350                         VN_RELE(svp);
 351                         pn_free(&dpn);
 352                         return (ENOTBLK);
 353                 }
 354 
 355                 if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0) {
 356                         VN_RELE(svp);
 357                         pn_free(&dpn);
 358                         return (error);
 359                 }
 360         }
 361 
 362         dev = bvp->v_rdev;
 363         if (getmajor(dev) >= devcnt) {
 364                 pn_free(&dpn);
 365                 if (lvp != NULL)
 366                         VN_RELE(lvp);
 367                 if (svp != NULL)
 368                         VN_RELE(svp);
 369                 return (ENXIO);
 370         }
 371         if (uap->flags & MS_REMOUNT)
 372                 why = ROOT_REMOUNT;
 373 
 374         /*
 375          * In SunCluster, requests to a global device are satisfied by a
 376          * local device. We substitute the global pxfs node with a local
 377          * spec node here.
 378          *
 379          * Open device/file mounted on.  We need this to check whether
 380          * the caller has sufficient rights to access the resource in
 381          * question.  When bio is fixed for vnodes this can all be vnode
 382          * operations.
 383          */
 384         if (IS_PXFSVP(bvp)) {
 385                 ASSERT(lvp == NULL);
 386                 VN_RELE(svp);
 387                 svp = NULL;
 388                 bvp = makespecvp(dev, VBLK);
 389                 error = VOP_ACCESS(bvp, aflag, 0, cr, NULL);












 390         } else {
 391                 error = VOP_ACCESS(svp, aflag, 0, cr, NULL);

 392         }
 393 
 394         if (error != 0) {
 395                 pn_free(&dpn);
 396                 if (lvp != NULL)
 397                         VN_RELE(lvp);
 398                 if (svp != NULL)
 399                         VN_RELE(svp);
 400                 return (error);
 401         }
 402 
 403         /*
 404          * Ensure that this device isn't already mounted or in progress on a
 405          * mount unless this is a REMOUNT request or we are told to suppress
 406          * mount checks. Global mounts require special handling.
 407          */
 408         if ((uap->flags & MS_NOCHECK) == 0) {
 409                 if ((uap->flags & MS_GLOBAL) == 0 &&
 410                     vfs_devmounting(dev, vfsp)) {
 411                         pn_free(&dpn);
 412                         if (lvp != NULL)
 413                                 VN_RELE(lvp);
 414                         if (svp != NULL)
 415                                 VN_RELE(svp);
 416                         return (EBUSY);
 417                 }
 418                 if (vfs_devismounted(dev)) {
 419                         if ((uap->flags & MS_REMOUNT) == 0) {
 420                                 pn_free(&dpn);
 421                                 if (lvp != NULL)
 422                                         VN_RELE(lvp);
 423                                 if (svp != NULL)
 424                                         VN_RELE(svp);
 425                                 return (EBUSY);
 426                         }
 427                 }
 428         }
 429 
 430         /*
 431          * If the device is a tape, mount it read only
 432          */
 433         if (devopsp[getmajor(dev)]->devo_cb_ops->cb_flag & D_TAPE) {
 434                 vfsp->vfs_flag |= VFS_RDONLY;
 435                 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
 436         }
 437         if (uap->flags & MS_RDONLY)
 438                 vfsp->vfs_flag |= VFS_RDONLY;
 439 
 440         /*
 441          * Mount the filesystem, free the device vnode on error.
 442          */
 443         error = mountfs(vfsp, why, bvp, dpn.pn_path, cr, 0, &args, datalen);
 444         pn_free(&dpn);
 445 
 446         if (error) {
 447                 if (lvp != NULL)
 448                         VN_RELE(lvp);
 449                 if (svp != NULL)
 450                         VN_RELE(svp);
 451         } else {
 452                 /*
 453                  * If lofi, drop our reference to the original file.
 454                  */
 455                 if (lvp != NULL)
 456                         VN_RELE(svp);
 457         }
 458 
 459         if (error == 0)
 460                 vfs_set_feature(vfsp, VFSFT_XVATTR);
 461         return (error);
 462 }
 463 /*
 464  * Mount root file system.
 465  * "why" is ROOT_INIT on initial call ROOT_REMOUNT if called to
 466  * remount the root file system, and ROOT_UNMOUNT if called to
 467  * unmount the root (e.g., as part of a system shutdown).
 468  *
 469  * XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP
 470  * operation, goes along with auto-configuration.  A mechanism should be
 471  * provided by which machine-INdependent code in the kernel can say "get me the
 472  * right root file system" and "get me the right initial swap area", and have
 473  * that done in what may well be a machine-dependent fashion.
 474  * Unfortunately, it is also file-system-type dependent (NFS gets it via
 475  * bootparams calls, UFS gets it from various and sundry machine-dependent
 476  * mechanisms, as SPECFS does for swap).
 477  */
 478 static int