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 /*
23a19609f8Sjv227347  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
244bff34e3Sthurlow  *
254bff34e3Sthurlow  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
264bff34e3Sthurlow  *	All rights reserved.
27*8329232eSGordon Ross  *
28*8329232eSGordon Ross  * Copyright 2017 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 
65*8329232eSGordon 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>
73*8329232eSGordon 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
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
14902d09e03SGordon Ross smbfs_validate_caches(
15002d09e03SGordon Ross 	struct vnode *vp,
15102d09e03SGordon Ross 	cred_t *cr)
15202d09e03SGordon Ross {
1535f4fc069Sjilinxpd 	struct smbfattr fa;
1545f4fc069Sjilinxpd 	int error;
15502d09e03SGordon Ross 
1565f4fc069Sjilinxpd 	if (ATTRCACHE_VALID(vp)) {
1575f4fc069Sjilinxpd 		error = smbfs_waitfor_purge_complete(vp);
1585f4fc069Sjilinxpd 		if (error)
1595f4fc069Sjilinxpd 			return (error);
1605f4fc069Sjilinxpd 		return (0);
1615f4fc069Sjilinxpd 	}
1625f4fc069Sjilinxpd 
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  */
17202d09e03SGordon Ross /* ARGSUSED */
17302d09e03SGordon Ross void
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 
19602d09e03SGordon Ross /*
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 
2045f4fc069Sjilinxpd /*
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
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
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
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
39902d09e03SGordon Ross smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
40002d09e03SGordon Ross {
40102d09e03SGordon Ross 	struct smbnode *np;
40202d09e03SGordon Ross 	struct smb_cred scred;
40302d09e03SGordon Ross 	int error;
40402d09e03SGordon Ross 
40502d09e03SGordon Ross 	np = VTOSMB(vp);
40602d09e03SGordon Ross 
40702d09e03SGordon Ross 	/*
4085f4fc069Sjilinxpd 	 * Here NFS uses the ACL RPC (if smi_flags & SMI_ACL)
409bd7c6f51SGordon Ross 	 * With SMB, getting the ACL is a significantly more
410bd7c6f51SGordon Ross 	 * expensive operation, so we do that only when asked
411bd7c6f51SGordon Ross 	 * for the uid/gid.  See smbfsgetattr().
41202d09e03SGordon Ross 	 */
41302d09e03SGordon Ross 
41402d09e03SGordon Ross 	/* Shared lock for (possible) n_fid use. */
41502d09e03SGordon Ross 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
41602d09e03SGordon Ross 		return (EINTR);
41702d09e03SGordon Ross 	smb_credinit(&scred, cr);
41802d09e03SGordon Ross 
41902d09e03SGordon Ross 	bzero(fap, sizeof (*fap));
42002d09e03SGordon Ross 	error = smbfs_smb_getfattr(np, fap, &scred);
42102d09e03SGordon Ross 
42202d09e03SGordon Ross 	smb_credrele(&scred);
42302d09e03SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
42402d09e03SGordon Ross 
42502d09e03SGordon Ross 	if (error) {
4265f4fc069Sjilinxpd 		/* Here NFS has: PURGE_STALE_FH(error, vp, cr) */
42702d09e03SGordon Ross 		smbfs_attrcache_remove(np);
42802d09e03SGordon Ross 		if (error == ENOENT || error == ENOTDIR) {
42902d09e03SGordon Ross 			/*
43002d09e03SGordon Ross 			 * Getattr failed because the object was
43102d09e03SGordon Ross 			 * removed or renamed by another client.
43202d09e03SGordon Ross 			 * Remove any cached attributes under it.
43302d09e03SGordon Ross 			 */
43402d09e03SGordon Ross 			smbfs_attrcache_prune(np);
43502d09e03SGordon Ross 		}
43602d09e03SGordon Ross 		return (error);
43702d09e03SGordon Ross 	}
43802d09e03SGordon Ross 
43902d09e03SGordon Ross 	/*
4405f4fc069Sjilinxpd 	 * Here NFS has: nfs_cache_fattr(vap, fa, vap, t, cr);
44102d09e03SGordon Ross 	 * which did: fattr_to_vattr, nfs_attr_cache.
44202d09e03SGordon Ross 	 * We cache the fattr form, so just do the
44302d09e03SGordon Ross 	 * cache check and store the attributes.
44402d09e03SGordon Ross 	 */
4455f4fc069Sjilinxpd 	smbfs_cache_check(vp, fap, cr);
44602d09e03SGordon Ross 	smbfs_attrcache_fa(vp, fap);
44702d09e03SGordon Ross 
44802d09e03SGordon Ross 	return (0);
44902d09e03SGordon Ross }
45002d09e03SGordon Ross 
45102d09e03SGordon Ross /*
4525f4fc069Sjilinxpd  * Return either cached or remote attributes. If we get remote attrs,
45302d09e03SGordon Ross  * use them to check and invalidate caches, then cache the new attributes.
45402d09e03SGordon Ross  *
45502d09e03SGordon Ross  * From NFS: nfsgetattr()
45602d09e03SGordon Ross  */
45702d09e03SGordon Ross int
45802d09e03SGordon Ross smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
45902d09e03SGordon Ross {
46002d09e03SGordon Ross 	struct smbfattr fa;
461bd7c6f51SGordon Ross 	smbmntinfo_t *smi;
462bd7c6f51SGordon Ross 	uint_t mask;
46302d09e03SGordon Ross 	int error;
46402d09e03SGordon Ross 
465bd7c6f51SGordon Ross 	smi = VTOSMI(vp);
466bd7c6f51SGordon Ross 
467a19609f8Sjv227347 	ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
468bd7c6f51SGordon Ross 
469bd7c6f51SGordon Ross 	/*
470bd7c6f51SGordon Ross 	 * If asked for UID or GID, update n_uid, n_gid.
471bd7c6f51SGordon Ross 	 */
472bd7c6f51SGordon Ross 	mask = AT_ALL;
473bd7c6f51SGordon Ross 	if (vap->va_mask & (AT_UID | AT_GID)) {
474bd7c6f51SGordon Ross 		if (smi->smi_flags & SMI_ACL)
475bd7c6f51SGordon Ross 			(void) smbfs_acl_getids(vp, cr);
476bd7c6f51SGordon Ross 		/* else leave as set in make_smbnode */
477bd7c6f51SGordon Ross 	} else {
478bd7c6f51SGordon Ross 		mask &= ~(AT_UID | AT_GID);
479bd7c6f51SGordon Ross 	}
48002d09e03SGordon Ross 
48102d09e03SGordon Ross 	/*
48202d09e03SGordon Ross 	 * If we've got cached attributes, just use them;
48302d09e03SGordon Ross 	 * otherwise go to the server to get attributes,
48402d09e03SGordon Ross 	 * which will update the cache in the process.
48502d09e03SGordon Ross 	 */
48602d09e03SGordon Ross 	error = smbfs_getattr_cache(vp, &fa);
48702d09e03SGordon Ross 	if (error)
48802d09e03SGordon Ross 		error = smbfs_getattr_otw(vp, &fa, cr);
48902d09e03SGordon Ross 	if (error)
49002d09e03SGordon Ross 		return (error);
49128162916SGordon Ross 	vap->va_mask |= mask;
49202d09e03SGordon Ross 
49302d09e03SGordon Ross 	/*
49402d09e03SGordon Ross 	 * Re. client's view of the file size, see:
49502d09e03SGordon Ross 	 * smbfs_attrcache_fa, smbfs_getattr_otw
49602d09e03SGordon Ross 	 */
49728162916SGordon Ross 	smbfattr_to_vattr(vp, &fa, vap);
49828162916SGordon Ross 	if (vap->va_mask & AT_XVATTR)
49928162916SGordon Ross 		smbfattr_to_xvattr(&fa, vap);
50002d09e03SGordon Ross 
50128162916SGordon Ross 	return (0);
50202d09e03SGordon Ross }
50302d09e03SGordon Ross 
50402d09e03SGordon Ross 
50502d09e03SGordon Ross /*
50602d09e03SGordon Ross  * Convert SMB over the wire attributes to vnode form.
50702d09e03SGordon Ross  * Returns 0 for success, error if failed (overflow, etc).
50802d09e03SGordon Ross  * From NFS: nattr_to_vattr()
50902d09e03SGordon Ross  */
51028162916SGordon Ross void
51102d09e03SGordon Ross smbfattr_to_vattr(vnode_t *vp, struct smbfattr *fa, struct vattr *vap)
51202d09e03SGordon Ross {
51302d09e03SGordon Ross 	struct smbnode *np = VTOSMB(vp);
51402d09e03SGordon Ross 
51502d09e03SGordon Ross 	/*
51602d09e03SGordon Ross 	 * Take type, mode, uid, gid from the smbfs node,
51702d09e03SGordon Ross 	 * which has have been updated by _getattr_otw.
51802d09e03SGordon Ross 	 */
51902d09e03SGordon Ross 	vap->va_type = vp->v_type;
52002d09e03SGordon Ross 	vap->va_mode = np->n_mode;
52102d09e03SGordon Ross 
52202d09e03SGordon Ross 	vap->va_uid = np->n_uid;
52302d09e03SGordon Ross 	vap->va_gid = np->n_gid;
52402d09e03SGordon Ross 
52502d09e03SGordon Ross 	vap->va_fsid = vp->v_vfsp->vfs_dev;
52602d09e03SGordon Ross 	vap->va_nodeid = np->n_ino;
52702d09e03SGordon Ross 	vap->va_nlink = 1;
52802d09e03SGordon Ross 
52902d09e03SGordon Ross 	/*
53002d09e03SGordon Ross 	 * Difference from NFS here:  We cache attributes as
53102d09e03SGordon Ross 	 * reported by the server, so r_attr.fa_size is the
53202d09e03SGordon Ross 	 * server's idea of the file size.  This is called
53302d09e03SGordon Ross 	 * for getattr, so we want to return the client's
53402d09e03SGordon Ross 	 * idea of the file size.  NFS deals with that in
53502d09e03SGordon Ross 	 * nfsgetattr(), the equivalent of our caller.
53602d09e03SGordon Ross 	 */
53702d09e03SGordon Ross 	vap->va_size = np->r_size;
53802d09e03SGordon Ross 
53902d09e03SGordon Ross 	/*
54002d09e03SGordon Ross 	 * Times.  Note, already converted from NT to
54102d09e03SGordon Ross 	 * Unix form (in the unmarshalling code).
54202d09e03SGordon Ross 	 */
54302d09e03SGordon Ross 	vap->va_atime = fa->fa_atime;
54402d09e03SGordon Ross 	vap->va_mtime = fa->fa_mtime;
54502d09e03SGordon Ross 	vap->va_ctime = fa->fa_ctime;
54602d09e03SGordon Ross 
54702d09e03SGordon Ross 	/*
54802d09e03SGordon Ross 	 * rdev, blksize, seq are made up.
54902d09e03SGordon Ross 	 * va_nblocks is 512 byte blocks.
55002d09e03SGordon Ross 	 */
55102d09e03SGordon Ross 	vap->va_rdev = vp->v_rdev;
55202d09e03SGordon Ross 	vap->va_blksize = MAXBSIZE;
55302d09e03SGordon Ross 	vap->va_nblocks = (fsblkcnt64_t)btod(np->r_attr.fa_allocsz);
55402d09e03SGordon Ross 	vap->va_seq = 0;
55502d09e03SGordon Ross }
55602d09e03SGordon Ross 
55728162916SGordon Ross /*
55828162916SGordon Ross  * smbfattr_to_xvattr: like smbfattr_to_vattr but for
55928162916SGordon Ross  * Extensible system attributes (PSARC 2007/315)
56028162916SGordon Ross  */
56128162916SGordon Ross static void
56228162916SGordon Ross smbfattr_to_xvattr(struct smbfattr *fa, struct vattr *vap)
56328162916SGordon Ross {
56428162916SGordon Ross 	xvattr_t *xvap = (xvattr_t *)vap;	/* *vap may be xvattr_t */
56528162916SGordon Ross 	xoptattr_t *xoap = NULL;
56628162916SGordon Ross 
56728162916SGordon Ross 	if ((xoap = xva_getxoptattr(xvap)) == NULL)
56828162916SGordon Ross 		return;
56928162916SGordon Ross 
57028162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
57128162916SGordon Ross 		xoap->xoa_createtime = fa->fa_createtime;
57228162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_CREATETIME);
57328162916SGordon Ross 	}
57428162916SGordon Ross 
57528162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
57628162916SGordon Ross 		xoap->xoa_archive =
57728162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_ARCHIVE) != 0);
57828162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_ARCHIVE);
57928162916SGordon Ross 	}
58028162916SGordon Ross 
58128162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
58228162916SGordon Ross 		xoap->xoa_system =
58328162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_SYSTEM) != 0);
58428162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_SYSTEM);
58528162916SGordon Ross 	}
58628162916SGordon Ross 
58728162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
58828162916SGordon Ross 		xoap->xoa_readonly =
58928162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_RDONLY) != 0);
59028162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_READONLY);
59128162916SGordon Ross 	}
59228162916SGordon Ross 
59328162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
59428162916SGordon Ross 		xoap->xoa_hidden =
59528162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_HIDDEN) != 0);
59628162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_HIDDEN);
59728162916SGordon Ross 	}
59828162916SGordon Ross }
59902d09e03SGordon Ross 
60002d09e03SGordon Ross /*
6015f4fc069Sjilinxpd  * Here NFS has:
6025f4fc069Sjilinxpd  *	nfs_async_... stuff
6035f4fc069Sjilinxpd  * which we're not using (no async I/O), and:
6045f4fc069Sjilinxpd  *	writerp(),
6055f4fc069Sjilinxpd  *	nfs_putpages()
6065f4fc069Sjilinxpd  *	nfs_invalidate_pages()
6075f4fc069Sjilinxpd  * which we have in smbfs_vnops.c, and
6085f4fc069Sjilinxpd  *	nfs_printfhandle()
6095f4fc069Sjilinxpd  *	nfs_write_error()
6105f4fc069Sjilinxpd  * not needed here.
6115f4fc069Sjilinxpd  */
6125f4fc069Sjilinxpd 
6135f4fc069Sjilinxpd /*
6145f4fc069Sjilinxpd  * Helper function for smbfs_sync
6155f4fc069Sjilinxpd  *
6165f4fc069Sjilinxpd  * Walk the per-zone list of smbfs mounts, calling smbfs_rflush
6175f4fc069Sjilinxpd  * on each one.  This is a little tricky because we need to exit
6185f4fc069Sjilinxpd  * the list mutex before each _rflush call and then try to resume
6195f4fc069Sjilinxpd  * where we were in the list after re-entering the mutex.
6205f4fc069Sjilinxpd  */
6215f4fc069Sjilinxpd void
6225f4fc069Sjilinxpd smbfs_flushall(cred_t *cr)
6235f4fc069Sjilinxpd {
6245f4fc069Sjilinxpd 	smi_globals_t *smg;
6255f4fc069Sjilinxpd 	smbmntinfo_t *tmp_smi, *cur_smi, *next_smi;
6265f4fc069Sjilinxpd 
6275f4fc069Sjilinxpd 	smg = zone_getspecific(smi_list_key, crgetzone(cr));
6285f4fc069Sjilinxpd 	ASSERT(smg != NULL);
6295f4fc069Sjilinxpd 
6305f4fc069Sjilinxpd 	mutex_enter(&smg->smg_lock);
6315f4fc069Sjilinxpd 	cur_smi = list_head(&smg->smg_list);
6325f4fc069Sjilinxpd 	if (cur_smi == NULL) {
6335f4fc069Sjilinxpd 		mutex_exit(&smg->smg_lock);
6345f4fc069Sjilinxpd 		return;
6355f4fc069Sjilinxpd 	}
6365f4fc069Sjilinxpd 	VFS_HOLD(cur_smi->smi_vfsp);
6375f4fc069Sjilinxpd 	mutex_exit(&smg->smg_lock);
6385f4fc069Sjilinxpd 
6395f4fc069Sjilinxpd flush:
6405f4fc069Sjilinxpd 	smbfs_rflush(cur_smi->smi_vfsp, cr);
6415f4fc069Sjilinxpd 
6425f4fc069Sjilinxpd 	mutex_enter(&smg->smg_lock);
6435f4fc069Sjilinxpd 	/*
6445f4fc069Sjilinxpd 	 * Resume after cur_smi if that's still on the list,
6455f4fc069Sjilinxpd 	 * otherwise restart at the head.
6465f4fc069Sjilinxpd 	 */
6475f4fc069Sjilinxpd 	for (tmp_smi = list_head(&smg->smg_list);
6485f4fc069Sjilinxpd 	    tmp_smi != NULL;
6495f4fc069Sjilinxpd 	    tmp_smi = list_next(&smg->smg_list, tmp_smi))
6505f4fc069Sjilinxpd 		if (tmp_smi == cur_smi)
6515f4fc069Sjilinxpd 			break;
6525f4fc069Sjilinxpd 	if (tmp_smi != NULL)
6535f4fc069Sjilinxpd 		next_smi = list_next(&smg->smg_list, tmp_smi);
6545f4fc069Sjilinxpd 	else
6555f4fc069Sjilinxpd 		next_smi = list_head(&smg->smg_list);
6565f4fc069Sjilinxpd 
6575f4fc069Sjilinxpd 	if (next_smi != NULL)
6585f4fc069Sjilinxpd 		VFS_HOLD(next_smi->smi_vfsp);
6595f4fc069Sjilinxpd 	VFS_RELE(cur_smi->smi_vfsp);
6605f4fc069Sjilinxpd 
6615f4fc069Sjilinxpd 	mutex_exit(&smg->smg_lock);
6625f4fc069Sjilinxpd 
6635f4fc069Sjilinxpd 	if (next_smi != NULL) {
6645f4fc069Sjilinxpd 		cur_smi = next_smi;
6655f4fc069Sjilinxpd 		goto flush;
6665f4fc069Sjilinxpd 	}
6675f4fc069Sjilinxpd }
6685f4fc069Sjilinxpd 
6695f4fc069Sjilinxpd /*
67002d09e03SGordon Ross  * SMB Client initialization and cleanup.
67102d09e03SGordon Ross  * Much of it is per-zone now.
67202d09e03SGordon Ross  */
67302d09e03SGordon Ross 
67402d09e03SGordon Ross 
6754bff34e3Sthurlow /* ARGSUSED */
6764bff34e3Sthurlow static void *
6774bff34e3Sthurlow smbfs_zone_init(zoneid_t zoneid)
6784bff34e3Sthurlow {
6794bff34e3Sthurlow 	smi_globals_t *smg;
6804bff34e3Sthurlow 
6814bff34e3Sthurlow 	smg = kmem_alloc(sizeof (*smg), KM_SLEEP);
6824bff34e3Sthurlow 	mutex_init(&smg->smg_lock, NULL, MUTEX_DEFAULT, NULL);
6834bff34e3Sthurlow 	list_create(&smg->smg_list, sizeof (smbmntinfo_t),
6844bff34e3Sthurlow 	    offsetof(smbmntinfo_t, smi_zone_node));
6854bff34e3Sthurlow 	smg->smg_destructor_called = B_FALSE;
6864bff34e3Sthurlow 	return (smg);
6874bff34e3Sthurlow }
6884bff34e3Sthurlow 
6894bff34e3Sthurlow /*
6904bff34e3Sthurlow  * Callback routine to tell all SMBFS mounts in the zone to stop creating new
6914bff34e3Sthurlow  * threads.  Existing threads should exit.
6924bff34e3Sthurlow  */
6934bff34e3Sthurlow /* ARGSUSED */
6944bff34e3Sthurlow static void
6954bff34e3Sthurlow smbfs_zone_shutdown(zoneid_t zoneid, void *data)
6964bff34e3Sthurlow {
6974bff34e3Sthurlow 	smi_globals_t *smg = data;
6984bff34e3Sthurlow 	smbmntinfo_t *smi;
6994bff34e3Sthurlow 
7004bff34e3Sthurlow 	ASSERT(smg != NULL);
7014bff34e3Sthurlow again:
7024bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7034bff34e3Sthurlow 	for (smi = list_head(&smg->smg_list); smi != NULL;
7044bff34e3Sthurlow 	    smi = list_next(&smg->smg_list, smi)) {
7054bff34e3Sthurlow 
7064bff34e3Sthurlow 		/*
7074bff34e3Sthurlow 		 * If we've done the shutdown work for this FS, skip.
7084bff34e3Sthurlow 		 * Once we go off the end of the list, we're done.
7094bff34e3Sthurlow 		 */
7104bff34e3Sthurlow 		if (smi->smi_flags & SMI_DEAD)
7114bff34e3Sthurlow 			continue;
7124bff34e3Sthurlow 
7134bff34e3Sthurlow 		/*
7144bff34e3Sthurlow 		 * We will do work, so not done.  Get a hold on the FS.
7154bff34e3Sthurlow 		 */
7164bff34e3Sthurlow 		VFS_HOLD(smi->smi_vfsp);
7174bff34e3Sthurlow 
7184bff34e3Sthurlow 		mutex_enter(&smi->smi_lock);
7194bff34e3Sthurlow 		smi->smi_flags |= SMI_DEAD;
7204bff34e3Sthurlow 		mutex_exit(&smi->smi_lock);
7214bff34e3Sthurlow 
7224bff34e3Sthurlow 		/*
7234bff34e3Sthurlow 		 * Drop lock and release FS, which may change list, then repeat.
7244bff34e3Sthurlow 		 * We're done when every mi has been done or the list is empty.
7254bff34e3Sthurlow 		 */
7264bff34e3Sthurlow 		mutex_exit(&smg->smg_lock);
7274bff34e3Sthurlow 		VFS_RELE(smi->smi_vfsp);
7284bff34e3Sthurlow 		goto again;
7294bff34e3Sthurlow 	}
7304bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
7314bff34e3Sthurlow }
7324bff34e3Sthurlow 
7334bff34e3Sthurlow static void
7344bff34e3Sthurlow smbfs_zone_free_globals(smi_globals_t *smg)
7354bff34e3Sthurlow {
7364bff34e3Sthurlow 	list_destroy(&smg->smg_list);	/* makes sure the list is empty */
7374bff34e3Sthurlow 	mutex_destroy(&smg->smg_lock);
7384bff34e3Sthurlow 	kmem_free(smg, sizeof (*smg));
7394bff34e3Sthurlow 
7404bff34e3Sthurlow }
7414bff34e3Sthurlow 
7424bff34e3Sthurlow /* ARGSUSED */
7434bff34e3Sthurlow static void
7444bff34e3Sthurlow smbfs_zone_destroy(zoneid_t zoneid, void *data)
7454bff34e3Sthurlow {
7464bff34e3Sthurlow 	smi_globals_t *smg = data;
7474bff34e3Sthurlow 
7484bff34e3Sthurlow 	ASSERT(smg != NULL);
7494bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7504bff34e3Sthurlow 	if (list_head(&smg->smg_list) != NULL) {
7514bff34e3Sthurlow 		/* Still waiting for VFS_FREEVFS() */
7524bff34e3Sthurlow 		smg->smg_destructor_called = B_TRUE;
7534bff34e3Sthurlow 		mutex_exit(&smg->smg_lock);
7544bff34e3Sthurlow 		return;
7554bff34e3Sthurlow 	}
7564bff34e3Sthurlow 	smbfs_zone_free_globals(smg);
7574bff34e3Sthurlow }
7584bff34e3Sthurlow 
7594bff34e3Sthurlow /*
7604bff34e3Sthurlow  * Add an SMBFS mount to the per-zone list of SMBFS mounts.
7614bff34e3Sthurlow  */
7624bff34e3Sthurlow void
7634bff34e3Sthurlow smbfs_zonelist_add(smbmntinfo_t *smi)
7644bff34e3Sthurlow {
7654bff34e3Sthurlow 	smi_globals_t *smg;
7664bff34e3Sthurlow 
767a19609f8Sjv227347 	smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone);
7684bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7694bff34e3Sthurlow 	list_insert_head(&smg->smg_list, smi);
7704bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
7714bff34e3Sthurlow }
7724bff34e3Sthurlow 
7734bff34e3Sthurlow /*
7744bff34e3Sthurlow  * Remove an SMBFS mount from the per-zone list of SMBFS mounts.
7754bff34e3Sthurlow  */
7764bff34e3Sthurlow void
7774bff34e3Sthurlow smbfs_zonelist_remove(smbmntinfo_t *smi)
7784bff34e3Sthurlow {
7794bff34e3Sthurlow 	smi_globals_t *smg;
7804bff34e3Sthurlow 
781a19609f8Sjv227347 	smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone);
7824bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7834bff34e3Sthurlow 	list_remove(&smg->smg_list, smi);
7844bff34e3Sthurlow 	/*
7854bff34e3Sthurlow 	 * We can be called asynchronously by VFS_FREEVFS() after the zone
7864bff34e3Sthurlow 	 * shutdown/destroy callbacks have executed; if so, clean up the zone's
7874bff34e3Sthurlow 	 * smi_globals.
7884bff34e3Sthurlow 	 */
7894bff34e3Sthurlow 	if (list_head(&smg->smg_list) == NULL &&
7904bff34e3Sthurlow 	    smg->smg_destructor_called == B_TRUE) {
7914bff34e3Sthurlow 		smbfs_zone_free_globals(smg);
7924bff34e3Sthurlow 		return;
7934bff34e3Sthurlow 	}
7944bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
7954bff34e3Sthurlow }
7964bff34e3Sthurlow 
797613a2f6bSGordon Ross #ifdef	lint
798613a2f6bSGordon Ross #define	NEED_SMBFS_CALLBACKS	1
799613a2f6bSGordon Ross #endif
8004bff34e3Sthurlow 
8014bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
8024bff34e3Sthurlow /*
8034bff34e3Sthurlow  * Call-back hooks for netsmb, in case we want them.
8044bff34e3Sthurlow  * Apple's VFS wants them.  We may not need them.
8054bff34e3Sthurlow  */
806613a2f6bSGordon Ross /*ARGSUSED*/
8074bff34e3Sthurlow static void smbfs_dead(smb_share_t *ssp)
8084bff34e3Sthurlow {
809613a2f6bSGordon Ross 	/*
810613a2f6bSGordon Ross 	 * Walk the mount list, finding all mounts
811613a2f6bSGordon Ross 	 * using this share...
812613a2f6bSGordon Ross 	 */
8134bff34e3Sthurlow }
8144bff34e3Sthurlow 
815613a2f6bSGordon Ross /*ARGSUSED*/
816613a2f6bSGordon Ross static void smbfs_cb_nop(smb_share_t *ss)
8174bff34e3Sthurlow {
8184bff34e3Sthurlow 	/* no-op */
8194bff34e3Sthurlow }
8204bff34e3Sthurlow 
8214bff34e3Sthurlow smb_fscb_t smbfs_cb = {
822613a2f6bSGordon Ross 	.fscb_disconn	= smbfs_dead,
823613a2f6bSGordon Ross 	.fscb_connect	= smbfs_cb_nop,
824613a2f6bSGordon Ross 	.fscb_down	= smbfs_cb_nop,
825613a2f6bSGordon Ross 	.fscb_up	= smbfs_cb_nop };
8264bff34e3Sthurlow 
8274bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8284bff34e3Sthurlow 
8294bff34e3Sthurlow /*
8304bff34e3Sthurlow  * SMBFS Client initialization routine.  This routine should only be called
8314bff34e3Sthurlow  * once.  It performs the following tasks:
8324bff34e3Sthurlow  *      - Initalize all global locks
8334bff34e3Sthurlow  *      - Call sub-initialization routines (localize access to variables)
8344bff34e3Sthurlow  */
8354bff34e3Sthurlow int
8364bff34e3Sthurlow smbfs_clntinit(void)
8374bff34e3Sthurlow {
8384bff34e3Sthurlow 
8394bff34e3Sthurlow 	zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown,
8404bff34e3Sthurlow 	    smbfs_zone_destroy);
8414bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
842c1374a13SSurya Prakki 	(void) smb_fscb_set(&smbfs_cb);
8434bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8444bff34e3Sthurlow 	return (0);
8454bff34e3Sthurlow }
8464bff34e3Sthurlow 
8474bff34e3Sthurlow /*
8484bff34e3Sthurlow  * This routine is called when the modunload is called. This will cleanup
8494bff34e3Sthurlow  * the previously allocated/initialized nodes.
8504bff34e3Sthurlow  */
8514bff34e3Sthurlow void
8524bff34e3Sthurlow smbfs_clntfini(void)
8534bff34e3Sthurlow {
8544bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
855c1374a13SSurya Prakki 	(void) smb_fscb_set(NULL);
8564bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8574bff34e3Sthurlow 	(void) zone_key_delete(smi_list_key);
8584bff34e3Sthurlow }
859