/* * ctfs_mount - the VFS_MOUNT entry point */ static int ctfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) { ctfs_vfs_t *data; dev_t dev; gfs_dirent_t *dirent; int i; if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) return (EPERM); if (mvp->v_type != VDIR) return (ENOTDIR); if ((uap->flags & MS_OVERLAY) == 0 && (mvp->v_count > 1 || (mvp->v_flag & VROOT))) return (EBUSY); data = kmem_alloc(sizeof (ctfs_vfs_t), KM_SLEEP); /* * Initialize vfs fields not initialized by VFS_INIT/domount */ vfsp->vfs_bsize = DEV_BSIZE; vfsp->vfs_fstype = ctfs_fstype; do dev = makedevice(ctfs_major, atomic_add_32_nv(&ctfs_minor, 1) & L_MAXMIN32); while (vfs_devismounted(dev)); vfs_make_fsid(&vfsp->vfs_fsid, dev, ctfs_fstype); vfsp->vfs_data = data; vfsp->vfs_dev = dev; /* * Dynamically create gfs_dirent_t array for the root directory. */ dirent = kmem_zalloc((ct_ntypes + 2) * sizeof (gfs_dirent_t), KM_SLEEP); for (i = 0; i < ct_ntypes; i++) { dirent[i].gfse_name = (char *)ct_types[i]->ct_type_name; dirent[i].gfse_ctor = ctfs_create_tdirnode; dirent[i].gfse_flags = GFS_CACHE_VNODE; } dirent[i].gfse_name = "all"; dirent[i].gfse_ctor = ctfs_create_adirnode; dirent[i].gfse_flags = GFS_CACHE_VNODE; dirent[i+1].gfse_name = NULL; /* * Create root vnode */ data->ctvfs_root = gfs_root_create(sizeof (ctfs_rootnode_t), vfsp, ctfs_ops_root, CTFS_INO_ROOT, dirent, ctfs_root_do_inode, CTFS_NAME_MAX, NULL, NULL); kmem_free(dirent, (ct_ntypes + 2) * sizeof (gfs_dirent_t)); return (0); }
/*ARGSUSED*/ static int fdmount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) { struct vnode *vp; if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) return (EPERM); if (mvp->v_type != VDIR) return (ENOTDIR); mutex_enter(&mvp->v_lock); if ((uap->flags & MS_OVERLAY) == 0 && (mvp->v_count > 1 || (mvp->v_flag & VROOT))) { mutex_exit(&mvp->v_lock); return (EBUSY); } mutex_exit(&mvp->v_lock); /* * Having the resource be anything but "fd" doesn't make sense */ vfs_setresource(vfsp, "fd"); vp = vn_alloc(KM_SLEEP); vp->v_vfsp = vfsp; vn_setops(vp, fd_vnodeops); vp->v_type = VDIR; vp->v_data = NULL; vp->v_flag |= VROOT; vfsp->vfs_fstype = fdfstype; vfsp->vfs_data = (char *)vp; mutex_enter(&fd_minor_lock); do { fdfsmin = (fdfsmin + 1) & L_MAXMIN32; vfsp->vfs_dev = makedevice(fdfsmaj, fdfsmin); } while (vfs_devismounted(vfsp->vfs_dev)); mutex_exit(&fd_minor_lock); vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, fdfstype); vfsp->vfs_bsize = 1024; return (0); }
/* * VFS entry points */ static int objfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) { objfs_vfs_t *data; dev_t dev; if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) return (EPERM); if (mvp->v_type != VDIR) return (ENOTDIR); if ((uap->flags & MS_OVERLAY) == 0 && (mvp->v_count > 1 || (mvp->v_flag & VROOT))) return (EBUSY); data = kmem_alloc(sizeof (objfs_vfs_t), KM_SLEEP); /* * Initialize vfs fields */ vfsp->vfs_bsize = DEV_BSIZE; vfsp->vfs_fstype = objfs_fstype; do { dev = makedevice(objfs_major, atomic_add_32_nv(&objfs_minor, 1) & L_MAXMIN32); } while (vfs_devismounted(dev)); vfs_make_fsid(&vfsp->vfs_fsid, dev, objfs_fstype); vfsp->vfs_data = data; vfsp->vfs_dev = dev; /* * Create root */ data->objfs_vfs_root = objfs_create_root(vfsp); return (0); }
/************************************************************************ * iumfs_mount() VFS オペレーション * * マウントルーチン * * vfsp : kernel が確保した、これからマウントする新しいファイルシステム * の為の vfs 構造体のポインタ * mvnode : ディレクトリマウントポイントの vnode * mntarg : mount の引数(注: ユーザ空間のデータ) * cr : ユーザクレデンシャル(UID, GID 等) * * 戻り値 * 正常時 : 0 * エラー時 : 0 以外 * *************************************************************************/ static int iumfs_mount(vfs_t *vfsp, vnode_t *mvnode, struct mounta *mntarg, struct cred *cr) { iumfs_t *iumfsp = NULL; // ファイルシステム型依存のプライベートデータ構造体 vnode_t *rootvp = NULL; int err = 0; dev_t dev; DEBUG_PRINT((CE_CONT, "iumfs_mount called\n")); DEBUG_PRINT((CE_CONT, "iumfs_mount: vfs_count = %d\n", vfsp->vfs_count)); /* * このファイルシステム用のデバイス番号をもとめ、そのデバイス番号 * からファイルシステム ID をもとめる。 */ mutex_enter(&iumfs_global_lock); dev = makedevice(iumfs_major, ++iumfs_last_minor); DEBUG_PRINT((CE_CONT, "iumfs_mount: new minor : %d\n", iumfs_last_minor)); mutex_exit(&iumfs_global_lock); vfs_make_fsid(&vfsp->vfs_fsid, dev, iumfs_fstype); DEBUG_PRINT((CE_CONT, "iumfs_mount: new fsid : 0x%x 0x%x \n", vfsp->vfs_fsid.val[0], vfsp->vfs_fsid.val[1])); // 途中で break するためだけの do-while 文 do { /* * ファイルシステムのプライベートデータ構造体を確保 */ iumfsp = (iumfs_t *) kmem_zalloc(sizeof (iumfs_t), KM_NOSLEEP); if (iumfsp == NULL) { cmn_err(CE_CONT, "iumfs_mount: kmem_zalloc failed"); err = ENOMEM; break; } /* * ロックを初期化 */ mutex_init(&(iumfsp->iumfs_lock), NULL, MUTEX_DEFAULT, NULL); mutex_init(&(iumfsp->node_list_head.i_dlock), NULL, MUTEX_DEFAULT, NULL); /* * vfs 構造体にファイルシステムのプライベートデータ構造体をセット */ vfsp->vfs_data = (char *) iumfsp; /* * ファイルシステムのルートディレクトリを作成 */ if ((err = iumfs_create_fs_root(vfsp, &rootvp, mvnode, cr)) != SUCCESS) break; /* * マウントコマンドから渡されたオプション(サーバ名や、パスワードなど)を格納 */ if (mntarg->flags & MS_SYSSPACE) { DEBUG_PRINT((CE_CONT, "iumfs_mount: MS_SYSSPACE flag is set\n")); // FKIOCTL を指定すると bcopy と同様に振舞う ddi_copyin(mntarg->dataptr, iumfsp->mountopts, mntarg->datalen, FKIOCTL); } else { DEBUG_PRINT((CE_CONT, "iumfs_mount: MS_SYSSPACE flag is not set\n")); ddi_copyin(mntarg->dataptr, iumfsp->mountopts, mntarg->datalen, 0); } DEBUG_PRINT((CE_CONT, "iumfs_mount: user=%s, pass=%s, server=%s, basepath=%s\n", iumfsp->mountopts->user, iumfsp->mountopts->pass, iumfsp->mountopts->server, iumfsp->mountopts->basepath)); /* * 上でもとめたデバイス番号をセット */ vfsp->vfs_dev = iumfsp->dev = dev; vfsp->vfs_fstype = iumfs_fstype; vfsp->vfs_bsize = 0; } while (FALSE); /* * エラーが発生した場合には確保したリソースを解放し、エラーを返す */ if (err) { if (iumfsp != NULL) { if (rootvp != NULL) { iumfs_free_all_node(vfsp, cr); } // ロックを削除し、確保したメモリを開放 mutex_destroy(&(iumfsp->iumfs_lock)); mutex_destroy(&(iumfsp->node_list_head.i_dlock)); kmem_free(iumfsp, sizeof (iumfs_t)); vfsp->vfs_data = (char *) NULL; } } DEBUG_PRINT((CE_CONT, "iumfs_mount: return(%d)\n", err)); return (err); }
static int VMBlockMount(struct vfs *vfsp, // IN: file system to mount struct vnode *vnodep, // IN: Vnode that we are mounting on struct mounta *mntp, // IN: Arguments to mount(2) from user struct cred *credp) // IN: Credentials of caller { VMBlockMountInfo *mip; int ret; Debug(VMBLOCK_ENTRY_LOGLEVEL, "VMBlockMount: entry\n"); /* * These next few checks are done by all other Solaris file systems, so * let's follow their lead. */ ret = secpolicy_fs_mount(credp, vnodep, vfsp); if (ret) { Warning("VMBlockMount: mounting security check failed.\n"); return ret; } if (vnodep->v_type != VDIR) { Warning("VMBlockMount: not mounting on a directory.\n"); return ENOTDIR; } mutex_enter(&vnodep->v_lock); if ((mntp->flags & MS_OVERLAY) == 0 && (vnodep->v_count != 1 || (vnodep->v_flag & VROOT))) { mutex_exit(&vnodep->v_lock); Warning("VMBlockMount: cannot allow unrequested overlay mount.\n"); return EBUSY; } mutex_exit(&vnodep->v_lock); /* * The directory we are redirecting to is specified as the special file * since we have no actual device to mount on. We store that path in the * mount information structure (note that there's another allocation inside * pn_get() so we must pn_free() that path at unmount time). KM_SLEEP * guarantees our memory allocation will succeed (pn_get() uses this flag * too). */ mip = kmem_zalloc(sizeof *mip, KM_SLEEP); ret = pn_get(mntp->spec, (mntp->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &mip->redirectPath); if (ret) { Warning("VMBlockMount: could not obtain redirecting directory.\n"); kmem_free(mip, sizeof *mip); return ret; } /* Do a lookup on the specified path. */ ret = lookupname(mntp->spec, (mntp->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, FOLLOW, NULLVPP, &mip->redirectVnode); if (ret) { Warning("VMBlockMount: could not obtain redirecting directory.\n"); goto error_lookup; } if (mip->redirectVnode->v_type != VDIR) { Warning("VMBlockMount: not redirecting to a directory.\n"); ret = ENOTDIR; goto error; } /* * Initialize our vfs structure. */ vfsp->vfs_vnodecovered = vnodep; vfsp->vfs_flag &= ~VFS_UNMOUNTED; vfsp->vfs_flag |= VMBLOCK_VFS_FLAGS; vfsp->vfs_bsize = PAGESIZE; vfsp->vfs_fstype = vmblockType; vfsp->vfs_bcount = 0; /* If we had mount options, we'd call vfs_setmntopt with vfsp->vfs_mntopts */ /* Locate a unique device minor number for this mount. */ mutex_enter(&vmblockMutex); do { vfsp->vfs_dev = makedevice(vmblockMajor, vmblockMinor); vmblockMinor = (vmblockMinor + 1) & L_MAXMIN32; } while (vfs_devismounted(vfsp->vfs_dev)); mutex_exit(&vmblockMutex); vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, vmblockType); vfsp->vfs_data = (caddr_t)mip; /* * Now create the root vnode of the file system. */ ret = VMBlockVnodeGet(&mip->root, mip->redirectVnode, mip->redirectPath.pn_path, mip->redirectPath.pn_pathlen, NULL, vfsp, TRUE); if (ret) { Warning("VMBlockMount: couldn't create root vnode.\n"); ret = EFAULT; goto error; } VN_HOLD(vfsp->vfs_vnodecovered); return 0; error: /* lookupname() provides a held vnode. */ VN_RELE(mip->redirectVnode); error_lookup: pn_free(&mip->redirectPath); kmem_free(mip, sizeof *mip); return ret; }
/* * Save file system type/index, initialize vfs operations vector, get * unique device number for FIFOFS and initialize the FIFOFS hash. * Create and initialize a "generic" vfs pointer that will be placed * in the v_vfsp field of each pipe's vnode. */ int fifoinit(int fstype, char *name) { static const fs_operation_def_t fifo_vfsops_template[] = { NULL, NULL }; int error; major_t dev; fifofstype = fstype; error = vfs_setfsops(fstype, fifo_vfsops_template, &fifo_vfsops); if (error != 0) { cmn_err(CE_WARN, "fifoinit: bad vfs ops template"); return (error); } error = vn_make_ops(name, fifo_vnodeops_template, &fifo_vnodeops); if (error != 0) { (void) vfs_freevfsops_by_type(fstype); cmn_err(CE_WARN, "fifoinit: bad vnode ops template"); return (error); } if ((dev = getudev()) == (major_t)-1) { cmn_err(CE_WARN, "fifoinit: can't get unique device number"); dev = 0; } fifodev = makedevice(dev, 0); fifovfsp = kmem_zalloc(sizeof (struct vfs), KM_SLEEP); fifovfsp->vfs_next = NULL; vfs_setops(fifovfsp, fifo_vfsops); fifovfsp->vfs_vnodecovered = NULL; fifovfsp->vfs_flag = 0; fifovfsp->vfs_bsize = 1024; fifovfsp->vfs_fstype = fifofstype; vfs_make_fsid(&fifovfsp->vfs_fsid, fifodev, fifofstype); fifovfsp->vfs_data = NULL; fifovfsp->vfs_dev = fifodev; fifovfsp->vfs_bcount = 0; /* * It is necessary to initialize vfs_count here to 1. * This prevents the fifovfsp from getting freed when * a thread does a VFS_HOLD followed by a VFS_RELE * on the fifovfsp * * The fifovfsp should never be freed. */ fifovfsp->vfs_count = 1; mutex_init(&ftable_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&fino_lock, NULL, MUTEX_DEFAULT, NULL); /* * vnodes are cached aligned */ fnode_cache = kmem_cache_create("fnode_cache", sizeof (fifodata_t) - sizeof (fifonode_t), 32, fnode_constructor, fnode_destructor, NULL, (void *)(sizeof (fifodata_t) - sizeof (fifonode_t)), NULL, 0); pipe_cache = kmem_cache_create("pipe_cache", sizeof (fifodata_t), 32, pipe_constructor, pipe_destructor, NULL, (void *)(sizeof (fifodata_t)), NULL, 0); #if FIFODEBUG if (Fifohiwat < FIFOHIWAT) Fifohiwat = FIFOHIWAT; #endif /* FIFODEBUG */ fifo_strdata.qi_minfo->mi_hiwat = Fifohiwat; return (0); }
/* * Mount a file descriptor onto the node in the file system. * Create a new vnode, update the attributes with info from the * file descriptor and the mount point. The mask, mode, uid, gid, * atime, mtime and ctime are taken from the mountpt. Link count is * set to one, the file system id is namedev and nodeid is unique * for each mounted object. Other attributes are taken from mount point. * Make sure user is owner (or root) with write permissions on mount point. * Hash the new vnode and return 0. * Upon entry to this routine, the file descriptor is in the * fd field of a struct namefd. Copy that structure from user * space and retrieve the file descriptor. */ static int nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp) { struct namefd namefdp; struct vnode *filevp; /* file descriptor vnode */ struct file *fp; struct vnode *newvp; /* vnode representing this mount */ struct vnode *rvp; /* realvp (if any) for the mountpt */ struct namenode *nodep; /* namenode for this mount */ struct vattr filevattr; /* attributes of file dec. */ struct vattr *vattrp; /* attributes of this mount */ char *resource_name; char *resource_nodetype; statvfs64_t *svfsp; int error = 0; /* * Get the file descriptor from user space. * Make sure the file descriptor is valid and has an * associated file pointer. * If so, extract the vnode from the file pointer. */ if (uap->datalen != sizeof (struct namefd)) return (EINVAL); if (copyin(uap->dataptr, &namefdp, uap->datalen)) return (EFAULT); if ((fp = getf(namefdp.fd)) == NULL) return (EBADF); /* * If the mount point already has something mounted * on it, disallow this mount. (This restriction may * be removed in a later release). * Or unmount has completed but the namefs ROOT vnode * count has not decremented to zero, disallow this mount. */ mutex_enter(&mvp->v_lock); if ((mvp->v_flag & VROOT) || vfs_matchops(mvp->v_vfsp, namefs_vfsops)) { mutex_exit(&mvp->v_lock); releasef(namefdp.fd); return (EBUSY); } mutex_exit(&mvp->v_lock); /* * Cannot allow users to fattach() in /dev/pts. * First, there is no need for doing so and secondly * we cannot allow arbitrary users to park on a node in * /dev/pts or /dev/vt. */ rvp = NULLVP; if (vn_matchops(mvp, spec_getvnodeops()) && VOP_REALVP(mvp, &rvp, NULL) == 0 && rvp && (vn_matchops(rvp, devpts_getvnodeops()) || vn_matchops(rvp, devvt_getvnodeops()))) { releasef(namefdp.fd); return (ENOTSUP); } filevp = fp->f_vnode; if (filevp->v_type == VDIR || filevp->v_type == VPORT) { releasef(namefdp.fd); return (EINVAL); } /* * If the fd being mounted refers to neither a door nor a stream, * make sure the caller is privileged. */ if (filevp->v_type != VDOOR && filevp->v_stream == NULL) { if (secpolicy_fs_mount(crp, filevp, vfsp) != 0) { /* fd is neither a stream nor a door */ releasef(namefdp.fd); return (EINVAL); } } /* * Make sure the file descriptor is not the root of some * file system. * If it's not, create a reference and allocate a namenode * to represent this mount request. */ if (filevp->v_flag & VROOT) { releasef(namefdp.fd); return (EBUSY); } nodep = kmem_zalloc(sizeof (struct namenode), KM_SLEEP); mutex_init(&nodep->nm_lock, NULL, MUTEX_DEFAULT, NULL); vattrp = &nodep->nm_vattr; vattrp->va_mask = AT_ALL; if (error = VOP_GETATTR(mvp, vattrp, 0, crp, NULL)) goto out; filevattr.va_mask = AT_ALL; if (error = VOP_GETATTR(filevp, &filevattr, 0, crp, NULL)) goto out; /* * Make sure the user is the owner of the mount point * or has sufficient privileges. */ if (error = secpolicy_vnode_owner(crp, vattrp->va_uid)) goto out; /* * Make sure the user has write permissions on the * mount point (or has sufficient privileges). */ if (!(vattrp->va_mode & VWRITE) && secpolicy_vnode_access(crp, mvp, vattrp->va_uid, VWRITE) != 0) { error = EACCES; goto out; } /* * If the file descriptor has file/record locking, don't * allow the mount to succeed. */ if (vn_has_flocks(filevp)) { error = EACCES; goto out; } /* * Initialize the namenode. */ if (filevp->v_stream) { struct stdata *stp = filevp->v_stream; mutex_enter(&stp->sd_lock); stp->sd_flag |= STRMOUNT; mutex_exit(&stp->sd_lock); } nodep->nm_filevp = filevp; mutex_enter(&fp->f_tlock); fp->f_count++; mutex_exit(&fp->f_tlock); releasef(namefdp.fd); nodep->nm_filep = fp; nodep->nm_mountpt = mvp; /* * The attributes for the mounted file descriptor were initialized * above by applying VOP_GETATTR to the mount point. Some of * the fields of the attributes structure will be overwritten * by the attributes from the file descriptor. */ vattrp->va_type = filevattr.va_type; vattrp->va_fsid = namedev; vattrp->va_nodeid = namenodeno_alloc(); vattrp->va_nlink = 1; vattrp->va_size = filevattr.va_size; vattrp->va_rdev = filevattr.va_rdev; vattrp->va_blksize = filevattr.va_blksize; vattrp->va_nblocks = filevattr.va_nblocks; vattrp->va_seq = 0; /* * Initialize new vnode structure for the mounted file descriptor. */ nodep->nm_vnode = vn_alloc(KM_SLEEP); newvp = NMTOV(nodep); newvp->v_flag = filevp->v_flag | VROOT | VNOMAP | VNOSWAP; vn_setops(newvp, nm_vnodeops); newvp->v_vfsp = vfsp; newvp->v_stream = filevp->v_stream; newvp->v_type = filevp->v_type; newvp->v_rdev = filevp->v_rdev; newvp->v_data = (caddr_t)nodep; VFS_HOLD(vfsp); vn_exists(newvp); /* * Initialize the vfs structure. */ vfsp->vfs_vnodecovered = NULL; vfsp->vfs_flag |= VFS_UNLINKABLE; vfsp->vfs_bsize = 1024; vfsp->vfs_fstype = namefstype; vfs_make_fsid(&vfsp->vfs_fsid, namedev, namefstype); vfsp->vfs_data = (caddr_t)nodep; vfsp->vfs_dev = namedev; vfsp->vfs_bcount = 0; /* * Set the name we mounted from. */ switch (filevp->v_type) { case VPROC: /* VOP_GETATTR() translates this to VREG */ case VREG: resource_nodetype = "file"; break; case VDIR: resource_nodetype = "directory"; break; case VBLK: resource_nodetype = "device"; break; case VCHR: resource_nodetype = "device"; break; case VLNK: resource_nodetype = "link"; break; case VFIFO: resource_nodetype = "fifo"; break; case VDOOR: resource_nodetype = "door"; break; case VSOCK: resource_nodetype = "socket"; break; default: resource_nodetype = "resource"; break; } #define RESOURCE_NAME_SZ 128 /* Maximum length of the resource name */ resource_name = kmem_alloc(RESOURCE_NAME_SZ, KM_SLEEP); svfsp = kmem_alloc(sizeof (statvfs64_t), KM_SLEEP); error = VFS_STATVFS(filevp->v_vfsp, svfsp); if (error == 0) { (void) snprintf(resource_name, RESOURCE_NAME_SZ, "unspecified_%s_%s", svfsp->f_basetype, resource_nodetype); } else { (void) snprintf(resource_name, RESOURCE_NAME_SZ, "unspecified_%s", resource_nodetype); } vfs_setresource(vfsp, resource_name); kmem_free(svfsp, sizeof (statvfs64_t)); kmem_free(resource_name, RESOURCE_NAME_SZ); #undef RESOURCE_NAME_SZ /* * Insert the namenode. */ mutex_enter(&ntable_lock); nameinsert(nodep); mutex_exit(&ntable_lock); return (0); out: releasef(namefdp.fd); kmem_free(nodep, sizeof (struct namenode)); return (error); }
/* * smbfs mount vfsop * Set up mount info record and attach it to vfs struct. */ static int smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) { char *data = uap->dataptr; int error; smbnode_t *rtnp = NULL; /* root of this fs */ smbmntinfo_t *smi = NULL; dev_t smbfs_dev; int version; int devfd; zone_t *zone = curproc->p_zone; zone_t *mntzone = NULL; smb_share_t *ssp = NULL; smb_cred_t scred; int flags, sec; STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) return (error); if (mvp->v_type != VDIR) return (ENOTDIR); /* * get arguments * * uap->datalen might be different from sizeof (args) * in a compatible situation. */ STRUCT_INIT(args, get_udatamodel()); bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)))) return (EFAULT); /* * Check mount program version */ version = STRUCT_FGET(args, version); if (version != SMBFS_VERSION) { cmn_err(CE_WARN, "mount version mismatch:" " kernel=%d, mount=%d\n", SMBFS_VERSION, version); return (EINVAL); } /* * Deal with re-mount requests. */ if (uap->flags & MS_REMOUNT) { cmn_err(CE_WARN, "MS_REMOUNT not implemented"); return (ENOTSUP); } /* * Check for busy */ mutex_enter(&mvp->v_lock); if (!(uap->flags & MS_OVERLAY) && (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { mutex_exit(&mvp->v_lock); return (EBUSY); } mutex_exit(&mvp->v_lock); /* * Get the "share" from the netsmb driver (ssp). * It is returned with a "ref" (hold) for us. * Release this hold: at errout below, or in * smbfs_freevfs(). */ devfd = STRUCT_FGET(args, devfd); error = smb_dev2share(devfd, &ssp); if (error) { cmn_err(CE_WARN, "invalid device handle %d (%d)\n", devfd, error); return (error); } /* * Use "goto errout" from here on. * See: ssp, smi, rtnp, mntzone */ /* * Determine the zone we're being mounted into. */ zone_hold(mntzone = zone); /* start with this assumption */ if (getzoneid() == GLOBAL_ZONEID) { zone_rele(mntzone); mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); ASSERT(mntzone != NULL); if (mntzone != zone) { error = EBUSY; goto errout; } } /* * Stop the mount from going any further if the zone is going away. */ if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { error = EBUSY; goto errout; } /* * On a Trusted Extensions client, we may have to force read-only * for read-down mounts. */ if (is_system_labeled()) { void *addr; int ipvers = 0; struct smb_vc *vcp; vcp = SSTOVC(ssp); addr = smb_vc_getipaddr(vcp, &ipvers); error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr); if (error > 0) goto errout; if (error == -1) { /* change mount to read-only to prevent write-down */ vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); } } /* Prevent unload. */ atomic_inc_32(&smbfs_mountcount); /* * Create a mount record and link it to the vfs struct. * No more possiblities for errors from here on. * Tear-down of this stuff is in smbfs_free_smi() * * Compare with NFS: nfsrootvp() */ smi = kmem_zalloc(sizeof (*smi), KM_SLEEP); mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL); cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL); rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL); smbfs_init_hash_avl(&smi->smi_hash_avl); smi->smi_share = ssp; ssp = NULL; /* * Convert the anonymous zone hold acquired via zone_hold() above * into a zone reference. */ zone_init_ref(&smi->smi_zone_ref); zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS); zone_rele(mntzone); mntzone = NULL; /* * Initialize option defaults */ smi->smi_flags = SMI_LLOCK; smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN); smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX); smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN); smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX); /* * All "generic" mount options have already been * handled in vfs.c:domount() - see mntopts stuff. * Query generic options using vfs_optionisset(). */ if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) smi->smi_flags |= SMI_INT; if (vfs_optionisset(vfsp, MNTOPT_ACL, NULL)) smi->smi_flags |= SMI_ACL; /* * Get the mount options that come in as smbfs_args, * starting with args.flags (SMBFS_MF_xxx) */ flags = STRUCT_FGET(args, flags); smi->smi_uid = STRUCT_FGET(args, uid); smi->smi_gid = STRUCT_FGET(args, gid); smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777; smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777; /* * Hande the SMBFS_MF_xxx flags. */ if (flags & SMBFS_MF_NOAC) smi->smi_flags |= SMI_NOAC; if (flags & SMBFS_MF_ACREGMIN) { sec = STRUCT_FGET(args, acregmin); if (sec < 0 || sec > SMBFS_ACMINMAX) sec = SMBFS_ACMINMAX; smi->smi_acregmin = SEC2HR(sec); } if (flags & SMBFS_MF_ACREGMAX) { sec = STRUCT_FGET(args, acregmax); if (sec < 0 || sec > SMBFS_ACMAXMAX) sec = SMBFS_ACMAXMAX; smi->smi_acregmax = SEC2HR(sec); } if (flags & SMBFS_MF_ACDIRMIN) { sec = STRUCT_FGET(args, acdirmin); if (sec < 0 || sec > SMBFS_ACMINMAX) sec = SMBFS_ACMINMAX; smi->smi_acdirmin = SEC2HR(sec); } if (flags & SMBFS_MF_ACDIRMAX) { sec = STRUCT_FGET(args, acdirmax); if (sec < 0 || sec > SMBFS_ACMAXMAX) sec = SMBFS_ACMAXMAX; smi->smi_acdirmax = SEC2HR(sec); } /* * Get attributes of the remote file system, * i.e. ACL support, named streams, etc. */ smb_credinit(&scred, cr); error = smbfs_smb_qfsattr(smi->smi_share, &smi->smi_fsa, &scred); smb_credrele(&scred); if (error) { SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error); } /* * We enable XATTR by default (via smbfs_mntopts) * but if the share does not support named streams, * force the NOXATTR option (also clears XATTR). * Caller will set or clear VFS_XATTR after this. */ if ((smi->smi_fsattr & FILE_NAMED_STREAMS) == 0) vfs_setmntopt(vfsp, MNTOPT_NOXATTR, NULL, 0); /* * Ditto ACLs (disable if not supported on this share) */ if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) { vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0); smi->smi_flags &= ~SMI_ACL; } /* * Assign a unique device id to the mount */ mutex_enter(&smbfs_minor_lock); do { smbfs_minor = (smbfs_minor + 1) & MAXMIN32; smbfs_dev = makedevice(smbfs_major, smbfs_minor); } while (vfs_devismounted(smbfs_dev)); mutex_exit(&smbfs_minor_lock); vfsp->vfs_dev = smbfs_dev; vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp); vfsp->vfs_data = (caddr_t)smi; vfsp->vfs_fstype = smbfsfstyp; vfsp->vfs_bsize = MAXBSIZE; vfsp->vfs_bcount = 0; smi->smi_vfsp = vfsp; smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */ /* * Create the root vnode, which we need in unmount * for the call to smbfs_check_table(), etc. * Release this hold in smbfs_unmount. */ rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0, &smbfs_fattr0); ASSERT(rtnp != NULL); rtnp->r_vnode->v_type = VDIR; rtnp->r_vnode->v_flag |= VROOT; smi->smi_root = rtnp; /* * NFS does other stuff here too: * async worker threads * init kstats * * End of code from NFS nfsrootvp() */ return (0); errout: vfsp->vfs_data = NULL; if (smi != NULL) smbfs_free_smi(smi); if (mntzone != NULL) zone_rele(mntzone); if (ssp != NULL) smb_share_rele(ssp); return (error); }