14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000-2001, Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 354bff34e3Sthurlow /* 360fbb751dSJohn Levon * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 37*8cd81a20SJerry Jelinek * Copyright 2013, Joyent, Inc. All rights reserved. 384bff34e3Sthurlow */ 394bff34e3Sthurlow 404bff34e3Sthurlow #include <sys/systm.h> 414bff34e3Sthurlow #include <sys/cred.h> 4202d09e03SGordon Ross #include <sys/time.h> 434bff34e3Sthurlow #include <sys/vfs.h> 444bff34e3Sthurlow #include <sys/vnode.h> 454bff34e3Sthurlow #include <fs/fs_subr.h> 464bff34e3Sthurlow #include <sys/sysmacros.h> 474bff34e3Sthurlow #include <sys/kmem.h> 484bff34e3Sthurlow #include <sys/mkdev.h> 494bff34e3Sthurlow #include <sys/mount.h> 504bff34e3Sthurlow #include <sys/statvfs.h> 514bff34e3Sthurlow #include <sys/errno.h> 524bff34e3Sthurlow #include <sys/debug.h> 534bff34e3Sthurlow #include <sys/cmn_err.h> 544bff34e3Sthurlow #include <sys/modctl.h> 554bff34e3Sthurlow #include <sys/policy.h> 564bff34e3Sthurlow #include <sys/atomic.h> 574bff34e3Sthurlow #include <sys/zone.h> 584bff34e3Sthurlow #include <sys/vfs_opreg.h> 594bff34e3Sthurlow #include <sys/mntent.h> 604bff34e3Sthurlow #include <sys/priv.h> 614bff34e3Sthurlow #include <sys/tsol/label.h> 624bff34e3Sthurlow #include <sys/tsol/tndb.h> 634bff34e3Sthurlow #include <inet/ip.h> 644bff34e3Sthurlow 654bff34e3Sthurlow #include <netsmb/smb_osdep.h> 664bff34e3Sthurlow #include <netsmb/smb.h> 674bff34e3Sthurlow #include <netsmb/smb_conn.h> 684bff34e3Sthurlow #include <netsmb/smb_subr.h> 694bff34e3Sthurlow #include <netsmb/smb_dev.h> 704bff34e3Sthurlow 714bff34e3Sthurlow #include <smbfs/smbfs.h> 724bff34e3Sthurlow #include <smbfs/smbfs_node.h> 734bff34e3Sthurlow #include <smbfs/smbfs_subr.h> 744bff34e3Sthurlow 754bff34e3Sthurlow /* 764bff34e3Sthurlow * Local functions definitions. 774bff34e3Sthurlow */ 784bff34e3Sthurlow int smbfsinit(int fstyp, char *name); 794bff34e3Sthurlow void smbfsfini(); 804bff34e3Sthurlow static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *); 814bff34e3Sthurlow 8291d632c8Sgwr /* 8391d632c8Sgwr * SMBFS Mount options table for MS_OPTIONSTR 8491d632c8Sgwr * Note: These are not all the options. 8591d632c8Sgwr * Some options come in via MS_DATA. 8691d632c8Sgwr * Others are generic (see vfs.c) 8791d632c8Sgwr */ 8891d632c8Sgwr static char *intr_cancel[] = { MNTOPT_NOINTR, NULL }; 8991d632c8Sgwr static char *nointr_cancel[] = { MNTOPT_INTR, NULL }; 90bd7c6f51SGordon Ross static char *acl_cancel[] = { MNTOPT_NOACL, NULL }; 91bd7c6f51SGordon Ross static char *noacl_cancel[] = { MNTOPT_ACL, NULL }; 9291d632c8Sgwr static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 9391d632c8Sgwr static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 9491d632c8Sgwr 9591d632c8Sgwr static mntopt_t mntopts[] = { 9691d632c8Sgwr /* 9791d632c8Sgwr * option name cancel option default arg flags 9891d632c8Sgwr * ufs arg flag 9991d632c8Sgwr */ 10091d632c8Sgwr { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 0 }, 10191d632c8Sgwr { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 0 }, 102bd7c6f51SGordon Ross { MNTOPT_ACL, acl_cancel, NULL, MO_DEFAULT, 0 }, 103bd7c6f51SGordon Ross { MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 }, 10491d632c8Sgwr { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 }, 10591d632c8Sgwr { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 } 10691d632c8Sgwr }; 10791d632c8Sgwr 10891d632c8Sgwr static mntopts_t smbfs_mntopts = { 10991d632c8Sgwr sizeof (mntopts) / sizeof (mntopt_t), 11091d632c8Sgwr mntopts 11191d632c8Sgwr }; 11291d632c8Sgwr 113613a2f6bSGordon Ross static const char fs_type_name[FSTYPSZ] = "smbfs"; 114613a2f6bSGordon Ross 1154bff34e3Sthurlow static vfsdef_t vfw = { 1164bff34e3Sthurlow VFSDEF_VERSION, 117613a2f6bSGordon Ross (char *)fs_type_name, 1184bff34e3Sthurlow smbfsinit, /* init routine */ 119*8cd81a20SJerry Jelinek VSW_HASPROTO|VSW_NOTZONESAFE, /* flags */ 12091d632c8Sgwr &smbfs_mntopts /* mount options table prototype */ 1214bff34e3Sthurlow }; 1224bff34e3Sthurlow 1234bff34e3Sthurlow static struct modlfs modlfs = { 1244bff34e3Sthurlow &mod_fsops, 125613a2f6bSGordon Ross "SMBFS filesystem", 1264bff34e3Sthurlow &vfw 1274bff34e3Sthurlow }; 1284bff34e3Sthurlow 1294bff34e3Sthurlow static struct modlinkage modlinkage = { 1304bff34e3Sthurlow MODREV_1, (void *)&modlfs, NULL 1314bff34e3Sthurlow }; 1324bff34e3Sthurlow 1334bff34e3Sthurlow /* 1344bff34e3Sthurlow * Mutex to protect the following variables: 1354bff34e3Sthurlow * smbfs_major 1364bff34e3Sthurlow * smbfs_minor 1374bff34e3Sthurlow */ 1384bff34e3Sthurlow extern kmutex_t smbfs_minor_lock; 1394bff34e3Sthurlow extern int smbfs_major; 1404bff34e3Sthurlow extern int smbfs_minor; 1414bff34e3Sthurlow 1424bff34e3Sthurlow /* 1434bff34e3Sthurlow * Prevent unloads while we have mounts 1444bff34e3Sthurlow */ 1454bff34e3Sthurlow uint32_t smbfs_mountcount; 1464bff34e3Sthurlow 1474bff34e3Sthurlow /* 1484bff34e3Sthurlow * smbfs vfs operations. 1494bff34e3Sthurlow */ 1504bff34e3Sthurlow static int smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 1514bff34e3Sthurlow static int smbfs_unmount(vfs_t *, int, cred_t *); 1524bff34e3Sthurlow static int smbfs_root(vfs_t *, vnode_t **); 1534bff34e3Sthurlow static int smbfs_statvfs(vfs_t *, statvfs64_t *); 1544bff34e3Sthurlow static int smbfs_sync(vfs_t *, short, cred_t *); 1554bff34e3Sthurlow static void smbfs_freevfs(vfs_t *); 1564bff34e3Sthurlow 1574bff34e3Sthurlow /* 1584bff34e3Sthurlow * Module loading 1594bff34e3Sthurlow */ 1604bff34e3Sthurlow 1614bff34e3Sthurlow /* 1624bff34e3Sthurlow * This routine is invoked automatically when the kernel module 1634bff34e3Sthurlow * containing this routine is loaded. This allows module specific 1644bff34e3Sthurlow * initialization to be done when the module is loaded. 1654bff34e3Sthurlow */ 1664bff34e3Sthurlow int 1674bff34e3Sthurlow _init(void) 1684bff34e3Sthurlow { 16902d09e03SGordon Ross int error; 1704bff34e3Sthurlow 1714bff34e3Sthurlow /* 1724bff34e3Sthurlow * Check compiled-in version of "nsmb" 1734bff34e3Sthurlow * that we're linked with. (paranoid) 1744bff34e3Sthurlow */ 1754bff34e3Sthurlow if (nsmb_version != NSMB_VERSION) { 1764bff34e3Sthurlow cmn_err(CE_WARN, "_init: nsmb version mismatch"); 1774bff34e3Sthurlow return (ENOTTY); 1784bff34e3Sthurlow } 1794bff34e3Sthurlow 1804bff34e3Sthurlow smbfs_mountcount = 0; 1814bff34e3Sthurlow 18202d09e03SGordon Ross /* 18302d09e03SGordon Ross * NFS calls these two in _clntinit 18402d09e03SGordon Ross * Easier to follow this way. 18502d09e03SGordon Ross */ 18602d09e03SGordon Ross if ((error = smbfs_subrinit()) != 0) { 18702d09e03SGordon Ross cmn_err(CE_WARN, "_init: smbfs_subrinit failed"); 18802d09e03SGordon Ross return (error); 18902d09e03SGordon Ross } 19002d09e03SGordon Ross 19102d09e03SGordon Ross if ((error = smbfs_vfsinit()) != 0) { 19202d09e03SGordon Ross cmn_err(CE_WARN, "_init: smbfs_vfsinit failed"); 19302d09e03SGordon Ross smbfs_subrfini(); 19402d09e03SGordon Ross return (error); 19502d09e03SGordon Ross } 19602d09e03SGordon Ross 19702d09e03SGordon Ross if ((error = smbfs_clntinit()) != 0) { 1984bff34e3Sthurlow cmn_err(CE_WARN, "_init: smbfs_clntinit failed"); 19902d09e03SGordon Ross smbfs_vfsfini(); 20002d09e03SGordon Ross smbfs_subrfini(); 20102d09e03SGordon Ross return (error); 2024bff34e3Sthurlow } 2034bff34e3Sthurlow 20402d09e03SGordon Ross error = mod_install((struct modlinkage *)&modlinkage); 20502d09e03SGordon Ross return (error); 2064bff34e3Sthurlow } 2074bff34e3Sthurlow 2084bff34e3Sthurlow /* 2094bff34e3Sthurlow * Free kernel module resources that were allocated in _init 2104bff34e3Sthurlow * and remove the linkage information into the kernel 2114bff34e3Sthurlow */ 2124bff34e3Sthurlow int 2134bff34e3Sthurlow _fini(void) 2144bff34e3Sthurlow { 2154bff34e3Sthurlow int error; 2164bff34e3Sthurlow 2174bff34e3Sthurlow /* 2184bff34e3Sthurlow * If a forcedly unmounted instance is still hanging around, 2194bff34e3Sthurlow * we cannot allow the module to be unloaded because that would 2204bff34e3Sthurlow * cause panics once the VFS framework decides it's time to call 2214bff34e3Sthurlow * into VFS_FREEVFS(). 2224bff34e3Sthurlow */ 2234bff34e3Sthurlow if (smbfs_mountcount) 2244bff34e3Sthurlow return (EBUSY); 2254bff34e3Sthurlow 2264bff34e3Sthurlow error = mod_remove(&modlinkage); 2274bff34e3Sthurlow if (error) 2284bff34e3Sthurlow return (error); 2294bff34e3Sthurlow 2304bff34e3Sthurlow /* 2314bff34e3Sthurlow * Free the allocated smbnodes, etc. 2324bff34e3Sthurlow */ 2334bff34e3Sthurlow smbfs_clntfini(); 2344bff34e3Sthurlow 23502d09e03SGordon Ross /* NFS calls these two in _clntfini */ 23602d09e03SGordon Ross smbfs_vfsfini(); 23702d09e03SGordon Ross smbfs_subrfini(); 23802d09e03SGordon Ross 2394bff34e3Sthurlow /* 2404bff34e3Sthurlow * Free the ops vectors 2414bff34e3Sthurlow */ 2424bff34e3Sthurlow smbfsfini(); 2434bff34e3Sthurlow return (0); 2444bff34e3Sthurlow } 2454bff34e3Sthurlow 2464bff34e3Sthurlow /* 2474bff34e3Sthurlow * Return information about the module 2484bff34e3Sthurlow */ 2494bff34e3Sthurlow int 2504bff34e3Sthurlow _info(struct modinfo *modinfop) 2514bff34e3Sthurlow { 2524bff34e3Sthurlow return (mod_info((struct modlinkage *)&modlinkage, modinfop)); 2534bff34e3Sthurlow } 2544bff34e3Sthurlow 2554bff34e3Sthurlow /* 2564bff34e3Sthurlow * Initialize the vfs structure 2574bff34e3Sthurlow */ 2584bff34e3Sthurlow 2594bff34e3Sthurlow int smbfsfstyp; 2604bff34e3Sthurlow vfsops_t *smbfs_vfsops = NULL; 2614bff34e3Sthurlow 2624bff34e3Sthurlow static const fs_operation_def_t smbfs_vfsops_template[] = { 2634bff34e3Sthurlow { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } }, 2644bff34e3Sthurlow { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } }, 2654bff34e3Sthurlow { VFSNAME_ROOT, { .vfs_root = smbfs_root } }, 2664bff34e3Sthurlow { VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } }, 2674bff34e3Sthurlow { VFSNAME_SYNC, { .vfs_sync = smbfs_sync } }, 2684bff34e3Sthurlow { VFSNAME_VGET, { .error = fs_nosys } }, 2694bff34e3Sthurlow { VFSNAME_MOUNTROOT, { .error = fs_nosys } }, 2704bff34e3Sthurlow { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } }, 2714bff34e3Sthurlow { NULL, NULL } 2724bff34e3Sthurlow }; 2734bff34e3Sthurlow 2744bff34e3Sthurlow int 2754bff34e3Sthurlow smbfsinit(int fstyp, char *name) 2764bff34e3Sthurlow { 2774bff34e3Sthurlow int error; 2784bff34e3Sthurlow 2794bff34e3Sthurlow error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); 2804bff34e3Sthurlow if (error != 0) { 2814bff34e3Sthurlow zcmn_err(GLOBAL_ZONEID, CE_WARN, 2824bff34e3Sthurlow "smbfsinit: bad vfs ops template"); 2834bff34e3Sthurlow return (error); 2844bff34e3Sthurlow } 2854bff34e3Sthurlow 2864bff34e3Sthurlow error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); 2874bff34e3Sthurlow if (error != 0) { 2884bff34e3Sthurlow (void) vfs_freevfsops_by_type(fstyp); 2894bff34e3Sthurlow zcmn_err(GLOBAL_ZONEID, CE_WARN, 2904bff34e3Sthurlow "smbfsinit: bad vnode ops template"); 2914bff34e3Sthurlow return (error); 2924bff34e3Sthurlow } 2934bff34e3Sthurlow 2944bff34e3Sthurlow smbfsfstyp = fstyp; 2954bff34e3Sthurlow 2964bff34e3Sthurlow return (0); 2974bff34e3Sthurlow } 2984bff34e3Sthurlow 2994bff34e3Sthurlow void 3004bff34e3Sthurlow smbfsfini() 3014bff34e3Sthurlow { 3024bff34e3Sthurlow if (smbfs_vfsops) { 3034bff34e3Sthurlow (void) vfs_freevfsops_by_type(smbfsfstyp); 3044bff34e3Sthurlow smbfs_vfsops = NULL; 3054bff34e3Sthurlow } 3064bff34e3Sthurlow if (smbfs_vnodeops) { 3074bff34e3Sthurlow vn_freevnodeops(smbfs_vnodeops); 3084bff34e3Sthurlow smbfs_vnodeops = NULL; 3094bff34e3Sthurlow } 3104bff34e3Sthurlow } 3114bff34e3Sthurlow 3124bff34e3Sthurlow void 3134bff34e3Sthurlow smbfs_free_smi(smbmntinfo_t *smi) 3144bff34e3Sthurlow { 31502d09e03SGordon Ross if (smi == NULL) 31602d09e03SGordon Ross return; 31702d09e03SGordon Ross 318a19609f8Sjv if (smi->smi_zone_ref.zref_zone != NULL) 319a19609f8Sjv zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS); 32002d09e03SGordon Ross 32102d09e03SGordon Ross if (smi->smi_share != NULL) 32202d09e03SGordon Ross smb_share_rele(smi->smi_share); 32302d09e03SGordon Ross 32402d09e03SGordon Ross avl_destroy(&smi->smi_hash_avl); 32502d09e03SGordon Ross rw_destroy(&smi->smi_hash_lk); 32602d09e03SGordon Ross cv_destroy(&smi->smi_statvfs_cv); 32702d09e03SGordon Ross mutex_destroy(&smi->smi_lock); 32802d09e03SGordon Ross 32902d09e03SGordon Ross kmem_free(smi, sizeof (smbmntinfo_t)); 3304bff34e3Sthurlow } 3314bff34e3Sthurlow 3324bff34e3Sthurlow /* 3334bff34e3Sthurlow * smbfs mount vfsop 3344bff34e3Sthurlow * Set up mount info record and attach it to vfs struct. 3354bff34e3Sthurlow */ 3364bff34e3Sthurlow static int 3374bff34e3Sthurlow smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 3384bff34e3Sthurlow { 3394bff34e3Sthurlow char *data = uap->dataptr; 3404bff34e3Sthurlow int error; 34102d09e03SGordon Ross smbnode_t *rtnp = NULL; /* root of this fs */ 3424bff34e3Sthurlow smbmntinfo_t *smi = NULL; 3434bff34e3Sthurlow dev_t smbfs_dev; 3444bff34e3Sthurlow int version; 3454bff34e3Sthurlow int devfd; 3464bff34e3Sthurlow zone_t *zone = curproc->p_zone; 3474bff34e3Sthurlow zone_t *mntzone = NULL; 3484bff34e3Sthurlow smb_share_t *ssp = NULL; 3494bff34e3Sthurlow smb_cred_t scred; 35002d09e03SGordon Ross int flags, sec; 3514bff34e3Sthurlow 3524bff34e3Sthurlow STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ 3534bff34e3Sthurlow 3544bff34e3Sthurlow if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 3554bff34e3Sthurlow return (error); 3564bff34e3Sthurlow 3574bff34e3Sthurlow if (mvp->v_type != VDIR) 3584bff34e3Sthurlow return (ENOTDIR); 3594bff34e3Sthurlow 3604bff34e3Sthurlow /* 3614bff34e3Sthurlow * get arguments 3624bff34e3Sthurlow * 3634bff34e3Sthurlow * uap->datalen might be different from sizeof (args) 3644bff34e3Sthurlow * in a compatible situation. 3654bff34e3Sthurlow */ 3664bff34e3Sthurlow STRUCT_INIT(args, get_udatamodel()); 3674bff34e3Sthurlow bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); 3684bff34e3Sthurlow if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, 3694bff34e3Sthurlow SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)))) 3704bff34e3Sthurlow return (EFAULT); 3714bff34e3Sthurlow 3724bff34e3Sthurlow /* 3734bff34e3Sthurlow * Check mount program version 3744bff34e3Sthurlow */ 3754bff34e3Sthurlow version = STRUCT_FGET(args, version); 3764bff34e3Sthurlow if (version != SMBFS_VERSION) { 3774bff34e3Sthurlow cmn_err(CE_WARN, "mount version mismatch:" 3784bff34e3Sthurlow " kernel=%d, mount=%d\n", 3794bff34e3Sthurlow SMBFS_VERSION, version); 3804bff34e3Sthurlow return (EINVAL); 3814bff34e3Sthurlow } 3824bff34e3Sthurlow 38302d09e03SGordon Ross /* 38402d09e03SGordon Ross * Deal with re-mount requests. 38502d09e03SGordon Ross */ 3864bff34e3Sthurlow if (uap->flags & MS_REMOUNT) { 3874bff34e3Sthurlow cmn_err(CE_WARN, "MS_REMOUNT not implemented"); 3884bff34e3Sthurlow return (ENOTSUP); 3894bff34e3Sthurlow } 3904bff34e3Sthurlow 3914bff34e3Sthurlow /* 3924bff34e3Sthurlow * Check for busy 3934bff34e3Sthurlow */ 3944bff34e3Sthurlow mutex_enter(&mvp->v_lock); 3954bff34e3Sthurlow if (!(uap->flags & MS_OVERLAY) && 3964bff34e3Sthurlow (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 3974bff34e3Sthurlow mutex_exit(&mvp->v_lock); 3984bff34e3Sthurlow return (EBUSY); 3994bff34e3Sthurlow } 4004bff34e3Sthurlow mutex_exit(&mvp->v_lock); 4014bff34e3Sthurlow 4024bff34e3Sthurlow /* 4034bff34e3Sthurlow * Get the "share" from the netsmb driver (ssp). 4044bff34e3Sthurlow * It is returned with a "ref" (hold) for us. 4054bff34e3Sthurlow * Release this hold: at errout below, or in 4064bff34e3Sthurlow * smbfs_freevfs(). 4074bff34e3Sthurlow */ 4084bff34e3Sthurlow devfd = STRUCT_FGET(args, devfd); 4094bff34e3Sthurlow error = smb_dev2share(devfd, &ssp); 4104bff34e3Sthurlow if (error) { 4114bff34e3Sthurlow cmn_err(CE_WARN, "invalid device handle %d (%d)\n", 4124bff34e3Sthurlow devfd, error); 4134bff34e3Sthurlow return (error); 4144bff34e3Sthurlow } 4154bff34e3Sthurlow 4164bff34e3Sthurlow /* 4174bff34e3Sthurlow * Use "goto errout" from here on. 41802d09e03SGordon Ross * See: ssp, smi, rtnp, mntzone 4194bff34e3Sthurlow */ 4204bff34e3Sthurlow 4214bff34e3Sthurlow /* 4224bff34e3Sthurlow * Determine the zone we're being mounted into. 4234bff34e3Sthurlow */ 4244bff34e3Sthurlow zone_hold(mntzone = zone); /* start with this assumption */ 4254bff34e3Sthurlow if (getzoneid() == GLOBAL_ZONEID) { 4264bff34e3Sthurlow zone_rele(mntzone); 4274bff34e3Sthurlow mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 4284bff34e3Sthurlow ASSERT(mntzone != NULL); 4294bff34e3Sthurlow if (mntzone != zone) { 4304bff34e3Sthurlow error = EBUSY; 4314bff34e3Sthurlow goto errout; 4324bff34e3Sthurlow } 4334bff34e3Sthurlow } 4344bff34e3Sthurlow 4354bff34e3Sthurlow /* 4364bff34e3Sthurlow * Stop the mount from going any further if the zone is going away. 4374bff34e3Sthurlow */ 4384bff34e3Sthurlow if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { 4394bff34e3Sthurlow error = EBUSY; 4404bff34e3Sthurlow goto errout; 4414bff34e3Sthurlow } 4424bff34e3Sthurlow 4434bff34e3Sthurlow /* 4444bff34e3Sthurlow * On a Trusted Extensions client, we may have to force read-only 4454bff34e3Sthurlow * for read-down mounts. 4464bff34e3Sthurlow */ 4474bff34e3Sthurlow if (is_system_labeled()) { 4484bff34e3Sthurlow void *addr; 4494bff34e3Sthurlow int ipvers = 0; 4504bff34e3Sthurlow struct smb_vc *vcp; 4514bff34e3Sthurlow 4524bff34e3Sthurlow vcp = SSTOVC(ssp); 4534bff34e3Sthurlow addr = smb_vc_getipaddr(vcp, &ipvers); 4544bff34e3Sthurlow error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr); 4554bff34e3Sthurlow 4564bff34e3Sthurlow if (error > 0) 4574bff34e3Sthurlow goto errout; 4584bff34e3Sthurlow 4594bff34e3Sthurlow if (error == -1) { 4604bff34e3Sthurlow /* change mount to read-only to prevent write-down */ 4614bff34e3Sthurlow vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 4624bff34e3Sthurlow } 4634bff34e3Sthurlow } 4644bff34e3Sthurlow 46502d09e03SGordon Ross /* Prevent unload. */ 46602d09e03SGordon Ross atomic_inc_32(&smbfs_mountcount); 4674bff34e3Sthurlow 4684bff34e3Sthurlow /* 4694bff34e3Sthurlow * Create a mount record and link it to the vfs struct. 47002d09e03SGordon Ross * No more possiblities for errors from here on. 47102d09e03SGordon Ross * Tear-down of this stuff is in smbfs_free_smi() 47202d09e03SGordon Ross * 4734bff34e3Sthurlow * Compare with NFS: nfsrootvp() 4744bff34e3Sthurlow */ 47502d09e03SGordon Ross smi = kmem_zalloc(sizeof (*smi), KM_SLEEP); 47602d09e03SGordon Ross 47702d09e03SGordon Ross mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL); 47802d09e03SGordon Ross cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL); 4794bff34e3Sthurlow 48002d09e03SGordon Ross rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL); 48102d09e03SGordon Ross smbfs_init_hash_avl(&smi->smi_hash_avl); 48202d09e03SGordon Ross 48302d09e03SGordon Ross smi->smi_share = ssp; 48402d09e03SGordon Ross ssp = NULL; 485a19609f8Sjv 486a19609f8Sjv /* 487a19609f8Sjv * Convert the anonymous zone hold acquired via zone_hold() above 488a19609f8Sjv * into a zone reference. 489a19609f8Sjv */ 490a19609f8Sjv zone_init_ref(&smi->smi_zone_ref); 491a19609f8Sjv zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS); 492a19609f8Sjv zone_rele(mntzone); 49302d09e03SGordon Ross mntzone = NULL; 49402d09e03SGordon Ross 49502d09e03SGordon Ross /* 49602d09e03SGordon Ross * Initialize option defaults 49702d09e03SGordon Ross */ 49891d632c8Sgwr smi->smi_flags = SMI_LLOCK; 49902d09e03SGordon Ross smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN); 50002d09e03SGordon Ross smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX); 50102d09e03SGordon Ross smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN); 50202d09e03SGordon Ross smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX); 50391d632c8Sgwr 50491d632c8Sgwr /* 50502d09e03SGordon Ross * All "generic" mount options have already been 50602d09e03SGordon Ross * handled in vfs.c:domount() - see mntopts stuff. 50702d09e03SGordon Ross * Query generic options using vfs_optionisset(). 50891d632c8Sgwr */ 50991d632c8Sgwr if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) 51091d632c8Sgwr smi->smi_flags |= SMI_INT; 511bd7c6f51SGordon Ross if (vfs_optionisset(vfsp, MNTOPT_ACL, NULL)) 512bd7c6f51SGordon Ross smi->smi_flags |= SMI_ACL; 5134bff34e3Sthurlow 5144bff34e3Sthurlow /* 51502d09e03SGordon Ross * Get the mount options that come in as smbfs_args, 51602d09e03SGordon Ross * starting with args.flags (SMBFS_MF_xxx) 51702d09e03SGordon Ross */ 51802d09e03SGordon Ross flags = STRUCT_FGET(args, flags); 51902d09e03SGordon Ross smi->smi_uid = STRUCT_FGET(args, uid); 52002d09e03SGordon Ross smi->smi_gid = STRUCT_FGET(args, gid); 52102d09e03SGordon Ross smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777; 52202d09e03SGordon Ross smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777; 52302d09e03SGordon Ross 52402d09e03SGordon Ross /* 52502d09e03SGordon Ross * Hande the SMBFS_MF_xxx flags. 5264bff34e3Sthurlow */ 52702d09e03SGordon Ross if (flags & SMBFS_MF_NOAC) 52802d09e03SGordon Ross smi->smi_flags |= SMI_NOAC; 52902d09e03SGordon Ross if (flags & SMBFS_MF_ACREGMIN) { 53002d09e03SGordon Ross sec = STRUCT_FGET(args, acregmin); 53102d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMINMAX) 53202d09e03SGordon Ross sec = SMBFS_ACMINMAX; 53302d09e03SGordon Ross smi->smi_acregmin = SEC2HR(sec); 53402d09e03SGordon Ross } 53502d09e03SGordon Ross if (flags & SMBFS_MF_ACREGMAX) { 53602d09e03SGordon Ross sec = STRUCT_FGET(args, acregmax); 53702d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMAXMAX) 53802d09e03SGordon Ross sec = SMBFS_ACMAXMAX; 53902d09e03SGordon Ross smi->smi_acregmax = SEC2HR(sec); 54002d09e03SGordon Ross } 54102d09e03SGordon Ross if (flags & SMBFS_MF_ACDIRMIN) { 54202d09e03SGordon Ross sec = STRUCT_FGET(args, acdirmin); 54302d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMINMAX) 54402d09e03SGordon Ross sec = SMBFS_ACMINMAX; 54502d09e03SGordon Ross smi->smi_acdirmin = SEC2HR(sec); 54602d09e03SGordon Ross } 54702d09e03SGordon Ross if (flags & SMBFS_MF_ACDIRMAX) { 54802d09e03SGordon Ross sec = STRUCT_FGET(args, acdirmax); 54902d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMAXMAX) 55002d09e03SGordon Ross sec = SMBFS_ACMAXMAX; 55102d09e03SGordon Ross smi->smi_acdirmax = SEC2HR(sec); 55202d09e03SGordon Ross } 5534bff34e3Sthurlow 55491d632c8Sgwr /* 55591d632c8Sgwr * Get attributes of the remote file system, 55691d632c8Sgwr * i.e. ACL support, named streams, etc. 55791d632c8Sgwr */ 55802d09e03SGordon Ross smb_credinit(&scred, cr); 55902d09e03SGordon Ross error = smbfs_smb_qfsattr(smi->smi_share, &smi->smi_fsa, &scred); 56002d09e03SGordon Ross smb_credrele(&scred); 5614bff34e3Sthurlow if (error) { 5624bff34e3Sthurlow SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error); 5634bff34e3Sthurlow } 5644bff34e3Sthurlow 56591d632c8Sgwr /* 56691d632c8Sgwr * We enable XATTR by default (via smbfs_mntopts) 56791d632c8Sgwr * but if the share does not support named streams, 56891d632c8Sgwr * force the NOXATTR option (also clears XATTR). 56991d632c8Sgwr * Caller will set or clear VFS_XATTR after this. 57091d632c8Sgwr */ 57191d632c8Sgwr if ((smi->smi_fsattr & FILE_NAMED_STREAMS) == 0) 57291d632c8Sgwr vfs_setmntopt(vfsp, MNTOPT_NOXATTR, NULL, 0); 5734bff34e3Sthurlow 574bd7c6f51SGordon Ross /* 575bd7c6f51SGordon Ross * Ditto ACLs (disable if not supported on this share) 576bd7c6f51SGordon Ross */ 577bd7c6f51SGordon Ross if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) { 578bd7c6f51SGordon Ross vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0); 579bd7c6f51SGordon Ross smi->smi_flags &= ~SMI_ACL; 580bd7c6f51SGordon Ross } 581bd7c6f51SGordon Ross 5824bff34e3Sthurlow /* 5834bff34e3Sthurlow * Assign a unique device id to the mount 5844bff34e3Sthurlow */ 5854bff34e3Sthurlow mutex_enter(&smbfs_minor_lock); 5864bff34e3Sthurlow do { 5874bff34e3Sthurlow smbfs_minor = (smbfs_minor + 1) & MAXMIN32; 5884bff34e3Sthurlow smbfs_dev = makedevice(smbfs_major, smbfs_minor); 5894bff34e3Sthurlow } while (vfs_devismounted(smbfs_dev)); 5904bff34e3Sthurlow mutex_exit(&smbfs_minor_lock); 5914bff34e3Sthurlow 5924bff34e3Sthurlow vfsp->vfs_dev = smbfs_dev; 5934bff34e3Sthurlow vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp); 5944bff34e3Sthurlow vfsp->vfs_data = (caddr_t)smi; 5954bff34e3Sthurlow vfsp->vfs_fstype = smbfsfstyp; 5964bff34e3Sthurlow vfsp->vfs_bsize = MAXBSIZE; 5974bff34e3Sthurlow vfsp->vfs_bcount = 0; 5984bff34e3Sthurlow 5994bff34e3Sthurlow smi->smi_vfsp = vfsp; 60002d09e03SGordon Ross smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */ 6014bff34e3Sthurlow 6024bff34e3Sthurlow /* 6034bff34e3Sthurlow * Create the root vnode, which we need in unmount 60402d09e03SGordon Ross * for the call to smbfs_check_table(), etc. 60502d09e03SGordon Ross * Release this hold in smbfs_unmount. 6064bff34e3Sthurlow */ 60702d09e03SGordon Ross rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0, 60802d09e03SGordon Ross &smbfs_fattr0); 60902d09e03SGordon Ross ASSERT(rtnp != NULL); 61002d09e03SGordon Ross rtnp->r_vnode->v_type = VDIR; 61102d09e03SGordon Ross rtnp->r_vnode->v_flag |= VROOT; 61202d09e03SGordon Ross smi->smi_root = rtnp; 6134bff34e3Sthurlow 6144bff34e3Sthurlow /* 6154bff34e3Sthurlow * NFS does other stuff here too: 6164bff34e3Sthurlow * async worker threads 6174bff34e3Sthurlow * init kstats 6184bff34e3Sthurlow * 6194bff34e3Sthurlow * End of code from NFS nfsrootvp() 6204bff34e3Sthurlow */ 6214bff34e3Sthurlow return (0); 6224bff34e3Sthurlow 6234bff34e3Sthurlow errout: 6244bff34e3Sthurlow vfsp->vfs_data = NULL; 62502d09e03SGordon Ross if (smi != NULL) 6264bff34e3Sthurlow smbfs_free_smi(smi); 6274bff34e3Sthurlow 6284bff34e3Sthurlow if (mntzone != NULL) 6294bff34e3Sthurlow zone_rele(mntzone); 6304bff34e3Sthurlow 63102d09e03SGordon Ross if (ssp != NULL) 6324bff34e3Sthurlow smb_share_rele(ssp); 6334bff34e3Sthurlow 6344bff34e3Sthurlow return (error); 6354bff34e3Sthurlow } 6364bff34e3Sthurlow 6374bff34e3Sthurlow /* 6384bff34e3Sthurlow * vfs operations 6394bff34e3Sthurlow */ 6404bff34e3Sthurlow static int 6414bff34e3Sthurlow smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) 6424bff34e3Sthurlow { 6434bff34e3Sthurlow smbmntinfo_t *smi; 6444bff34e3Sthurlow smbnode_t *rtnp; 6454bff34e3Sthurlow 6464bff34e3Sthurlow smi = VFTOSMI(vfsp); 6474bff34e3Sthurlow 6484bff34e3Sthurlow if (secpolicy_fs_unmount(cr, vfsp) != 0) 6494bff34e3Sthurlow return (EPERM); 6504bff34e3Sthurlow 6514bff34e3Sthurlow if ((flag & MS_FORCE) == 0) { 6524bff34e3Sthurlow smbfs_rflush(vfsp, cr); 6534bff34e3Sthurlow 6544bff34e3Sthurlow /* 6554bff34e3Sthurlow * If there are any active vnodes on this file system, 6564bff34e3Sthurlow * (other than the root vnode) then the file system is 6574bff34e3Sthurlow * busy and can't be umounted. 6584bff34e3Sthurlow */ 65902d09e03SGordon Ross if (smbfs_check_table(vfsp, smi->smi_root)) 6604bff34e3Sthurlow return (EBUSY); 6614bff34e3Sthurlow 6624bff34e3Sthurlow /* 6634bff34e3Sthurlow * We normally hold a ref to the root vnode, so 6644bff34e3Sthurlow * check for references beyond the one we expect: 6654bff34e3Sthurlow * smbmntinfo_t -> smi_root 6664bff34e3Sthurlow * Note that NFS does not hold the root vnode. 6674bff34e3Sthurlow */ 6684bff34e3Sthurlow if (smi->smi_root && 6694bff34e3Sthurlow smi->smi_root->r_vnode->v_count > 1) 6704bff34e3Sthurlow return (EBUSY); 6714bff34e3Sthurlow } 6724bff34e3Sthurlow 6734bff34e3Sthurlow /* 6744bff34e3Sthurlow * common code for both forced and non-forced 6754bff34e3Sthurlow * 6764bff34e3Sthurlow * Setting VFS_UNMOUNTED prevents new operations. 6774bff34e3Sthurlow * Operations already underway may continue, 6784bff34e3Sthurlow * but not for long. 6794bff34e3Sthurlow */ 6804bff34e3Sthurlow vfsp->vfs_flag |= VFS_UNMOUNTED; 6814bff34e3Sthurlow 6824bff34e3Sthurlow /* 6834bff34e3Sthurlow * Shutdown any outstanding I/O requests on this share, 6844bff34e3Sthurlow * and force a tree disconnect. The share object will 6854bff34e3Sthurlow * continue to hang around until smb_share_rele(). 6864bff34e3Sthurlow * This should also cause most active nodes to be 6874bff34e3Sthurlow * released as their operations fail with EIO. 6884bff34e3Sthurlow */ 6894bff34e3Sthurlow smb_share_kill(smi->smi_share); 6904bff34e3Sthurlow 6914bff34e3Sthurlow /* 6924bff34e3Sthurlow * If we hold the root VP (and we normally do) 6934bff34e3Sthurlow * then it's safe to release it now. 6944bff34e3Sthurlow */ 6954bff34e3Sthurlow if (smi->smi_root) { 6964bff34e3Sthurlow rtnp = smi->smi_root; 6974bff34e3Sthurlow smi->smi_root = NULL; 6984bff34e3Sthurlow VN_RELE(rtnp->r_vnode); /* release root vnode */ 6994bff34e3Sthurlow } 7004bff34e3Sthurlow 7014bff34e3Sthurlow /* 7024bff34e3Sthurlow * Remove all nodes from the node hash tables. 70302d09e03SGordon Ross * This (indirectly) calls: smbfs_addfree, smbinactive, 7044bff34e3Sthurlow * which will try to flush dirty pages, etc. so 7054bff34e3Sthurlow * don't destroy the underlying share just yet. 7064bff34e3Sthurlow * 7074bff34e3Sthurlow * Also, with a forced unmount, some nodes may 7084bff34e3Sthurlow * remain active, and those will get cleaned up 7094bff34e3Sthurlow * after their last vn_rele. 7104bff34e3Sthurlow */ 7114bff34e3Sthurlow smbfs_destroy_table(vfsp); 7124bff34e3Sthurlow 7134bff34e3Sthurlow /* 7144bff34e3Sthurlow * Delete our kstats... 7154bff34e3Sthurlow * 7164bff34e3Sthurlow * Doing it here, rather than waiting until 7174bff34e3Sthurlow * smbfs_freevfs so these are not visible 7184bff34e3Sthurlow * after the unmount. 7194bff34e3Sthurlow */ 7204bff34e3Sthurlow if (smi->smi_io_kstats) { 7214bff34e3Sthurlow kstat_delete(smi->smi_io_kstats); 7224bff34e3Sthurlow smi->smi_io_kstats = NULL; 7234bff34e3Sthurlow } 7244bff34e3Sthurlow if (smi->smi_ro_kstats) { 7254bff34e3Sthurlow kstat_delete(smi->smi_ro_kstats); 7264bff34e3Sthurlow smi->smi_ro_kstats = NULL; 7274bff34e3Sthurlow } 7284bff34e3Sthurlow 7294bff34e3Sthurlow /* 73002d09e03SGordon Ross * The rest happens in smbfs_freevfs() 7314bff34e3Sthurlow */ 7324bff34e3Sthurlow return (0); 7334bff34e3Sthurlow } 7344bff34e3Sthurlow 7354bff34e3Sthurlow 7364bff34e3Sthurlow /* 7374bff34e3Sthurlow * find root of smbfs 7384bff34e3Sthurlow */ 7394bff34e3Sthurlow static int 7404bff34e3Sthurlow smbfs_root(vfs_t *vfsp, vnode_t **vpp) 7414bff34e3Sthurlow { 7424bff34e3Sthurlow smbmntinfo_t *smi; 7434bff34e3Sthurlow vnode_t *vp; 7444bff34e3Sthurlow 7454bff34e3Sthurlow smi = VFTOSMI(vfsp); 7464bff34e3Sthurlow 747a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 7484bff34e3Sthurlow return (EPERM); 7494bff34e3Sthurlow 7504bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 7514bff34e3Sthurlow return (EIO); 7524bff34e3Sthurlow 7534bff34e3Sthurlow /* 7544bff34e3Sthurlow * The root vp is created in mount and held 7554bff34e3Sthurlow * until unmount, so this is paranoia. 7564bff34e3Sthurlow */ 7574bff34e3Sthurlow if (smi->smi_root == NULL) 7584bff34e3Sthurlow return (EIO); 7594bff34e3Sthurlow 7604bff34e3Sthurlow /* Just take a reference and return it. */ 7614bff34e3Sthurlow vp = SMBTOV(smi->smi_root); 7624bff34e3Sthurlow VN_HOLD(vp); 7634bff34e3Sthurlow *vpp = vp; 7644bff34e3Sthurlow 7654bff34e3Sthurlow return (0); 7664bff34e3Sthurlow } 7674bff34e3Sthurlow 7684bff34e3Sthurlow /* 7694bff34e3Sthurlow * Get file system statistics. 7704bff34e3Sthurlow */ 7714bff34e3Sthurlow static int 7724bff34e3Sthurlow smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp) 7734bff34e3Sthurlow { 7744bff34e3Sthurlow int error; 7754bff34e3Sthurlow smbmntinfo_t *smi = VFTOSMI(vfsp); 7764bff34e3Sthurlow smb_share_t *ssp = smi->smi_share; 7774bff34e3Sthurlow statvfs64_t stvfs; 7784bff34e3Sthurlow hrtime_t now; 7794bff34e3Sthurlow smb_cred_t scred; 7804bff34e3Sthurlow 781a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 7824bff34e3Sthurlow return (EPERM); 7834bff34e3Sthurlow 7844bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 7854bff34e3Sthurlow return (EIO); 7864bff34e3Sthurlow 7874bff34e3Sthurlow mutex_enter(&smi->smi_lock); 7884bff34e3Sthurlow 7894bff34e3Sthurlow /* 7904bff34e3Sthurlow * Use cached result if still valid. 7914bff34e3Sthurlow */ 7924bff34e3Sthurlow recheck: 7934bff34e3Sthurlow now = gethrtime(); 7944bff34e3Sthurlow if (now < smi->smi_statfstime) { 795613a2f6bSGordon Ross error = 0; 7964bff34e3Sthurlow goto cache_hit; 7974bff34e3Sthurlow } 7984bff34e3Sthurlow 7994bff34e3Sthurlow /* 8004bff34e3Sthurlow * FS attributes are stale, so someone 8014bff34e3Sthurlow * needs to do an OTW call to get them. 8024bff34e3Sthurlow * Serialize here so only one thread 8034bff34e3Sthurlow * does the OTW call. 8044bff34e3Sthurlow */ 8054bff34e3Sthurlow if (smi->smi_status & SM_STATUS_STATFS_BUSY) { 8064bff34e3Sthurlow smi->smi_status |= SM_STATUS_STATFS_WANT; 8074bff34e3Sthurlow if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) { 8084bff34e3Sthurlow mutex_exit(&smi->smi_lock); 8094bff34e3Sthurlow return (EINTR); 8104bff34e3Sthurlow } 8114bff34e3Sthurlow /* Hope status is valid now. */ 8124bff34e3Sthurlow goto recheck; 8134bff34e3Sthurlow } 8144bff34e3Sthurlow smi->smi_status |= SM_STATUS_STATFS_BUSY; 8154bff34e3Sthurlow mutex_exit(&smi->smi_lock); 8164bff34e3Sthurlow 8174bff34e3Sthurlow /* 8184bff34e3Sthurlow * Do the OTW call. Note: lock NOT held. 8194bff34e3Sthurlow */ 820613a2f6bSGordon Ross smb_credinit(&scred, NULL); 8214bff34e3Sthurlow bzero(&stvfs, sizeof (stvfs)); 8224bff34e3Sthurlow error = smbfs_smb_statfs(ssp, &stvfs, &scred); 8234bff34e3Sthurlow smb_credrele(&scred); 824613a2f6bSGordon Ross if (error) { 825613a2f6bSGordon Ross SMBVDEBUG("statfs error=%d\n", error); 826613a2f6bSGordon Ross } else { 827613a2f6bSGordon Ross 828613a2f6bSGordon Ross /* 829613a2f6bSGordon Ross * Set a few things the OTW call didn't get. 830613a2f6bSGordon Ross */ 831613a2f6bSGordon Ross stvfs.f_frsize = stvfs.f_bsize; 832613a2f6bSGordon Ross stvfs.f_favail = stvfs.f_ffree; 833613a2f6bSGordon Ross stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0]; 834613a2f6bSGordon Ross bcopy(fs_type_name, stvfs.f_basetype, FSTYPSZ); 835613a2f6bSGordon Ross stvfs.f_flag = vf_to_stf(vfsp->vfs_flag); 836613a2f6bSGordon Ross stvfs.f_namemax = smi->smi_fsa.fsa_maxname; 837613a2f6bSGordon Ross 838613a2f6bSGordon Ross /* 839613a2f6bSGordon Ross * Save the result, update lifetime 840613a2f6bSGordon Ross */ 841613a2f6bSGordon Ross now = gethrtime(); 842613a2f6bSGordon Ross smi->smi_statfstime = now + 843613a2f6bSGordon Ross (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC); 844613a2f6bSGordon Ross smi->smi_statvfsbuf = stvfs; /* struct assign! */ 845613a2f6bSGordon Ross } 8464bff34e3Sthurlow 8474bff34e3Sthurlow mutex_enter(&smi->smi_lock); 8484bff34e3Sthurlow if (smi->smi_status & SM_STATUS_STATFS_WANT) 8494bff34e3Sthurlow cv_broadcast(&smi->smi_statvfs_cv); 8504bff34e3Sthurlow smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT); 8514bff34e3Sthurlow 8524bff34e3Sthurlow /* 8534bff34e3Sthurlow * Copy the statvfs data to caller's buf. 8544bff34e3Sthurlow * Note: struct assignment 8554bff34e3Sthurlow */ 8564bff34e3Sthurlow cache_hit: 857613a2f6bSGordon Ross if (error == 0) 858613a2f6bSGordon Ross *sbp = smi->smi_statvfsbuf; 8594bff34e3Sthurlow mutex_exit(&smi->smi_lock); 8604bff34e3Sthurlow return (error); 8614bff34e3Sthurlow } 8624bff34e3Sthurlow 8634bff34e3Sthurlow static kmutex_t smbfs_syncbusy; 8644bff34e3Sthurlow 8654bff34e3Sthurlow /* 8664bff34e3Sthurlow * Flush dirty smbfs files for file system vfsp. 8674bff34e3Sthurlow * If vfsp == NULL, all smbfs files are flushed. 8684bff34e3Sthurlow */ 8694bff34e3Sthurlow /*ARGSUSED*/ 8704bff34e3Sthurlow static int 8714bff34e3Sthurlow smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) 8724bff34e3Sthurlow { 8734bff34e3Sthurlow /* 8744bff34e3Sthurlow * Cross-zone calls are OK here, since this translates to a 8754bff34e3Sthurlow * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. 8764bff34e3Sthurlow */ 8774bff34e3Sthurlow if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) { 8784bff34e3Sthurlow smbfs_rflush(vfsp, cr); 8794bff34e3Sthurlow mutex_exit(&smbfs_syncbusy); 8804bff34e3Sthurlow } 88102d09e03SGordon Ross 8824bff34e3Sthurlow return (0); 8834bff34e3Sthurlow } 8844bff34e3Sthurlow 8854bff34e3Sthurlow /* 8864bff34e3Sthurlow * Initialization routine for VFS routines. Should only be called once 8874bff34e3Sthurlow */ 8884bff34e3Sthurlow int 8894bff34e3Sthurlow smbfs_vfsinit(void) 8904bff34e3Sthurlow { 8914bff34e3Sthurlow mutex_init(&smbfs_syncbusy, NULL, MUTEX_DEFAULT, NULL); 8924bff34e3Sthurlow return (0); 8934bff34e3Sthurlow } 8944bff34e3Sthurlow 8954bff34e3Sthurlow /* 8964bff34e3Sthurlow * Shutdown routine for VFS routines. Should only be called once 8974bff34e3Sthurlow */ 8984bff34e3Sthurlow void 8994bff34e3Sthurlow smbfs_vfsfini(void) 9004bff34e3Sthurlow { 9014bff34e3Sthurlow mutex_destroy(&smbfs_syncbusy); 9024bff34e3Sthurlow } 9034bff34e3Sthurlow 9044bff34e3Sthurlow void 9054bff34e3Sthurlow smbfs_freevfs(vfs_t *vfsp) 9064bff34e3Sthurlow { 9074bff34e3Sthurlow smbmntinfo_t *smi; 9084bff34e3Sthurlow 9094bff34e3Sthurlow /* free up the resources */ 9104bff34e3Sthurlow smi = VFTOSMI(vfsp); 9114bff34e3Sthurlow 9124bff34e3Sthurlow /* 9134bff34e3Sthurlow * By this time we should have already deleted the 9144bff34e3Sthurlow * smi kstats in the unmount code. If they are still around 9154bff34e3Sthurlow * something is wrong 9164bff34e3Sthurlow */ 9174bff34e3Sthurlow ASSERT(smi->smi_io_kstats == NULL); 9184bff34e3Sthurlow 91902d09e03SGordon Ross smbfs_zonelist_remove(smi); 9204bff34e3Sthurlow 9214bff34e3Sthurlow smbfs_free_smi(smi); 9224bff34e3Sthurlow 9234bff34e3Sthurlow /* 9244bff34e3Sthurlow * Allow _fini() to succeed now, if so desired. 9254bff34e3Sthurlow */ 9264bff34e3Sthurlow atomic_dec_32(&smbfs_mountcount); 9274bff34e3Sthurlow } 9284bff34e3Sthurlow 9294bff34e3Sthurlow /* 9304bff34e3Sthurlow * smbfs_mount_label_policy: 9314bff34e3Sthurlow * Determine whether the mount is allowed according to MAC check, 9324bff34e3Sthurlow * by comparing (where appropriate) label of the remote server 9334bff34e3Sthurlow * against the label of the zone being mounted into. 9344bff34e3Sthurlow * 9354bff34e3Sthurlow * Returns: 9364bff34e3Sthurlow * 0 : access allowed 9374bff34e3Sthurlow * -1 : read-only access allowed (i.e., read-down) 9384bff34e3Sthurlow * >0 : error code, such as EACCES 9394bff34e3Sthurlow * 9404bff34e3Sthurlow * NB: 9414bff34e3Sthurlow * NFS supports Cipso labels by parsing the vfs_resource 9424bff34e3Sthurlow * to see what the Solaris server global zone has shared. 9434bff34e3Sthurlow * We can't support that for CIFS since resource names 9444bff34e3Sthurlow * contain share names, not paths. 9454bff34e3Sthurlow */ 9464bff34e3Sthurlow static int 9474bff34e3Sthurlow smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr) 9484bff34e3Sthurlow { 9494bff34e3Sthurlow bslabel_t *server_sl, *mntlabel; 9504bff34e3Sthurlow zone_t *mntzone = NULL; 9514bff34e3Sthurlow ts_label_t *zlabel; 9524bff34e3Sthurlow tsol_tpc_t *tp; 9534bff34e3Sthurlow ts_label_t *tsl = NULL; 9544bff34e3Sthurlow int retv; 9554bff34e3Sthurlow 9564bff34e3Sthurlow /* 9574bff34e3Sthurlow * Get the zone's label. Each zone on a labeled system has a label. 9584bff34e3Sthurlow */ 9594bff34e3Sthurlow mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); 9604bff34e3Sthurlow zlabel = mntzone->zone_slabel; 9614bff34e3Sthurlow ASSERT(zlabel != NULL); 9624bff34e3Sthurlow label_hold(zlabel); 9634bff34e3Sthurlow 9644bff34e3Sthurlow retv = EACCES; /* assume the worst */ 9654bff34e3Sthurlow 9664bff34e3Sthurlow /* 9674bff34e3Sthurlow * Next, get the assigned label of the remote server. 9684bff34e3Sthurlow */ 9694bff34e3Sthurlow tp = find_tpc(ipaddr, addr_type, B_FALSE); 9704bff34e3Sthurlow if (tp == NULL) 9714bff34e3Sthurlow goto out; /* error getting host entry */ 9724bff34e3Sthurlow 9734bff34e3Sthurlow if (tp->tpc_tp.tp_doi != zlabel->tsl_doi) 9744bff34e3Sthurlow goto rel_tpc; /* invalid domain */ 9754bff34e3Sthurlow if ((tp->tpc_tp.host_type != UNLABELED)) 9764bff34e3Sthurlow goto rel_tpc; /* invalid hosttype */ 9774bff34e3Sthurlow 9784bff34e3Sthurlow server_sl = &tp->tpc_tp.tp_def_label; 9794bff34e3Sthurlow mntlabel = label2bslabel(zlabel); 9804bff34e3Sthurlow 9814bff34e3Sthurlow /* 9824bff34e3Sthurlow * Now compare labels to complete the MAC check. If the labels 9834bff34e3Sthurlow * are equal or if the requestor is in the global zone and has 9844bff34e3Sthurlow * NET_MAC_AWARE, then allow read-write access. (Except for 9854bff34e3Sthurlow * mounts into the global zone itself; restrict these to 9864bff34e3Sthurlow * read-only.) 9874bff34e3Sthurlow * 9884bff34e3Sthurlow * If the requestor is in some other zone, but his label 9894bff34e3Sthurlow * dominates the server, then allow read-down. 9904bff34e3Sthurlow * 9914bff34e3Sthurlow * Otherwise, access is denied. 9924bff34e3Sthurlow */ 9934bff34e3Sthurlow if (blequal(mntlabel, server_sl) || 9944bff34e3Sthurlow (crgetzoneid(cr) == GLOBAL_ZONEID && 9954bff34e3Sthurlow getpflags(NET_MAC_AWARE, cr) != 0)) { 9964bff34e3Sthurlow if ((mntzone == global_zone) || 9974bff34e3Sthurlow !blequal(mntlabel, server_sl)) 9984bff34e3Sthurlow retv = -1; /* read-only */ 9994bff34e3Sthurlow else 10004bff34e3Sthurlow retv = 0; /* access OK */ 10014bff34e3Sthurlow } else if (bldominates(mntlabel, server_sl)) { 10024bff34e3Sthurlow retv = -1; /* read-only */ 10034bff34e3Sthurlow } else { 10044bff34e3Sthurlow retv = EACCES; 10054bff34e3Sthurlow } 10064bff34e3Sthurlow 10074bff34e3Sthurlow if (tsl != NULL) 10084bff34e3Sthurlow label_rele(tsl); 10094bff34e3Sthurlow 10104bff34e3Sthurlow rel_tpc: 10114bff34e3Sthurlow /*LINTED*/ 10124bff34e3Sthurlow TPC_RELE(tp); 10134bff34e3Sthurlow out: 10144bff34e3Sthurlow if (mntzone) 10154bff34e3Sthurlow zone_rele(mntzone); 10164bff34e3Sthurlow label_rele(zlabel); 10174bff34e3Sthurlow return (retv); 10184bff34e3Sthurlow } 1019