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 } 766