1 /*
   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 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  22 /*        All Rights Reserved   */
  23 
  24 
  25 /*
  26  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  27  */
  28 
  29 /*
  30  * This file defines the vnode operations for mounted file descriptors.
  31  * The routines in this file act as a layer between the NAMEFS file
  32  * system and SPECFS/FIFOFS.  With the exception of nm_open(), nm_setattr(),
  33  * nm_getattr() and nm_access(), the routines simply apply the VOP operation
  34  * to the vnode representing the file descriptor.  This switches control
  35  * to the underlying file system to which the file descriptor belongs.
  36  */
  37 #include <sys/types.h>
  38 #include <sys/param.h>
  39 #include <sys/systm.h>
  40 #include <sys/cred.h>
  41 #include <sys/errno.h>
  42 #include <sys/time.h>
  43 #include <sys/file.h>
  44 #include <sys/fcntl.h>
  45 #include <sys/flock.h>
  46 #include <sys/kmem.h>
  47 #include <sys/uio.h>
  48 #include <sys/vfs.h>
  49 #include <sys/vfs_opreg.h>
  50 #include <sys/vnode.h>
  51 #include <sys/pcb.h>
  52 #include <sys/signal.h>
  53 #include <sys/user.h>
  54 #include <sys/proc.h>
  55 #include <sys/conf.h>
  56 #include <sys/debug.h>
  57 #include <vm/seg.h>
  58 #include <sys/fs/namenode.h>
  59 #include <sys/stream.h>
  60 #include <fs/fs_subr.h>
  61 #include <sys/policy.h>
  62 
  63 /*
  64  * Create a reference to the vnode representing the file descriptor.
  65  * Then, apply the VOP_OPEN operation to that vnode.
  66  *
  67  * The vnode for the file descriptor may be switched under you.
  68  * If it is, search the hash list for an nodep - nodep->nm_filevp
  69  * pair. If it exists, return that nodep to the user.
  70  * If it does not exist, create a new namenode to attach
  71  * to the nodep->nm_filevp then place the pair on the hash list.
  72  *
  73  * Newly created objects are like children/nodes in the mounted
  74  * file system, with the parent being the initial mount.
  75  */
  76 int
  77 nm_open(vnode_t **vpp, int flag, cred_t *crp, caller_context_t *ct)
  78 {
  79         struct namenode *nodep = VTONM(*vpp);
  80         int error = 0;
  81         struct namenode *newnamep;
  82         struct vnode *newvp;
  83         struct vnode *infilevp;
  84         struct vnode *outfilevp;
  85 
  86         /*
  87          * If the vnode is switched under us, the corresponding
  88          * VN_RELE for this VN_HOLD will be done by the file system
  89          * performing the switch. Otherwise, the corresponding
  90          * VN_RELE will be done by nm_close().
  91          */
  92         infilevp = outfilevp = nodep->nm_filevp;
  93         VN_HOLD(outfilevp);
  94 
  95         if ((error = VOP_OPEN(&outfilevp, flag, crp, ct)) != 0) {
  96                 VN_RELE(outfilevp);
  97                 return (error);
  98         }
  99         if (infilevp != outfilevp) {
 100                 /*
 101                  * See if the new filevp (outfilevp) is already associated
 102                  * with the mount point. If it is, then it already has a
 103                  * namenode associated with it.
 104                  */
 105                 mutex_enter(&ntable_lock);
 106                 if ((newnamep =
 107                     namefind(outfilevp, nodep->nm_mountpt)) != NULL) {
 108                         struct vnode *vp = NMTOV(newnamep);
 109 
 110                         VN_HOLD(vp);
 111                         goto gotit;
 112                 }
 113 
 114                 newnamep = kmem_zalloc(sizeof (struct namenode), KM_SLEEP);
 115                 newvp = vn_alloc(KM_SLEEP);
 116                 newnamep->nm_vnode = newvp;
 117 
 118                 mutex_init(&newnamep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
 119 
 120                 mutex_enter(&nodep->nm_lock);
 121                 newvp->v_flag = ((*vpp)->v_flag | VNOMAP | VNOSWAP) & ~VROOT;
 122                 vn_setops(newvp, vn_getops(*vpp));
 123                 newvp->v_vfsp = &namevfs;
 124                 newvp->v_stream = outfilevp->v_stream;
 125                 newvp->v_type = outfilevp->v_type;
 126                 newvp->v_rdev = outfilevp->v_rdev;
 127                 newvp->v_data = (caddr_t)newnamep;
 128                 vn_exists(newvp);
 129                 bcopy(&nodep->nm_vattr, &newnamep->nm_vattr, sizeof (vattr_t));
 130                 newnamep->nm_vattr.va_type = outfilevp->v_type;
 131                 newnamep->nm_vattr.va_nodeid = namenodeno_alloc();
 132                 newnamep->nm_vattr.va_size = (u_offset_t)0;
 133                 newnamep->nm_vattr.va_rdev = outfilevp->v_rdev;
 134                 newnamep->nm_flag = NMNMNT;
 135                 newnamep->nm_filevp = outfilevp;
 136                 newnamep->nm_filep = nodep->nm_filep;
 137                 newnamep->nm_mountpt = nodep->nm_mountpt;
 138                 mutex_exit(&nodep->nm_lock);
 139 
 140                 /*
 141                  * Insert the new namenode into the hash list.
 142                  */
 143                 nameinsert(newnamep);
 144 gotit:
 145                 mutex_exit(&ntable_lock);
 146                 /*
 147                  * Release the above reference to the infilevp, the reference
 148                  * to the NAMEFS vnode, create a reference to the new vnode
 149                  * and return the new vnode to the user.
 150                  */
 151                 VN_RELE(*vpp);
 152                 *vpp = NMTOV(newnamep);
 153         }
 154         return (0);
 155 }
 156 
 157 /*
 158  * Close a mounted file descriptor.
 159  * Remove any locks and apply the VOP_CLOSE operation to the vnode for
 160  * the file descriptor.
 161  */
 162 static int
 163 nm_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp,
 164         caller_context_t *ct)
 165 {
 166         struct namenode *nodep = VTONM(vp);
 167         int error = 0;
 168 
 169         (void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
 170         cleanshares(vp, ttoproc(curthread)->p_pid);
 171         error = VOP_CLOSE(nodep->nm_filevp, flag, count, offset, crp, ct);
 172         if (count == 1) {
 173                 (void) VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, ct);
 174                 /*
 175                  * Before VN_RELE() we need to remove the vnode from
 176                  * the hash table.  We should only do so in the  NMNMNT case.
 177                  * In other cases, nodep->nm_filep keeps a reference
 178                  * to nm_filevp and the entry in the hash table doesn't
 179                  * hurt.
 180                  */
 181                 if ((nodep->nm_flag & NMNMNT) != 0) {
 182                         mutex_enter(&ntable_lock);
 183                         nameremove(nodep);
 184                         mutex_exit(&ntable_lock);
 185                 }
 186                 VN_RELE(nodep->nm_filevp);
 187         }
 188         return (error);
 189 }
 190 
 191 static int
 192 nm_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *crp,
 193         caller_context_t *ct)
 194 {
 195         return (VOP_READ(VTONM(vp)->nm_filevp, uiop, ioflag, crp, ct));
 196 }
 197 
 198 static int
 199 nm_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *crp,
 200         caller_context_t *ct)
 201 {
 202         return (VOP_WRITE(VTONM(vp)->nm_filevp, uiop, ioflag, crp, ct));
 203 }
 204 
 205 static int
 206 nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp,
 207         caller_context_t *ct)
 208 {
 209         return (VOP_IOCTL(VTONM(vp)->nm_filevp, cmd, arg, mode, cr, rvalp, ct));
 210 }
 211 
 212 /*
 213  * Return in vap the attributes that are stored in the namenode
 214  * structure.  Only the size is taken from the mounted object.
 215  */
 216 /* ARGSUSED */
 217 static int
 218 nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
 219         caller_context_t *ct)
 220 {
 221         struct namenode *nodep = VTONM(vp);
 222         struct vattr va;
 223         int error;
 224 
 225         mutex_enter(&nodep->nm_lock);
 226         bcopy(&nodep->nm_vattr, vap, sizeof (vattr_t));
 227         mutex_exit(&nodep->nm_lock);
 228 
 229         if ((va.va_mask = vap->va_mask & AT_SIZE) != 0) {
 230                 if (error = VOP_GETATTR(nodep->nm_filevp, &va, flags, crp, ct))
 231                         return (error);
 232                 vap->va_size = va.va_size;
 233         }
 234 
 235         return (0);
 236 }
 237 
 238 /*
 239  * Standard access() like check.  Figure out which mode bits apply
 240  * to the caller then pass the missing mode bits to the secpolicy function.
 241  */
 242 static int
 243 nm_access_unlocked(void *vnp, int mode, cred_t *crp)
 244 {
 245         struct namenode *nodep = vnp;
 246         int shift = 0;
 247 
 248         if (crgetuid(crp) != nodep->nm_vattr.va_uid) {
 249                 shift += 3;
 250                 if (!groupmember(nodep->nm_vattr.va_gid, crp))
 251                         shift += 3;
 252         }
 253 
 254         return (secpolicy_vnode_access2(crp, NMTOV(nodep),
 255             nodep->nm_vattr.va_uid, nodep->nm_vattr.va_mode << shift,
 256             mode));
 257 }
 258 /*
 259  * Set the attributes of the namenode from the attributes in vap.
 260  */
 261 /* ARGSUSED */
 262 static int
 263 nm_setattr(
 264         vnode_t *vp,
 265         vattr_t *vap,
 266         int flags,
 267         cred_t *crp,
 268         caller_context_t *ctp)
 269 {
 270         struct namenode *nodep = VTONM(vp);
 271         struct vattr *nmvap = &nodep->nm_vattr;
 272         long mask = vap->va_mask;
 273         int error = 0;
 274 
 275         /*
 276          * Cannot set these attributes.
 277          */
 278         if (mask & (AT_NOSET|AT_SIZE))
 279                 return (EINVAL);
 280 
 281         (void) VOP_RWLOCK(nodep->nm_filevp, V_WRITELOCK_TRUE, ctp);
 282         mutex_enter(&nodep->nm_lock);
 283 
 284         /*
 285          * Change ownership/group/time/access mode of mounted file
 286          * descriptor.
 287          */
 288 
 289         error = secpolicy_vnode_setattr(crp, vp, vap, nmvap, flags,
 290             nm_access_unlocked, nodep);
 291         if (error)
 292                 goto out;
 293 
 294         mask = vap->va_mask;
 295         /*
 296          * If request to change mode, copy new
 297          * mode into existing attribute structure.
 298          */
 299         if (mask & AT_MODE)
 300                 nmvap->va_mode = vap->va_mode & ~VSVTX;
 301 
 302         /*
 303          * If request was to change user or group, turn off suid and sgid
 304          * bits.
 305          * If the system was configured with the "rstchown" option, the
 306          * owner is not permitted to give away the file, and can change
 307          * the group id only to a group of which he or she is a member.
 308          */
 309         if (mask & AT_UID)
 310                 nmvap->va_uid = vap->va_uid;
 311         if (mask & AT_GID)
 312                 nmvap->va_gid = vap->va_gid;
 313         /*
 314          * If request is to modify times, make sure user has write
 315          * permissions on the file.
 316          */
 317         if (mask & AT_ATIME)
 318                 nmvap->va_atime = vap->va_atime;
 319         if (mask & AT_MTIME) {
 320                 nmvap->va_mtime = vap->va_mtime;
 321                 gethrestime(&nmvap->va_ctime);
 322         }
 323 out:
 324         mutex_exit(&nodep->nm_lock);
 325         VOP_RWUNLOCK(nodep->nm_filevp, V_WRITELOCK_TRUE, ctp);
 326         return (error);
 327 }
 328 
 329 /*
 330  * Check mode permission on the namenode.  First nm_access_unlocked()
 331  * checks the bits on the name node, then an access check is performed
 332  * on the underlying file.
 333  */
 334 /* ARGSUSED */
 335 static int
 336 nm_access(vnode_t *vp, int mode, int flags, cred_t *crp,
 337         caller_context_t *ct)
 338 {
 339         struct namenode *nodep = VTONM(vp);
 340         int error;
 341 
 342         mutex_enter(&nodep->nm_lock);
 343         error = nm_access_unlocked(nodep, mode, crp);
 344         mutex_exit(&nodep->nm_lock);
 345         if (error == 0)
 346                 return (VOP_ACCESS(nodep->nm_filevp, mode, flags, crp, ct));
 347         else
 348                 return (error);
 349 }
 350 
 351 /*
 352  * We can get here if a creat or open with O_CREAT is done on a namefs
 353  * mount point, for example, as the object of a shell output redirection to
 354  * the mount point.
 355  */
 356 /*ARGSUSED*/
 357 static int
 358 nm_create(vnode_t *dvp, char *name, vattr_t *vap, enum vcexcl excl,
 359         int mode, vnode_t **vpp, cred_t *cr, int flag,
 360         caller_context_t *ct, vsecattr_t *vsecp)
 361 {
 362         int error;
 363 
 364         ASSERT(dvp && *name == '\0');
 365         if (excl == NONEXCL) {
 366                 if (mode && (error = nm_access(dvp, mode, 0, cr, ct)) != 0)
 367                         return (error);
 368                 VN_HOLD(dvp);
 369                 return (0);
 370         }
 371         return (EEXIST);
 372 }
 373 
 374 /*
 375  * Links are not allowed on mounted file descriptors.
 376  */
 377 /*ARGSUSED*/
 378 static int
 379 nm_link(vnode_t *tdvp, vnode_t *vp, char *tnm, cred_t *crp,
 380         caller_context_t *ct, int flags)
 381 {
 382         return (EXDEV);
 383 }
 384 
 385 static int
 386 nm_fsync(vnode_t *vp, int syncflag, cred_t *crp, caller_context_t *ct)
 387 {
 388         return (VOP_FSYNC(VTONM(vp)->nm_filevp, syncflag, crp, ct));
 389 }
 390 
 391 /* Free the namenode */
 392 /* ARGSUSED */
 393 static void
 394 nm_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
 395 {
 396         struct namenode *nodep = VTONM(vp);
 397         vfs_t *vfsp = vp->v_vfsp;
 398 
 399         mutex_enter(&vp->v_lock);
 400         ASSERT(vp->v_count >= 1);
 401         if (--vp->v_count != 0) {
 402                 mutex_exit(&vp->v_lock);
 403                 return;
 404         }
 405         mutex_exit(&vp->v_lock);
 406         if (!(nodep->nm_flag & NMNMNT)) {
 407                 ASSERT(nodep->nm_filep->f_vnode == nodep->nm_filevp);
 408                 (void) closef(nodep->nm_filep);
 409         }
 410         vn_invalid(vp);
 411         vn_free(vp);
 412         if (vfsp != &namevfs)
 413                 VFS_RELE(vfsp);
 414         namenodeno_free(nodep->nm_vattr.va_nodeid);
 415         kmem_free(nodep, sizeof (struct namenode));
 416 }
 417 
 418 static int
 419 nm_fid(vnode_t *vp, struct fid *fidnodep, caller_context_t *ct)
 420 {
 421         return (VOP_FID(VTONM(vp)->nm_filevp, fidnodep, ct));
 422 }
 423 
 424 static int
 425 nm_rwlock(vnode_t *vp, int write, caller_context_t *ctp)
 426 {
 427         return (VOP_RWLOCK(VTONM(vp)->nm_filevp, write, ctp));
 428 }
 429 
 430 static void
 431 nm_rwunlock(vnode_t *vp, int write, caller_context_t *ctp)
 432 {
 433         VOP_RWUNLOCK(VTONM(vp)->nm_filevp, write, ctp);
 434 }
 435 
 436 static int
 437 nm_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
 438 {
 439         return (VOP_SEEK(VTONM(vp)->nm_filevp, ooff, noffp, ct));
 440 }
 441 
 442 /*
 443  * Return the vnode representing the file descriptor in vpp.
 444  */
 445 static int
 446 nm_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
 447 {
 448         struct vnode *rvp;
 449 
 450         vp = VTONM(vp)->nm_filevp;
 451         if (VOP_REALVP(vp, &rvp, ct) == 0)
 452                 vp = rvp;
 453         *vpp = vp;
 454         return (0);
 455 }
 456 
 457 static int
 458 nm_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
 459         pollhead_t **phpp, caller_context_t *ct)
 460 {
 461         return (VOP_POLL(VTONM(vp)->nm_filevp, events, anyyet, reventsp,
 462             phpp, ct));
 463 }
 464 
 465 struct vnodeops *nm_vnodeops;
 466 
 467 const fs_operation_def_t nm_vnodeops_template[] = {
 468         { VOPNAME_OPEN,         { .vop_open = nm_open } },
 469         { VOPNAME_CLOSE,        { .vop_close = nm_close } },
 470         { VOPNAME_READ,         { .vop_read = nm_read } },
 471         { VOPNAME_WRITE,        { .vop_write = nm_write } },
 472         { VOPNAME_IOCTL,        { .vop_ioctl = nm_ioctl } },
 473         { VOPNAME_GETATTR,      { .vop_getattr = nm_getattr } },
 474         { VOPNAME_SETATTR,      { .vop_setattr = nm_setattr } },
 475         { VOPNAME_ACCESS,       { .vop_access = nm_access } },
 476         { VOPNAME_CREATE,       { .vop_create = nm_create } },
 477         { VOPNAME_LINK,         { .vop_link = nm_link } },
 478         { VOPNAME_FSYNC,        { .vop_fsync = nm_fsync } },
 479         { VOPNAME_INACTIVE,     { .vop_inactive = nm_inactive } },
 480         { VOPNAME_FID,          { .vop_fid = nm_fid } },
 481         { VOPNAME_RWLOCK,       { .vop_rwlock = nm_rwlock } },
 482         { VOPNAME_RWUNLOCK,     { .vop_rwunlock = nm_rwunlock } },
 483         { VOPNAME_SEEK,         { .vop_seek = nm_seek } },
 484         { VOPNAME_REALVP,       { .vop_realvp = nm_realvp } },
 485         { VOPNAME_POLL,         { .vop_poll = nm_poll } },
 486         { VOPNAME_DISPOSE,      { .error = fs_error } },
 487         { NULL,                 { NULL } }
 488 };