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