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 /*
  22  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  26 /*        All Rights Reserved   */
  27 
  28 
  29 /*
  30  * This file supports the vfs operations for the NAMEFS file system.
  31  */
  32 
  33 #include <sys/types.h>
  34 #include <sys/param.h>
  35 #include <sys/systm.h>
  36 #include <sys/debug.h>
  37 #include <sys/errno.h>
  38 #include <sys/kmem.h>
  39 #include <sys/inline.h>
  40 #include <sys/file.h>
  41 #include <sys/proc.h>
  42 #include <sys/stat.h>
  43 #include <sys/statvfs.h>
  44 #include <sys/mount.h>
  45 #include <sys/sysmacros.h>
  46 #include <sys/var.h>
  47 #include <sys/vfs.h>
  48 #include <sys/vfs_opreg.h>
  49 #include <sys/vnode.h>
  50 #include <sys/mode.h>
  51 #include <sys/pcb.h>
  52 #include <sys/signal.h>
  53 #include <sys/user.h>
  54 #include <sys/uio.h>
  55 #include <sys/cred.h>
  56 #include <sys/fs/namenode.h>
  57 #include <sys/stream.h>
  58 #include <sys/strsubr.h>
  59 #include <sys/cmn_err.h>
  60 #include <sys/modctl.h>
  61 #include <fs/fs_subr.h>
  62 #include <sys/policy.h>
  63 #include <sys/vmem.h>
  64 #include <sys/fs/sdev_impl.h>
  65 
  66 #define NM_INOQUANT             (64 * 1024)
  67 
  68 /*
  69  * Define global data structures.
  70  */
  71 dev_t   namedev;
  72 int     namefstype;
  73 struct  namenode *nm_filevp_hash[NM_FILEVP_HASH_SIZE];
  74 struct  vfs namevfs;
  75 kmutex_t ntable_lock;
  76 
  77 static vmem_t   *nm_inoarena;   /* vmem arena to allocate inode no's from */
  78 static kmutex_t nm_inolock;
  79 
  80 vfsops_t *namefs_vfsops;
  81 /*
  82  * Functions to allocate node id's starting from 1. Based on vmem routines.
  83  * The vmem arena is extended in NM_INOQUANT chunks.
  84  */
  85 uint64_t
  86 namenodeno_alloc(void)
  87 {
  88         uint64_t nno;
  89 
  90         mutex_enter(&nm_inolock);
  91         nno = (uint64_t)(uintptr_t)
  92             vmem_alloc(nm_inoarena, 1, VM_NOSLEEP + VM_FIRSTFIT);
  93         if (nno == 0) {
  94                 (void) vmem_add(nm_inoarena, (void *)(vmem_size(nm_inoarena,
  95                     VMEM_ALLOC | VMEM_FREE) + 1), NM_INOQUANT, VM_SLEEP);
  96                 nno = (uint64_t)(uintptr_t)
  97                     vmem_alloc(nm_inoarena, 1, VM_SLEEP + VM_FIRSTFIT);
  98                 ASSERT(nno != 0);
  99         }
 100         mutex_exit(&nm_inolock);
 101         ASSERT32(nno <= ULONG_MAX);
 102         return (nno);
 103 }
 104 
 105 static void
 106 namenodeno_init(void)
 107 {
 108         nm_inoarena = vmem_create("namefs_inodes", (void *)1, NM_INOQUANT, 1,
 109             NULL, NULL, NULL, 1, VM_SLEEP);
 110         mutex_init(&nm_inolock, NULL, MUTEX_DEFAULT, NULL);
 111 }
 112 
 113 void
 114 namenodeno_free(uint64_t nn)
 115 {
 116         void *vaddr = (void *)(uintptr_t)nn;
 117 
 118         ASSERT32((uint64_t)(uintptr_t)vaddr == nn);
 119 
 120         mutex_enter(&nm_inolock);
 121         vmem_free(nm_inoarena, vaddr, 1);
 122         mutex_exit(&nm_inolock);
 123 }
 124 
 125 /*
 126  * Insert a namenode into the nm_filevp_hash table.
 127  *
 128  * Each link has a unique namenode with a unique nm_mountvp field.
 129  * The nm_filevp field of the namenode need not be unique, since a
 130  * file descriptor may be mounted to multiple nodes at the same time.
 131  * We hash on nm_filevp since that's what discriminates the searches
 132  * in namefind() and nm_unmountall().
 133  */
 134 void
 135 nameinsert(struct namenode *nodep)
 136 {
 137         struct namenode **bucket;
 138 
 139         ASSERT(MUTEX_HELD(&ntable_lock));
 140 
 141         bucket = NM_FILEVP_HASH(nodep->nm_filevp);
 142         nodep->nm_nextp = *bucket;
 143         *bucket = nodep;
 144 }
 145 
 146 /*
 147  * Remove a namenode from the hash table, if present.
 148  */
 149 void
 150 nameremove(struct namenode *nodep)
 151 {
 152         struct namenode *np, **npp;
 153 
 154         ASSERT(MUTEX_HELD(&ntable_lock));
 155 
 156         for (npp = NM_FILEVP_HASH(nodep->nm_filevp); (np = *npp) != NULL;
 157             npp = &np->nm_nextp) {
 158                 if (np == nodep) {
 159                         *npp = np->nm_nextp;
 160                         return;
 161                 }
 162         }
 163 }
 164 
 165 /*
 166  * Search for a namenode that has a nm_filevp == vp and nm_mountpt == mnt.
 167  * If mnt is NULL, return the first link with nm_filevp of vp.
 168  * Returns namenode pointer on success, NULL on failure.
 169  */
 170 struct namenode *
 171 namefind(vnode_t *vp, vnode_t *mnt)
 172 {
 173         struct namenode *np;
 174 
 175         ASSERT(MUTEX_HELD(&ntable_lock));
 176         for (np = *NM_FILEVP_HASH(vp); np != NULL; np = np->nm_nextp)
 177                 if (np->nm_filevp == vp &&
 178                     (mnt == NULL || np->nm_mountpt == mnt))
 179                         break;
 180         return (np);
 181 }
 182 
 183 /*
 184  * Force the unmouting of a file descriptor from ALL of the nodes
 185  * that it was mounted to.
 186  * At the present time, the only usage for this routine is in the
 187  * event one end of a pipe was mounted. At the time the unmounted
 188  * end gets closed down, the mounted end is forced to be unmounted.
 189  *
 190  * This routine searches the namenode hash list for all namenodes
 191  * that have a nm_filevp field equal to vp. Each time one is found,
 192  * the dounmount() routine is called. This causes the nm_unmount()
 193  * routine to be called and thus, the file descriptor is unmounted
 194  * from the node.
 195  *
 196  * At the start of this routine, the reference count for vp is
 197  * incremented to protect the vnode from being released in the
 198  * event the mount was the only thing keeping the vnode active.
 199  * If that is the case, the VOP_CLOSE operation is applied to
 200  * the vnode, prior to it being released.
 201  */
 202 static int
 203 nm_umountall(vnode_t *vp, cred_t *crp)
 204 {
 205         vfs_t *vfsp;
 206         struct namenode *nodep;
 207         int error = 0;
 208         int realerr = 0;
 209 
 210         /*
 211          * For each namenode that is associated with the file:
 212          * If the v_vfsp field is not namevfs, dounmount it.  Otherwise,
 213          * it was created in nm_open() and will be released in time.
 214          * The following loop replicates some code from nm_find.  That
 215          * routine can't be used as is since the list isn't strictly
 216          * consumed as it is traversed.
 217          */
 218         mutex_enter(&ntable_lock);
 219         nodep = *NM_FILEVP_HASH(vp);
 220         while (nodep) {
 221                 if (nodep->nm_filevp == vp &&
 222                     (vfsp = NMTOV(nodep)->v_vfsp) != NULL &&
 223                     vfsp != &namevfs && (NMTOV(nodep)->v_flag & VROOT)) {
 224 
 225                         /*
 226                          * If the vn_vfswlock fails, skip the vfs since
 227                          * somebody else may be unmounting it.
 228                          */
 229                         if (vn_vfswlock(vfsp->vfs_vnodecovered)) {
 230                                 realerr = EBUSY;
 231                                 nodep = nodep->nm_nextp;
 232                                 continue;
 233                         }
 234 
 235                         /*
 236                          * Can't hold ntable_lock across call to do_unmount
 237                          * because nm_unmount tries to acquire it.  This means
 238                          * there is a window where another mount of vp can
 239                          * happen so it is possible that after nm_unmountall
 240                          * there are still some mounts.  This situation existed
 241                          * without MT locking because dounmount can sleep
 242                          * so another mount could happen during that time.
 243                          * This situation is unlikely and doesn't really cause
 244                          * any problems.
 245                          */
 246                         mutex_exit(&ntable_lock);
 247                         if ((error = dounmount(vfsp, 0, crp)) != 0)
 248                                 realerr = error;
 249                         mutex_enter(&ntable_lock);
 250                         /*
 251                          * Since we dropped the ntable_lock, we
 252                          * have to start over from the beginning.
 253                          * If for some reasons dounmount() fails,
 254                          * start from beginning means that we will keep on
 255                          * trying unless another thread unmounts it for us.
 256                          */
 257                         nodep = *NM_FILEVP_HASH(vp);
 258                 } else
 259                         nodep = nodep->nm_nextp;
 260         }
 261         mutex_exit(&ntable_lock);
 262         return (realerr);
 263 }
 264 
 265 /*
 266  * Force the unmouting of a file descriptor from ALL of the nodes
 267  * that it was mounted to.  XXX: fifo_close() calls this routine.
 268  *
 269  * nm_umountall() may return EBUSY.
 270  * nm_unmountall() will keep on trying until it succeeds.
 271  */
 272 int
 273 nm_unmountall(vnode_t *vp, cred_t *crp)
 274 {
 275         int error;
 276 
 277         /*
 278          * Nm_umuontall() returns only if it succeeds or
 279          * return with error EBUSY.  If EBUSY, that means
 280          * it cannot acquire the lock on the covered vnode,
 281          * and we will keep on trying.
 282          */
 283         for (;;) {
 284                 error = nm_umountall(vp, crp);
 285                 if (error != EBUSY)
 286                         break;
 287                 delay(1);       /* yield cpu briefly, then try again */
 288         }
 289         return (error);
 290 }
 291 
 292 /*
 293  * Mount a file descriptor onto the node in the file system.
 294  * Create a new vnode, update the attributes with info from the
 295  * file descriptor and the mount point.  The mask, mode, uid, gid,
 296  * atime, mtime and ctime are taken from the mountpt.  Link count is
 297  * set to one, the file system id is namedev and nodeid is unique
 298  * for each mounted object.  Other attributes are taken from mount point.
 299  * Make sure user is owner (or root) with write permissions on mount point.
 300  * Hash the new vnode and return 0.
 301  * Upon entry to this routine, the file descriptor is in the
 302  * fd field of a struct namefd.  Copy that structure from user
 303  * space and retrieve the file descriptor.
 304  */
 305 static int
 306 nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
 307 {
 308         struct namefd namefdp;
 309         struct vnode *filevp;           /* file descriptor vnode */
 310         struct file *fp;
 311         struct vnode *newvp;            /* vnode representing this mount */
 312         struct vnode *rvp;              /* realvp (if any) for the mountpt */
 313         struct namenode *nodep;         /* namenode for this mount */
 314         struct vattr filevattr;         /* attributes of file dec.  */
 315         struct vattr *vattrp;           /* attributes of this mount */
 316         char *resource_name;
 317         char *resource_nodetype;
 318         statvfs64_t *svfsp;
 319         int error = 0;
 320 
 321         /*
 322          * Get the file descriptor from user space.
 323          * Make sure the file descriptor is valid and has an
 324          * associated file pointer.
 325          * If so, extract the vnode from the file pointer.
 326          */
 327         if (uap->datalen != sizeof (struct namefd))
 328                 return (EINVAL);
 329 
 330         if (copyin(uap->dataptr, &namefdp, uap->datalen))
 331                 return (EFAULT);
 332 
 333         if ((fp = getf(namefdp.fd)) == NULL)
 334                 return (EBADF);
 335 
 336         /*
 337          * If the mount point already has something mounted
 338          * on it, disallow this mount.  (This restriction may
 339          * be removed in a later release).
 340          * Or unmount has completed but the namefs ROOT vnode
 341          * count has not decremented to zero, disallow this mount.
 342          */
 343 
 344         mutex_enter(&mvp->v_lock);
 345         if ((mvp->v_flag & VROOT) ||
 346             vfs_matchops(mvp->v_vfsp, namefs_vfsops)) {
 347                 mutex_exit(&mvp->v_lock);
 348                 releasef(namefdp.fd);
 349                 return (EBUSY);
 350         }
 351         mutex_exit(&mvp->v_lock);
 352 
 353         /*
 354          * Cannot allow users to fattach() in /dev/pts.
 355          * First, there is no need for doing so and secondly
 356          * we cannot allow arbitrary users to park on a node in
 357          * /dev/pts or /dev/vt.
 358          */
 359         rvp = NULLVP;
 360         if (vn_matchops(mvp, spec_getvnodeops()) &&
 361             VOP_REALVP(mvp, &rvp, NULL) == 0 && rvp &&
 362             (vn_matchops(rvp, devpts_getvnodeops()) ||
 363             vn_matchops(rvp, devvt_getvnodeops()))) {
 364                 releasef(namefdp.fd);
 365                 return (ENOTSUP);
 366         }
 367 
 368         filevp = fp->f_vnode;
 369         if (filevp->v_type == VDIR || filevp->v_type == VPORT) {
 370                 releasef(namefdp.fd);
 371                 return (EINVAL);
 372         }
 373 
 374         /*
 375          * If the fd being mounted refers to neither a door nor a stream,
 376          * make sure the caller is privileged.
 377          */
 378         if (filevp->v_type != VDOOR && filevp->v_stream == NULL) {
 379                 if (secpolicy_fs_mount(crp, filevp, vfsp) != 0) {
 380                         /* fd is neither a stream nor a door */
 381                         releasef(namefdp.fd);
 382                         return (EINVAL);
 383                 }
 384         }
 385 
 386         /*
 387          * Make sure the file descriptor is not the root of some
 388          * file system.
 389          * If it's not, create a reference and allocate a namenode
 390          * to represent this mount request.
 391          */
 392         if (filevp->v_flag & VROOT) {
 393                 releasef(namefdp.fd);
 394                 return (EBUSY);
 395         }
 396 
 397         nodep = kmem_zalloc(sizeof (struct namenode), KM_SLEEP);
 398 
 399         mutex_init(&nodep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
 400         vattrp = &nodep->nm_vattr;
 401         vattrp->va_mask = AT_ALL;
 402         if (error = VOP_GETATTR(mvp, vattrp, 0, crp, NULL))
 403                 goto out;
 404 
 405         filevattr.va_mask = AT_ALL;
 406         if (error = VOP_GETATTR(filevp, &filevattr, 0, crp, NULL))
 407                 goto out;
 408         /*
 409          * Make sure the user is the owner of the mount point
 410          * or has sufficient privileges.
 411          */
 412         if (error = secpolicy_vnode_owner(crp, vattrp->va_uid))
 413                 goto out;
 414 
 415         /*
 416          * Make sure the user has write permissions on the
 417          * mount point (or has sufficient privileges).
 418          */
 419         if (secpolicy_vnode_access2(crp, mvp, vattrp->va_uid, vattrp->va_mode,
 420             VWRITE) != 0) {
 421                 error = EACCES;
 422                 goto out;
 423         }
 424 
 425         /*
 426          * If the file descriptor has file/record locking, don't
 427          * allow the mount to succeed.
 428          */
 429         if (vn_has_flocks(filevp)) {
 430                 error = EACCES;
 431                 goto out;
 432         }
 433 
 434         /*
 435          * Initialize the namenode.
 436          */
 437         if (filevp->v_stream) {
 438                 struct stdata *stp = filevp->v_stream;
 439                 mutex_enter(&stp->sd_lock);
 440                 stp->sd_flag |= STRMOUNT;
 441                 mutex_exit(&stp->sd_lock);
 442         }
 443         nodep->nm_filevp = filevp;
 444         mutex_enter(&fp->f_tlock);
 445         fp->f_count++;
 446         mutex_exit(&fp->f_tlock);
 447 
 448         releasef(namefdp.fd);
 449         nodep->nm_filep = fp;
 450         nodep->nm_mountpt = mvp;
 451 
 452         /*
 453          * The attributes for the mounted file descriptor were initialized
 454          * above by applying VOP_GETATTR to the mount point.  Some of
 455          * the fields of the attributes structure will be overwritten
 456          * by the attributes from the file descriptor.
 457          */
 458         vattrp->va_type    = filevattr.va_type;
 459         vattrp->va_fsid    = namedev;
 460         vattrp->va_nodeid  = namenodeno_alloc();
 461         vattrp->va_nlink   = 1;
 462         vattrp->va_size    = filevattr.va_size;
 463         vattrp->va_rdev    = filevattr.va_rdev;
 464         vattrp->va_blksize = filevattr.va_blksize;
 465         vattrp->va_nblocks = filevattr.va_nblocks;
 466         vattrp->va_seq          = 0;
 467 
 468         /*
 469          * Initialize new vnode structure for the mounted file descriptor.
 470          */
 471         nodep->nm_vnode = vn_alloc(KM_SLEEP);
 472         newvp = NMTOV(nodep);
 473 
 474         newvp->v_flag = filevp->v_flag | VROOT | VNOMAP | VNOSWAP;
 475         vn_setops(newvp, nm_vnodeops);
 476         newvp->v_vfsp = vfsp;
 477         newvp->v_stream = filevp->v_stream;
 478         newvp->v_type = filevp->v_type;
 479         newvp->v_rdev = filevp->v_rdev;
 480         newvp->v_data = (caddr_t)nodep;
 481         VFS_HOLD(vfsp);
 482         vn_exists(newvp);
 483 
 484         /*
 485          * Initialize the vfs structure.
 486          */
 487         vfsp->vfs_vnodecovered = NULL;
 488         vfsp->vfs_flag |= VFS_UNLINKABLE;
 489         vfsp->vfs_bsize = 1024;
 490         vfsp->vfs_fstype = namefstype;
 491         vfs_make_fsid(&vfsp->vfs_fsid, namedev, namefstype);
 492         vfsp->vfs_data = (caddr_t)nodep;
 493         vfsp->vfs_dev = namedev;
 494         vfsp->vfs_bcount = 0;
 495 
 496         /*
 497          * Set the name we mounted from.
 498          */
 499         switch (filevp->v_type) {
 500         case VPROC:     /* VOP_GETATTR() translates this to VREG */
 501         case VREG:      resource_nodetype = "file"; break;
 502         case VDIR:      resource_nodetype = "directory"; break;
 503         case VBLK:      resource_nodetype = "device"; break;
 504         case VCHR:      resource_nodetype = "device"; break;
 505         case VLNK:      resource_nodetype = "link"; break;
 506         case VFIFO:     resource_nodetype = "fifo"; break;
 507         case VDOOR:     resource_nodetype = "door"; break;
 508         case VSOCK:     resource_nodetype = "socket"; break;
 509         default:        resource_nodetype = "resource"; break;
 510         }
 511 
 512 #define RESOURCE_NAME_SZ 128 /* Maximum length of the resource name */
 513         resource_name = kmem_alloc(RESOURCE_NAME_SZ, KM_SLEEP);
 514         svfsp = kmem_alloc(sizeof (statvfs64_t), KM_SLEEP);
 515 
 516         error = VFS_STATVFS(filevp->v_vfsp, svfsp);
 517         if (error == 0) {
 518                 (void) snprintf(resource_name, RESOURCE_NAME_SZ,
 519                     "unspecified_%s_%s", svfsp->f_basetype, resource_nodetype);
 520         } else {
 521                 (void) snprintf(resource_name, RESOURCE_NAME_SZ,
 522                     "unspecified_%s", resource_nodetype);
 523         }
 524 
 525         vfs_setresource(vfsp, resource_name, 0);
 526 
 527         kmem_free(svfsp, sizeof (statvfs64_t));
 528         kmem_free(resource_name, RESOURCE_NAME_SZ);
 529 #undef RESOURCE_NAME_SZ
 530 
 531         /*
 532          * Insert the namenode.
 533          */
 534         mutex_enter(&ntable_lock);
 535         nameinsert(nodep);
 536         mutex_exit(&ntable_lock);
 537         return (0);
 538 out:
 539         releasef(namefdp.fd);
 540         kmem_free(nodep, sizeof (struct namenode));
 541         return (error);
 542 }
 543 
 544 /*
 545  * Unmount a file descriptor from a node in the file system.
 546  * If the user is not the owner of the file and is not privileged,
 547  * the request is denied.
 548  * Otherwise, remove the namenode from the hash list.
 549  * If the mounted file descriptor was that of a stream and this
 550  * was the last mount of the stream, turn off the STRMOUNT flag.
 551  * If the rootvp is referenced other than through the mount,
 552  * nm_inactive will clean up.
 553  */
 554 static int
 555 nm_unmount(vfs_t *vfsp, int flag, cred_t *crp)
 556 {
 557         struct namenode *nodep = (struct namenode *)vfsp->vfs_data;
 558         vnode_t *vp, *thisvp;
 559         struct file *fp = NULL;
 560 
 561         ASSERT((nodep->nm_flag & NMNMNT) == 0);
 562 
 563         /*
 564          * forced unmount is not supported by this file system
 565          * and thus, ENOTSUP, is being returned.
 566          */
 567         if (flag & MS_FORCE) {
 568                 return (ENOTSUP);
 569         }
 570 
 571         vp = nodep->nm_filevp;
 572         mutex_enter(&nodep->nm_lock);
 573         if (secpolicy_vnode_owner(crp, nodep->nm_vattr.va_uid) != 0) {
 574                 mutex_exit(&nodep->nm_lock);
 575                 return (EPERM);
 576         }
 577 
 578         mutex_exit(&nodep->nm_lock);
 579 
 580         mutex_enter(&ntable_lock);
 581         nameremove(nodep);
 582         thisvp = NMTOV(nodep);
 583         mutex_enter(&thisvp->v_lock);
 584         if (thisvp->v_count-- == 1) {
 585                 fp = nodep->nm_filep;
 586                 mutex_exit(&thisvp->v_lock);
 587                 vn_invalid(thisvp);
 588                 vn_free(thisvp);
 589                 VFS_RELE(vfsp);
 590                 namenodeno_free(nodep->nm_vattr.va_nodeid);
 591                 kmem_free(nodep, sizeof (struct namenode));
 592         } else {
 593                 thisvp->v_flag &= ~VROOT;
 594                 mutex_exit(&thisvp->v_lock);
 595         }
 596         if (namefind(vp, NULLVP) == NULL && vp->v_stream) {
 597                 struct stdata *stp = vp->v_stream;
 598                 mutex_enter(&stp->sd_lock);
 599                 stp->sd_flag &= ~STRMOUNT;
 600                 mutex_exit(&stp->sd_lock);
 601         }
 602         mutex_exit(&ntable_lock);
 603         if (fp != NULL)
 604                 (void) closef(fp);
 605         return (0);
 606 }
 607 
 608 /*
 609  * Create a reference to the root of a mounted file descriptor.
 610  * This routine is called from lookupname() in the event a path
 611  * is being searched that has a mounted file descriptor in it.
 612  */
 613 static int
 614 nm_root(vfs_t *vfsp, vnode_t **vpp)
 615 {
 616         struct namenode *nodep = (struct namenode *)vfsp->vfs_data;
 617         struct vnode *vp = NMTOV(nodep);
 618 
 619         VN_HOLD(vp);
 620         *vpp = vp;
 621         return (0);
 622 }
 623 
 624 /*
 625  * Return in sp the status of this file system.
 626  */
 627 static int
 628 nm_statvfs(vfs_t *vfsp, struct statvfs64 *sp)
 629 {
 630         dev32_t d32;
 631 
 632         bzero(sp, sizeof (*sp));
 633         sp->f_bsize  = 1024;
 634         sp->f_frsize = 1024;
 635         (void) cmpldev(&d32, vfsp->vfs_dev);
 636         sp->f_fsid = d32;
 637         (void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
 638         sp->f_flag   = vf_to_stf(vfsp->vfs_flag);
 639         return (0);
 640 }
 641 
 642 /*
 643  * Since this file system has no disk blocks of its own, apply
 644  * the VOP_FSYNC operation on the mounted file descriptor.
 645  */
 646 static int
 647 nm_sync(vfs_t *vfsp, short flag, cred_t *crp)
 648 {
 649         struct namenode *nodep;
 650 
 651         if (vfsp == NULL)
 652                 return (0);
 653 
 654         nodep = (struct namenode *)vfsp->vfs_data;
 655         if (flag & SYNC_CLOSE)
 656                 return (nm_umountall(nodep->nm_filevp, crp));
 657 
 658         return (VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, NULL));
 659 }
 660 
 661 /*
 662  * File system initialization routine. Save the file system type,
 663  * establish a file system device number and initialize nm_filevp_hash[].
 664  */
 665 int
 666 nameinit(int fstype, char *name)
 667 {
 668         static const fs_operation_def_t nm_vfsops_template[] = {
 669                 VFSNAME_MOUNT,          { .vfs_mount = nm_mount },
 670                 VFSNAME_UNMOUNT,        { .vfs_unmount = nm_unmount },
 671                 VFSNAME_ROOT,           { .vfs_root = nm_root },
 672                 VFSNAME_STATVFS,        { .vfs_statvfs = nm_statvfs },
 673                 VFSNAME_SYNC,           { .vfs_sync = nm_sync },
 674                 NULL,                   NULL
 675         };
 676         static const fs_operation_def_t nm_dummy_vfsops_template[] = {
 677                 VFSNAME_STATVFS,        { .vfs_statvfs = nm_statvfs },
 678                 VFSNAME_SYNC,           { .vfs_sync = nm_sync },
 679                 NULL,                   NULL
 680         };
 681         int error;
 682         int dev;
 683         vfsops_t *dummy_vfsops;
 684 
 685         error = vfs_setfsops(fstype, nm_vfsops_template, &namefs_vfsops);
 686         if (error != 0) {
 687                 cmn_err(CE_WARN, "nameinit: bad vfs ops template");
 688                 return (error);
 689         }
 690 
 691         error = vfs_makefsops(nm_dummy_vfsops_template, &dummy_vfsops);
 692         if (error != 0) {
 693                 (void) vfs_freevfsops_by_type(fstype);
 694                 cmn_err(CE_WARN, "nameinit: bad dummy vfs ops template");
 695                 return (error);
 696         }
 697 
 698         error = vn_make_ops(name, nm_vnodeops_template, &nm_vnodeops);
 699         if (error != 0) {
 700                 (void) vfs_freevfsops_by_type(fstype);
 701                 vfs_freevfsops(dummy_vfsops);
 702                 cmn_err(CE_WARN, "nameinit: bad vnode ops template");
 703                 return (error);
 704         }
 705 
 706         namefstype = fstype;
 707 
 708         if ((dev = getudev()) == (major_t)-1) {
 709                 cmn_err(CE_WARN, "nameinit: can't get unique device");
 710                 dev = 0;
 711         }
 712         mutex_init(&ntable_lock, NULL, MUTEX_DEFAULT, NULL);
 713         namedev = makedevice(dev, 0);
 714         bzero(nm_filevp_hash, sizeof (nm_filevp_hash));
 715         vfs_setops(&namevfs, dummy_vfsops);
 716         namevfs.vfs_vnodecovered = NULL;
 717         namevfs.vfs_bsize = 1024;
 718         namevfs.vfs_fstype = namefstype;
 719         vfs_make_fsid(&namevfs.vfs_fsid, namedev, namefstype);
 720         namevfs.vfs_dev = namedev;
 721         return (0);
 722 }
 723 
 724 static mntopts_t nm_mntopts = {
 725         NULL,
 726         0
 727 };
 728 
 729 static vfsdef_t vfw = {
 730         VFSDEF_VERSION,
 731         "namefs",
 732         nameinit,
 733         VSW_HASPROTO | VSW_ZMOUNT,
 734         &nm_mntopts
 735 };
 736 
 737 /*
 738  * Module linkage information for the kernel.
 739  */
 740 static struct modlfs modlfs = {
 741         &mod_fsops, "filesystem for namefs", &vfw
 742 };
 743 
 744 static struct modlinkage modlinkage = {
 745         MODREV_1, (void *)&modlfs, NULL
 746 };
 747 
 748 int
 749 _init(void)
 750 {
 751         namenodeno_init();
 752         return (mod_install(&modlinkage));
 753 }
 754 
 755 int
 756 _fini(void)
 757 {
 758         return (EBUSY);
 759 }
 760 
 761 int
 762 _info(struct modinfo *modinfop)
 763 {
 764         return (mod_info(&modlinkage, modinfop));
 765 }