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. 379005860cSGordon 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> 55*4e72ade1SGordon Ross #include <sys/disp.h> 564bff34e3Sthurlow #include <sys/cmn_err.h> 574bff34e3Sthurlow #include <sys/modctl.h> 584bff34e3Sthurlow #include <sys/policy.h> 594bff34e3Sthurlow #include <sys/atomic.h> 604bff34e3Sthurlow #include <sys/zone.h> 614bff34e3Sthurlow #include <sys/vfs_opreg.h> 624bff34e3Sthurlow #include <sys/mntent.h> 634bff34e3Sthurlow #include <sys/priv.h> 64*4e72ade1SGordon Ross #include <sys/taskq.h> 654bff34e3Sthurlow #include <sys/tsol/label.h> 664bff34e3Sthurlow #include <sys/tsol/tndb.h> 674bff34e3Sthurlow #include <inet/ip.h> 684bff34e3Sthurlow 694bff34e3Sthurlow #include <netsmb/smb_osdep.h> 704bff34e3Sthurlow #include <netsmb/smb.h> 714bff34e3Sthurlow #include <netsmb/smb_conn.h> 724bff34e3Sthurlow #include <netsmb/smb_subr.h> 734bff34e3Sthurlow #include <netsmb/smb_dev.h> 744bff34e3Sthurlow 754bff34e3Sthurlow #include <smbfs/smbfs.h> 764bff34e3Sthurlow #include <smbfs/smbfs_node.h> 774bff34e3Sthurlow #include <smbfs/smbfs_subr.h> 784bff34e3Sthurlow 799005860cSGordon Ross /* 809005860cSGordon Ross * Should smbfs mount enable "-o acl" by default? There are good 819005860cSGordon Ross * arguments for both. The most common use case is individual users 829005860cSGordon Ross * accessing files on some SMB server, for which "noacl" is the more 839005860cSGordon Ross * convenient default. A less common use case is data migration, 849005860cSGordon Ross * where the "acl" option might be a desirable default. We'll make 859005860cSGordon Ross * the common use case the default. This default can be changed via 869005860cSGordon Ross * /etc/system, and/or set per-mount via the "acl" mount option. 879005860cSGordon Ross */ 889005860cSGordon Ross int smbfs_default_opt_acl = 0; 899005860cSGordon Ross 90*4e72ade1SGordon Ross /* 91*4e72ade1SGordon Ross * How many taskq threads per-mount should we use. 92*4e72ade1SGordon Ross * Just one is fine (until we do more async work). 93*4e72ade1SGordon Ross */ 94*4e72ade1SGordon Ross int smbfs_tq_nthread = 1; 95*4e72ade1SGordon Ross 964bff34e3Sthurlow /* 974bff34e3Sthurlow * Local functions definitions. 984bff34e3Sthurlow */ 994bff34e3Sthurlow int smbfsinit(int fstyp, char *name); 1004bff34e3Sthurlow void smbfsfini(); 1014bff34e3Sthurlow static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *); 1024bff34e3Sthurlow 10391d632c8Sgwr /* 10491d632c8Sgwr * SMBFS Mount options table for MS_OPTIONSTR 10591d632c8Sgwr * Note: These are not all the options. 10691d632c8Sgwr * Some options come in via MS_DATA. 10791d632c8Sgwr * Others are generic (see vfs.c) 10891d632c8Sgwr */ 10991d632c8Sgwr static char *intr_cancel[] = { MNTOPT_NOINTR, NULL }; 11091d632c8Sgwr static char *nointr_cancel[] = { MNTOPT_INTR, NULL }; 111bd7c6f51SGordon Ross static char *acl_cancel[] = { MNTOPT_NOACL, NULL }; 112bd7c6f51SGordon Ross static char *noacl_cancel[] = { MNTOPT_ACL, NULL }; 11391d632c8Sgwr static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 11491d632c8Sgwr static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 11591d632c8Sgwr 11691d632c8Sgwr static mntopt_t mntopts[] = { 11791d632c8Sgwr /* 11891d632c8Sgwr * option name cancel option default arg flags 11991d632c8Sgwr * ufs arg flag 12091d632c8Sgwr */ 12191d632c8Sgwr { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 0 }, 12291d632c8Sgwr { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 0 }, 1239005860cSGordon Ross { MNTOPT_ACL, acl_cancel, NULL, 0, 0 }, 124bd7c6f51SGordon Ross { MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 }, 12591d632c8Sgwr { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 }, 12691d632c8Sgwr { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 } 12791d632c8Sgwr }; 12891d632c8Sgwr 12991d632c8Sgwr static mntopts_t smbfs_mntopts = { 13091d632c8Sgwr sizeof (mntopts) / sizeof (mntopt_t), 13191d632c8Sgwr mntopts 13291d632c8Sgwr }; 13391d632c8Sgwr 134613a2f6bSGordon Ross static const char fs_type_name[FSTYPSZ] = "smbfs"; 135613a2f6bSGordon Ross 1364bff34e3Sthurlow static vfsdef_t vfw = { 1374bff34e3Sthurlow VFSDEF_VERSION, 138613a2f6bSGordon Ross (char *)fs_type_name, 1394bff34e3Sthurlow smbfsinit, /* init routine */ 1408cd81a20SJerry Jelinek VSW_HASPROTO|VSW_NOTZONESAFE, /* flags */ 14191d632c8Sgwr &smbfs_mntopts /* mount options table prototype */ 1424bff34e3Sthurlow }; 1434bff34e3Sthurlow 1444bff34e3Sthurlow static struct modlfs modlfs = { 1454bff34e3Sthurlow &mod_fsops, 146613a2f6bSGordon Ross "SMBFS filesystem", 1474bff34e3Sthurlow &vfw 1484bff34e3Sthurlow }; 1494bff34e3Sthurlow 1504bff34e3Sthurlow static struct modlinkage modlinkage = { 1514bff34e3Sthurlow MODREV_1, (void *)&modlfs, NULL 1524bff34e3Sthurlow }; 1534bff34e3Sthurlow 1544bff34e3Sthurlow /* 1554bff34e3Sthurlow * Mutex to protect the following variables: 1564bff34e3Sthurlow * smbfs_major 1574bff34e3Sthurlow * smbfs_minor 1584bff34e3Sthurlow */ 1594bff34e3Sthurlow extern kmutex_t smbfs_minor_lock; 1604bff34e3Sthurlow extern int smbfs_major; 1614bff34e3Sthurlow extern int smbfs_minor; 1624bff34e3Sthurlow 1634bff34e3Sthurlow /* 1644bff34e3Sthurlow * Prevent unloads while we have mounts 1654bff34e3Sthurlow */ 1664bff34e3Sthurlow uint32_t smbfs_mountcount; 1674bff34e3Sthurlow 1684bff34e3Sthurlow /* 1694bff34e3Sthurlow * smbfs vfs operations. 1704bff34e3Sthurlow */ 1714bff34e3Sthurlow static int smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 1724bff34e3Sthurlow static int smbfs_unmount(vfs_t *, int, cred_t *); 1734bff34e3Sthurlow static int smbfs_root(vfs_t *, vnode_t **); 1744bff34e3Sthurlow static int smbfs_statvfs(vfs_t *, statvfs64_t *); 1754bff34e3Sthurlow static int smbfs_sync(vfs_t *, short, cred_t *); 1764bff34e3Sthurlow static void smbfs_freevfs(vfs_t *); 1774bff34e3Sthurlow 1784bff34e3Sthurlow /* 1794bff34e3Sthurlow * Module loading 1804bff34e3Sthurlow */ 1814bff34e3Sthurlow 1824bff34e3Sthurlow /* 1834bff34e3Sthurlow * This routine is invoked automatically when the kernel module 1844bff34e3Sthurlow * containing this routine is loaded. This allows module specific 1854bff34e3Sthurlow * initialization to be done when the module is loaded. 1864bff34e3Sthurlow */ 1874bff34e3Sthurlow int 1884bff34e3Sthurlow _init(void) 1894bff34e3Sthurlow { 19002d09e03SGordon Ross int error; 1914bff34e3Sthurlow 1924bff34e3Sthurlow /* 1934bff34e3Sthurlow * Check compiled-in version of "nsmb" 1944bff34e3Sthurlow * that we're linked with. (paranoid) 1954bff34e3Sthurlow */ 1964bff34e3Sthurlow if (nsmb_version != NSMB_VERSION) { 1974bff34e3Sthurlow cmn_err(CE_WARN, "_init: nsmb version mismatch"); 1984bff34e3Sthurlow return (ENOTTY); 1994bff34e3Sthurlow } 2004bff34e3Sthurlow 2014bff34e3Sthurlow smbfs_mountcount = 0; 2024bff34e3Sthurlow 20302d09e03SGordon Ross /* 20402d09e03SGordon Ross * NFS calls these two in _clntinit 20502d09e03SGordon Ross * Easier to follow this way. 20602d09e03SGordon Ross */ 20702d09e03SGordon Ross if ((error = smbfs_subrinit()) != 0) { 20802d09e03SGordon Ross cmn_err(CE_WARN, "_init: smbfs_subrinit failed"); 20902d09e03SGordon Ross return (error); 21002d09e03SGordon Ross } 21102d09e03SGordon Ross 21202d09e03SGordon Ross if ((error = smbfs_vfsinit()) != 0) { 21302d09e03SGordon Ross cmn_err(CE_WARN, "_init: smbfs_vfsinit failed"); 21402d09e03SGordon Ross smbfs_subrfini(); 21502d09e03SGordon Ross return (error); 21602d09e03SGordon Ross } 21702d09e03SGordon Ross 21802d09e03SGordon Ross if ((error = smbfs_clntinit()) != 0) { 2194bff34e3Sthurlow cmn_err(CE_WARN, "_init: smbfs_clntinit failed"); 22002d09e03SGordon Ross smbfs_vfsfini(); 22102d09e03SGordon Ross smbfs_subrfini(); 22202d09e03SGordon Ross return (error); 2234bff34e3Sthurlow } 2244bff34e3Sthurlow 22502d09e03SGordon Ross error = mod_install((struct modlinkage *)&modlinkage); 22602d09e03SGordon Ross return (error); 2274bff34e3Sthurlow } 2284bff34e3Sthurlow 2294bff34e3Sthurlow /* 2304bff34e3Sthurlow * Free kernel module resources that were allocated in _init 2314bff34e3Sthurlow * and remove the linkage information into the kernel 2324bff34e3Sthurlow */ 2334bff34e3Sthurlow int 2344bff34e3Sthurlow _fini(void) 2354bff34e3Sthurlow { 2364bff34e3Sthurlow int error; 2374bff34e3Sthurlow 2384bff34e3Sthurlow /* 2394bff34e3Sthurlow * If a forcedly unmounted instance is still hanging around, 2404bff34e3Sthurlow * we cannot allow the module to be unloaded because that would 2414bff34e3Sthurlow * cause panics once the VFS framework decides it's time to call 2424bff34e3Sthurlow * into VFS_FREEVFS(). 2434bff34e3Sthurlow */ 2444bff34e3Sthurlow if (smbfs_mountcount) 2454bff34e3Sthurlow return (EBUSY); 2464bff34e3Sthurlow 2474bff34e3Sthurlow error = mod_remove(&modlinkage); 2484bff34e3Sthurlow if (error) 2494bff34e3Sthurlow return (error); 2504bff34e3Sthurlow 2514bff34e3Sthurlow /* 2524bff34e3Sthurlow * Free the allocated smbnodes, etc. 2534bff34e3Sthurlow */ 2544bff34e3Sthurlow smbfs_clntfini(); 2554bff34e3Sthurlow 25602d09e03SGordon Ross /* NFS calls these two in _clntfini */ 25702d09e03SGordon Ross smbfs_vfsfini(); 25802d09e03SGordon Ross smbfs_subrfini(); 25902d09e03SGordon Ross 2604bff34e3Sthurlow /* 2614bff34e3Sthurlow * Free the ops vectors 2624bff34e3Sthurlow */ 2634bff34e3Sthurlow smbfsfini(); 2644bff34e3Sthurlow return (0); 2654bff34e3Sthurlow } 2664bff34e3Sthurlow 2674bff34e3Sthurlow /* 2684bff34e3Sthurlow * Return information about the module 2694bff34e3Sthurlow */ 2704bff34e3Sthurlow int 2714bff34e3Sthurlow _info(struct modinfo *modinfop) 2724bff34e3Sthurlow { 2734bff34e3Sthurlow return (mod_info((struct modlinkage *)&modlinkage, modinfop)); 2744bff34e3Sthurlow } 2754bff34e3Sthurlow 2764bff34e3Sthurlow /* 2774bff34e3Sthurlow * Initialize the vfs structure 2784bff34e3Sthurlow */ 2794bff34e3Sthurlow 2804bff34e3Sthurlow int smbfsfstyp; 2814bff34e3Sthurlow vfsops_t *smbfs_vfsops = NULL; 2824bff34e3Sthurlow 2834bff34e3Sthurlow static const fs_operation_def_t smbfs_vfsops_template[] = { 2844bff34e3Sthurlow { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } }, 2854bff34e3Sthurlow { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } }, 2864bff34e3Sthurlow { VFSNAME_ROOT, { .vfs_root = smbfs_root } }, 2874bff34e3Sthurlow { VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } }, 2884bff34e3Sthurlow { VFSNAME_SYNC, { .vfs_sync = smbfs_sync } }, 2894bff34e3Sthurlow { VFSNAME_VGET, { .error = fs_nosys } }, 2904bff34e3Sthurlow { VFSNAME_MOUNTROOT, { .error = fs_nosys } }, 2914bff34e3Sthurlow { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } }, 2924bff34e3Sthurlow { NULL, NULL } 2934bff34e3Sthurlow }; 2944bff34e3Sthurlow 2954bff34e3Sthurlow int 2964bff34e3Sthurlow smbfsinit(int fstyp, char *name) 2974bff34e3Sthurlow { 2984bff34e3Sthurlow int error; 2994bff34e3Sthurlow 3004bff34e3Sthurlow error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); 3014bff34e3Sthurlow if (error != 0) { 3024bff34e3Sthurlow zcmn_err(GLOBAL_ZONEID, CE_WARN, 3034bff34e3Sthurlow "smbfsinit: bad vfs ops template"); 3044bff34e3Sthurlow return (error); 3054bff34e3Sthurlow } 3064bff34e3Sthurlow 3074bff34e3Sthurlow error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); 3084bff34e3Sthurlow if (error != 0) { 3094bff34e3Sthurlow (void) vfs_freevfsops_by_type(fstyp); 3104bff34e3Sthurlow zcmn_err(GLOBAL_ZONEID, CE_WARN, 3114bff34e3Sthurlow "smbfsinit: bad vnode ops template"); 3124bff34e3Sthurlow return (error); 3134bff34e3Sthurlow } 3144bff34e3Sthurlow 3154bff34e3Sthurlow smbfsfstyp = fstyp; 3164bff34e3Sthurlow 3174bff34e3Sthurlow return (0); 3184bff34e3Sthurlow } 3194bff34e3Sthurlow 3204bff34e3Sthurlow void 3214bff34e3Sthurlow smbfsfini() 3224bff34e3Sthurlow { 3234bff34e3Sthurlow if (smbfs_vfsops) { 3244bff34e3Sthurlow (void) vfs_freevfsops_by_type(smbfsfstyp); 3254bff34e3Sthurlow smbfs_vfsops = NULL; 3264bff34e3Sthurlow } 3274bff34e3Sthurlow if (smbfs_vnodeops) { 3284bff34e3Sthurlow vn_freevnodeops(smbfs_vnodeops); 3294bff34e3Sthurlow smbfs_vnodeops = NULL; 3304bff34e3Sthurlow } 3314bff34e3Sthurlow } 3324bff34e3Sthurlow 3334bff34e3Sthurlow void 3344bff34e3Sthurlow smbfs_free_smi(smbmntinfo_t *smi) 3354bff34e3Sthurlow { 33602d09e03SGordon Ross if (smi == NULL) 33702d09e03SGordon Ross return; 33802d09e03SGordon Ross 339a19609f8Sjv if (smi->smi_zone_ref.zref_zone != NULL) 340a19609f8Sjv zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS); 34102d09e03SGordon Ross 34202d09e03SGordon Ross if (smi->smi_share != NULL) 34302d09e03SGordon Ross smb_share_rele(smi->smi_share); 34402d09e03SGordon Ross 34502d09e03SGordon Ross avl_destroy(&smi->smi_hash_avl); 34602d09e03SGordon Ross rw_destroy(&smi->smi_hash_lk); 34702d09e03SGordon Ross cv_destroy(&smi->smi_statvfs_cv); 34802d09e03SGordon Ross mutex_destroy(&smi->smi_lock); 34902d09e03SGordon Ross 35002d09e03SGordon Ross kmem_free(smi, sizeof (smbmntinfo_t)); 3514bff34e3Sthurlow } 3524bff34e3Sthurlow 3534bff34e3Sthurlow /* 3544bff34e3Sthurlow * smbfs mount vfsop 3554bff34e3Sthurlow * Set up mount info record and attach it to vfs struct. 3564bff34e3Sthurlow */ 3574bff34e3Sthurlow static int 3584bff34e3Sthurlow smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 3594bff34e3Sthurlow { 3604bff34e3Sthurlow char *data = uap->dataptr; 3614bff34e3Sthurlow int error; 3625f4fc069Sjilinxpd smbnode_t *rtnp = NULL; /* root of this fs */ 3635f4fc069Sjilinxpd smbmntinfo_t *smi = NULL; 3645f4fc069Sjilinxpd dev_t smbfs_dev; 3655f4fc069Sjilinxpd int version; 3665f4fc069Sjilinxpd int devfd; 3674bff34e3Sthurlow zone_t *zone = curproc->p_zone; 3684bff34e3Sthurlow zone_t *mntzone = NULL; 3695f4fc069Sjilinxpd smb_share_t *ssp = NULL; 3705f4fc069Sjilinxpd smb_cred_t scred; 37102d09e03SGordon Ross int flags, sec; 3724bff34e3Sthurlow 3734bff34e3Sthurlow STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ 3744bff34e3Sthurlow 3754bff34e3Sthurlow if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 3764bff34e3Sthurlow return (error); 3774bff34e3Sthurlow 3784bff34e3Sthurlow if (mvp->v_type != VDIR) 3794bff34e3Sthurlow return (ENOTDIR); 3804bff34e3Sthurlow 3814bff34e3Sthurlow /* 3824bff34e3Sthurlow * get arguments 3834bff34e3Sthurlow * 3844bff34e3Sthurlow * uap->datalen might be different from sizeof (args) 3854bff34e3Sthurlow * in a compatible situation. 3864bff34e3Sthurlow */ 3874bff34e3Sthurlow STRUCT_INIT(args, get_udatamodel()); 3884bff34e3Sthurlow bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); 3894bff34e3Sthurlow if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, 3904bff34e3Sthurlow SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)))) 3914bff34e3Sthurlow return (EFAULT); 3924bff34e3Sthurlow 3934bff34e3Sthurlow /* 3944bff34e3Sthurlow * Check mount program version 3954bff34e3Sthurlow */ 3964bff34e3Sthurlow version = STRUCT_FGET(args, version); 3974bff34e3Sthurlow if (version != SMBFS_VERSION) { 3984bff34e3Sthurlow cmn_err(CE_WARN, "mount version mismatch:" 3994bff34e3Sthurlow " kernel=%d, mount=%d\n", 4004bff34e3Sthurlow SMBFS_VERSION, version); 4014bff34e3Sthurlow return (EINVAL); 4024bff34e3Sthurlow } 4034bff34e3Sthurlow 40402d09e03SGordon Ross /* 40502d09e03SGordon Ross * Deal with re-mount requests. 40602d09e03SGordon Ross */ 4074bff34e3Sthurlow if (uap->flags & MS_REMOUNT) { 4084bff34e3Sthurlow cmn_err(CE_WARN, "MS_REMOUNT not implemented"); 4094bff34e3Sthurlow return (ENOTSUP); 4104bff34e3Sthurlow } 4114bff34e3Sthurlow 4124bff34e3Sthurlow /* 4134bff34e3Sthurlow * Check for busy 4144bff34e3Sthurlow */ 4154bff34e3Sthurlow mutex_enter(&mvp->v_lock); 4164bff34e3Sthurlow if (!(uap->flags & MS_OVERLAY) && 4174bff34e3Sthurlow (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 4184bff34e3Sthurlow mutex_exit(&mvp->v_lock); 4194bff34e3Sthurlow return (EBUSY); 4204bff34e3Sthurlow } 4214bff34e3Sthurlow mutex_exit(&mvp->v_lock); 4224bff34e3Sthurlow 4234bff34e3Sthurlow /* 4244bff34e3Sthurlow * Get the "share" from the netsmb driver (ssp). 4254bff34e3Sthurlow * It is returned with a "ref" (hold) for us. 4264bff34e3Sthurlow * Release this hold: at errout below, or in 4274bff34e3Sthurlow * smbfs_freevfs(). 4284bff34e3Sthurlow */ 4294bff34e3Sthurlow devfd = STRUCT_FGET(args, devfd); 4304bff34e3Sthurlow error = smb_dev2share(devfd, &ssp); 4314bff34e3Sthurlow if (error) { 4324bff34e3Sthurlow cmn_err(CE_WARN, "invalid device handle %d (%d)\n", 4334bff34e3Sthurlow devfd, error); 4344bff34e3Sthurlow return (error); 4354bff34e3Sthurlow } 4364bff34e3Sthurlow 4374bff34e3Sthurlow /* 4384bff34e3Sthurlow * Use "goto errout" from here on. 43902d09e03SGordon Ross * See: ssp, smi, rtnp, mntzone 4404bff34e3Sthurlow */ 4414bff34e3Sthurlow 4424bff34e3Sthurlow /* 4434bff34e3Sthurlow * Determine the zone we're being mounted into. 4444bff34e3Sthurlow */ 4454bff34e3Sthurlow zone_hold(mntzone = zone); /* start with this assumption */ 4464bff34e3Sthurlow if (getzoneid() == GLOBAL_ZONEID) { 4474bff34e3Sthurlow zone_rele(mntzone); 4484bff34e3Sthurlow mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 4494bff34e3Sthurlow ASSERT(mntzone != NULL); 4504bff34e3Sthurlow if (mntzone != zone) { 4514bff34e3Sthurlow error = EBUSY; 4524bff34e3Sthurlow goto errout; 4534bff34e3Sthurlow } 4544bff34e3Sthurlow } 4554bff34e3Sthurlow 4564bff34e3Sthurlow /* 4574bff34e3Sthurlow * Stop the mount from going any further if the zone is going away. 4584bff34e3Sthurlow */ 4594bff34e3Sthurlow if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { 4604bff34e3Sthurlow error = EBUSY; 4614bff34e3Sthurlow goto errout; 4624bff34e3Sthurlow } 4634bff34e3Sthurlow 4644bff34e3Sthurlow /* 4654bff34e3Sthurlow * On a Trusted Extensions client, we may have to force read-only 4664bff34e3Sthurlow * for read-down mounts. 4674bff34e3Sthurlow */ 4684bff34e3Sthurlow if (is_system_labeled()) { 4694bff34e3Sthurlow void *addr; 4704bff34e3Sthurlow int ipvers = 0; 4714bff34e3Sthurlow struct smb_vc *vcp; 4724bff34e3Sthurlow 4734bff34e3Sthurlow vcp = SSTOVC(ssp); 4744bff34e3Sthurlow addr = smb_vc_getipaddr(vcp, &ipvers); 4754bff34e3Sthurlow error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr); 4764bff34e3Sthurlow 4774bff34e3Sthurlow if (error > 0) 4784bff34e3Sthurlow goto errout; 4794bff34e3Sthurlow 4804bff34e3Sthurlow if (error == -1) { 4814bff34e3Sthurlow /* change mount to read-only to prevent write-down */ 4824bff34e3Sthurlow vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 4834bff34e3Sthurlow } 4844bff34e3Sthurlow } 4854bff34e3Sthurlow 48602d09e03SGordon Ross /* Prevent unload. */ 48702d09e03SGordon Ross atomic_inc_32(&smbfs_mountcount); 4884bff34e3Sthurlow 4894bff34e3Sthurlow /* 4904bff34e3Sthurlow * Create a mount record and link it to the vfs struct. 49102d09e03SGordon Ross * No more possiblities for errors from here on. 49202d09e03SGordon Ross * Tear-down of this stuff is in smbfs_free_smi() 49302d09e03SGordon Ross * 4944bff34e3Sthurlow * Compare with NFS: nfsrootvp() 4954bff34e3Sthurlow */ 49602d09e03SGordon Ross smi = kmem_zalloc(sizeof (*smi), KM_SLEEP); 49702d09e03SGordon Ross 49802d09e03SGordon Ross mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL); 49902d09e03SGordon Ross cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL); 5004bff34e3Sthurlow 50102d09e03SGordon Ross rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL); 50202d09e03SGordon Ross smbfs_init_hash_avl(&smi->smi_hash_avl); 50302d09e03SGordon Ross 50402d09e03SGordon Ross smi->smi_share = ssp; 50502d09e03SGordon Ross ssp = NULL; 506a19609f8Sjv 507a19609f8Sjv /* 508a19609f8Sjv * Convert the anonymous zone hold acquired via zone_hold() above 509a19609f8Sjv * into a zone reference. 510a19609f8Sjv */ 511a19609f8Sjv zone_init_ref(&smi->smi_zone_ref); 512a19609f8Sjv zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS); 513a19609f8Sjv zone_rele(mntzone); 51402d09e03SGordon Ross mntzone = NULL; 51502d09e03SGordon Ross 51602d09e03SGordon Ross /* 51702d09e03SGordon Ross * Initialize option defaults 51802d09e03SGordon Ross */ 51991d632c8Sgwr smi->smi_flags = SMI_LLOCK; 52002d09e03SGordon Ross smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN); 52102d09e03SGordon Ross smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX); 52202d09e03SGordon Ross smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN); 52302d09e03SGordon Ross smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX); 52491d632c8Sgwr 52591d632c8Sgwr /* 52602d09e03SGordon Ross * All "generic" mount options have already been 52702d09e03SGordon Ross * handled in vfs.c:domount() - see mntopts stuff. 52802d09e03SGordon Ross * Query generic options using vfs_optionisset(). 5299005860cSGordon Ross * Give ACL an adjustable system-wide default. 53091d632c8Sgwr */ 5319005860cSGordon Ross if (smbfs_default_opt_acl || 5329005860cSGordon Ross vfs_optionisset(vfsp, MNTOPT_ACL, NULL)) 5339005860cSGordon Ross smi->smi_flags |= SMI_ACL; 5349005860cSGordon Ross if (vfs_optionisset(vfsp, MNTOPT_NOACL, NULL)) 5359005860cSGordon Ross smi->smi_flags &= ~SMI_ACL; 53691d632c8Sgwr if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) 53791d632c8Sgwr smi->smi_flags |= SMI_INT; 5384bff34e3Sthurlow 5394bff34e3Sthurlow /* 54002d09e03SGordon Ross * Get the mount options that come in as smbfs_args, 54102d09e03SGordon Ross * starting with args.flags (SMBFS_MF_xxx) 54202d09e03SGordon Ross */ 54302d09e03SGordon Ross flags = STRUCT_FGET(args, flags); 5445f4fc069Sjilinxpd smi->smi_uid = STRUCT_FGET(args, uid); 5455f4fc069Sjilinxpd smi->smi_gid = STRUCT_FGET(args, gid); 54602d09e03SGordon Ross smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777; 54702d09e03SGordon Ross smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777; 54802d09e03SGordon Ross 54902d09e03SGordon Ross /* 55002d09e03SGordon Ross * Hande the SMBFS_MF_xxx flags. 5514bff34e3Sthurlow */ 55202d09e03SGordon Ross if (flags & SMBFS_MF_NOAC) 55302d09e03SGordon Ross smi->smi_flags |= SMI_NOAC; 55402d09e03SGordon Ross if (flags & SMBFS_MF_ACREGMIN) { 55502d09e03SGordon Ross sec = STRUCT_FGET(args, acregmin); 55602d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMINMAX) 55702d09e03SGordon Ross sec = SMBFS_ACMINMAX; 55802d09e03SGordon Ross smi->smi_acregmin = SEC2HR(sec); 55902d09e03SGordon Ross } 56002d09e03SGordon Ross if (flags & SMBFS_MF_ACREGMAX) { 56102d09e03SGordon Ross sec = STRUCT_FGET(args, acregmax); 56202d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMAXMAX) 56302d09e03SGordon Ross sec = SMBFS_ACMAXMAX; 56402d09e03SGordon Ross smi->smi_acregmax = SEC2HR(sec); 56502d09e03SGordon Ross } 56602d09e03SGordon Ross if (flags & SMBFS_MF_ACDIRMIN) { 56702d09e03SGordon Ross sec = STRUCT_FGET(args, acdirmin); 56802d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMINMAX) 56902d09e03SGordon Ross sec = SMBFS_ACMINMAX; 57002d09e03SGordon Ross smi->smi_acdirmin = SEC2HR(sec); 57102d09e03SGordon Ross } 57202d09e03SGordon Ross if (flags & SMBFS_MF_ACDIRMAX) { 57302d09e03SGordon Ross sec = STRUCT_FGET(args, acdirmax); 57402d09e03SGordon Ross if (sec < 0 || sec > SMBFS_ACMAXMAX) 57502d09e03SGordon Ross sec = SMBFS_ACMAXMAX; 57602d09e03SGordon Ross smi->smi_acdirmax = SEC2HR(sec); 57702d09e03SGordon Ross } 5784bff34e3Sthurlow 57991d632c8Sgwr /* 58091d632c8Sgwr * Get attributes of the remote file system, 58191d632c8Sgwr * i.e. ACL support, named streams, etc. 58291d632c8Sgwr */ 58302d09e03SGordon Ross smb_credinit(&scred, cr); 58402d09e03SGordon Ross error = smbfs_smb_qfsattr(smi->smi_share, &smi->smi_fsa, &scred); 58502d09e03SGordon Ross smb_credrele(&scred); 5864bff34e3Sthurlow if (error) { 5874bff34e3Sthurlow SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error); 5884bff34e3Sthurlow } 5894bff34e3Sthurlow 59091d632c8Sgwr /* 59191d632c8Sgwr * We enable XATTR by default (via smbfs_mntopts) 59291d632c8Sgwr * but if the share does not support named streams, 59391d632c8Sgwr * force the NOXATTR option (also clears XATTR). 59491d632c8Sgwr * Caller will set or clear VFS_XATTR after this. 59591d632c8Sgwr */ 59691d632c8Sgwr if ((smi->smi_fsattr & FILE_NAMED_STREAMS) == 0) 59791d632c8Sgwr vfs_setmntopt(vfsp, MNTOPT_NOXATTR, NULL, 0); 5984bff34e3Sthurlow 599bd7c6f51SGordon Ross /* 600bd7c6f51SGordon Ross * Ditto ACLs (disable if not supported on this share) 601bd7c6f51SGordon Ross */ 602bd7c6f51SGordon Ross if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) { 603bd7c6f51SGordon Ross vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0); 604bd7c6f51SGordon Ross smi->smi_flags &= ~SMI_ACL; 605bd7c6f51SGordon Ross } 606bd7c6f51SGordon Ross 6074bff34e3Sthurlow /* 6084bff34e3Sthurlow * Assign a unique device id to the mount 6094bff34e3Sthurlow */ 6104bff34e3Sthurlow mutex_enter(&smbfs_minor_lock); 6114bff34e3Sthurlow do { 6124bff34e3Sthurlow smbfs_minor = (smbfs_minor + 1) & MAXMIN32; 6134bff34e3Sthurlow smbfs_dev = makedevice(smbfs_major, smbfs_minor); 6144bff34e3Sthurlow } while (vfs_devismounted(smbfs_dev)); 6154bff34e3Sthurlow mutex_exit(&smbfs_minor_lock); 6164bff34e3Sthurlow 6174bff34e3Sthurlow vfsp->vfs_dev = smbfs_dev; 6184bff34e3Sthurlow vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp); 6194bff34e3Sthurlow vfsp->vfs_data = (caddr_t)smi; 6204bff34e3Sthurlow vfsp->vfs_fstype = smbfsfstyp; 6214bff34e3Sthurlow vfsp->vfs_bsize = MAXBSIZE; 6224bff34e3Sthurlow vfsp->vfs_bcount = 0; 6234bff34e3Sthurlow 6244bff34e3Sthurlow smi->smi_vfsp = vfsp; 62502d09e03SGordon Ross smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */ 6264bff34e3Sthurlow 62728162916SGordon Ross /* PSARC 2007/227 VFS Feature Registration */ 62828162916SGordon Ross vfs_set_feature(vfsp, VFSFT_XVATTR); 62928162916SGordon Ross vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS); 63028162916SGordon Ross 6314bff34e3Sthurlow /* 6324bff34e3Sthurlow * Create the root vnode, which we need in unmount 63302d09e03SGordon Ross * for the call to smbfs_check_table(), etc. 63402d09e03SGordon Ross * Release this hold in smbfs_unmount. 6354bff34e3Sthurlow */ 63602d09e03SGordon Ross rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0, 63702d09e03SGordon Ross &smbfs_fattr0); 63802d09e03SGordon Ross ASSERT(rtnp != NULL); 63902d09e03SGordon Ross rtnp->r_vnode->v_type = VDIR; 64002d09e03SGordon Ross rtnp->r_vnode->v_flag |= VROOT; 64102d09e03SGordon Ross smi->smi_root = rtnp; 6424bff34e3Sthurlow 643*4e72ade1SGordon Ross /* 644*4e72ade1SGordon Ross * Create a taskq for async work (i.e. putpage) 645*4e72ade1SGordon Ross */ 646*4e72ade1SGordon Ross smi->smi_taskq = taskq_create_proc("smbfs", 647*4e72ade1SGordon Ross smbfs_tq_nthread, minclsyspri, 648*4e72ade1SGordon Ross smbfs_tq_nthread, smbfs_tq_nthread * 2, 649*4e72ade1SGordon Ross zone->zone_zsched, TASKQ_PREPOPULATE); 650*4e72ade1SGordon Ross 6514bff34e3Sthurlow /* 6524bff34e3Sthurlow * NFS does other stuff here too: 6534bff34e3Sthurlow * async worker threads 6544bff34e3Sthurlow * init kstats 6554bff34e3Sthurlow * 6564bff34e3Sthurlow * End of code from NFS nfsrootvp() 6574bff34e3Sthurlow */ 6584bff34e3Sthurlow return (0); 6594bff34e3Sthurlow 6604bff34e3Sthurlow errout: 6614bff34e3Sthurlow vfsp->vfs_data = NULL; 66202d09e03SGordon Ross if (smi != NULL) 6634bff34e3Sthurlow smbfs_free_smi(smi); 6644bff34e3Sthurlow 6654bff34e3Sthurlow if (mntzone != NULL) 6664bff34e3Sthurlow zone_rele(mntzone); 6674bff34e3Sthurlow 66802d09e03SGordon Ross if (ssp != NULL) 6694bff34e3Sthurlow smb_share_rele(ssp); 6704bff34e3Sthurlow 6714bff34e3Sthurlow return (error); 6724bff34e3Sthurlow } 6734bff34e3Sthurlow 6744bff34e3Sthurlow /* 6754bff34e3Sthurlow * vfs operations 6764bff34e3Sthurlow */ 6774bff34e3Sthurlow static int 6784bff34e3Sthurlow smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) 6794bff34e3Sthurlow { 6804bff34e3Sthurlow smbmntinfo_t *smi; 6814bff34e3Sthurlow smbnode_t *rtnp; 6824bff34e3Sthurlow 6834bff34e3Sthurlow smi = VFTOSMI(vfsp); 6844bff34e3Sthurlow 6854bff34e3Sthurlow if (secpolicy_fs_unmount(cr, vfsp) != 0) 6864bff34e3Sthurlow return (EPERM); 6874bff34e3Sthurlow 6884bff34e3Sthurlow if ((flag & MS_FORCE) == 0) { 6894bff34e3Sthurlow smbfs_rflush(vfsp, cr); 6904bff34e3Sthurlow 6914bff34e3Sthurlow /* 6924bff34e3Sthurlow * If there are any active vnodes on this file system, 6934bff34e3Sthurlow * (other than the root vnode) then the file system is 6944bff34e3Sthurlow * busy and can't be umounted. 6954bff34e3Sthurlow */ 69602d09e03SGordon Ross if (smbfs_check_table(vfsp, smi->smi_root)) 6974bff34e3Sthurlow return (EBUSY); 6984bff34e3Sthurlow 6994bff34e3Sthurlow /* 7004bff34e3Sthurlow * We normally hold a ref to the root vnode, so 7014bff34e3Sthurlow * check for references beyond the one we expect: 7024bff34e3Sthurlow * smbmntinfo_t -> smi_root 7034bff34e3Sthurlow * Note that NFS does not hold the root vnode. 7044bff34e3Sthurlow */ 7054bff34e3Sthurlow if (smi->smi_root && 7064bff34e3Sthurlow smi->smi_root->r_vnode->v_count > 1) 7074bff34e3Sthurlow return (EBUSY); 7084bff34e3Sthurlow } 7094bff34e3Sthurlow 7104bff34e3Sthurlow /* 7114bff34e3Sthurlow * common code for both forced and non-forced 7124bff34e3Sthurlow * 7134bff34e3Sthurlow * Setting VFS_UNMOUNTED prevents new operations. 7144bff34e3Sthurlow * Operations already underway may continue, 7154bff34e3Sthurlow * but not for long. 7164bff34e3Sthurlow */ 7174bff34e3Sthurlow vfsp->vfs_flag |= VFS_UNMOUNTED; 7184bff34e3Sthurlow 7194bff34e3Sthurlow /* 7204bff34e3Sthurlow * If we hold the root VP (and we normally do) 7214bff34e3Sthurlow * then it's safe to release it now. 7224bff34e3Sthurlow */ 7234bff34e3Sthurlow if (smi->smi_root) { 7244bff34e3Sthurlow rtnp = smi->smi_root; 7254bff34e3Sthurlow smi->smi_root = NULL; 7264bff34e3Sthurlow VN_RELE(rtnp->r_vnode); /* release root vnode */ 7274bff34e3Sthurlow } 7284bff34e3Sthurlow 7294bff34e3Sthurlow /* 7304bff34e3Sthurlow * Remove all nodes from the node hash tables. 73102d09e03SGordon Ross * This (indirectly) calls: smbfs_addfree, smbinactive, 7324bff34e3Sthurlow * which will try to flush dirty pages, etc. so 7334bff34e3Sthurlow * don't destroy the underlying share just yet. 7344bff34e3Sthurlow * 7354bff34e3Sthurlow * Also, with a forced unmount, some nodes may 7364bff34e3Sthurlow * remain active, and those will get cleaned up 7374bff34e3Sthurlow * after their last vn_rele. 7384bff34e3Sthurlow */ 7394bff34e3Sthurlow smbfs_destroy_table(vfsp); 7404bff34e3Sthurlow 741*4e72ade1SGordon Ross /* 742*4e72ade1SGordon Ross * Shutdown any outstanding I/O requests on this share, 743*4e72ade1SGordon Ross * and force a tree disconnect. The share object will 744*4e72ade1SGordon Ross * continue to hang around until smb_share_rele(). 745*4e72ade1SGordon Ross * This should also cause most active nodes to be 746*4e72ade1SGordon Ross * released as their operations fail with EIO. 747*4e72ade1SGordon Ross */ 748*4e72ade1SGordon Ross smb_share_kill(smi->smi_share); 749*4e72ade1SGordon Ross 750*4e72ade1SGordon Ross /* 751*4e72ade1SGordon Ross * Any async taskq work should be giving up. 752*4e72ade1SGordon Ross * Wait for those to exit. 753*4e72ade1SGordon Ross */ 754*4e72ade1SGordon Ross taskq_destroy(smi->smi_taskq); 755*4e72ade1SGordon Ross 7564bff34e3Sthurlow /* 7574bff34e3Sthurlow * Delete our kstats... 7584bff34e3Sthurlow * 7594bff34e3Sthurlow * Doing it here, rather than waiting until 7604bff34e3Sthurlow * smbfs_freevfs so these are not visible 7614bff34e3Sthurlow * after the unmount. 7624bff34e3Sthurlow */ 7634bff34e3Sthurlow if (smi->smi_io_kstats) { 7644bff34e3Sthurlow kstat_delete(smi->smi_io_kstats); 7654bff34e3Sthurlow smi->smi_io_kstats = NULL; 7664bff34e3Sthurlow } 7674bff34e3Sthurlow if (smi->smi_ro_kstats) { 7684bff34e3Sthurlow kstat_delete(smi->smi_ro_kstats); 7694bff34e3Sthurlow smi->smi_ro_kstats = NULL; 7704bff34e3Sthurlow } 7714bff34e3Sthurlow 7724bff34e3Sthurlow /* 77302d09e03SGordon Ross * The rest happens in smbfs_freevfs() 7744bff34e3Sthurlow */ 7754bff34e3Sthurlow return (0); 7764bff34e3Sthurlow } 7774bff34e3Sthurlow 7784bff34e3Sthurlow 7794bff34e3Sthurlow /* 7804bff34e3Sthurlow * find root of smbfs 7814bff34e3Sthurlow */ 7824bff34e3Sthurlow static int 7834bff34e3Sthurlow smbfs_root(vfs_t *vfsp, vnode_t **vpp) 7844bff34e3Sthurlow { 7854bff34e3Sthurlow smbmntinfo_t *smi; 7864bff34e3Sthurlow vnode_t *vp; 7874bff34e3Sthurlow 7884bff34e3Sthurlow smi = VFTOSMI(vfsp); 7894bff34e3Sthurlow 790a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 7914bff34e3Sthurlow return (EPERM); 7924bff34e3Sthurlow 7934bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 7944bff34e3Sthurlow return (EIO); 7954bff34e3Sthurlow 7964bff34e3Sthurlow /* 7974bff34e3Sthurlow * The root vp is created in mount and held 7984bff34e3Sthurlow * until unmount, so this is paranoia. 7994bff34e3Sthurlow */ 8004bff34e3Sthurlow if (smi->smi_root == NULL) 8014bff34e3Sthurlow return (EIO); 8024bff34e3Sthurlow 8034bff34e3Sthurlow /* Just take a reference and return it. */ 8044bff34e3Sthurlow vp = SMBTOV(smi->smi_root); 8054bff34e3Sthurlow VN_HOLD(vp); 8064bff34e3Sthurlow *vpp = vp; 8074bff34e3Sthurlow 8084bff34e3Sthurlow return (0); 8094bff34e3Sthurlow } 8104bff34e3Sthurlow 8114bff34e3Sthurlow /* 8124bff34e3Sthurlow * Get file system statistics. 8134bff34e3Sthurlow */ 8144bff34e3Sthurlow static int 8154bff34e3Sthurlow smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp) 8164bff34e3Sthurlow { 8174bff34e3Sthurlow int error; 8184bff34e3Sthurlow smbmntinfo_t *smi = VFTOSMI(vfsp); 8194bff34e3Sthurlow smb_share_t *ssp = smi->smi_share; 8204bff34e3Sthurlow statvfs64_t stvfs; 8214bff34e3Sthurlow hrtime_t now; 8224bff34e3Sthurlow smb_cred_t scred; 8234bff34e3Sthurlow 824a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 8254bff34e3Sthurlow return (EPERM); 8264bff34e3Sthurlow 8274bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 8284bff34e3Sthurlow return (EIO); 8294bff34e3Sthurlow 8304bff34e3Sthurlow mutex_enter(&smi->smi_lock); 8314bff34e3Sthurlow 8324bff34e3Sthurlow /* 8334bff34e3Sthurlow * Use cached result if still valid. 8344bff34e3Sthurlow */ 8354bff34e3Sthurlow recheck: 8364bff34e3Sthurlow now = gethrtime(); 8374bff34e3Sthurlow if (now < smi->smi_statfstime) { 838613a2f6bSGordon Ross error = 0; 8394bff34e3Sthurlow goto cache_hit; 8404bff34e3Sthurlow } 8414bff34e3Sthurlow 8424bff34e3Sthurlow /* 8434bff34e3Sthurlow * FS attributes are stale, so someone 8444bff34e3Sthurlow * needs to do an OTW call to get them. 8454bff34e3Sthurlow * Serialize here so only one thread 8464bff34e3Sthurlow * does the OTW call. 8474bff34e3Sthurlow */ 8484bff34e3Sthurlow if (smi->smi_status & SM_STATUS_STATFS_BUSY) { 8494bff34e3Sthurlow smi->smi_status |= SM_STATUS_STATFS_WANT; 8504bff34e3Sthurlow if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) { 8514bff34e3Sthurlow mutex_exit(&smi->smi_lock); 8524bff34e3Sthurlow return (EINTR); 8534bff34e3Sthurlow } 8544bff34e3Sthurlow /* Hope status is valid now. */ 8554bff34e3Sthurlow goto recheck; 8564bff34e3Sthurlow } 8574bff34e3Sthurlow smi->smi_status |= SM_STATUS_STATFS_BUSY; 8584bff34e3Sthurlow mutex_exit(&smi->smi_lock); 8594bff34e3Sthurlow 8604bff34e3Sthurlow /* 8614bff34e3Sthurlow * Do the OTW call. Note: lock NOT held. 8624bff34e3Sthurlow */ 863613a2f6bSGordon Ross smb_credinit(&scred, NULL); 8644bff34e3Sthurlow bzero(&stvfs, sizeof (stvfs)); 8654bff34e3Sthurlow error = smbfs_smb_statfs(ssp, &stvfs, &scred); 8664bff34e3Sthurlow smb_credrele(&scred); 867613a2f6bSGordon Ross if (error) { 868613a2f6bSGordon Ross SMBVDEBUG("statfs error=%d\n", error); 869613a2f6bSGordon Ross } else { 870613a2f6bSGordon Ross 871613a2f6bSGordon Ross /* 872613a2f6bSGordon Ross * Set a few things the OTW call didn't get. 873613a2f6bSGordon Ross */ 874613a2f6bSGordon Ross stvfs.f_frsize = stvfs.f_bsize; 875613a2f6bSGordon Ross stvfs.f_favail = stvfs.f_ffree; 876613a2f6bSGordon Ross stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0]; 877613a2f6bSGordon Ross bcopy(fs_type_name, stvfs.f_basetype, FSTYPSZ); 878613a2f6bSGordon Ross stvfs.f_flag = vf_to_stf(vfsp->vfs_flag); 879613a2f6bSGordon Ross stvfs.f_namemax = smi->smi_fsa.fsa_maxname; 880613a2f6bSGordon Ross 881613a2f6bSGordon Ross /* 882613a2f6bSGordon Ross * Save the result, update lifetime 883613a2f6bSGordon Ross */ 884613a2f6bSGordon Ross now = gethrtime(); 885613a2f6bSGordon Ross smi->smi_statfstime = now + 886613a2f6bSGordon Ross (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC); 887613a2f6bSGordon Ross smi->smi_statvfsbuf = stvfs; /* struct assign! */ 888613a2f6bSGordon Ross } 8894bff34e3Sthurlow 8904bff34e3Sthurlow mutex_enter(&smi->smi_lock); 8914bff34e3Sthurlow if (smi->smi_status & SM_STATUS_STATFS_WANT) 8924bff34e3Sthurlow cv_broadcast(&smi->smi_statvfs_cv); 8934bff34e3Sthurlow smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT); 8944bff34e3Sthurlow 8954bff34e3Sthurlow /* 8964bff34e3Sthurlow * Copy the statvfs data to caller's buf. 8974bff34e3Sthurlow * Note: struct assignment 8984bff34e3Sthurlow */ 8994bff34e3Sthurlow cache_hit: 900613a2f6bSGordon Ross if (error == 0) 901613a2f6bSGordon Ross *sbp = smi->smi_statvfsbuf; 9024bff34e3Sthurlow mutex_exit(&smi->smi_lock); 9034bff34e3Sthurlow return (error); 9044bff34e3Sthurlow } 9054bff34e3Sthurlow 9064bff34e3Sthurlow /* 9074bff34e3Sthurlow * Flush dirty smbfs files for file system vfsp. 9084bff34e3Sthurlow * If vfsp == NULL, all smbfs files are flushed. 9094bff34e3Sthurlow */ 9104bff34e3Sthurlow /*ARGSUSED*/ 9114bff34e3Sthurlow static int 9124bff34e3Sthurlow smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) 9134bff34e3Sthurlow { 9145f4fc069Sjilinxpd 9154bff34e3Sthurlow /* 9165f4fc069Sjilinxpd * SYNC_ATTR is used by fsflush() to force old filesystems like UFS 9175f4fc069Sjilinxpd * to sync metadata, which they would otherwise cache indefinitely. 9185f4fc069Sjilinxpd * Semantically, the only requirement is that the sync be initiated. 9195f4fc069Sjilinxpd * Assume the server-side takes care of attribute sync. 9204bff34e3Sthurlow */ 9215f4fc069Sjilinxpd if (flag & SYNC_ATTR) 9225f4fc069Sjilinxpd return (0); 9235f4fc069Sjilinxpd 9245f4fc069Sjilinxpd if (vfsp == NULL) { 9255f4fc069Sjilinxpd /* 9265f4fc069Sjilinxpd * Flush ALL smbfs mounts in this zone. 9275f4fc069Sjilinxpd */ 9285f4fc069Sjilinxpd smbfs_flushall(cr); 9295f4fc069Sjilinxpd return (0); 9304bff34e3Sthurlow } 93102d09e03SGordon Ross 9325f4fc069Sjilinxpd smbfs_rflush(vfsp, cr); 9335f4fc069Sjilinxpd 9344bff34e3Sthurlow return (0); 9354bff34e3Sthurlow } 9364bff34e3Sthurlow 9374bff34e3Sthurlow /* 9384bff34e3Sthurlow * Initialization routine for VFS routines. Should only be called once 9394bff34e3Sthurlow */ 9404bff34e3Sthurlow int 9414bff34e3Sthurlow smbfs_vfsinit(void) 9424bff34e3Sthurlow { 9434bff34e3Sthurlow return (0); 9444bff34e3Sthurlow } 9454bff34e3Sthurlow 9464bff34e3Sthurlow /* 9474bff34e3Sthurlow * Shutdown routine for VFS routines. Should only be called once 9484bff34e3Sthurlow */ 9494bff34e3Sthurlow void 9504bff34e3Sthurlow smbfs_vfsfini(void) 9514bff34e3Sthurlow { 9524bff34e3Sthurlow } 9534bff34e3Sthurlow 9544bff34e3Sthurlow void 9554bff34e3Sthurlow smbfs_freevfs(vfs_t *vfsp) 9564bff34e3Sthurlow { 9574bff34e3Sthurlow smbmntinfo_t *smi; 9584bff34e3Sthurlow 9594bff34e3Sthurlow /* free up the resources */ 9604bff34e3Sthurlow smi = VFTOSMI(vfsp); 9614bff34e3Sthurlow 9624bff34e3Sthurlow /* 9634bff34e3Sthurlow * By this time we should have already deleted the 9644bff34e3Sthurlow * smi kstats in the unmount code. If they are still around 9654bff34e3Sthurlow * something is wrong 9664bff34e3Sthurlow */ 9674bff34e3Sthurlow ASSERT(smi->smi_io_kstats == NULL); 9684bff34e3Sthurlow 96902d09e03SGordon Ross smbfs_zonelist_remove(smi); 9704bff34e3Sthurlow 9714bff34e3Sthurlow smbfs_free_smi(smi); 9724bff34e3Sthurlow 9734bff34e3Sthurlow /* 9744bff34e3Sthurlow * Allow _fini() to succeed now, if so desired. 9754bff34e3Sthurlow */ 9764bff34e3Sthurlow atomic_dec_32(&smbfs_mountcount); 9774bff34e3Sthurlow } 9784bff34e3Sthurlow 9794bff34e3Sthurlow /* 9804bff34e3Sthurlow * smbfs_mount_label_policy: 9814bff34e3Sthurlow * Determine whether the mount is allowed according to MAC check, 9824bff34e3Sthurlow * by comparing (where appropriate) label of the remote server 9834bff34e3Sthurlow * against the label of the zone being mounted into. 9844bff34e3Sthurlow * 9854bff34e3Sthurlow * Returns: 9864bff34e3Sthurlow * 0 : access allowed 9874bff34e3Sthurlow * -1 : read-only access allowed (i.e., read-down) 9884bff34e3Sthurlow * >0 : error code, such as EACCES 9894bff34e3Sthurlow * 9904bff34e3Sthurlow * NB: 9914bff34e3Sthurlow * NFS supports Cipso labels by parsing the vfs_resource 9924bff34e3Sthurlow * to see what the Solaris server global zone has shared. 9934bff34e3Sthurlow * We can't support that for CIFS since resource names 9944bff34e3Sthurlow * contain share names, not paths. 9954bff34e3Sthurlow */ 9964bff34e3Sthurlow static int 9974bff34e3Sthurlow smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr) 9984bff34e3Sthurlow { 9994bff34e3Sthurlow bslabel_t *server_sl, *mntlabel; 10004bff34e3Sthurlow zone_t *mntzone = NULL; 10014bff34e3Sthurlow ts_label_t *zlabel; 10024bff34e3Sthurlow tsol_tpc_t *tp; 10034bff34e3Sthurlow ts_label_t *tsl = NULL; 10044bff34e3Sthurlow int retv; 10054bff34e3Sthurlow 10064bff34e3Sthurlow /* 10074bff34e3Sthurlow * Get the zone's label. Each zone on a labeled system has a label. 10084bff34e3Sthurlow */ 10094bff34e3Sthurlow mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); 10104bff34e3Sthurlow zlabel = mntzone->zone_slabel; 10114bff34e3Sthurlow ASSERT(zlabel != NULL); 10124bff34e3Sthurlow label_hold(zlabel); 10134bff34e3Sthurlow 10144bff34e3Sthurlow retv = EACCES; /* assume the worst */ 10154bff34e3Sthurlow 10164bff34e3Sthurlow /* 10174bff34e3Sthurlow * Next, get the assigned label of the remote server. 10184bff34e3Sthurlow */ 10194bff34e3Sthurlow tp = find_tpc(ipaddr, addr_type, B_FALSE); 10204bff34e3Sthurlow if (tp == NULL) 10214bff34e3Sthurlow goto out; /* error getting host entry */ 10224bff34e3Sthurlow 10234bff34e3Sthurlow if (tp->tpc_tp.tp_doi != zlabel->tsl_doi) 10244bff34e3Sthurlow goto rel_tpc; /* invalid domain */ 10254bff34e3Sthurlow if ((tp->tpc_tp.host_type != UNLABELED)) 10264bff34e3Sthurlow goto rel_tpc; /* invalid hosttype */ 10274bff34e3Sthurlow 10284bff34e3Sthurlow server_sl = &tp->tpc_tp.tp_def_label; 10294bff34e3Sthurlow mntlabel = label2bslabel(zlabel); 10304bff34e3Sthurlow 10314bff34e3Sthurlow /* 10324bff34e3Sthurlow * Now compare labels to complete the MAC check. If the labels 10334bff34e3Sthurlow * are equal or if the requestor is in the global zone and has 10344bff34e3Sthurlow * NET_MAC_AWARE, then allow read-write access. (Except for 10354bff34e3Sthurlow * mounts into the global zone itself; restrict these to 10364bff34e3Sthurlow * read-only.) 10374bff34e3Sthurlow * 103848bbca81SDaniel Hoffman * If the requestor is in some other zone, but their label 10394bff34e3Sthurlow * dominates the server, then allow read-down. 10404bff34e3Sthurlow * 10414bff34e3Sthurlow * Otherwise, access is denied. 10424bff34e3Sthurlow */ 10434bff34e3Sthurlow if (blequal(mntlabel, server_sl) || 10444bff34e3Sthurlow (crgetzoneid(cr) == GLOBAL_ZONEID && 10454bff34e3Sthurlow getpflags(NET_MAC_AWARE, cr) != 0)) { 10464bff34e3Sthurlow if ((mntzone == global_zone) || 10474bff34e3Sthurlow !blequal(mntlabel, server_sl)) 10484bff34e3Sthurlow retv = -1; /* read-only */ 10494bff34e3Sthurlow else 10504bff34e3Sthurlow retv = 0; /* access OK */ 10514bff34e3Sthurlow } else if (bldominates(mntlabel, server_sl)) { 10524bff34e3Sthurlow retv = -1; /* read-only */ 10534bff34e3Sthurlow } else { 10544bff34e3Sthurlow retv = EACCES; 10554bff34e3Sthurlow } 10564bff34e3Sthurlow 10574bff34e3Sthurlow if (tsl != NULL) 10584bff34e3Sthurlow label_rele(tsl); 10594bff34e3Sthurlow 10604bff34e3Sthurlow rel_tpc: 10614bff34e3Sthurlow /*LINTED*/ 10624bff34e3Sthurlow TPC_RELE(tp); 10634bff34e3Sthurlow out: 10644bff34e3Sthurlow if (mntzone) 10654bff34e3Sthurlow zone_rele(mntzone); 10664bff34e3Sthurlow label_rele(zlabel); 10674bff34e3Sthurlow return (retv); 10684bff34e3Sthurlow } 1069