static int nsmb_close2(smb_dev_t *sdp, cred_t *cr) { struct smb_vc *vcp; struct smb_share *ssp; struct smb_cred scred; smb_credinit(&scred, cr); ssp = sdp->sd_share; if (ssp != NULL) smb_share_rele(ssp); vcp = sdp->sd_vc; if (vcp != NULL) { /* * If this dev minor was opened by smbiod, * mark this VC as "dead" because it now * will have no IOD to service it. */ if (sdp->sd_flags & NSMBFL_IOD) smb_iod_disconnect(vcp); smb_vc_rele(vcp); } smb_credrele(&scred); return (0); }
/* * Get file system statistics. */ static int smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp) { int error; smbmntinfo_t *smi = VFTOSMI(vfsp); smb_share_t *ssp = smi->smi_share; statvfs64_t stvfs; hrtime_t now; smb_cred_t scred; if (curproc->p_zone != smi->smi_zone_ref.zref_zone) return (EPERM); if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) return (EIO); mutex_enter(&smi->smi_lock); /* * Use cached result if still valid. */ recheck: now = gethrtime(); if (now < smi->smi_statfstime) { error = 0; goto cache_hit; } /* * FS attributes are stale, so someone * needs to do an OTW call to get them. * Serialize here so only one thread * does the OTW call. */ if (smi->smi_status & SM_STATUS_STATFS_BUSY) { smi->smi_status |= SM_STATUS_STATFS_WANT; if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) { mutex_exit(&smi->smi_lock); return (EINTR); } /* Hope status is valid now. */ goto recheck; } smi->smi_status |= SM_STATUS_STATFS_BUSY; mutex_exit(&smi->smi_lock); /* * Do the OTW call. Note: lock NOT held. */ smb_credinit(&scred, NULL); bzero(&stvfs, sizeof (stvfs)); error = smbfs_smb_statfs(ssp, &stvfs, &scred); smb_credrele(&scred); if (error) { SMBVDEBUG("statfs error=%d\n", error); } else { /* * Set a few things the OTW call didn't get. */ stvfs.f_frsize = stvfs.f_bsize; stvfs.f_favail = stvfs.f_ffree; stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0]; bcopy(fs_type_name, stvfs.f_basetype, FSTYPSZ); stvfs.f_flag = vf_to_stf(vfsp->vfs_flag); stvfs.f_namemax = smi->smi_fsa.fsa_maxname; /* * Save the result, update lifetime */ now = gethrtime(); smi->smi_statfstime = now + (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC); smi->smi_statvfsbuf = stvfs; /* struct assign! */ } mutex_enter(&smi->smi_lock); if (smi->smi_status & SM_STATUS_STATFS_WANT) cv_broadcast(&smi->smi_statvfs_cv); smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT); /* * Copy the statvfs data to caller's buf. * Note: struct assignment */ cache_hit: if (error == 0) *sbp = smi->smi_statvfsbuf; mutex_exit(&smi->smi_lock); 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); }