14bff34e3Sthurlow /*
24bff34e3Sthurlow  * CDDL HEADER START
34bff34e3Sthurlow  *
44bff34e3Sthurlow  * The contents of this file are subject to the terms of the
54bff34e3Sthurlow  * Common Development and Distribution License (the "License").
64bff34e3Sthurlow  * You may not use this file except in compliance with the License.
74bff34e3Sthurlow  *
84bff34e3Sthurlow  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94bff34e3Sthurlow  * or http://www.opensolaris.org/os/licensing.
104bff34e3Sthurlow  * See the License for the specific language governing permissions
114bff34e3Sthurlow  * and limitations under the License.
124bff34e3Sthurlow  *
134bff34e3Sthurlow  * When distributing Covered Code, include this CDDL HEADER in each
144bff34e3Sthurlow  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154bff34e3Sthurlow  * If applicable, add the following below this CDDL HEADER, with the
164bff34e3Sthurlow  * fields enclosed by brackets "[]" replaced with your own identifying
174bff34e3Sthurlow  * information: Portions Copyright [yyyy] [name of copyright owner]
184bff34e3Sthurlow  *
194bff34e3Sthurlow  * CDDL HEADER END
204bff34e3Sthurlow  */
21613a2f6bSGordon Ross 
224bff34e3Sthurlow /*
23a19609f8Sjv  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
244bff34e3Sthurlow  *
255f4fc069Sjilinxpd  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
264bff34e3Sthurlow  *	All rights reserved.
278329232eSGordon Ross  *
28*adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
294bff34e3Sthurlow  */
304bff34e3Sthurlow 
314bff34e3Sthurlow #include <sys/param.h>
324bff34e3Sthurlow #include <sys/systm.h>
334bff34e3Sthurlow #include <sys/thread.h>
344bff34e3Sthurlow #include <sys/t_lock.h>
354bff34e3Sthurlow #include <sys/time.h>
364bff34e3Sthurlow #include <sys/vnode.h>
374bff34e3Sthurlow #include <sys/vfs.h>
384bff34e3Sthurlow #include <sys/errno.h>
394bff34e3Sthurlow #include <sys/buf.h>
404bff34e3Sthurlow #include <sys/stat.h>
414bff34e3Sthurlow #include <sys/cred.h>
424bff34e3Sthurlow #include <sys/kmem.h>
434bff34e3Sthurlow #include <sys/debug.h>
444bff34e3Sthurlow #include <sys/vmsystm.h>
454bff34e3Sthurlow #include <sys/flock.h>
464bff34e3Sthurlow #include <sys/share.h>
474bff34e3Sthurlow #include <sys/cmn_err.h>
484bff34e3Sthurlow #include <sys/tiuser.h>
494bff34e3Sthurlow #include <sys/sysmacros.h>
504bff34e3Sthurlow #include <sys/callb.h>
514bff34e3Sthurlow #include <sys/acl.h>
524bff34e3Sthurlow #include <sys/kstat.h>
534bff34e3Sthurlow #include <sys/signal.h>
544bff34e3Sthurlow #include <sys/list.h>
554bff34e3Sthurlow #include <sys/zone.h>
564bff34e3Sthurlow 
5702d09e03SGordon Ross #include <netsmb/smb.h>
584bff34e3Sthurlow #include <netsmb/smb_conn.h>
5902d09e03SGordon Ross #include <netsmb/smb_subr.h>
604bff34e3Sthurlow 
614bff34e3Sthurlow #include <smbfs/smbfs.h>
624bff34e3Sthurlow #include <smbfs/smbfs_node.h>
634bff34e3Sthurlow #include <smbfs/smbfs_subr.h>
644bff34e3Sthurlow 
658329232eSGordon Ross #ifdef	_KERNEL
664bff34e3Sthurlow #include <vm/hat.h>
674bff34e3Sthurlow #include <vm/as.h>
684bff34e3Sthurlow #include <vm/page.h>
694bff34e3Sthurlow #include <vm/pvn.h>
704bff34e3Sthurlow #include <vm/seg.h>
714bff34e3Sthurlow #include <vm/seg_map.h>
724bff34e3Sthurlow #include <vm/seg_vn.h>
738329232eSGordon Ross #endif	// _KERNEL
744bff34e3Sthurlow 
755f4fc069Sjilinxpd #define	ATTRCACHE_VALID(vp)	(gethrtime() < VTOSMB(vp)->r_attrtime)
765f4fc069Sjilinxpd 
7728162916SGordon Ross static int smbfs_getattr_cache(vnode_t *, smbfattr_t *);
7828162916SGordon Ross static void smbfattr_to_vattr(vnode_t *, smbfattr_t *, vattr_t *);
7928162916SGordon Ross static void smbfattr_to_xvattr(smbfattr_t *, vattr_t *);
805f4fc069Sjilinxpd static int smbfs_getattr_otw(vnode_t *, struct smbfattr *, cred_t *);
815f4fc069Sjilinxpd 
8202d09e03SGordon Ross 
834bff34e3Sthurlow /*
844bff34e3Sthurlow  * The following code provide zone support in order to perform an action
854bff34e3Sthurlow  * for each smbfs mount in a zone.  This is also where we would add
864bff34e3Sthurlow  * per-zone globals and kernel threads for the smbfs module (since
874bff34e3Sthurlow  * they must be terminated by the shutdown callback).
884bff34e3Sthurlow  */
894bff34e3Sthurlow 
904bff34e3Sthurlow struct smi_globals {
914bff34e3Sthurlow 	kmutex_t	smg_lock;  /* lock protecting smg_list */
924bff34e3Sthurlow 	list_t		smg_list;  /* list of SMBFS mounts in zone */
934bff34e3Sthurlow 	boolean_t	smg_destructor_called;
944bff34e3Sthurlow };
954bff34e3Sthurlow typedef struct smi_globals smi_globals_t;
964bff34e3Sthurlow 
974bff34e3Sthurlow static zone_key_t smi_list_key;
984bff34e3Sthurlow 
9902d09e03SGordon Ross /*
10002d09e03SGordon Ross  * Attributes caching:
10102d09e03SGordon Ross  *
10202d09e03SGordon Ross  * Attributes are cached in the smbnode in struct vattr form.
10302d09e03SGordon Ross  * There is a time associated with the cached attributes (r_attrtime)
10402d09e03SGordon Ross  * which tells whether the attributes are valid. The time is initialized
10502d09e03SGordon Ross  * to the difference between current time and the modify time of the vnode
10602d09e03SGordon Ross  * when new attributes are cached. This allows the attributes for
10702d09e03SGordon Ross  * files that have changed recently to be timed out sooner than for files
10802d09e03SGordon Ross  * that have not changed for a long time. There are minimum and maximum
10902d09e03SGordon Ross  * timeout values that can be set per mount point.
11002d09e03SGordon Ross  */
11102d09e03SGordon Ross 
11202d09e03SGordon Ross /*
1135f4fc069Sjilinxpd  * Helper for _validate_caches
1145f4fc069Sjilinxpd  */
1155f4fc069Sjilinxpd int
smbfs_waitfor_purge_complete(vnode_t * vp)1165f4fc069Sjilinxpd smbfs_waitfor_purge_complete(vnode_t *vp)
1175f4fc069Sjilinxpd {
1185f4fc069Sjilinxpd 	smbnode_t *np;
1195f4fc069Sjilinxpd 	k_sigset_t smask;
1205f4fc069Sjilinxpd 
1215f4fc069Sjilinxpd 	np = VTOSMB(vp);
1225f4fc069Sjilinxpd 	if (np->r_serial != NULL && np->r_serial != curthread) {
1235f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
1245f4fc069Sjilinxpd 		sigintr(&smask, VTOSMI(vp)->smi_flags & SMI_INT);
1255f4fc069Sjilinxpd 		while (np->r_serial != NULL) {
1265f4fc069Sjilinxpd 			if (!cv_wait_sig(&np->r_cv, &np->r_statelock)) {
1275f4fc069Sjilinxpd 				sigunintr(&smask);
1285f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
1295f4fc069Sjilinxpd 				return (EINTR);
1305f4fc069Sjilinxpd 			}
1315f4fc069Sjilinxpd 		}
1325f4fc069Sjilinxpd 		sigunintr(&smask);
1335f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
1345f4fc069Sjilinxpd 	}
1355f4fc069Sjilinxpd 	return (0);
1365f4fc069Sjilinxpd }
1375f4fc069Sjilinxpd 
1385f4fc069Sjilinxpd /*
1395f4fc069Sjilinxpd  * Validate caches by checking cached attributes. If the cached
1405f4fc069Sjilinxpd  * attributes have timed out, then get new attributes from the server.
1415f4fc069Sjilinxpd  * As a side affect, this will do cache invalidation if the attributes
1425f4fc069Sjilinxpd  * have changed.
1435f4fc069Sjilinxpd  *
1445f4fc069Sjilinxpd  * If the attributes have not timed out and if there is a cache
1455f4fc069Sjilinxpd  * invalidation being done by some other thread, then wait until that
1465f4fc069Sjilinxpd  * thread has completed the cache invalidation.
14702d09e03SGordon Ross  */
14802d09e03SGordon Ross int
smbfs_validate_caches(struct vnode * vp,cred_t * cr)14902d09e03SGordon Ross smbfs_validate_caches(
15002d09e03SGordon Ross 	struct vnode *vp,
15102d09e03SGordon Ross 	cred_t *cr)
15202d09e03SGordon Ross {
1535f4fc069Sjilinxpd 	struct smbfattr fa;
1545f4fc069Sjilinxpd 	int error;
1555f4fc069Sjilinxpd 
1565f4fc069Sjilinxpd 	if (ATTRCACHE_VALID(vp)) {
1575f4fc069Sjilinxpd 		error = smbfs_waitfor_purge_complete(vp);
1585f4fc069Sjilinxpd 		if (error)
1595f4fc069Sjilinxpd 			return (error);
1605f4fc069Sjilinxpd 		return (0);
1615f4fc069Sjilinxpd 	}
16202d09e03SGordon Ross 
1635f4fc069Sjilinxpd 	return (smbfs_getattr_otw(vp, &fa, cr));
16402d09e03SGordon Ross }
16502d09e03SGordon Ross 
16602d09e03SGordon Ross /*
16702d09e03SGordon Ross  * Purge all of the various data caches.
1685f4fc069Sjilinxpd  *
1695f4fc069Sjilinxpd  * Here NFS also had a flags arg to control what gets flushed.
1705f4fc069Sjilinxpd  * We only have the page cache, so no flags arg.
17102d09e03SGordon Ross  */
1725f4fc069Sjilinxpd /* ARGSUSED */
17302d09e03SGordon Ross void
smbfs_purge_caches(struct vnode * vp,cred_t * cr)1745f4fc069Sjilinxpd smbfs_purge_caches(struct vnode *vp, cred_t *cr)
17502d09e03SGordon Ross {
1765f4fc069Sjilinxpd 
17702d09e03SGordon Ross 	/*
1785f4fc069Sjilinxpd 	 * Here NFS has: Purge the DNLC for this vp,
17902d09e03SGordon Ross 	 * Clear any readdir state bits,
18002d09e03SGordon Ross 	 * the readlink response cache, ...
18102d09e03SGordon Ross 	 */
18202d09e03SGordon Ross 
18302d09e03SGordon Ross 	/*
18402d09e03SGordon Ross 	 * Flush the page cache.
18502d09e03SGordon Ross 	 */
18602d09e03SGordon Ross 	if (vn_has_cached_data(vp)) {
18702d09e03SGordon Ross 		(void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL);
18802d09e03SGordon Ross 	}
1895f4fc069Sjilinxpd 
1905f4fc069Sjilinxpd 	/*
1915f4fc069Sjilinxpd 	 * Here NFS has: Flush the readdir response cache.
1925f4fc069Sjilinxpd 	 * No readdir cache in smbfs.
1935f4fc069Sjilinxpd 	 */
19402d09e03SGordon Ross }
19502d09e03SGordon Ross 
1965f4fc069Sjilinxpd /*
1975f4fc069Sjilinxpd  * Here NFS has:
1985f4fc069Sjilinxpd  * nfs_purge_rddir_cache()
1995f4fc069Sjilinxpd  * nfs3_cache_post_op_attr()
2005f4fc069Sjilinxpd  * nfs3_cache_post_op_vattr()
2015f4fc069Sjilinxpd  * nfs3_cache_wcc_data()
2025f4fc069Sjilinxpd  */
2035f4fc069Sjilinxpd 
20402d09e03SGordon Ross /*
20502d09e03SGordon Ross  * Check the attribute cache to see if the new attributes match
20602d09e03SGordon Ross  * those cached.  If they do, the various `data' caches are
20702d09e03SGordon Ross  * considered to be good.  Otherwise, purge the cached data.
20802d09e03SGordon Ross  */
2095f4fc069Sjilinxpd static void
smbfs_cache_check(struct vnode * vp,struct smbfattr * fap,cred_t * cr)21002d09e03SGordon Ross smbfs_cache_check(
21102d09e03SGordon Ross 	struct vnode *vp,
2125f4fc069Sjilinxpd 	struct smbfattr *fap,
2135f4fc069Sjilinxpd 	cred_t *cr)
21402d09e03SGordon Ross {
21502d09e03SGordon Ross 	smbnode_t *np;
21602d09e03SGordon Ross 	int purge_data = 0;
21702d09e03SGordon Ross 	int purge_acl = 0;
21802d09e03SGordon Ross 
21902d09e03SGordon Ross 	np = VTOSMB(vp);
22002d09e03SGordon Ross 	mutex_enter(&np->r_statelock);
22102d09e03SGordon Ross 
22202d09e03SGordon Ross 	/*
22302d09e03SGordon Ross 	 * Compare with NFS macro: CACHE_VALID
22402d09e03SGordon Ross 	 * If the mtime or size has changed,
22502d09e03SGordon Ross 	 * purge cached data.
22602d09e03SGordon Ross 	 */
22702d09e03SGordon Ross 	if (np->r_attr.fa_mtime.tv_sec != fap->fa_mtime.tv_sec ||
22802d09e03SGordon Ross 	    np->r_attr.fa_mtime.tv_nsec != fap->fa_mtime.tv_nsec)
22902d09e03SGordon Ross 		purge_data = 1;
23002d09e03SGordon Ross 	if (np->r_attr.fa_size != fap->fa_size)
23102d09e03SGordon Ross 		purge_data = 1;
23202d09e03SGordon Ross 
23302d09e03SGordon Ross 	if (np->r_attr.fa_ctime.tv_sec != fap->fa_ctime.tv_sec ||
23402d09e03SGordon Ross 	    np->r_attr.fa_ctime.tv_nsec != fap->fa_ctime.tv_nsec)
23502d09e03SGordon Ross 		purge_acl = 1;
236bd7c6f51SGordon Ross 
237bd7c6f51SGordon Ross 	if (purge_acl) {
238bd7c6f51SGordon Ross 		np->r_sectime = gethrtime();
239bd7c6f51SGordon Ross 	}
24002d09e03SGordon Ross 
24102d09e03SGordon Ross 	mutex_exit(&np->r_statelock);
24202d09e03SGordon Ross 
24302d09e03SGordon Ross 	if (purge_data)
2445f4fc069Sjilinxpd 		smbfs_purge_caches(vp, cr);
24502d09e03SGordon Ross }
24602d09e03SGordon Ross 
24702d09e03SGordon Ross /*
24802d09e03SGordon Ross  * Set attributes cache for given vnode using SMB fattr
24902d09e03SGordon Ross  * and update the attribute cache timeout.
25002d09e03SGordon Ross  *
2515f4fc069Sjilinxpd  * Based on NFS: nfs_attrcache, nfs_attrcache_va
25202d09e03SGordon Ross  */
25302d09e03SGordon Ross void
smbfs_attrcache_fa(vnode_t * vp,struct smbfattr * fap)25402d09e03SGordon Ross smbfs_attrcache_fa(vnode_t *vp, struct smbfattr *fap)
25502d09e03SGordon Ross {
25602d09e03SGordon Ross 	smbnode_t *np;
25702d09e03SGordon Ross 	smbmntinfo_t *smi;
25802d09e03SGordon Ross 	hrtime_t delta, now;
25902d09e03SGordon Ross 	u_offset_t newsize;
26002d09e03SGordon Ross 	vtype_t	 vtype, oldvt;
26102d09e03SGordon Ross 	mode_t mode;
26202d09e03SGordon Ross 
26302d09e03SGordon Ross 	np = VTOSMB(vp);
26402d09e03SGordon Ross 	smi = VTOSMI(vp);
26502d09e03SGordon Ross 
26602d09e03SGordon Ross 	/*
26702d09e03SGordon Ross 	 * We allow v_type to change, so set that here
26842d15982SGordon Ross 	 * (and the mode, which depends on the type).
26902d09e03SGordon Ross 	 */
27002d09e03SGordon Ross 	if (fap->fa_attr & SMB_FA_DIR) {
27102d09e03SGordon Ross 		vtype = VDIR;
27242d15982SGordon Ross 		mode = smi->smi_dmode;
27302d09e03SGordon Ross 	} else {
27402d09e03SGordon Ross 		vtype = VREG;
27542d15982SGordon Ross 		mode = smi->smi_fmode;
27602d09e03SGordon Ross 	}
27702d09e03SGordon Ross 
27802d09e03SGordon Ross 	mutex_enter(&np->r_statelock);
27902d09e03SGordon Ross 	now = gethrtime();
28002d09e03SGordon Ross 
28102d09e03SGordon Ross 	/*
28202d09e03SGordon Ross 	 * Delta is the number of nanoseconds that we will
28302d09e03SGordon Ross 	 * cache the attributes of the file.  It is based on
28402d09e03SGordon Ross 	 * the number of nanoseconds since the last time that
28502d09e03SGordon Ross 	 * we detected a change.  The assumption is that files
28602d09e03SGordon Ross 	 * that changed recently are likely to change again.
28702d09e03SGordon Ross 	 * There is a minimum and a maximum for regular files
28802d09e03SGordon Ross 	 * and for directories which is enforced though.
28902d09e03SGordon Ross 	 *
29002d09e03SGordon Ross 	 * Using the time since last change was detected
29102d09e03SGordon Ross 	 * eliminates direct comparison or calculation
29202d09e03SGordon Ross 	 * using mixed client and server times.  SMBFS
29302d09e03SGordon Ross 	 * does not make any assumptions regarding the
29402d09e03SGordon Ross 	 * client and server clocks being synchronized.
29502d09e03SGordon Ross 	 */
29602d09e03SGordon Ross 	if (fap->fa_mtime.tv_sec  != np->r_attr.fa_mtime.tv_sec ||
29702d09e03SGordon Ross 	    fap->fa_mtime.tv_nsec != np->r_attr.fa_mtime.tv_nsec ||
29802d09e03SGordon Ross 	    fap->fa_size	  != np->r_attr.fa_size)
29902d09e03SGordon Ross 		np->r_mtime = now;
30002d09e03SGordon Ross 
30102d09e03SGordon Ross 	if ((smi->smi_flags & SMI_NOAC) || (vp->v_flag & VNOCACHE))
30202d09e03SGordon Ross 		delta = 0;
30302d09e03SGordon Ross 	else {
30402d09e03SGordon Ross 		delta = now - np->r_mtime;
30502d09e03SGordon Ross 		if (vtype == VDIR) {
30602d09e03SGordon Ross 			if (delta < smi->smi_acdirmin)
30702d09e03SGordon Ross 				delta = smi->smi_acdirmin;
30802d09e03SGordon Ross 			else if (delta > smi->smi_acdirmax)
30902d09e03SGordon Ross 				delta = smi->smi_acdirmax;
31002d09e03SGordon Ross 		} else {
31102d09e03SGordon Ross 			if (delta < smi->smi_acregmin)
31202d09e03SGordon Ross 				delta = smi->smi_acregmin;
31302d09e03SGordon Ross 			else if (delta > smi->smi_acregmax)
31402d09e03SGordon Ross 				delta = smi->smi_acregmax;
31502d09e03SGordon Ross 		}
31602d09e03SGordon Ross 	}
31702d09e03SGordon Ross 
31802d09e03SGordon Ross 	np->r_attrtime = now + delta;
31902d09e03SGordon Ross 	np->r_attr = *fap;
32002d09e03SGordon Ross 	np->n_mode = mode;
32102d09e03SGordon Ross 	oldvt = vp->v_type;
32202d09e03SGordon Ross 	vp->v_type = vtype;
32302d09e03SGordon Ross 
32402d09e03SGordon Ross 	/*
32502d09e03SGordon Ross 	 * Shall we update r_size? (local notion of size)
32602d09e03SGordon Ross 	 *
32702d09e03SGordon Ross 	 * The real criteria for updating r_size should be:
32802d09e03SGordon Ross 	 * if the file has grown on the server, or if
32902d09e03SGordon Ross 	 * the client has not modified the file.
33002d09e03SGordon Ross 	 *
33102d09e03SGordon Ross 	 * Also deal with the fact that SMB presents
33202d09e03SGordon Ross 	 * directories as having size=0.  Doing that
33302d09e03SGordon Ross 	 * here and leaving fa_size as returned OtW
33402d09e03SGordon Ross 	 * avoids fixing the size lots of places.
33502d09e03SGordon Ross 	 */
33602d09e03SGordon Ross 	newsize = fap->fa_size;
33702d09e03SGordon Ross 	if (vtype == VDIR && newsize < DEV_BSIZE)
33802d09e03SGordon Ross 		newsize = DEV_BSIZE;
33902d09e03SGordon Ross 
3405f4fc069Sjilinxpd 	if (np->r_size != newsize &&
3415f4fc069Sjilinxpd 	    (!vn_has_cached_data(vp) ||
3425f4fc069Sjilinxpd 	    (!(np->r_flags & RDIRTY) && np->r_count == 0))) {
34302d09e03SGordon Ross 		/* OK to set the size. */
34402d09e03SGordon Ross 		np->r_size = newsize;
34502d09e03SGordon Ross 	}
34602d09e03SGordon Ross 
3475f4fc069Sjilinxpd 	/*
3485f4fc069Sjilinxpd 	 * Here NFS has:
3495f4fc069Sjilinxpd 	 * nfs_setswaplike(vp, va);
3505f4fc069Sjilinxpd 	 * np->r_flags &= ~RWRITEATTR;
3515f4fc069Sjilinxpd 	 * (not needed here)
3525f4fc069Sjilinxpd 	 */
35302d09e03SGordon Ross 
3545f4fc069Sjilinxpd 	np->n_flag &= ~NATTRCHANGED;
35502d09e03SGordon Ross 	mutex_exit(&np->r_statelock);
35602d09e03SGordon Ross 
35702d09e03SGordon Ross 	if (oldvt != vtype) {
35802d09e03SGordon Ross 		SMBVDEBUG("vtype change %d to %d\n", oldvt, vtype);
35902d09e03SGordon Ross 	}
36002d09e03SGordon Ross }
36102d09e03SGordon Ross 
36202d09e03SGordon Ross /*
36302d09e03SGordon Ross  * Fill in attribute from the cache.
36402d09e03SGordon Ross  *
36502d09e03SGordon Ross  * If valid, copy to *fap and return zero,
36602d09e03SGordon Ross  * otherwise return an error.
36702d09e03SGordon Ross  *
36802d09e03SGordon Ross  * From NFS: nfs_getattr_cache()
36902d09e03SGordon Ross  */
37002d09e03SGordon Ross int
smbfs_getattr_cache(vnode_t * vp,struct smbfattr * fap)37102d09e03SGordon Ross smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap)
37202d09e03SGordon Ross {
37302d09e03SGordon Ross 	smbnode_t *np;
37402d09e03SGordon Ross 	int error;
37502d09e03SGordon Ross 
37602d09e03SGordon Ross 	np = VTOSMB(vp);
37702d09e03SGordon Ross 
37802d09e03SGordon Ross 	mutex_enter(&np->r_statelock);
37902d09e03SGordon Ross 	if (gethrtime() >= np->r_attrtime) {
38002d09e03SGordon Ross 		/* cache expired */
38102d09e03SGordon Ross 		error = ENOENT;
38202d09e03SGordon Ross 	} else {
38302d09e03SGordon Ross 		/* cache is valid */
38402d09e03SGordon Ross 		*fap = np->r_attr;
38502d09e03SGordon Ross 		error = 0;
38602d09e03SGordon Ross 	}
38702d09e03SGordon Ross 	mutex_exit(&np->r_statelock);
38802d09e03SGordon Ross 
38902d09e03SGordon Ross 	return (error);
39002d09e03SGordon Ross }
39102d09e03SGordon Ross 
39202d09e03SGordon Ross /*
39302d09e03SGordon Ross  * Get attributes over-the-wire and update attributes cache
39402d09e03SGordon Ross  * if no error occurred in the over-the-wire operation.
39502d09e03SGordon Ross  * Return 0 if successful, otherwise error.
39602d09e03SGordon Ross  * From NFS: nfs_getattr_otw
39702d09e03SGordon Ross  */
3985f4fc069Sjilinxpd static int
smbfs_getattr_otw(vnode_t * vp,struct smbfattr * fap,cred_t * cr)39902d09e03SGordon Ross smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
40002d09e03SGordon Ross {
40102d09e03SGordon Ross 	struct smb_cred scred;
402*adee6784SGordon Ross 	smbnode_t	*np = VTOSMB(vp);
403*adee6784SGordon Ross 	smb_share_t	*ssp = np->n_mount->smi_share;
404*adee6784SGordon Ross 	smb_fh_t	*fhp = NULL;
40502d09e03SGordon Ross 	int error;
40602d09e03SGordon Ross 
407*adee6784SGordon Ross 	bzero(fap, sizeof (*fap));
408*adee6784SGordon Ross 
409*adee6784SGordon Ross 	/*
410*adee6784SGordon Ross 	 * Special case the XATTR directory here (all fake).
411*adee6784SGordon Ross 	 * OK to leave a,c,m times zero (expected).
412*adee6784SGordon Ross 	 */
413*adee6784SGordon Ross 	if (vp->v_flag & V_XATTRDIR) {
414*adee6784SGordon Ross 		fap->fa_attr = SMB_FA_DIR;
415*adee6784SGordon Ross 		fap->fa_size = DEV_BSIZE;
416*adee6784SGordon Ross 		return (0);
417*adee6784SGordon Ross 	}
41802d09e03SGordon Ross 
41902d09e03SGordon Ross 	/*
4205f4fc069Sjilinxpd 	 * Here NFS uses the ACL RPC (if smi_flags & SMI_ACL)
421bd7c6f51SGordon Ross 	 * With SMB, getting the ACL is a significantly more
422bd7c6f51SGordon Ross 	 * expensive operation, so we do that only when asked
423bd7c6f51SGordon Ross 	 * for the uid/gid.  See smbfsgetattr().
42402d09e03SGordon Ross 	 */
42502d09e03SGordon Ross 
42602d09e03SGordon Ross 	/* Shared lock for (possible) n_fid use. */
42702d09e03SGordon Ross 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
42802d09e03SGordon Ross 		return (EINTR);
42902d09e03SGordon Ross 	smb_credinit(&scred, cr);
43002d09e03SGordon Ross 
431*adee6784SGordon Ross // Does the attr. open code path work for streams?
432*adee6784SGordon Ross // Trying that, and if it doesn't work enable this.
433*adee6784SGordon Ross #if 0	// XXX
434*adee6784SGordon Ross 	/*
435*adee6784SGordon Ross 	 * Extended attribute files
436*adee6784SGordon Ross 	 */
437*adee6784SGordon Ross 	if (np->n_flag & N_XATTR) {
438*adee6784SGordon Ross 		error = smbfs_xa_getfattr(np, fap, scrp);
439*adee6784SGordon Ross 		goto out;
440*adee6784SGordon Ross 	}
441*adee6784SGordon Ross #endif	// XXX
442*adee6784SGordon Ross 
443*adee6784SGordon Ross 	if (np->n_fidrefs > 0 &&
444*adee6784SGordon Ross 	    (fhp = np->n_fid) != NULL &&
445*adee6784SGordon Ross 	    (fhp->fh_vcgenid == ssp->ss_vcgenid)) {
446*adee6784SGordon Ross 		/* Use the FID we have. */
447*adee6784SGordon Ross 		error = smbfs_smb_getfattr(np, fhp, fap, &scred);
448*adee6784SGordon Ross 
449*adee6784SGordon Ross 	} else {
450*adee6784SGordon Ross 		/* This will do an attr open */
451*adee6784SGordon Ross 		error = smbfs_smb_getpattr(np, fap, &scred);
452*adee6784SGordon Ross 	}
45302d09e03SGordon Ross 
45402d09e03SGordon Ross 	smb_credrele(&scred);
45502d09e03SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
45602d09e03SGordon Ross 
45702d09e03SGordon Ross 	if (error) {
4585f4fc069Sjilinxpd 		/* Here NFS has: PURGE_STALE_FH(error, vp, cr) */
45902d09e03SGordon Ross 		smbfs_attrcache_remove(np);
46002d09e03SGordon Ross 		if (error == ENOENT || error == ENOTDIR) {
46102d09e03SGordon Ross 			/*
46202d09e03SGordon Ross 			 * Getattr failed because the object was
46302d09e03SGordon Ross 			 * removed or renamed by another client.
46402d09e03SGordon Ross 			 * Remove any cached attributes under it.
46502d09e03SGordon Ross 			 */
46602d09e03SGordon Ross 			smbfs_attrcache_prune(np);
46702d09e03SGordon Ross 		}
46802d09e03SGordon Ross 		return (error);
46902d09e03SGordon Ross 	}
47002d09e03SGordon Ross 
47102d09e03SGordon Ross 	/*
4725f4fc069Sjilinxpd 	 * Here NFS has: nfs_cache_fattr(vap, fa, vap, t, cr);
47302d09e03SGordon Ross 	 * which did: fattr_to_vattr, nfs_attr_cache.
47402d09e03SGordon Ross 	 * We cache the fattr form, so just do the
47502d09e03SGordon Ross 	 * cache check and store the attributes.
47602d09e03SGordon Ross 	 */
4775f4fc069Sjilinxpd 	smbfs_cache_check(vp, fap, cr);
47802d09e03SGordon Ross 	smbfs_attrcache_fa(vp, fap);
47902d09e03SGordon Ross 
48002d09e03SGordon Ross 	return (0);
48102d09e03SGordon Ross }
48202d09e03SGordon Ross 
48302d09e03SGordon Ross /*
4845f4fc069Sjilinxpd  * Return either cached or remote attributes. If we get remote attrs,
48502d09e03SGordon Ross  * use them to check and invalidate caches, then cache the new attributes.
48602d09e03SGordon Ross  *
48702d09e03SGordon Ross  * From NFS: nfsgetattr()
48802d09e03SGordon Ross  */
48902d09e03SGordon Ross int
smbfsgetattr(vnode_t * vp,struct vattr * vap,cred_t * cr)49002d09e03SGordon Ross smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
49102d09e03SGordon Ross {
49202d09e03SGordon Ross 	struct smbfattr fa;
493bd7c6f51SGordon Ross 	smbmntinfo_t *smi;
494bd7c6f51SGordon Ross 	uint_t mask;
49502d09e03SGordon Ross 	int error;
49602d09e03SGordon Ross 
497bd7c6f51SGordon Ross 	smi = VTOSMI(vp);
498bd7c6f51SGordon Ross 
499a19609f8Sjv 	ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
500bd7c6f51SGordon Ross 
501bd7c6f51SGordon Ross 	/*
502bd7c6f51SGordon Ross 	 * If asked for UID or GID, update n_uid, n_gid.
503bd7c6f51SGordon Ross 	 */
504bd7c6f51SGordon Ross 	mask = AT_ALL;
505bd7c6f51SGordon Ross 	if (vap->va_mask & (AT_UID | AT_GID)) {
506bd7c6f51SGordon Ross 		if (smi->smi_flags & SMI_ACL)
507bd7c6f51SGordon Ross 			(void) smbfs_acl_getids(vp, cr);
508bd7c6f51SGordon Ross 		/* else leave as set in make_smbnode */
509bd7c6f51SGordon Ross 	} else {
510bd7c6f51SGordon Ross 		mask &= ~(AT_UID | AT_GID);
511bd7c6f51SGordon Ross 	}
51202d09e03SGordon Ross 
51302d09e03SGordon Ross 	/*
51402d09e03SGordon Ross 	 * If we've got cached attributes, just use them;
51502d09e03SGordon Ross 	 * otherwise go to the server to get attributes,
51602d09e03SGordon Ross 	 * which will update the cache in the process.
51702d09e03SGordon Ross 	 */
51802d09e03SGordon Ross 	error = smbfs_getattr_cache(vp, &fa);
51902d09e03SGordon Ross 	if (error)
52002d09e03SGordon Ross 		error = smbfs_getattr_otw(vp, &fa, cr);
52102d09e03SGordon Ross 	if (error)
52202d09e03SGordon Ross 		return (error);
52328162916SGordon Ross 	vap->va_mask |= mask;
52402d09e03SGordon Ross 
52502d09e03SGordon Ross 	/*
52602d09e03SGordon Ross 	 * Re. client's view of the file size, see:
52702d09e03SGordon Ross 	 * smbfs_attrcache_fa, smbfs_getattr_otw
52802d09e03SGordon Ross 	 */
52928162916SGordon Ross 	smbfattr_to_vattr(vp, &fa, vap);
53028162916SGordon Ross 	if (vap->va_mask & AT_XVATTR)
53128162916SGordon Ross 		smbfattr_to_xvattr(&fa, vap);
53202d09e03SGordon Ross 
53328162916SGordon Ross 	return (0);
53402d09e03SGordon Ross }
53502d09e03SGordon Ross 
53602d09e03SGordon Ross 
53702d09e03SGordon Ross /*
53802d09e03SGordon Ross  * Convert SMB over the wire attributes to vnode form.
53902d09e03SGordon Ross  * Returns 0 for success, error if failed (overflow, etc).
54002d09e03SGordon Ross  * From NFS: nattr_to_vattr()
54102d09e03SGordon Ross  */
54228162916SGordon Ross void
smbfattr_to_vattr(vnode_t * vp,struct smbfattr * fa,struct vattr * vap)54302d09e03SGordon Ross smbfattr_to_vattr(vnode_t *vp, struct smbfattr *fa, struct vattr *vap)
54402d09e03SGordon Ross {
54502d09e03SGordon Ross 	struct smbnode *np = VTOSMB(vp);
54602d09e03SGordon Ross 
54702d09e03SGordon Ross 	/*
54802d09e03SGordon Ross 	 * Take type, mode, uid, gid from the smbfs node,
54902d09e03SGordon Ross 	 * which has have been updated by _getattr_otw.
55002d09e03SGordon Ross 	 */
55102d09e03SGordon Ross 	vap->va_type = vp->v_type;
55202d09e03SGordon Ross 	vap->va_mode = np->n_mode;
55302d09e03SGordon Ross 
55402d09e03SGordon Ross 	vap->va_uid = np->n_uid;
55502d09e03SGordon Ross 	vap->va_gid = np->n_gid;
55602d09e03SGordon Ross 
55702d09e03SGordon Ross 	vap->va_fsid = vp->v_vfsp->vfs_dev;
55802d09e03SGordon Ross 	vap->va_nodeid = np->n_ino;
55902d09e03SGordon Ross 	vap->va_nlink = 1;
56002d09e03SGordon Ross 
56102d09e03SGordon Ross 	/*
56202d09e03SGordon Ross 	 * Difference from NFS here:  We cache attributes as
56302d09e03SGordon Ross 	 * reported by the server, so r_attr.fa_size is the
56402d09e03SGordon Ross 	 * server's idea of the file size.  This is called
56502d09e03SGordon Ross 	 * for getattr, so we want to return the client's
56602d09e03SGordon Ross 	 * idea of the file size.  NFS deals with that in
56702d09e03SGordon Ross 	 * nfsgetattr(), the equivalent of our caller.
56802d09e03SGordon Ross 	 */
56902d09e03SGordon Ross 	vap->va_size = np->r_size;
57002d09e03SGordon Ross 
57102d09e03SGordon Ross 	/*
57202d09e03SGordon Ross 	 * Times.  Note, already converted from NT to
57302d09e03SGordon Ross 	 * Unix form (in the unmarshalling code).
57402d09e03SGordon Ross 	 */
57502d09e03SGordon Ross 	vap->va_atime = fa->fa_atime;
57602d09e03SGordon Ross 	vap->va_mtime = fa->fa_mtime;
57702d09e03SGordon Ross 	vap->va_ctime = fa->fa_ctime;
57802d09e03SGordon Ross 
57902d09e03SGordon Ross 	/*
58002d09e03SGordon Ross 	 * rdev, blksize, seq are made up.
58102d09e03SGordon Ross 	 * va_nblocks is 512 byte blocks.
58202d09e03SGordon Ross 	 */
58302d09e03SGordon Ross 	vap->va_rdev = vp->v_rdev;
58402d09e03SGordon Ross 	vap->va_blksize = MAXBSIZE;
58502d09e03SGordon Ross 	vap->va_nblocks = (fsblkcnt64_t)btod(np->r_attr.fa_allocsz);
58602d09e03SGordon Ross 	vap->va_seq = 0;
58702d09e03SGordon Ross }
58802d09e03SGordon Ross 
58928162916SGordon Ross /*
59028162916SGordon Ross  * smbfattr_to_xvattr: like smbfattr_to_vattr but for
59128162916SGordon Ross  * Extensible system attributes (PSARC 2007/315)
59228162916SGordon Ross  */
59328162916SGordon Ross static void
smbfattr_to_xvattr(struct smbfattr * fa,struct vattr * vap)59428162916SGordon Ross smbfattr_to_xvattr(struct smbfattr *fa, struct vattr *vap)
59528162916SGordon Ross {
59628162916SGordon Ross 	xvattr_t *xvap = (xvattr_t *)vap;	/* *vap may be xvattr_t */
59728162916SGordon Ross 	xoptattr_t *xoap = NULL;
59828162916SGordon Ross 
59928162916SGordon Ross 	if ((xoap = xva_getxoptattr(xvap)) == NULL)
60028162916SGordon Ross 		return;
60128162916SGordon Ross 
60228162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
60328162916SGordon Ross 		xoap->xoa_createtime = fa->fa_createtime;
60428162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_CREATETIME);
60528162916SGordon Ross 	}
60628162916SGordon Ross 
60728162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
60828162916SGordon Ross 		xoap->xoa_archive =
60928162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_ARCHIVE) != 0);
61028162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_ARCHIVE);
61128162916SGordon Ross 	}
61228162916SGordon Ross 
61328162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
61428162916SGordon Ross 		xoap->xoa_system =
61528162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_SYSTEM) != 0);
61628162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_SYSTEM);
61728162916SGordon Ross 	}
61828162916SGordon Ross 
61928162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
62028162916SGordon Ross 		xoap->xoa_readonly =
62128162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_RDONLY) != 0);
62228162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_READONLY);
62328162916SGordon Ross 	}
62428162916SGordon Ross 
62528162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
62628162916SGordon Ross 		xoap->xoa_hidden =
62728162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_HIDDEN) != 0);
62828162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_HIDDEN);
62928162916SGordon Ross 	}
63028162916SGordon Ross }
63102d09e03SGordon Ross 
6325f4fc069Sjilinxpd /*
6335f4fc069Sjilinxpd  * Here NFS has:
6345f4fc069Sjilinxpd  *	nfs_async_... stuff
6355f4fc069Sjilinxpd  * which we're not using (no async I/O), and:
6365f4fc069Sjilinxpd  *	writerp(),
6375f4fc069Sjilinxpd  *	nfs_putpages()
6385f4fc069Sjilinxpd  *	nfs_invalidate_pages()
6395f4fc069Sjilinxpd  * which we have in smbfs_vnops.c, and
6405f4fc069Sjilinxpd  *	nfs_printfhandle()
6415f4fc069Sjilinxpd  *	nfs_write_error()
6425f4fc069Sjilinxpd  * not needed here.
6435f4fc069Sjilinxpd  */
6445f4fc069Sjilinxpd 
6455f4fc069Sjilinxpd /*
6465f4fc069Sjilinxpd  * Helper function for smbfs_sync
6475f4fc069Sjilinxpd  *
6485f4fc069Sjilinxpd  * Walk the per-zone list of smbfs mounts, calling smbfs_rflush
6495f4fc069Sjilinxpd  * on each one.  This is a little tricky because we need to exit
6505f4fc069Sjilinxpd  * the list mutex before each _rflush call and then try to resume
6515f4fc069Sjilinxpd  * where we were in the list after re-entering the mutex.
6525f4fc069Sjilinxpd  */
6535f4fc069Sjilinxpd void
smbfs_flushall(cred_t * cr)6545f4fc069Sjilinxpd smbfs_flushall(cred_t *cr)
6555f4fc069Sjilinxpd {
6565f4fc069Sjilinxpd 	smi_globals_t *smg;
6575f4fc069Sjilinxpd 	smbmntinfo_t *tmp_smi, *cur_smi, *next_smi;
6585f4fc069Sjilinxpd 
6595f4fc069Sjilinxpd 	smg = zone_getspecific(smi_list_key, crgetzone(cr));
6605f4fc069Sjilinxpd 	ASSERT(smg != NULL);
6615f4fc069Sjilinxpd 
6625f4fc069Sjilinxpd 	mutex_enter(&smg->smg_lock);
6635f4fc069Sjilinxpd 	cur_smi = list_head(&smg->smg_list);
6645f4fc069Sjilinxpd 	if (cur_smi == NULL) {
6655f4fc069Sjilinxpd 		mutex_exit(&smg->smg_lock);
6665f4fc069Sjilinxpd 		return;
6675f4fc069Sjilinxpd 	}
6685f4fc069Sjilinxpd 	VFS_HOLD(cur_smi->smi_vfsp);
6695f4fc069Sjilinxpd 	mutex_exit(&smg->smg_lock);
6705f4fc069Sjilinxpd 
6715f4fc069Sjilinxpd flush:
6725f4fc069Sjilinxpd 	smbfs_rflush(cur_smi->smi_vfsp, cr);
6735f4fc069Sjilinxpd 
6745f4fc069Sjilinxpd 	mutex_enter(&smg->smg_lock);
6755f4fc069Sjilinxpd 	/*
6765f4fc069Sjilinxpd 	 * Resume after cur_smi if that's still on the list,
6775f4fc069Sjilinxpd 	 * otherwise restart at the head.
6785f4fc069Sjilinxpd 	 */
6795f4fc069Sjilinxpd 	for (tmp_smi = list_head(&smg->smg_list);
6805f4fc069Sjilinxpd 	    tmp_smi != NULL;
6815f4fc069Sjilinxpd 	    tmp_smi = list_next(&smg->smg_list, tmp_smi))
6825f4fc069Sjilinxpd 		if (tmp_smi == cur_smi)
6835f4fc069Sjilinxpd 			break;
6845f4fc069Sjilinxpd 	if (tmp_smi != NULL)
6855f4fc069Sjilinxpd 		next_smi = list_next(&smg->smg_list, tmp_smi);
6865f4fc069Sjilinxpd 	else
6875f4fc069Sjilinxpd 		next_smi = list_head(&smg->smg_list);
6885f4fc069Sjilinxpd 
6895f4fc069Sjilinxpd 	if (next_smi != NULL)
6905f4fc069Sjilinxpd 		VFS_HOLD(next_smi->smi_vfsp);
6915f4fc069Sjilinxpd 	VFS_RELE(cur_smi->smi_vfsp);
6925f4fc069Sjilinxpd 
6935f4fc069Sjilinxpd 	mutex_exit(&smg->smg_lock);
6945f4fc069Sjilinxpd 
6955f4fc069Sjilinxpd 	if (next_smi != NULL) {
6965f4fc069Sjilinxpd 		cur_smi = next_smi;
6975f4fc069Sjilinxpd 		goto flush;
6985f4fc069Sjilinxpd 	}
6995f4fc069Sjilinxpd }
7005f4fc069Sjilinxpd 
70102d09e03SGordon Ross /*
70202d09e03SGordon Ross  * SMB Client initialization and cleanup.
70302d09e03SGordon Ross  * Much of it is per-zone now.
70402d09e03SGordon Ross  */
70502d09e03SGordon Ross 
70602d09e03SGordon Ross 
7074bff34e3Sthurlow /* ARGSUSED */
7084bff34e3Sthurlow static void *
smbfs_zone_init(zoneid_t zoneid)7094bff34e3Sthurlow smbfs_zone_init(zoneid_t zoneid)
7104bff34e3Sthurlow {
7114bff34e3Sthurlow 	smi_globals_t *smg;
7124bff34e3Sthurlow 
7134bff34e3Sthurlow 	smg = kmem_alloc(sizeof (*smg), KM_SLEEP);
7144bff34e3Sthurlow 	mutex_init(&smg->smg_lock, NULL, MUTEX_DEFAULT, NULL);
7154bff34e3Sthurlow 	list_create(&smg->smg_list, sizeof (smbmntinfo_t),
7164bff34e3Sthurlow 	    offsetof(smbmntinfo_t, smi_zone_node));
7174bff34e3Sthurlow 	smg->smg_destructor_called = B_FALSE;
7184bff34e3Sthurlow 	return (smg);
7194bff34e3Sthurlow }
7204bff34e3Sthurlow 
7214bff34e3Sthurlow /*
7224bff34e3Sthurlow  * Callback routine to tell all SMBFS mounts in the zone to stop creating new
7234bff34e3Sthurlow  * threads.  Existing threads should exit.
7244bff34e3Sthurlow  */
7254bff34e3Sthurlow /* ARGSUSED */
7264bff34e3Sthurlow static void
smbfs_zone_shutdown(zoneid_t zoneid,void * data)7274bff34e3Sthurlow smbfs_zone_shutdown(zoneid_t zoneid, void *data)
7284bff34e3Sthurlow {
7294bff34e3Sthurlow 	smi_globals_t *smg = data;
7304bff34e3Sthurlow 	smbmntinfo_t *smi;
7314bff34e3Sthurlow 
7324bff34e3Sthurlow 	ASSERT(smg != NULL);
7334bff34e3Sthurlow again:
7344bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7354bff34e3Sthurlow 	for (smi = list_head(&smg->smg_list); smi != NULL;
7364bff34e3Sthurlow 	    smi = list_next(&smg->smg_list, smi)) {
7374bff34e3Sthurlow 
7384bff34e3Sthurlow 		/*
7394bff34e3Sthurlow 		 * If we've done the shutdown work for this FS, skip.
7404bff34e3Sthurlow 		 * Once we go off the end of the list, we're done.
7414bff34e3Sthurlow 		 */
7424bff34e3Sthurlow 		if (smi->smi_flags & SMI_DEAD)
7434bff34e3Sthurlow 			continue;
7444bff34e3Sthurlow 
7454bff34e3Sthurlow 		/*
7464bff34e3Sthurlow 		 * We will do work, so not done.  Get a hold on the FS.
7474bff34e3Sthurlow 		 */
7484bff34e3Sthurlow 		VFS_HOLD(smi->smi_vfsp);
7494bff34e3Sthurlow 
7504bff34e3Sthurlow 		mutex_enter(&smi->smi_lock);
7514bff34e3Sthurlow 		smi->smi_flags |= SMI_DEAD;
7524bff34e3Sthurlow 		mutex_exit(&smi->smi_lock);
7534bff34e3Sthurlow 
7544bff34e3Sthurlow 		/*
7554bff34e3Sthurlow 		 * Drop lock and release FS, which may change list, then repeat.
7564bff34e3Sthurlow 		 * We're done when every mi has been done or the list is empty.
7574bff34e3Sthurlow 		 */
7584bff34e3Sthurlow 		mutex_exit(&smg->smg_lock);
7594bff34e3Sthurlow 		VFS_RELE(smi->smi_vfsp);
7604bff34e3Sthurlow 		goto again;
7614bff34e3Sthurlow 	}
7624bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
7634bff34e3Sthurlow }
7644bff34e3Sthurlow 
7654bff34e3Sthurlow static void
smbfs_zone_free_globals(smi_globals_t * smg)7664bff34e3Sthurlow smbfs_zone_free_globals(smi_globals_t *smg)
7674bff34e3Sthurlow {
7684bff34e3Sthurlow 	list_destroy(&smg->smg_list);	/* makes sure the list is empty */
7694bff34e3Sthurlow 	mutex_destroy(&smg->smg_lock);
7704bff34e3Sthurlow 	kmem_free(smg, sizeof (*smg));
7714bff34e3Sthurlow 
7724bff34e3Sthurlow }
7734bff34e3Sthurlow 
7744bff34e3Sthurlow /* ARGSUSED */
7754bff34e3Sthurlow static void
smbfs_zone_destroy(zoneid_t zoneid,void * data)7764bff34e3Sthurlow smbfs_zone_destroy(zoneid_t zoneid, void *data)
7774bff34e3Sthurlow {
7784bff34e3Sthurlow 	smi_globals_t *smg = data;
7794bff34e3Sthurlow 
7804bff34e3Sthurlow 	ASSERT(smg != NULL);
7814bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7824bff34e3Sthurlow 	if (list_head(&smg->smg_list) != NULL) {
7834bff34e3Sthurlow 		/* Still waiting for VFS_FREEVFS() */
7844bff34e3Sthurlow 		smg->smg_destructor_called = B_TRUE;
7854bff34e3Sthurlow 		mutex_exit(&smg->smg_lock);
7864bff34e3Sthurlow 		return;
7874bff34e3Sthurlow 	}
7884bff34e3Sthurlow 	smbfs_zone_free_globals(smg);
7894bff34e3Sthurlow }
7904bff34e3Sthurlow 
7914bff34e3Sthurlow /*
7924bff34e3Sthurlow  * Add an SMBFS mount to the per-zone list of SMBFS mounts.
7934bff34e3Sthurlow  */
7944bff34e3Sthurlow void
smbfs_zonelist_add(smbmntinfo_t * smi)7954bff34e3Sthurlow smbfs_zonelist_add(smbmntinfo_t *smi)
7964bff34e3Sthurlow {
7974bff34e3Sthurlow 	smi_globals_t *smg;
7984bff34e3Sthurlow 
799a19609f8Sjv 	smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone);
8004bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
8014bff34e3Sthurlow 	list_insert_head(&smg->smg_list, smi);
8024bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
8034bff34e3Sthurlow }
8044bff34e3Sthurlow 
8054bff34e3Sthurlow /*
8064bff34e3Sthurlow  * Remove an SMBFS mount from the per-zone list of SMBFS mounts.
8074bff34e3Sthurlow  */
8084bff34e3Sthurlow void
smbfs_zonelist_remove(smbmntinfo_t * smi)8094bff34e3Sthurlow smbfs_zonelist_remove(smbmntinfo_t *smi)
8104bff34e3Sthurlow {
8114bff34e3Sthurlow 	smi_globals_t *smg;
8124bff34e3Sthurlow 
813a19609f8Sjv 	smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone);
8144bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
8154bff34e3Sthurlow 	list_remove(&smg->smg_list, smi);
8164bff34e3Sthurlow 	/*
8174bff34e3Sthurlow 	 * We can be called asynchronously by VFS_FREEVFS() after the zone
8184bff34e3Sthurlow 	 * shutdown/destroy callbacks have executed; if so, clean up the zone's
8194bff34e3Sthurlow 	 * smi_globals.
8204bff34e3Sthurlow 	 */
8214bff34e3Sthurlow 	if (list_head(&smg->smg_list) == NULL &&
8224bff34e3Sthurlow 	    smg->smg_destructor_called == B_TRUE) {
8234bff34e3Sthurlow 		smbfs_zone_free_globals(smg);
8244bff34e3Sthurlow 		return;
8254bff34e3Sthurlow 	}
8264bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
8274bff34e3Sthurlow }
8284bff34e3Sthurlow 
829613a2f6bSGordon Ross #ifdef	lint
830613a2f6bSGordon Ross #define	NEED_SMBFS_CALLBACKS	1
831613a2f6bSGordon Ross #endif
8324bff34e3Sthurlow 
8334bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
8344bff34e3Sthurlow /*
8354bff34e3Sthurlow  * Call-back hooks for netsmb, in case we want them.
8364bff34e3Sthurlow  * Apple's VFS wants them.  We may not need them.
8374bff34e3Sthurlow  */
838613a2f6bSGordon Ross /*ARGSUSED*/
smbfs_dead(smb_share_t * ssp)8394bff34e3Sthurlow static void smbfs_dead(smb_share_t *ssp)
8404bff34e3Sthurlow {
841613a2f6bSGordon Ross 	/*
842613a2f6bSGordon Ross 	 * Walk the mount list, finding all mounts
843613a2f6bSGordon Ross 	 * using this share...
844613a2f6bSGordon Ross 	 */
8454bff34e3Sthurlow }
8464bff34e3Sthurlow 
847613a2f6bSGordon Ross /*ARGSUSED*/
smbfs_cb_nop(smb_share_t * ss)848613a2f6bSGordon Ross static void smbfs_cb_nop(smb_share_t *ss)
8494bff34e3Sthurlow {
8504bff34e3Sthurlow 	/* no-op */
8514bff34e3Sthurlow }
8524bff34e3Sthurlow 
8534bff34e3Sthurlow smb_fscb_t smbfs_cb = {
854613a2f6bSGordon Ross 	.fscb_disconn	= smbfs_dead,
855*adee6784SGordon Ross 	.fscb_connect	= smbfs_cb_nop
856*adee6784SGordon Ross };
8574bff34e3Sthurlow 
8584bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8594bff34e3Sthurlow 
8604bff34e3Sthurlow /*
8614bff34e3Sthurlow  * SMBFS Client initialization routine.  This routine should only be called
8624bff34e3Sthurlow  * once.  It performs the following tasks:
8634bff34e3Sthurlow  *      - Initalize all global locks
8644bff34e3Sthurlow  *      - Call sub-initialization routines (localize access to variables)
8654bff34e3Sthurlow  */
8664bff34e3Sthurlow int
smbfs_clntinit(void)8674bff34e3Sthurlow smbfs_clntinit(void)
8684bff34e3Sthurlow {
8694bff34e3Sthurlow 
8704bff34e3Sthurlow 	zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown,
8714bff34e3Sthurlow 	    smbfs_zone_destroy);
8724bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
873c1374a13SSurya Prakki 	(void) smb_fscb_set(&smbfs_cb);
8744bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8754bff34e3Sthurlow 	return (0);
8764bff34e3Sthurlow }
8774bff34e3Sthurlow 
8784bff34e3Sthurlow /*
8794bff34e3Sthurlow  * This routine is called when the modunload is called. This will cleanup
8804bff34e3Sthurlow  * the previously allocated/initialized nodes.
8814bff34e3Sthurlow  */
8824bff34e3Sthurlow void
smbfs_clntfini(void)8834bff34e3Sthurlow smbfs_clntfini(void)
8844bff34e3Sthurlow {
8854bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
886c1374a13SSurya Prakki 	(void) smb_fscb_set(NULL);
8874bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8884bff34e3Sthurlow 	(void) zone_key_delete(smi_list_key);
8894bff34e3Sthurlow }
890