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