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*9005860cSGordon Ross * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 388cd81a20SJerry Jelinek * Copyright 2013, Joyent, Inc. All rights reserved. 3948bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved. 404bff34e3Sthurlow */ 414bff34e3Sthurlow 424bff34e3Sthurlow #include <sys/systm.h> 434bff34e3Sthurlow #include <sys/cred.h> 4402d09e03SGordon Ross #include <sys/time.h> 454bff34e3Sthurlow #include <sys/vfs.h> 464bff34e3Sthurlow #include <sys/vnode.h> 474bff34e3Sthurlow #include <fs/fs_subr.h> 484bff34e3Sthurlow #include <sys/sysmacros.h> 494bff34e3Sthurlow #include <sys/kmem.h> 504bff34e3Sthurlow #include <sys/mkdev.h> 514bff34e3Sthurlow #include <sys/mount.h> 524bff34e3Sthurlow #include <sys/statvfs.h> 534bff34e3Sthurlow #include <sys/errno.h> 544bff34e3Sthurlow #include <sys/debug.h> 554bff34e3Sthurlow #include <sys/cmn_err.h> 564bff34e3Sthurlow #include <sys/modctl.h> 574bff34e3Sthurlow #include <sys/policy.h> 584bff34e3Sthurlow #include <sys/atomic.h> 594bff34e3Sthurlow #include <sys/zone.h> 604bff34e3Sthurlow #include <sys/vfs_opreg.h> 614bff34e3Sthurlow #include <sys/mntent.h> 624bff34e3Sthurlow #include <sys/priv.h> 634bff34e3Sthurlow #include <sys/tsol/label.h> 644bff34e3Sthurlow #include <sys/tsol/tndb.h> 654bff34e3Sthurlow #include <inet/ip.h> 664bff34e3Sthurlow 674bff34e3Sthurlow #include <netsmb/smb_osdep.h> 684bff34e3Sthurlow #include <netsmb/smb.h> 694bff34e3Sthurlow #include <netsmb/smb_conn.h> 704bff34e3Sthurlow #include <netsmb/smb_subr.h> 714bff34e3Sthurlow #include <netsmb/smb_dev.h> 724bff34e3Sthurlow 734bff34e3Sthurlow #include <smbfs/smbfs.h> 744bff34e3Sthurlow #include <smbfs/smbfs_node.h> 754bff34e3Sthurlow #include <smbfs/smbfs_subr.h> 764bff34e3Sthurlow 77*9005860cSGordon Ross /* 78*9005860cSGordon Ross * Should smbfs mount enable "-o acl" by default? There are good 79*9005860cSGordon Ross * arguments for both. The most common use case is individual users 80*9005860cSGordon Ross * accessing files on some SMB server, for which "noacl" is the more 81*9005860cSGordon Ross * convenient default. A less common use case is data migration, 82*9005860cSGordon Ross * where the "acl" option might be a desirable default. We'll make 83*9005860cSGordon Ross * the common use case the default. This default can be changed via 84*9005860cSGordon Ross * /etc/system, and/or set per-mount via the "acl" mount option. 85*9005860cSGordon Ross */ 86*9005860cSGordon Ross int smbfs_default_opt_acl = 0; 87*9005860cSGordon Ross 884bff34e3Sthurlow /* 894bff34e3Sthurlow * Local functions definitions. 904bff34e3Sthurlow */ 914bff34e3Sthurlow int smbfsinit(int fstyp, char *name); 924bff34e3Sthurlow void smbfsfini(); 934bff34e3Sthurlow static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *); 944bff34e3Sthurlow 9591d632c8Sgwr /* 9691d632c8Sgwr * SMBFS Mount options table for MS_OPTIONSTR 9791d632c8Sgwr * Note: These are not all the options. 9891d632c8Sgwr * Some options come in via MS_DATA. 9991d632c8Sgwr * Others are generic (see vfs.c) 10091d632c8Sgwr */ 10191d632c8Sgwr static char *intr_cancel[] = { MNTOPT_NOINTR, NULL }; 10291d632c8Sgwr static char *nointr_cancel[] = { MNTOPT_INTR, NULL }; 103bd7c6f51SGordon Ross static char *acl_cancel[] = { MNTOPT_NOACL, NULL }; 104bd7c6f51SGordon Ross static char *noacl_cancel[] = { MNTOPT_ACL, NULL }; 10591d632c8Sgwr static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 10691d632c8Sgwr static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 10791d632c8Sgwr 10891d632c8Sgwr static mntopt_t mntopts[] = { 10991d632c8Sgwr /* 11091d632c8Sgwr * option name cancel option default arg flags 11191d632c8Sgwr * ufs arg flag 11291d632c8Sgwr */ 11391d632c8Sgwr { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 0 }, 11491d632c8Sgwr { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 0 }, 115*9005860cSGordon Ross { MNTOPT_ACL, acl_cancel, NULL, 0, 0 }, 116bd7c6f51SGordon Ross { MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 }, 11791d632c8Sgwr { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 }, 11891d632c8Sgwr { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 } 11991d632c8Sgwr }; 12091d632c8Sgwr 12191d632c8Sgwr static mntopts_t smbfs_mntopts = { 12291d632c8Sgwr sizeof (mntopts) / sizeof (mntopt_t), 12391d632c8Sgwr mntopts 12491d632c8Sgwr }; 12591d632c8Sgwr 126613a2f6bSGordon Ross static const char fs_type_name[FSTYPSZ] = "smbfs"; 127613a2f6bSGordon Ross 1284bff34e3Sthurlow static vfsdef_t vfw = { 1294bff34e3Sthurlow VFSDEF_VERSION, 130613a2f6bSGordon Ross (char *)fs_type_name, 1314bff34e3Sthurlow smbfsinit, /* init routine */ 1328cd81a20SJerry Jelinek VSW_HASPROTO|VSW_NOTZONESAFE, /* flags */ 13391d632c8Sgwr &smbfs_mntopts /* mount options table prototype */ 1344bff34e3Sthurlow }; 1354bff34e3Sthurlow 1364bff34e3Sthurlow static struct modlfs modlfs = { 1374bff34e3Sthurlow &mod_fsops, 138613a2f6bSGordon Ross "SMBFS filesystem", 1394bff34e3Sthurlow &vfw 1404bff34e3Sthurlow }; 1414bff34e3Sthurlow 1424bff34e3Sthurlow static struct modlinkage modlinkage = { 1434bff34e3Sthurlow MODREV_1, (void *)&modlfs, NULL 1444bff34e3Sthurlow }; 1454bff34e3Sthurlow 1464bff34e3Sthurlow /* 1474bff34e3Sthurlow * Mutex to protect the following variables: 1484bff34e3Sthurlow * smbfs_major 1494bff34e3Sthurlow * smbfs_minor 1504bff34e3Sthurlow */ 1514bff34e3Sthurlow extern kmutex_t smbfs_minor_lock; 1524bff34e3Sthurlow extern int smbfs_major; 1534bff34e3Sthurlow extern int smbfs_minor; 1544bff34e3Sthurlow 1554bff34e3Sthurlow /* 1564bff34e3Sthurlow * Prevent unloads while we have mounts 1574bff34e3Sthurlow */ 1584bff34e3Sthurlow uint32_t smbfs_mountcount; 1594bff34e3Sthurlow 1604bff34e3Sthurlow /* 1614bff34e3Sthurlow * smbfs vfs operations. 1624bff34e3Sthurlow */ 1634bff34e3Sthurlow static int smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 1644bff34e3Sthurlow static int smbfs_unmount(vfs_t *, int, cred_t *); 1654bff34e3Sthurlow static int smbfs_root(vfs_t *, vnode_t **); 1664bff34e3Sthurlow static int smbfs_statvfs(vfs_t *, statvfs64_t *); 1674bff34e3Sthurlow static int smbfs_sync(vfs_t *, short, cred_t *); 1684bff34e3Sthurlow static void smbfs_freevfs(vfs_t *); 1694bff34e3Sthurlow 1704bff34e3Sthurlow /* 1714bff34e3Sthurlow * Module loading 1724bff34e3Sthurlow */ 1734bff34e3Sthurlow 1744bff34e3Sthurlow /* 1754bff34e3Sthurlow * This routine is invoked automatically when the kernel module 1764bff34e3Sthurlow * containing this routine is loaded. This allows module specific 1774bff34e3Sthurlow * initialization to be done when the module is loaded. 1784bff34e3Sthurlow */ 1794bff34e3Sthurlow int 1804bff34e3Sthurlow _init(void) 1814bff34e3Sthurlow { 18202d09e03SGordon Ross int error; 1834bff34e3Sthurlow 1844bff34e3Sthurlow /* 1854bff34e3Sthurlow * Check compiled-in version of "nsmb" 1864bff34e3Sthurlow * that we're linked with. (paranoid) 1874bff34e3Sthurlow */ 1884bff34e3Sthurlow if (nsmb_version != NSMB_VERSION) { 1894bff34e3Sthurlow cmn_err(CE_WARN, "_init: nsmb version mismatch"); 1904bff34e3Sthurlow return (ENOTTY); 1914bff34e3Sthurlow } 1924bff34e3Sthurlow 1934bff34e3Sthurlow smbfs_mountcount = 0; 1944bff34e3Sthurlow 19502d09e03SGordon Ross /* 19602d09e03SGordon Ross * NFS calls these two in _clntinit 19702d09e03SGordon Ross * Easier to follow this way. 19802d09e03SGordon Ross */ 19902d09e03SGordon Ross if ((error = smbfs_subrinit()) != 0) { 20002d09e03SGordon Ross cmn_err(CE_WARN, "_init: smbfs_subrinit failed"); 20102d09e03SGordon Ross return (error); 20202d09e03SGordon Ross } 20302d09e03SGordon Ross 20402d09e03SGordon Ross if ((error = smbfs_vfsinit()) != 0) { 20502d09e03SGordon Ross cmn_err(CE_WARN, "_init: smbfs_vfsinit failed"); 20602d09e03SGordon Ross smbfs_subrfini(); 20702d09e03SGordon Ross return (error); 20802d09e03SGordon Ross } 20902d09e03SGordon Ross 21002d09e03SGordon Ross if ((error = smbfs_clntinit()) != 0) { 2114bff34e3Sthurlow cmn_err(CE_WARN, "_init: smbfs_clntinit failed"); 21202d09e03SGordon Ross smbfs_vfsfini(); 21302d09e03SGordon Ross smbfs_subrfini(); 21402d09e03SGordon Ross return (error); 2154bff34e3Sthurlow } 2164bff34e3Sthurlow 21702d09e03SGordon Ross error = mod_install((struct modlinkage *)&modlinkage); 21802d09e03SGordon Ross return (error); 2194bff34e3Sthurlow } 2204bff34e3Sthurlow 2214bff34e3Sthurlow /* 2224bff34e3Sthurlow * Free kernel module resources that were allocated in _init 2234bff34e3Sthurlow * and remove the linkage information into the kernel 2244bff34e3Sthurlow */ 2254bff34e3Sthurlow int 2264bff34e3Sthurlow _fini(void) 2274bff34e3Sthurlow { 2284bff34e3Sthurlow int error; 2294bff34e3Sthurlow 2304bff34e3Sthurlow /* 2314bff34e3Sthurlow * If a forcedly unmounted instance is still hanging around, 2324bff34e3Sthurlow * we cannot allow the module to be unloaded because that would 2334bff34e3Sthurlow * cause panics once the VFS framework decides it's time to call 2344bff34e3Sthurlow * into VFS_FREEVFS(). 2354bff34e3Sthurlow */ 2364bff34e3Sthurlow if (smbfs_mountcount) 2374bff34e3Sthurlow return (EBUSY); 2384bff34e3Sthurlow 2394bff34e3Sthurlow error = mod_remove(&modlinkage); 2404bff34e3Sthurlow if (error) 2414bff34e3Sthurlow return (error); 2424bff34e3Sthurlow 2434bff34e3Sthurlow /* 2444bff34e3Sthurlow * Free the allocated smbnodes, etc. 2454bff34e3Sthurlow */ 2464bff34e3Sthurlow smbfs_clntfini(); 2474bff34e3Sthurlow 24802d09e03SGordon Ross /* NFS calls these two in _clntfini */ 24902d09e03SGordon Ross smbfs_vfsfini(); 25002d09e03SGordon Ross smbfs_subrfini(); 25102d09e03SGordon Ross 2524bff34e3Sthurlow /* 2534bff34e3Sthurlow * Free the ops vectors 2544bff34e3Sthurlow */ 2554bff34e3Sthurlow smbfsfini(); 2564bff34e3Sthurlow return (0); 2574bff34e3Sthurlow } 2584bff34e3Sthurlow 2594bff34e3Sthurlow /* 2604bff34e3Sthurlow * Return information about the module 2614bff34e3Sthurlow */ 2624bff34e3Sthurlow int 2634bff34e3Sthurlow _info(struct modinfo *modinfop) 2644bff34e3Sthurlow { 2654bff34e3Sthurlow return (mod_info((struct modlinkage *)&modlinkage, modinfop)); 2664bff34e3Sthurlow } 2674bff34e3Sthurlow 2684bff34e3Sthurlow /* 2694bff34e3Sthurlow * Initialize the vfs structure 2704bff34e3Sthurlow */ 2714bff34e3Sthurlow 2724bff34e3Sthurlow int smbfsfstyp; 2734bff34e3Sthurlow vfsops_t *smbfs_vfsops = NULL; 2744bff34e3Sthurlow 2754bff34e3Sthurlow static const fs_operation_def_t smbfs_vfsops_template[] = { 2764bff34e3Sthurlow { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } }, 2774bff34e3Sthurlow { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } }, 2784bff34e3Sthurlow { VFSNAME_ROOT, { .vfs_root = smbfs_root } }, 2794bff34e3Sthurlow { VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } }, 2804bff34e3Sthurlow { VFSNAME_SYNC, { .vfs_sync = smbfs_sync } }, 2814bff34e3Sthurlow { VFSNAME_VGET, { .error = fs_nosys } }, 2824bff34e3Sthurlow { VFSNAME_MOUNTROOT, { .error = fs_nosys } }, 2834bff34e3Sthurlow { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } }, 2844bff34e3Sthurlow { NULL, NULL } 2854bff34e3Sthurlow }; 2864bff34e3Sthurlow 2874bff34e3Sthurlow int 2884bff34e3Sthurlow smbfsinit(int fstyp, char *name) 2894bff34e3Sthurlow { 2904bff34e3Sthurlow int error; 2914bff34e3Sthurlow 2924bff34e3Sthurlow error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); 2934bff34e3Sthurlow if (error != 0) { 2944bff34e3Sthurlow zcmn_err(GLOBAL_ZONEID, CE_WARN, 2954bff34e3Sthurlow "smbfsinit: bad vfs ops template"); 2964bff34e3Sthurlow return (error); 2974bff34e3Sthurlow } 2984bff34e3Sthurlow 2994bff34e3Sthurlow error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); 3004bff34e3Sthurlow if (error != 0) { 3014bff34e3Sthurlow (void) vfs_freevfsops_by_type(fstyp); 3024bff34e3Sthurlow zcmn_err(GLOBAL_ZONEID, CE_WARN, 3034bff34e3Sthurlow "smbfsinit: bad vnode ops template"); 3044bff34e3Sthurlow return (error); 3054bff34e3Sthurlow } 3064bff34e3Sthurlow 3074bff34e3Sthurlow smbfsfstyp = fstyp; 3084bff34e3Sthurlow 3094bff34e3Sthurlow return (0); 3104bff34e3Sthurlow } 3114bff34e3Sthurlow 3124bff34e3Sthurlow void 3134bff34e3Sthurlow smbfsfini() 3144bff34e3Sthurlow { 3154bff34e3Sthurlow if (smbfs_vfsops) { 3164bff34e3Sthurlow (void) vfs_freevfsops_by_type(smbfsfstyp); 3174bff34e3Sthurlow smbfs_vfsops = NULL; 3184bff34e3Sthurlow } 3194bff34e3Sthurlow if (smbfs_vnodeops) { 3204bff34e3Sthurlow vn_freevnodeops(smbfs_vnodeops); 3214bff34e3Sthurlow smbfs_vnodeops = NULL; 3224bff34e3Sthurlow } 3234bff34e3Sthurlow } 3244bff34e3Sthurlow 3254bff34e3Sthurlow void 3264bff34e3Sthurlow smbfs_free_smi(smbmntinfo_t *smi) 3274bff34e3Sthurlow { 32802d09e03SGordon Ross if (smi == NULL) 32902d09e03SGordon Ross return; 33002d09e03SGordon Ross 331a19609f8Sjv if (smi->smi_zone_ref.zref_zone != NULL) 332a19609f8Sjv zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS); 33302d09e03SGordon Ross 33402d09e03SGordon Ross if (smi->smi_share != NULL) 33502d09e03SGordon Ross smb_share_rele(smi->smi_share); 33602d09e03SGordon Ross 33702d09e03SGordon Ross avl_destroy(&smi->smi_hash_avl); 33802d09e03SGordon Ross rw_destroy(&smi->smi_hash_lk); 33902d09e03SGordon Ross cv_destroy(&smi->smi_statvfs_cv); 34002d09e03SGordon Ross mutex_destroy(&smi->smi_lock); 34102d09e03SGordon Ross 34202d09e03SGordon Ross kmem_free(smi, sizeof (smbmntinfo_t)); 3434bff34e3Sthurlow } 3444bff34e3Sthurlow 3454bff34e3Sthurlow /* 3464bff34e3Sthurlow * smbfs mount vfsop 3474bff34e3Sthurlow * Set up mount info record and attach it to vfs struct. 3484bff34e3Sthurlow */ 3494bff34e3Sthurlow static int 3504bff34e3Sthurlow smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 3514bff34e3Sthurlow { 3524bff34e3Sthurlow char *data = uap->dataptr; 3534bff34e3Sthurlow int error; 35402d09e03SGordon Ross smbnode_t *rtnp = NULL; /* root of this fs */ 3554bff34e3Sthurlow smbmntinfo_t *smi = NULL; 3564bff34e3Sthurlow dev_t smbfs_dev; 3574bff34e3Sthurlow int version; 3584bff34e3Sthurlow int devfd; 3594bff34e3Sthurlow zone_t *zone = curproc->p_zone; 3604bff34e3Sthurlow zone_t *mntzone = NULL; 3614bff34e3Sthurlow smb_share_t *ssp = NULL; 3624bff34e3Sthurlow smb_cred_t scred; 36302d09e03SGordon Ross int flags, sec; 3644bff34e3Sthurlow 3654bff34e3Sthurlow STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ 3664bff34e3Sthurlow 3674bff34e3Sthurlow if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 3684bff34e3Sthurlow return (error); 3694bff34e3Sthurlow 3704bff34e3Sthurlow if (mvp->v_type != VDIR) 3714bff34e3Sthurlow return (ENOTDIR); 3724bff34e3Sthurlow 3734bff34e3Sthurlow /* 3744bff34e3Sthurlow * get arguments 3754bff34e3Sthurlow * 3764bff34e3Sthurlow * uap->datalen might be different from sizeof (args) 3774bff34e3Sthurlow * in a compatible situation. 3784bff34e3Sthurlow */ 3794bff34e3Sthurlow STRUCT_INIT(args, get_udatamodel()); 3804bff34e3Sthurlow bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); 3814bff34e3Sthurlow if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, 3824bff34e3Sthurlow SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)))) 3834bff34e3Sthurlow return (EFAULT); 3844bff34e3Sthurlow 3854bff34e3Sthurlow /* 3864bff34e3Sthurlow * Check mount program version 3874bff34e3Sthurlow */ 3884bff34e3Sthurlow version = STRUCT_FGET(args, version); 3894bff34e3Sthurlow if (version != SMBFS_VERSION) { 3904bff34e3Sthurlow cmn_err(CE_WARN, "mount version mismatch:" 3914bff34e3Sthurlow " kernel=%d, mount=%d\n", 3924bff34e3Sthurlow SMBFS_VERSION, version); 3934bff34e3Sthurlow return (EINVAL); 3944bff34e3Sthurlow } 3954bff34e3Sthurlow 39602d09e03SGordon Ross /* 39702d09e03SGordon Ross * Deal with re-mount requests. 39802d09e03SGordon Ross */ 3994bff34e3Sthurlow if (uap->flags & MS_REMOUNT) { 4004bff34e3Sthurlow cmn_err(CE_WARN, "MS_REMOUNT not implemented"); 4014bff34e3Sthurlow return (ENOTSUP); 4024bff34e3Sthurlow } 4034bff34e3Sthurlow 4044bff34e3Sthurlow /* 4054bff34e3Sthurlow * Check for busy 4064bff34e3Sthurlow */ 4074bff34e3Sthurlow mutex_enter(&mvp->v_lock); 4084bff34e3Sthurlow if (!(uap->flags & MS_OVERLAY) && 4094bff34e3Sthurlow (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 4104bff34e3Sthurlow mutex_exit(&mvp->v_lock); 4114bff34e3Sthurlow return (EBUSY); 4124bff34e3Sthurlow } 4134bff34e3Sthurlow mutex_exit(&mvp->v_lock); 4144bff34e3Sthurlow 4154bff34e3Sthurlow /* 4164bff34e3Sthurlow * Get the "share" from the netsmb driver (ssp). 4174bff34e3Sthurlow * It is returned with a "ref" (hold) for us. 4184bff34e3Sthurlow * Release this hold: at errout below, or in 4194bff34e3Sthurlow * smbfs_freevfs(). 4204bff34e3Sthurlow */ 4214bff34e3Sthurlow devfd = STRUCT_FGET(args, devfd); 4224bff34e3Sthurlow error = smb_dev2share(devfd, &ssp); 4234bff34e3Sthurlow if (error) { 4244bff34e3Sthurlow cmn_err(CE_WARN, "invalid device handle %d (%d)\n", 4254bff34e3Sthurlow devfd, error); 4264bff34e3Sthurlow return (error); 4274bff34e3Sthurlow } 4284bff34e3Sthurlow 4294bff34e3Sthurlow /* 4304bff34e3Sthurlow * Use "goto errout" from here on. 43102d09e03SGordon Ross * See: ssp, smi, rtnp, mntzone 4324bff34e3Sthurlow */ 4334bff34e3Sthurlow 4344bff34e3Sthurlow /* 4354bff34e3Sthurlow * Determine the zone we're being mounted into. 4364bff34e3Sthurlow */ 4374bff34e3Sthurlow zone_hold(mntzone = zone); /* start with this assumption */ 4384bff34e3Sthurlow if (getzoneid() == GLOBAL_ZONEID) { 4394bff34e3Sthurlow zone_rele(mntzone); 4404bff34e3Sthurlow mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 4414bff34e3Sthurlow ASSERT(mntzone != NULL); 4424bff34e3Sthurlow if (mntzone != zone) { 4434bff34e3Sthurlow error = EBUSY; 4444bff34e3Sthurlow goto errout; 4454bff34e3Sthurlow } 4464bff34e3Sthurlow } 4474bff34e3Sthurlow 4484bff34e3Sthurlow /* 4494bff34e3Sthurlow * Stop the mount from going any further if the zone is going away. 4504bff34e3Sthurlow */ 4514bff34e3Sthurlow if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { 4524bff34e3Sthurlow error = EBUSY; 4534bff34e3Sthurlow goto errout; 4544bff34e3Sthurlow } 4554bff34e3Sthurlow 4564bff34e3Sthurlow /* 4574bff34e3Sthurlow * On a Trusted Extensions client, we may have to force read-only 4584bff34e3Sthurlow * for read-down mounts. 4594bff34e3Sthurlow */ 4604bff34e3Sthurlow if (is_system_labeled()) { 4614bff34e3Sthurlow void *addr; 4624bff34e3Sthurlow int ipvers = 0; 4634bff34e3Sthurlow struct smb_vc *vcp; 4644bff34e3Sthurlow 4654bff34e3Sthurlow vcp = SSTOVC(ssp); 4664bff34e3Sthurlow addr = smb_vc_getipaddr(vcp, &ipvers); 4674bff34e3Sthurlow error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr); 4684bff34e3Sthurlow 4694bff34e3Sthurlow if (error > 0) 4704bff34e3Sthurlow goto errout; 4714bff34e3Sthurlow 4724bff34e3Sthurlow if (error == -1) { 4734bff34e3Sthurlow /* change mount to read-only to prevent write-down */ 4744bff34e3Sthurlow vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 4754bff34e3Sthurlow } 4764bff34e3Sthurlow } 4774bff34e3Sthurlow 47802d09e03SGordon Ross /* Prevent unload. */ 47902d09e03SGordon Ross atomic_inc_32(&smbfs_mountcount); 4804bff34e3Sthurlow 4814bff34e3Sthurlow /* 4824bff34e3Sthurlow * Create a mount record and link it to the vfs struct. 48302d09e03SGordon Ross * No more possiblities for errors from here on. 48402d09e03SGordon Ross * Tear-down of this stuff is in smbfs_free_smi() 48502d09e03SGordon Ross * 4864bff34e3Sthurlow * Compare with NFS: nfsrootvp() 4874bff34e3Sthurlow */ 48802d09e03SGordon Ross smi = kmem_zalloc(sizeof (*smi), KM_SLEEP); 48902d09e03SGordon Ross 49002d09e03SGordon Ross mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL); 49102d09e03SGordon Ross cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL); 4924bff34e3Sthurlow 49302d09e03SGordon Ross rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL); 49402d09e03SGordon Ross smbfs_init_hash_avl(&smi->smi_hash_avl); 49502d09e03SGordon Ross 49602d09e03SGordon Ross smi->smi_share = ssp; 49702d09e03SGordon Ross ssp = NULL; 498a19609f8Sjv 499a19609f8Sjv /* 500a19609f8Sjv * Convert the anonymous zone hold acquired via zone_hold() above 501a19609f8Sjv * into a zone reference. 502a19609f8Sjv */ 503a19609f8Sjv zone_init_ref(&smi->smi_zone_ref); 504a19609f8Sjv zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS); 505a19609f8Sjv zone_rele(mntzone); 50602d09e03SGordon Ross mntzone = NULL; 50702d09e03SGordon Ross 50802d09e03SGordon Ross /* 50902d09e03SGordon Ross * Initialize option defaults 51002d09e03SGordon Ross */ 51191d632c8Sgwr smi->smi_flags = SMI_LLOCK; 51202d09e03SGordon Ross smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN); 51302d09e03SGordon Ross smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX); 51402d09e03SGordon Ross smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN); 51502d09e03SGordon Ross smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX); 51691d632c8Sgwr 51791d632c8Sgwr /* 51802d09e03SGordon Ross * All "generic" mount options have already been 51902d09e03SGordon Ross * handled in vfs.c:domount() - see mntopts stuff. 52002d09e03SGordon Ross * Query generic options using vfs_optionisset(). 521*9005860cSGordon Ross * Give ACL an adjustable system-wide default. 52291d632c8Sgwr */ 523*9005860cSGordon Ross if (smbfs_default_opt_acl || 524*9005860cSGordon Ross vfs_optionisset(vfsp, MNTOPT_ACL, NULL)) 525*9005860cSGordon Ross smi->smi_flags |= SMI_ACL; 526*9005860cSGordon Ross if (vfs_optionisset(vfsp, MNTOPT_NOACL, NULL)) 527*9005860cSGordon Ross smi->smi_flags &= ~SMI_ACL; 52891d632c8Sgwr if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) 52991d632c8Sgwr smi->smi_flags |= SMI_INT; 5304bff34e3Sthurlow 5314bff34e3Sthurlow /* 53202d09e03SGordon Ross * Get the mount options that come in as smbfs_args, 53302d09e03SGordon Ross * starting with args.flags (SMBFS_MF_xxx) 53402d09e03SGordon Ross */ 53502d09e03SGordon Ross flags = STRUCT_FGET(args, flags); 53602d09e03SGordon Ross smi->smi_uid = STRUCT_FGET(args, uid); 53702d09e03SGordon Ross smi->smi_gid = STRUCT_FGET(args, gid); 53802d09e03SGordon Ross smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777; 53902d09e03SGordon Ross smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777; 54002d09e03SGordon Ross 54102d09e03SGordon Ross /* 54202d09e03SGordon Ross * Hande the SMBFS_MF_xxx flags. 5434bff34e3Sthurlow */ 54402d09e03SGordon Ross if (flags & SMBFS_MF_NOAC) 54502d09e03SGordon Ross smi->smi_flags |= SMI_NOAC; 54602d09e03SGordon Ross if (flags & SMBFS_MF_ACREGMIN) { 54702d09e03SGordon Ross sec = STRUCT_FGET(args, acregmin); 54802d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMINMAX) 54902d09e03SGordon Ross sec = SMBFS_ACMINMAX; 55002d09e03SGordon Ross smi->smi_acregmin = SEC2HR(sec); 55102d09e03SGordon Ross } 55202d09e03SGordon Ross if (flags & SMBFS_MF_ACREGMAX) { 55302d09e03SGordon Ross sec = STRUCT_FGET(args, acregmax); 55402d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMAXMAX) 55502d09e03SGordon Ross sec = SMBFS_ACMAXMAX; 55602d09e03SGordon Ross smi->smi_acregmax = SEC2HR(sec); 55702d09e03SGordon Ross } 55802d09e03SGordon Ross if (flags & SMBFS_MF_ACDIRMIN) { 55902d09e03SGordon Ross sec = STRUCT_FGET(args, acdirmin); 56002d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMINMAX) 56102d09e03SGordon Ross sec = SMBFS_ACMINMAX; 56202d09e03SGordon Ross smi->smi_acdirmin = SEC2HR(sec); 56302d09e03SGordon Ross } 56402d09e03SGordon Ross if (flags & SMBFS_MF_ACDIRMAX) { 56502d09e03SGordon Ross sec = STRUCT_FGET(args, acdirmax); 56602d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMAXMAX) 56702d09e03SGordon Ross sec = SMBFS_ACMAXMAX; 56802d09e03SGordon Ross smi->smi_acdirmax = SEC2HR(sec); 56902d09e03SGordon Ross } 5704bff34e3Sthurlow 57191d632c8Sgwr /* 57291d632c8Sgwr * Get attributes of the remote file system, 57391d632c8Sgwr * i.e. ACL support, named streams, etc. 57491d632c8Sgwr */ 57502d09e03SGordon Ross smb_credinit(&scred, cr); 57602d09e03SGordon Ross error = smbfs_smb_qfsattr(smi->smi_share, &smi->smi_fsa, &scred); 57702d09e03SGordon Ross smb_credrele(&scred); 5784bff34e3Sthurlow if (error) { 5794bff34e3Sthurlow SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error); 5804bff34e3Sthurlow } 5814bff34e3Sthurlow 58291d632c8Sgwr /* 58391d632c8Sgwr * We enable XATTR by default (via smbfs_mntopts) 58491d632c8Sgwr * but if the share does not support named streams, 58591d632c8Sgwr * force the NOXATTR option (also clears XATTR). 58691d632c8Sgwr * Caller will set or clear VFS_XATTR after this. 58791d632c8Sgwr */ 58891d632c8Sgwr if ((smi->smi_fsattr & FILE_NAMED_STREAMS) == 0) 58991d632c8Sgwr vfs_setmntopt(vfsp, MNTOPT_NOXATTR, NULL, 0); 5904bff34e3Sthurlow 591bd7c6f51SGordon Ross /* 592bd7c6f51SGordon Ross * Ditto ACLs (disable if not supported on this share) 593bd7c6f51SGordon Ross */ 594bd7c6f51SGordon Ross if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) { 595bd7c6f51SGordon Ross vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0); 596bd7c6f51SGordon Ross smi->smi_flags &= ~SMI_ACL; 597bd7c6f51SGordon Ross } 598bd7c6f51SGordon Ross 5994bff34e3Sthurlow /* 6004bff34e3Sthurlow * Assign a unique device id to the mount 6014bff34e3Sthurlow */ 6024bff34e3Sthurlow mutex_enter(&smbfs_minor_lock); 6034bff34e3Sthurlow do { 6044bff34e3Sthurlow smbfs_minor = (smbfs_minor + 1) & MAXMIN32; 6054bff34e3Sthurlow smbfs_dev = makedevice(smbfs_major, smbfs_minor); 6064bff34e3Sthurlow } while (vfs_devismounted(smbfs_dev)); 6074bff34e3Sthurlow mutex_exit(&smbfs_minor_lock); 6084bff34e3Sthurlow 6094bff34e3Sthurlow vfsp->vfs_dev = smbfs_dev; 6104bff34e3Sthurlow vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp); 6114bff34e3Sthurlow vfsp->vfs_data = (caddr_t)smi; 6124bff34e3Sthurlow vfsp->vfs_fstype = smbfsfstyp; 6134bff34e3Sthurlow vfsp->vfs_bsize = MAXBSIZE; 6144bff34e3Sthurlow vfsp->vfs_bcount = 0; 6154bff34e3Sthurlow 6164bff34e3Sthurlow smi->smi_vfsp = vfsp; 61702d09e03SGordon Ross smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */ 6184bff34e3Sthurlow 61928162916SGordon Ross /* PSARC 2007/227 VFS Feature Registration */ 62028162916SGordon Ross vfs_set_feature(vfsp, VFSFT_XVATTR); 62128162916SGordon Ross vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS); 62228162916SGordon Ross 6234bff34e3Sthurlow /* 6244bff34e3Sthurlow * Create the root vnode, which we need in unmount 62502d09e03SGordon Ross * for the call to smbfs_check_table(), etc. 62602d09e03SGordon Ross * Release this hold in smbfs_unmount. 6274bff34e3Sthurlow */ 62802d09e03SGordon Ross rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0, 62902d09e03SGordon Ross &smbfs_fattr0); 63002d09e03SGordon Ross ASSERT(rtnp != NULL); 63102d09e03SGordon Ross rtnp->r_vnode->v_type = VDIR; 63202d09e03SGordon Ross rtnp->r_vnode->v_flag |= VROOT; 63302d09e03SGordon Ross smi->smi_root = rtnp; 6344bff34e3Sthurlow 6354bff34e3Sthurlow /* 6364bff34e3Sthurlow * NFS does other stuff here too: 6374bff34e3Sthurlow * async worker threads 6384bff34e3Sthurlow * init kstats 6394bff34e3Sthurlow * 6404bff34e3Sthurlow * End of code from NFS nfsrootvp() 6414bff34e3Sthurlow */ 6424bff34e3Sthurlow return (0); 6434bff34e3Sthurlow 6444bff34e3Sthurlow errout: 6454bff34e3Sthurlow vfsp->vfs_data = NULL; 64602d09e03SGordon Ross if (smi != NULL) 6474bff34e3Sthurlow smbfs_free_smi(smi); 6484bff34e3Sthurlow 6494bff34e3Sthurlow if (mntzone != NULL) 6504bff34e3Sthurlow zone_rele(mntzone); 6514bff34e3Sthurlow 65202d09e03SGordon Ross if (ssp != NULL) 6534bff34e3Sthurlow smb_share_rele(ssp); 6544bff34e3Sthurlow 6554bff34e3Sthurlow return (error); 6564bff34e3Sthurlow } 6574bff34e3Sthurlow 6584bff34e3Sthurlow /* 6594bff34e3Sthurlow * vfs operations 6604bff34e3Sthurlow */ 6614bff34e3Sthurlow static int 6624bff34e3Sthurlow smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) 6634bff34e3Sthurlow { 6644bff34e3Sthurlow smbmntinfo_t *smi; 6654bff34e3Sthurlow smbnode_t *rtnp; 6664bff34e3Sthurlow 6674bff34e3Sthurlow smi = VFTOSMI(vfsp); 6684bff34e3Sthurlow 6694bff34e3Sthurlow if (secpolicy_fs_unmount(cr, vfsp) != 0) 6704bff34e3Sthurlow return (EPERM); 6714bff34e3Sthurlow 6724bff34e3Sthurlow if ((flag & MS_FORCE) == 0) { 6734bff34e3Sthurlow smbfs_rflush(vfsp, cr); 6744bff34e3Sthurlow 6754bff34e3Sthurlow /* 6764bff34e3Sthurlow * If there are any active vnodes on this file system, 6774bff34e3Sthurlow * (other than the root vnode) then the file system is 6784bff34e3Sthurlow * busy and can't be umounted. 6794bff34e3Sthurlow */ 68002d09e03SGordon Ross if (smbfs_check_table(vfsp, smi->smi_root)) 6814bff34e3Sthurlow return (EBUSY); 6824bff34e3Sthurlow 6834bff34e3Sthurlow /* 6844bff34e3Sthurlow * We normally hold a ref to the root vnode, so 6854bff34e3Sthurlow * check for references beyond the one we expect: 6864bff34e3Sthurlow * smbmntinfo_t -> smi_root 6874bff34e3Sthurlow * Note that NFS does not hold the root vnode. 6884bff34e3Sthurlow */ 6894bff34e3Sthurlow if (smi->smi_root && 6904bff34e3Sthurlow smi->smi_root->r_vnode->v_count > 1) 6914bff34e3Sthurlow return (EBUSY); 6924bff34e3Sthurlow } 6934bff34e3Sthurlow 6944bff34e3Sthurlow /* 6954bff34e3Sthurlow * common code for both forced and non-forced 6964bff34e3Sthurlow * 6974bff34e3Sthurlow * Setting VFS_UNMOUNTED prevents new operations. 6984bff34e3Sthurlow * Operations already underway may continue, 6994bff34e3Sthurlow * but not for long. 7004bff34e3Sthurlow */ 7014bff34e3Sthurlow vfsp->vfs_flag |= VFS_UNMOUNTED; 7024bff34e3Sthurlow 7034bff34e3Sthurlow /* 7044bff34e3Sthurlow * Shutdown any outstanding I/O requests on this share, 7054bff34e3Sthurlow * and force a tree disconnect. The share object will 7064bff34e3Sthurlow * continue to hang around until smb_share_rele(). 7074bff34e3Sthurlow * This should also cause most active nodes to be 7084bff34e3Sthurlow * released as their operations fail with EIO. 7094bff34e3Sthurlow */ 7104bff34e3Sthurlow smb_share_kill(smi->smi_share); 7114bff34e3Sthurlow 7124bff34e3Sthurlow /* 7134bff34e3Sthurlow * If we hold the root VP (and we normally do) 7144bff34e3Sthurlow * then it's safe to release it now. 7154bff34e3Sthurlow */ 7164bff34e3Sthurlow if (smi->smi_root) { 7174bff34e3Sthurlow rtnp = smi->smi_root; 7184bff34e3Sthurlow smi->smi_root = NULL; 7194bff34e3Sthurlow VN_RELE(rtnp->r_vnode); /* release root vnode */ 7204bff34e3Sthurlow } 7214bff34e3Sthurlow 7224bff34e3Sthurlow /* 7234bff34e3Sthurlow * Remove all nodes from the node hash tables. 72402d09e03SGordon Ross * This (indirectly) calls: smbfs_addfree, smbinactive, 7254bff34e3Sthurlow * which will try to flush dirty pages, etc. so 7264bff34e3Sthurlow * don't destroy the underlying share just yet. 7274bff34e3Sthurlow * 7284bff34e3Sthurlow * Also, with a forced unmount, some nodes may 7294bff34e3Sthurlow * remain active, and those will get cleaned up 7304bff34e3Sthurlow * after their last vn_rele. 7314bff34e3Sthurlow */ 7324bff34e3Sthurlow smbfs_destroy_table(vfsp); 7334bff34e3Sthurlow 7344bff34e3Sthurlow /* 7354bff34e3Sthurlow * Delete our kstats... 7364bff34e3Sthurlow * 7374bff34e3Sthurlow * Doing it here, rather than waiting until 7384bff34e3Sthurlow * smbfs_freevfs so these are not visible 7394bff34e3Sthurlow * after the unmount. 7404bff34e3Sthurlow */ 7414bff34e3Sthurlow if (smi->smi_io_kstats) { 7424bff34e3Sthurlow kstat_delete(smi->smi_io_kstats); 7434bff34e3Sthurlow smi->smi_io_kstats = NULL; 7444bff34e3Sthurlow } 7454bff34e3Sthurlow if (smi->smi_ro_kstats) { 7464bff34e3Sthurlow kstat_delete(smi->smi_ro_kstats); 7474bff34e3Sthurlow smi->smi_ro_kstats = NULL; 7484bff34e3Sthurlow } 7494bff34e3Sthurlow 7504bff34e3Sthurlow /* 75102d09e03SGordon Ross * The rest happens in smbfs_freevfs() 7524bff34e3Sthurlow */ 7534bff34e3Sthurlow return (0); 7544bff34e3Sthurlow } 7554bff34e3Sthurlow 7564bff34e3Sthurlow 7574bff34e3Sthurlow /* 7584bff34e3Sthurlow * find root of smbfs 7594bff34e3Sthurlow */ 7604bff34e3Sthurlow static int 7614bff34e3Sthurlow smbfs_root(vfs_t *vfsp, vnode_t **vpp) 7624bff34e3Sthurlow { 7634bff34e3Sthurlow smbmntinfo_t *smi; 7644bff34e3Sthurlow vnode_t *vp; 7654bff34e3Sthurlow 7664bff34e3Sthurlow smi = VFTOSMI(vfsp); 7674bff34e3Sthurlow 768a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 7694bff34e3Sthurlow return (EPERM); 7704bff34e3Sthurlow 7714bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 7724bff34e3Sthurlow return (EIO); 7734bff34e3Sthurlow 7744bff34e3Sthurlow /* 7754bff34e3Sthurlow * The root vp is created in mount and held 7764bff34e3Sthurlow * until unmount, so this is paranoia. 7774bff34e3Sthurlow */ 7784bff34e3Sthurlow if (smi->smi_root == NULL) 7794bff34e3Sthurlow return (EIO); 7804bff34e3Sthurlow 7814bff34e3Sthurlow /* Just take a reference and return it. */ 7824bff34e3Sthurlow vp = SMBTOV(smi->smi_root); 7834bff34e3Sthurlow VN_HOLD(vp); 7844bff34e3Sthurlow *vpp = vp; 7854bff34e3Sthurlow 7864bff34e3Sthurlow return (0); 7874bff34e3Sthurlow } 7884bff34e3Sthurlow 7894bff34e3Sthurlow /* 7904bff34e3Sthurlow * Get file system statistics. 7914bff34e3Sthurlow */ 7924bff34e3Sthurlow static int 7934bff34e3Sthurlow smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp) 7944bff34e3Sthurlow { 7954bff34e3Sthurlow int error; 7964bff34e3Sthurlow smbmntinfo_t *smi = VFTOSMI(vfsp); 7974bff34e3Sthurlow smb_share_t *ssp = smi->smi_share; 7984bff34e3Sthurlow statvfs64_t stvfs; 7994bff34e3Sthurlow hrtime_t now; 8004bff34e3Sthurlow smb_cred_t scred; 8014bff34e3Sthurlow 802a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 8034bff34e3Sthurlow return (EPERM); 8044bff34e3Sthurlow 8054bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 8064bff34e3Sthurlow return (EIO); 8074bff34e3Sthurlow 8084bff34e3Sthurlow mutex_enter(&smi->smi_lock); 8094bff34e3Sthurlow 8104bff34e3Sthurlow /* 8114bff34e3Sthurlow * Use cached result if still valid. 8124bff34e3Sthurlow */ 8134bff34e3Sthurlow recheck: 8144bff34e3Sthurlow now = gethrtime(); 8154bff34e3Sthurlow if (now < smi->smi_statfstime) { 816613a2f6bSGordon Ross error = 0; 8174bff34e3Sthurlow goto cache_hit; 8184bff34e3Sthurlow } 8194bff34e3Sthurlow 8204bff34e3Sthurlow /* 8214bff34e3Sthurlow * FS attributes are stale, so someone 8224bff34e3Sthurlow * needs to do an OTW call to get them. 8234bff34e3Sthurlow * Serialize here so only one thread 8244bff34e3Sthurlow * does the OTW call. 8254bff34e3Sthurlow */ 8264bff34e3Sthurlow if (smi->smi_status & SM_STATUS_STATFS_BUSY) { 8274bff34e3Sthurlow smi->smi_status |= SM_STATUS_STATFS_WANT; 8284bff34e3Sthurlow if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) { 8294bff34e3Sthurlow mutex_exit(&smi->smi_lock); 8304bff34e3Sthurlow return (EINTR); 8314bff34e3Sthurlow } 8324bff34e3Sthurlow /* Hope status is valid now. */ 8334bff34e3Sthurlow goto recheck; 8344bff34e3Sthurlow } 8354bff34e3Sthurlow smi->smi_status |= SM_STATUS_STATFS_BUSY; 8364bff34e3Sthurlow mutex_exit(&smi->smi_lock); 8374bff34e3Sthurlow 8384bff34e3Sthurlow /* 8394bff34e3Sthurlow * Do the OTW call. Note: lock NOT held. 8404bff34e3Sthurlow */ 841613a2f6bSGordon Ross smb_credinit(&scred, NULL); 8424bff34e3Sthurlow bzero(&stvfs, sizeof (stvfs)); 8434bff34e3Sthurlow error = smbfs_smb_statfs(ssp, &stvfs, &scred); 8444bff34e3Sthurlow smb_credrele(&scred); 845613a2f6bSGordon Ross if (error) { 846613a2f6bSGordon Ross SMBVDEBUG("statfs error=%d\n", error); 847613a2f6bSGordon Ross } else { 848613a2f6bSGordon Ross 849613a2f6bSGordon Ross /* 850613a2f6bSGordon Ross * Set a few things the OTW call didn't get. 851613a2f6bSGordon Ross */ 852613a2f6bSGordon Ross stvfs.f_frsize = stvfs.f_bsize; 853613a2f6bSGordon Ross stvfs.f_favail = stvfs.f_ffree; 854613a2f6bSGordon Ross stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0]; 855613a2f6bSGordon Ross bcopy(fs_type_name, stvfs.f_basetype, FSTYPSZ); 856613a2f6bSGordon Ross stvfs.f_flag = vf_to_stf(vfsp->vfs_flag); 857613a2f6bSGordon Ross stvfs.f_namemax = smi->smi_fsa.fsa_maxname; 858613a2f6bSGordon Ross 859613a2f6bSGordon Ross /* 860613a2f6bSGordon Ross * Save the result, update lifetime 861613a2f6bSGordon Ross */ 862613a2f6bSGordon Ross now = gethrtime(); 863613a2f6bSGordon Ross smi->smi_statfstime = now + 864613a2f6bSGordon Ross (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC); 865613a2f6bSGordon Ross smi->smi_statvfsbuf = stvfs; /* struct assign! */ 866613a2f6bSGordon Ross } 8674bff34e3Sthurlow 8684bff34e3Sthurlow mutex_enter(&smi->smi_lock); 8694bff34e3Sthurlow if (smi->smi_status & SM_STATUS_STATFS_WANT) 8704bff34e3Sthurlow cv_broadcast(&smi->smi_statvfs_cv); 8714bff34e3Sthurlow smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT); 8724bff34e3Sthurlow 8734bff34e3Sthurlow /* 8744bff34e3Sthurlow * Copy the statvfs data to caller's buf. 8754bff34e3Sthurlow * Note: struct assignment 8764bff34e3Sthurlow */ 8774bff34e3Sthurlow cache_hit: 878613a2f6bSGordon Ross if (error == 0) 879613a2f6bSGordon Ross *sbp = smi->smi_statvfsbuf; 8804bff34e3Sthurlow mutex_exit(&smi->smi_lock); 8814bff34e3Sthurlow return (error); 8824bff34e3Sthurlow } 8834bff34e3Sthurlow 8844bff34e3Sthurlow static kmutex_t smbfs_syncbusy; 8854bff34e3Sthurlow 8864bff34e3Sthurlow /* 8874bff34e3Sthurlow * Flush dirty smbfs files for file system vfsp. 8884bff34e3Sthurlow * If vfsp == NULL, all smbfs files are flushed. 8894bff34e3Sthurlow */ 8904bff34e3Sthurlow /*ARGSUSED*/ 8914bff34e3Sthurlow static int 8924bff34e3Sthurlow smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) 8934bff34e3Sthurlow { 8944bff34e3Sthurlow /* 8954bff34e3Sthurlow * Cross-zone calls are OK here, since this translates to a 8964bff34e3Sthurlow * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. 8974bff34e3Sthurlow */ 8984bff34e3Sthurlow if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) { 8994bff34e3Sthurlow smbfs_rflush(vfsp, cr); 9004bff34e3Sthurlow mutex_exit(&smbfs_syncbusy); 9014bff34e3Sthurlow } 90202d09e03SGordon Ross 9034bff34e3Sthurlow return (0); 9044bff34e3Sthurlow } 9054bff34e3Sthurlow 9064bff34e3Sthurlow /* 9074bff34e3Sthurlow * Initialization routine for VFS routines. Should only be called once 9084bff34e3Sthurlow */ 9094bff34e3Sthurlow int 9104bff34e3Sthurlow smbfs_vfsinit(void) 9114bff34e3Sthurlow { 9124bff34e3Sthurlow mutex_init(&smbfs_syncbusy, NULL, MUTEX_DEFAULT, NULL); 9134bff34e3Sthurlow return (0); 9144bff34e3Sthurlow } 9154bff34e3Sthurlow 9164bff34e3Sthurlow /* 9174bff34e3Sthurlow * Shutdown routine for VFS routines. Should only be called once 9184bff34e3Sthurlow */ 9194bff34e3Sthurlow void 9204bff34e3Sthurlow smbfs_vfsfini(void) 9214bff34e3Sthurlow { 9224bff34e3Sthurlow mutex_destroy(&smbfs_syncbusy); 9234bff34e3Sthurlow } 9244bff34e3Sthurlow 9254bff34e3Sthurlow void 9264bff34e3Sthurlow smbfs_freevfs(vfs_t *vfsp) 9274bff34e3Sthurlow { 9284bff34e3Sthurlow smbmntinfo_t *smi; 9294bff34e3Sthurlow 9304bff34e3Sthurlow /* free up the resources */ 9314bff34e3Sthurlow smi = VFTOSMI(vfsp); 9324bff34e3Sthurlow 9334bff34e3Sthurlow /* 9344bff34e3Sthurlow * By this time we should have already deleted the 9354bff34e3Sthurlow * smi kstats in the unmount code. If they are still around 9364bff34e3Sthurlow * something is wrong 9374bff34e3Sthurlow */ 9384bff34e3Sthurlow ASSERT(smi->smi_io_kstats == NULL); 9394bff34e3Sthurlow 94002d09e03SGordon Ross smbfs_zonelist_remove(smi); 9414bff34e3Sthurlow 9424bff34e3Sthurlow smbfs_free_smi(smi); 9434bff34e3Sthurlow 9444bff34e3Sthurlow /* 9454bff34e3Sthurlow * Allow _fini() to succeed now, if so desired. 9464bff34e3Sthurlow */ 9474bff34e3Sthurlow atomic_dec_32(&smbfs_mountcount); 9484bff34e3Sthurlow } 9494bff34e3Sthurlow 9504bff34e3Sthurlow /* 9514bff34e3Sthurlow * smbfs_mount_label_policy: 9524bff34e3Sthurlow * Determine whether the mount is allowed according to MAC check, 9534bff34e3Sthurlow * by comparing (where appropriate) label of the remote server 9544bff34e3Sthurlow * against the label of the zone being mounted into. 9554bff34e3Sthurlow * 9564bff34e3Sthurlow * Returns: 9574bff34e3Sthurlow * 0 : access allowed 9584bff34e3Sthurlow * -1 : read-only access allowed (i.e., read-down) 9594bff34e3Sthurlow * >0 : error code, such as EACCES 9604bff34e3Sthurlow * 9614bff34e3Sthurlow * NB: 9624bff34e3Sthurlow * NFS supports Cipso labels by parsing the vfs_resource 9634bff34e3Sthurlow * to see what the Solaris server global zone has shared. 9644bff34e3Sthurlow * We can't support that for CIFS since resource names 9654bff34e3Sthurlow * contain share names, not paths. 9664bff34e3Sthurlow */ 9674bff34e3Sthurlow static int 9684bff34e3Sthurlow smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr) 9694bff34e3Sthurlow { 9704bff34e3Sthurlow bslabel_t *server_sl, *mntlabel; 9714bff34e3Sthurlow zone_t *mntzone = NULL; 9724bff34e3Sthurlow ts_label_t *zlabel; 9734bff34e3Sthurlow tsol_tpc_t *tp; 9744bff34e3Sthurlow ts_label_t *tsl = NULL; 9754bff34e3Sthurlow int retv; 9764bff34e3Sthurlow 9774bff34e3Sthurlow /* 9784bff34e3Sthurlow * Get the zone's label. Each zone on a labeled system has a label. 9794bff34e3Sthurlow */ 9804bff34e3Sthurlow mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); 9814bff34e3Sthurlow zlabel = mntzone->zone_slabel; 9824bff34e3Sthurlow ASSERT(zlabel != NULL); 9834bff34e3Sthurlow label_hold(zlabel); 9844bff34e3Sthurlow 9854bff34e3Sthurlow retv = EACCES; /* assume the worst */ 9864bff34e3Sthurlow 9874bff34e3Sthurlow /* 9884bff34e3Sthurlow * Next, get the assigned label of the remote server. 9894bff34e3Sthurlow */ 9904bff34e3Sthurlow tp = find_tpc(ipaddr, addr_type, B_FALSE); 9914bff34e3Sthurlow if (tp == NULL) 9924bff34e3Sthurlow goto out; /* error getting host entry */ 9934bff34e3Sthurlow 9944bff34e3Sthurlow if (tp->tpc_tp.tp_doi != zlabel->tsl_doi) 9954bff34e3Sthurlow goto rel_tpc; /* invalid domain */ 9964bff34e3Sthurlow if ((tp->tpc_tp.host_type != UNLABELED)) 9974bff34e3Sthurlow goto rel_tpc; /* invalid hosttype */ 9984bff34e3Sthurlow 9994bff34e3Sthurlow server_sl = &tp->tpc_tp.tp_def_label; 10004bff34e3Sthurlow mntlabel = label2bslabel(zlabel); 10014bff34e3Sthurlow 10024bff34e3Sthurlow /* 10034bff34e3Sthurlow * Now compare labels to complete the MAC check. If the labels 10044bff34e3Sthurlow * are equal or if the requestor is in the global zone and has 10054bff34e3Sthurlow * NET_MAC_AWARE, then allow read-write access. (Except for 10064bff34e3Sthurlow * mounts into the global zone itself; restrict these to 10074bff34e3Sthurlow * read-only.) 10084bff34e3Sthurlow * 100948bbca81SDaniel Hoffman * If the requestor is in some other zone, but their label 10104bff34e3Sthurlow * dominates the server, then allow read-down. 10114bff34e3Sthurlow * 10124bff34e3Sthurlow * Otherwise, access is denied. 10134bff34e3Sthurlow */ 10144bff34e3Sthurlow if (blequal(mntlabel, server_sl) || 10154bff34e3Sthurlow (crgetzoneid(cr) == GLOBAL_ZONEID && 10164bff34e3Sthurlow getpflags(NET_MAC_AWARE, cr) != 0)) { 10174bff34e3Sthurlow if ((mntzone == global_zone) || 10184bff34e3Sthurlow !blequal(mntlabel, server_sl)) 10194bff34e3Sthurlow retv = -1; /* read-only */ 10204bff34e3Sthurlow else 10214bff34e3Sthurlow retv = 0; /* access OK */ 10224bff34e3Sthurlow } else if (bldominates(mntlabel, server_sl)) { 10234bff34e3Sthurlow retv = -1; /* read-only */ 10244bff34e3Sthurlow } else { 10254bff34e3Sthurlow retv = EACCES; 10264bff34e3Sthurlow } 10274bff34e3Sthurlow 10284bff34e3Sthurlow if (tsl != NULL) 10294bff34e3Sthurlow label_rele(tsl); 10304bff34e3Sthurlow 10314bff34e3Sthurlow rel_tpc: 10324bff34e3Sthurlow /*LINTED*/ 10334bff34e3Sthurlow TPC_RELE(tp); 10344bff34e3Sthurlow out: 10354bff34e3Sthurlow if (mntzone) 10364bff34e3Sthurlow zone_rele(mntzone); 10374bff34e3Sthurlow label_rele(zlabel); 10384bff34e3Sthurlow return (retv); 10394bff34e3Sthurlow } 1040