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.
274bff34e3Sthurlow  */
284bff34e3Sthurlow 
294bff34e3Sthurlow #include <sys/param.h>
304bff34e3Sthurlow #include <sys/systm.h>
314bff34e3Sthurlow #include <sys/thread.h>
324bff34e3Sthurlow #include <sys/t_lock.h>
334bff34e3Sthurlow #include <sys/time.h>
344bff34e3Sthurlow #include <sys/vnode.h>
354bff34e3Sthurlow #include <sys/vfs.h>
364bff34e3Sthurlow #include <sys/errno.h>
374bff34e3Sthurlow #include <sys/buf.h>
384bff34e3Sthurlow #include <sys/stat.h>
394bff34e3Sthurlow #include <sys/cred.h>
404bff34e3Sthurlow #include <sys/kmem.h>
414bff34e3Sthurlow #include <sys/debug.h>
424bff34e3Sthurlow #include <sys/vmsystm.h>
434bff34e3Sthurlow #include <sys/flock.h>
444bff34e3Sthurlow #include <sys/share.h>
454bff34e3Sthurlow #include <sys/cmn_err.h>
464bff34e3Sthurlow #include <sys/tiuser.h>
474bff34e3Sthurlow #include <sys/sysmacros.h>
484bff34e3Sthurlow #include <sys/callb.h>
494bff34e3Sthurlow #include <sys/acl.h>
504bff34e3Sthurlow #include <sys/kstat.h>
514bff34e3Sthurlow #include <sys/signal.h>
524bff34e3Sthurlow #include <sys/list.h>
534bff34e3Sthurlow #include <sys/zone.h>
544bff34e3Sthurlow 
5502d09e03SGordon Ross #include <netsmb/smb.h>
564bff34e3Sthurlow #include <netsmb/smb_conn.h>
5702d09e03SGordon Ross #include <netsmb/smb_subr.h>
584bff34e3Sthurlow 
594bff34e3Sthurlow #include <smbfs/smbfs.h>
604bff34e3Sthurlow #include <smbfs/smbfs_node.h>
614bff34e3Sthurlow #include <smbfs/smbfs_subr.h>
624bff34e3Sthurlow 
634bff34e3Sthurlow #include <vm/hat.h>
644bff34e3Sthurlow #include <vm/as.h>
654bff34e3Sthurlow #include <vm/page.h>
664bff34e3Sthurlow #include <vm/pvn.h>
674bff34e3Sthurlow #include <vm/seg.h>
684bff34e3Sthurlow #include <vm/seg_map.h>
694bff34e3Sthurlow #include <vm/seg_vn.h>
704bff34e3Sthurlow 
71*5f4fc069Sjilinxpd #define	ATTRCACHE_VALID(vp)	(gethrtime() < VTOSMB(vp)->r_attrtime)
72*5f4fc069Sjilinxpd 
7328162916SGordon Ross static int smbfs_getattr_cache(vnode_t *, smbfattr_t *);
7428162916SGordon Ross static void smbfattr_to_vattr(vnode_t *, smbfattr_t *, vattr_t *);
7528162916SGordon Ross static void smbfattr_to_xvattr(smbfattr_t *, vattr_t *);
76*5f4fc069Sjilinxpd static int smbfs_getattr_otw(vnode_t *, struct smbfattr *, cred_t *);
77*5f4fc069Sjilinxpd 
7802d09e03SGordon Ross 
794bff34e3Sthurlow /*
804bff34e3Sthurlow  * The following code provide zone support in order to perform an action
814bff34e3Sthurlow  * for each smbfs mount in a zone.  This is also where we would add
824bff34e3Sthurlow  * per-zone globals and kernel threads for the smbfs module (since
834bff34e3Sthurlow  * they must be terminated by the shutdown callback).
844bff34e3Sthurlow  */
854bff34e3Sthurlow 
864bff34e3Sthurlow struct smi_globals {
874bff34e3Sthurlow 	kmutex_t	smg_lock;  /* lock protecting smg_list */
884bff34e3Sthurlow 	list_t		smg_list;  /* list of SMBFS mounts in zone */
894bff34e3Sthurlow 	boolean_t	smg_destructor_called;
904bff34e3Sthurlow };
914bff34e3Sthurlow typedef struct smi_globals smi_globals_t;
924bff34e3Sthurlow 
934bff34e3Sthurlow static zone_key_t smi_list_key;
944bff34e3Sthurlow 
9502d09e03SGordon Ross /*
9602d09e03SGordon Ross  * Attributes caching:
9702d09e03SGordon Ross  *
9802d09e03SGordon Ross  * Attributes are cached in the smbnode in struct vattr form.
9902d09e03SGordon Ross  * There is a time associated with the cached attributes (r_attrtime)
10002d09e03SGordon Ross  * which tells whether the attributes are valid. The time is initialized
10102d09e03SGordon Ross  * to the difference between current time and the modify time of the vnode
10202d09e03SGordon Ross  * when new attributes are cached. This allows the attributes for
10302d09e03SGordon Ross  * files that have changed recently to be timed out sooner than for files
10402d09e03SGordon Ross  * that have not changed for a long time. There are minimum and maximum
10502d09e03SGordon Ross  * timeout values that can be set per mount point.
10602d09e03SGordon Ross  */
10702d09e03SGordon Ross 
10802d09e03SGordon Ross /*
109*5f4fc069Sjilinxpd  * Helper for _validate_caches
110*5f4fc069Sjilinxpd  */
111*5f4fc069Sjilinxpd int
112*5f4fc069Sjilinxpd smbfs_waitfor_purge_complete(vnode_t *vp)
113*5f4fc069Sjilinxpd {
114*5f4fc069Sjilinxpd 	smbnode_t *np;
115*5f4fc069Sjilinxpd 	k_sigset_t smask;
116*5f4fc069Sjilinxpd 
117*5f4fc069Sjilinxpd 	np = VTOSMB(vp);
118*5f4fc069Sjilinxpd 	if (np->r_serial != NULL && np->r_serial != curthread) {
119*5f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
120*5f4fc069Sjilinxpd 		sigintr(&smask, VTOSMI(vp)->smi_flags & SMI_INT);
121*5f4fc069Sjilinxpd 		while (np->r_serial != NULL) {
122*5f4fc069Sjilinxpd 			if (!cv_wait_sig(&np->r_cv, &np->r_statelock)) {
123*5f4fc069Sjilinxpd 				sigunintr(&smask);
124*5f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
125*5f4fc069Sjilinxpd 				return (EINTR);
126*5f4fc069Sjilinxpd 			}
127*5f4fc069Sjilinxpd 		}
128*5f4fc069Sjilinxpd 		sigunintr(&smask);
129*5f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
130*5f4fc069Sjilinxpd 	}
131*5f4fc069Sjilinxpd 	return (0);
132*5f4fc069Sjilinxpd }
133*5f4fc069Sjilinxpd 
134*5f4fc069Sjilinxpd /*
135*5f4fc069Sjilinxpd  * Validate caches by checking cached attributes. If the cached
136*5f4fc069Sjilinxpd  * attributes have timed out, then get new attributes from the server.
137*5f4fc069Sjilinxpd  * As a side affect, this will do cache invalidation if the attributes
138*5f4fc069Sjilinxpd  * have changed.
139*5f4fc069Sjilinxpd  *
140*5f4fc069Sjilinxpd  * If the attributes have not timed out and if there is a cache
141*5f4fc069Sjilinxpd  * invalidation being done by some other thread, then wait until that
142*5f4fc069Sjilinxpd  * thread has completed the cache invalidation.
14302d09e03SGordon Ross  */
14402d09e03SGordon Ross int
14502d09e03SGordon Ross smbfs_validate_caches(
14602d09e03SGordon Ross 	struct vnode *vp,
14702d09e03SGordon Ross 	cred_t *cr)
14802d09e03SGordon Ross {
149*5f4fc069Sjilinxpd 	struct smbfattr fa;
150*5f4fc069Sjilinxpd 	int error;
15102d09e03SGordon Ross 
152*5f4fc069Sjilinxpd 	if (ATTRCACHE_VALID(vp)) {
153*5f4fc069Sjilinxpd 		error = smbfs_waitfor_purge_complete(vp);
154*5f4fc069Sjilinxpd 		if (error)
155*5f4fc069Sjilinxpd 			return (error);
156*5f4fc069Sjilinxpd 		return (0);
157*5f4fc069Sjilinxpd 	}
158*5f4fc069Sjilinxpd 
159*5f4fc069Sjilinxpd 	return (smbfs_getattr_otw(vp, &fa, cr));
16002d09e03SGordon Ross }
16102d09e03SGordon Ross 
16202d09e03SGordon Ross /*
16302d09e03SGordon Ross  * Purge all of the various data caches.
164*5f4fc069Sjilinxpd  *
165*5f4fc069Sjilinxpd  * Here NFS also had a flags arg to control what gets flushed.
166*5f4fc069Sjilinxpd  * We only have the page cache, so no flags arg.
16702d09e03SGordon Ross  */
16802d09e03SGordon Ross /* ARGSUSED */
16902d09e03SGordon Ross void
170*5f4fc069Sjilinxpd smbfs_purge_caches(struct vnode *vp, cred_t *cr)
17102d09e03SGordon Ross {
172*5f4fc069Sjilinxpd 
17302d09e03SGordon Ross 	/*
174*5f4fc069Sjilinxpd 	 * Here NFS has: Purge the DNLC for this vp,
17502d09e03SGordon Ross 	 * Clear any readdir state bits,
17602d09e03SGordon Ross 	 * the readlink response cache, ...
17702d09e03SGordon Ross 	 */
17802d09e03SGordon Ross 
17902d09e03SGordon Ross 	/*
18002d09e03SGordon Ross 	 * Flush the page cache.
18102d09e03SGordon Ross 	 */
18202d09e03SGordon Ross 	if (vn_has_cached_data(vp)) {
18302d09e03SGordon Ross 		(void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL);
18402d09e03SGordon Ross 	}
185*5f4fc069Sjilinxpd 
186*5f4fc069Sjilinxpd 	/*
187*5f4fc069Sjilinxpd 	 * Here NFS has: Flush the readdir response cache.
188*5f4fc069Sjilinxpd 	 * No readdir cache in smbfs.
189*5f4fc069Sjilinxpd 	 */
19002d09e03SGordon Ross }
19102d09e03SGordon Ross 
19202d09e03SGordon Ross /*
193*5f4fc069Sjilinxpd  * Here NFS has:
194*5f4fc069Sjilinxpd  * nfs_purge_rddir_cache()
195*5f4fc069Sjilinxpd  * nfs3_cache_post_op_attr()
196*5f4fc069Sjilinxpd  * nfs3_cache_post_op_vattr()
197*5f4fc069Sjilinxpd  * nfs3_cache_wcc_data()
198*5f4fc069Sjilinxpd  */
199*5f4fc069Sjilinxpd 
200*5f4fc069Sjilinxpd /*
20102d09e03SGordon Ross  * Check the attribute cache to see if the new attributes match
20202d09e03SGordon Ross  * those cached.  If they do, the various `data' caches are
20302d09e03SGordon Ross  * considered to be good.  Otherwise, purge the cached data.
20402d09e03SGordon Ross  */
205*5f4fc069Sjilinxpd static void
20602d09e03SGordon Ross smbfs_cache_check(
20702d09e03SGordon Ross 	struct vnode *vp,
208*5f4fc069Sjilinxpd 	struct smbfattr *fap,
209*5f4fc069Sjilinxpd 	cred_t *cr)
21002d09e03SGordon Ross {
21102d09e03SGordon Ross 	smbnode_t *np;
21202d09e03SGordon Ross 	int purge_data = 0;
21302d09e03SGordon Ross 	int purge_acl = 0;
21402d09e03SGordon Ross 
21502d09e03SGordon Ross 	np = VTOSMB(vp);
21602d09e03SGordon Ross 	mutex_enter(&np->r_statelock);
21702d09e03SGordon Ross 
21802d09e03SGordon Ross 	/*
21902d09e03SGordon Ross 	 * Compare with NFS macro: CACHE_VALID
22002d09e03SGordon Ross 	 * If the mtime or size has changed,
22102d09e03SGordon Ross 	 * purge cached data.
22202d09e03SGordon Ross 	 */
22302d09e03SGordon Ross 	if (np->r_attr.fa_mtime.tv_sec != fap->fa_mtime.tv_sec ||
22402d09e03SGordon Ross 	    np->r_attr.fa_mtime.tv_nsec != fap->fa_mtime.tv_nsec)
22502d09e03SGordon Ross 		purge_data = 1;
22602d09e03SGordon Ross 	if (np->r_attr.fa_size != fap->fa_size)
22702d09e03SGordon Ross 		purge_data = 1;
22802d09e03SGordon Ross 
22902d09e03SGordon Ross 	if (np->r_attr.fa_ctime.tv_sec != fap->fa_ctime.tv_sec ||
23002d09e03SGordon Ross 	    np->r_attr.fa_ctime.tv_nsec != fap->fa_ctime.tv_nsec)
23102d09e03SGordon Ross 		purge_acl = 1;
232bd7c6f51SGordon Ross 
233bd7c6f51SGordon Ross 	if (purge_acl) {
234bd7c6f51SGordon Ross 		np->r_sectime = gethrtime();
235bd7c6f51SGordon Ross 	}
23602d09e03SGordon Ross 
23702d09e03SGordon Ross 	mutex_exit(&np->r_statelock);
23802d09e03SGordon Ross 
23902d09e03SGordon Ross 	if (purge_data)
240*5f4fc069Sjilinxpd 		smbfs_purge_caches(vp, cr);
24102d09e03SGordon Ross }
24202d09e03SGordon Ross 
24302d09e03SGordon Ross /*
24402d09e03SGordon Ross  * Set attributes cache for given vnode using SMB fattr
24502d09e03SGordon Ross  * and update the attribute cache timeout.
24602d09e03SGordon Ross  *
247*5f4fc069Sjilinxpd  * Based on NFS: nfs_attrcache, nfs_attrcache_va
24802d09e03SGordon Ross  */
24902d09e03SGordon Ross void
25002d09e03SGordon Ross smbfs_attrcache_fa(vnode_t *vp, struct smbfattr *fap)
25102d09e03SGordon Ross {
25202d09e03SGordon Ross 	smbnode_t *np;
25302d09e03SGordon Ross 	smbmntinfo_t *smi;
25402d09e03SGordon Ross 	hrtime_t delta, now;
25502d09e03SGordon Ross 	u_offset_t newsize;
25602d09e03SGordon Ross 	vtype_t	 vtype, oldvt;
25702d09e03SGordon Ross 	mode_t mode;
25802d09e03SGordon Ross 
25902d09e03SGordon Ross 	np = VTOSMB(vp);
26002d09e03SGordon Ross 	smi = VTOSMI(vp);
26102d09e03SGordon Ross 
26202d09e03SGordon Ross 	/*
26302d09e03SGordon Ross 	 * We allow v_type to change, so set that here
26442d15982SGordon Ross 	 * (and the mode, which depends on the type).
26502d09e03SGordon Ross 	 */
26602d09e03SGordon Ross 	if (fap->fa_attr & SMB_FA_DIR) {
26702d09e03SGordon Ross 		vtype = VDIR;
26842d15982SGordon Ross 		mode = smi->smi_dmode;
26902d09e03SGordon Ross 	} else {
27002d09e03SGordon Ross 		vtype = VREG;
27142d15982SGordon Ross 		mode = smi->smi_fmode;
27202d09e03SGordon Ross 	}
27302d09e03SGordon Ross 
27402d09e03SGordon Ross 	mutex_enter(&np->r_statelock);
27502d09e03SGordon Ross 	now = gethrtime();
27602d09e03SGordon Ross 
27702d09e03SGordon Ross 	/*
27802d09e03SGordon Ross 	 * Delta is the number of nanoseconds that we will
27902d09e03SGordon Ross 	 * cache the attributes of the file.  It is based on
28002d09e03SGordon Ross 	 * the number of nanoseconds since the last time that
28102d09e03SGordon Ross 	 * we detected a change.  The assumption is that files
28202d09e03SGordon Ross 	 * that changed recently are likely to change again.
28302d09e03SGordon Ross 	 * There is a minimum and a maximum for regular files
28402d09e03SGordon Ross 	 * and for directories which is enforced though.
28502d09e03SGordon Ross 	 *
28602d09e03SGordon Ross 	 * Using the time since last change was detected
28702d09e03SGordon Ross 	 * eliminates direct comparison or calculation
28802d09e03SGordon Ross 	 * using mixed client and server times.  SMBFS
28902d09e03SGordon Ross 	 * does not make any assumptions regarding the
29002d09e03SGordon Ross 	 * client and server clocks being synchronized.
29102d09e03SGordon Ross 	 */
29202d09e03SGordon Ross 	if (fap->fa_mtime.tv_sec  != np->r_attr.fa_mtime.tv_sec ||
29302d09e03SGordon Ross 	    fap->fa_mtime.tv_nsec != np->r_attr.fa_mtime.tv_nsec ||
29402d09e03SGordon Ross 	    fap->fa_size	  != np->r_attr.fa_size)
29502d09e03SGordon Ross 		np->r_mtime = now;
29602d09e03SGordon Ross 
29702d09e03SGordon Ross 	if ((smi->smi_flags & SMI_NOAC) || (vp->v_flag & VNOCACHE))
29802d09e03SGordon Ross 		delta = 0;
29902d09e03SGordon Ross 	else {
30002d09e03SGordon Ross 		delta = now - np->r_mtime;
30102d09e03SGordon Ross 		if (vtype == VDIR) {
30202d09e03SGordon Ross 			if (delta < smi->smi_acdirmin)
30302d09e03SGordon Ross 				delta = smi->smi_acdirmin;
30402d09e03SGordon Ross 			else if (delta > smi->smi_acdirmax)
30502d09e03SGordon Ross 				delta = smi->smi_acdirmax;
30602d09e03SGordon Ross 		} else {
30702d09e03SGordon Ross 			if (delta < smi->smi_acregmin)
30802d09e03SGordon Ross 				delta = smi->smi_acregmin;
30902d09e03SGordon Ross 			else if (delta > smi->smi_acregmax)
31002d09e03SGordon Ross 				delta = smi->smi_acregmax;
31102d09e03SGordon Ross 		}
31202d09e03SGordon Ross 	}
31302d09e03SGordon Ross 
31402d09e03SGordon Ross 	np->r_attrtime = now + delta;
31502d09e03SGordon Ross 	np->r_attr = *fap;
31602d09e03SGordon Ross 	np->n_mode = mode;
31702d09e03SGordon Ross 	oldvt = vp->v_type;
31802d09e03SGordon Ross 	vp->v_type = vtype;
31902d09e03SGordon Ross 
32002d09e03SGordon Ross 	/*
32102d09e03SGordon Ross 	 * Shall we update r_size? (local notion of size)
32202d09e03SGordon Ross 	 *
32302d09e03SGordon Ross 	 * The real criteria for updating r_size should be:
32402d09e03SGordon Ross 	 * if the file has grown on the server, or if
32502d09e03SGordon Ross 	 * the client has not modified the file.
32602d09e03SGordon Ross 	 *
32702d09e03SGordon Ross 	 * Also deal with the fact that SMB presents
32802d09e03SGordon Ross 	 * directories as having size=0.  Doing that
32902d09e03SGordon Ross 	 * here and leaving fa_size as returned OtW
33002d09e03SGordon Ross 	 * avoids fixing the size lots of places.
33102d09e03SGordon Ross 	 */
33202d09e03SGordon Ross 	newsize = fap->fa_size;
33302d09e03SGordon Ross 	if (vtype == VDIR && newsize < DEV_BSIZE)
33402d09e03SGordon Ross 		newsize = DEV_BSIZE;
33502d09e03SGordon Ross 
336*5f4fc069Sjilinxpd 	if (np->r_size != newsize &&
337*5f4fc069Sjilinxpd 	    (!vn_has_cached_data(vp) ||
338*5f4fc069Sjilinxpd 	    (!(np->r_flags & RDIRTY) && np->r_count == 0))) {
33902d09e03SGordon Ross 		/* OK to set the size. */
34002d09e03SGordon Ross 		np->r_size = newsize;
34102d09e03SGordon Ross 	}
34202d09e03SGordon Ross 
343*5f4fc069Sjilinxpd 	/*
344*5f4fc069Sjilinxpd 	 * Here NFS has:
345*5f4fc069Sjilinxpd 	 * nfs_setswaplike(vp, va);
346*5f4fc069Sjilinxpd 	 * np->r_flags &= ~RWRITEATTR;
347*5f4fc069Sjilinxpd 	 * (not needed here)
348*5f4fc069Sjilinxpd 	 */
34902d09e03SGordon Ross 
350*5f4fc069Sjilinxpd 	np->n_flag &= ~NATTRCHANGED;
35102d09e03SGordon Ross 	mutex_exit(&np->r_statelock);
35202d09e03SGordon Ross 
35302d09e03SGordon Ross 	if (oldvt != vtype) {
35402d09e03SGordon Ross 		SMBVDEBUG("vtype change %d to %d\n", oldvt, vtype);
35502d09e03SGordon Ross 	}
35602d09e03SGordon Ross }
35702d09e03SGordon Ross 
35802d09e03SGordon Ross /*
35902d09e03SGordon Ross  * Fill in attribute from the cache.
36002d09e03SGordon Ross  *
36102d09e03SGordon Ross  * If valid, copy to *fap and return zero,
36202d09e03SGordon Ross  * otherwise return an error.
36302d09e03SGordon Ross  *
36402d09e03SGordon Ross  * From NFS: nfs_getattr_cache()
36502d09e03SGordon Ross  */
36602d09e03SGordon Ross int
36702d09e03SGordon Ross smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap)
36802d09e03SGordon Ross {
36902d09e03SGordon Ross 	smbnode_t *np;
37002d09e03SGordon Ross 	int error;
37102d09e03SGordon Ross 
37202d09e03SGordon Ross 	np = VTOSMB(vp);
37302d09e03SGordon Ross 
37402d09e03SGordon Ross 	mutex_enter(&np->r_statelock);
37502d09e03SGordon Ross 	if (gethrtime() >= np->r_attrtime) {
37602d09e03SGordon Ross 		/* cache expired */
37702d09e03SGordon Ross 		error = ENOENT;
37802d09e03SGordon Ross 	} else {
37902d09e03SGordon Ross 		/* cache is valid */
38002d09e03SGordon Ross 		*fap = np->r_attr;
38102d09e03SGordon Ross 		error = 0;
38202d09e03SGordon Ross 	}
38302d09e03SGordon Ross 	mutex_exit(&np->r_statelock);
38402d09e03SGordon Ross 
38502d09e03SGordon Ross 	return (error);
38602d09e03SGordon Ross }
38702d09e03SGordon Ross 
38802d09e03SGordon Ross /*
38902d09e03SGordon Ross  * Get attributes over-the-wire and update attributes cache
39002d09e03SGordon Ross  * if no error occurred in the over-the-wire operation.
39102d09e03SGordon Ross  * Return 0 if successful, otherwise error.
39202d09e03SGordon Ross  * From NFS: nfs_getattr_otw
39302d09e03SGordon Ross  */
394*5f4fc069Sjilinxpd static int
39502d09e03SGordon Ross smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
39602d09e03SGordon Ross {
39702d09e03SGordon Ross 	struct smbnode *np;
39802d09e03SGordon Ross 	struct smb_cred scred;
39902d09e03SGordon Ross 	int error;
40002d09e03SGordon Ross 
40102d09e03SGordon Ross 	np = VTOSMB(vp);
40202d09e03SGordon Ross 
40302d09e03SGordon Ross 	/*
404*5f4fc069Sjilinxpd 	 * Here NFS uses the ACL RPC (if smi_flags & SMI_ACL)
405bd7c6f51SGordon Ross 	 * With SMB, getting the ACL is a significantly more
406bd7c6f51SGordon Ross 	 * expensive operation, so we do that only when asked
407bd7c6f51SGordon Ross 	 * for the uid/gid.  See smbfsgetattr().
40802d09e03SGordon Ross 	 */
40902d09e03SGordon Ross 
41002d09e03SGordon Ross 	/* Shared lock for (possible) n_fid use. */
41102d09e03SGordon Ross 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
41202d09e03SGordon Ross 		return (EINTR);
41302d09e03SGordon Ross 	smb_credinit(&scred, cr);
41402d09e03SGordon Ross 
41502d09e03SGordon Ross 	bzero(fap, sizeof (*fap));
41602d09e03SGordon Ross 	error = smbfs_smb_getfattr(np, fap, &scred);
41702d09e03SGordon Ross 
41802d09e03SGordon Ross 	smb_credrele(&scred);
41902d09e03SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
42002d09e03SGordon Ross 
42102d09e03SGordon Ross 	if (error) {
422*5f4fc069Sjilinxpd 		/* Here NFS has: PURGE_STALE_FH(error, vp, cr) */
42302d09e03SGordon Ross 		smbfs_attrcache_remove(np);
42402d09e03SGordon Ross 		if (error == ENOENT || error == ENOTDIR) {
42502d09e03SGordon Ross 			/*
42602d09e03SGordon Ross 			 * Getattr failed because the object was
42702d09e03SGordon Ross 			 * removed or renamed by another client.
42802d09e03SGordon Ross 			 * Remove any cached attributes under it.
42902d09e03SGordon Ross 			 */
43002d09e03SGordon Ross 			smbfs_attrcache_prune(np);
43102d09e03SGordon Ross 		}
43202d09e03SGordon Ross 		return (error);
43302d09e03SGordon Ross 	}
43402d09e03SGordon Ross 
43502d09e03SGordon Ross 	/*
436*5f4fc069Sjilinxpd 	 * Here NFS has: nfs_cache_fattr(vap, fa, vap, t, cr);
43702d09e03SGordon Ross 	 * which did: fattr_to_vattr, nfs_attr_cache.
43802d09e03SGordon Ross 	 * We cache the fattr form, so just do the
43902d09e03SGordon Ross 	 * cache check and store the attributes.
44002d09e03SGordon Ross 	 */
441*5f4fc069Sjilinxpd 	smbfs_cache_check(vp, fap, cr);
44202d09e03SGordon Ross 	smbfs_attrcache_fa(vp, fap);
44302d09e03SGordon Ross 
44402d09e03SGordon Ross 	return (0);
44502d09e03SGordon Ross }
44602d09e03SGordon Ross 
44702d09e03SGordon Ross /*
448*5f4fc069Sjilinxpd  * Return either cached or remote attributes. If we get remote attrs,
44902d09e03SGordon Ross  * use them to check and invalidate caches, then cache the new attributes.
45002d09e03SGordon Ross  *
45102d09e03SGordon Ross  * From NFS: nfsgetattr()
45202d09e03SGordon Ross  */
45302d09e03SGordon Ross int
45402d09e03SGordon Ross smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
45502d09e03SGordon Ross {
45602d09e03SGordon Ross 	struct smbfattr fa;
457bd7c6f51SGordon Ross 	smbmntinfo_t *smi;
458bd7c6f51SGordon Ross 	uint_t mask;
45902d09e03SGordon Ross 	int error;
46002d09e03SGordon Ross 
461bd7c6f51SGordon Ross 	smi = VTOSMI(vp);
462bd7c6f51SGordon Ross 
463a19609f8Sjv227347 	ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
464bd7c6f51SGordon Ross 
465bd7c6f51SGordon Ross 	/*
466bd7c6f51SGordon Ross 	 * If asked for UID or GID, update n_uid, n_gid.
467bd7c6f51SGordon Ross 	 */
468bd7c6f51SGordon Ross 	mask = AT_ALL;
469bd7c6f51SGordon Ross 	if (vap->va_mask & (AT_UID | AT_GID)) {
470bd7c6f51SGordon Ross 		if (smi->smi_flags & SMI_ACL)
471bd7c6f51SGordon Ross 			(void) smbfs_acl_getids(vp, cr);
472bd7c6f51SGordon Ross 		/* else leave as set in make_smbnode */
473bd7c6f51SGordon Ross 	} else {
474bd7c6f51SGordon Ross 		mask &= ~(AT_UID | AT_GID);
475bd7c6f51SGordon Ross 	}
47602d09e03SGordon Ross 
47702d09e03SGordon Ross 	/*
47802d09e03SGordon Ross 	 * If we've got cached attributes, just use them;
47902d09e03SGordon Ross 	 * otherwise go to the server to get attributes,
48002d09e03SGordon Ross 	 * which will update the cache in the process.
48102d09e03SGordon Ross 	 */
48202d09e03SGordon Ross 	error = smbfs_getattr_cache(vp, &fa);
48302d09e03SGordon Ross 	if (error)
48402d09e03SGordon Ross 		error = smbfs_getattr_otw(vp, &fa, cr);
48502d09e03SGordon Ross 	if (error)
48602d09e03SGordon Ross 		return (error);
48728162916SGordon Ross 	vap->va_mask |= mask;
48802d09e03SGordon Ross 
48902d09e03SGordon Ross 	/*
49002d09e03SGordon Ross 	 * Re. client's view of the file size, see:
49102d09e03SGordon Ross 	 * smbfs_attrcache_fa, smbfs_getattr_otw
49202d09e03SGordon Ross 	 */
49328162916SGordon Ross 	smbfattr_to_vattr(vp, &fa, vap);
49428162916SGordon Ross 	if (vap->va_mask & AT_XVATTR)
49528162916SGordon Ross 		smbfattr_to_xvattr(&fa, vap);
49602d09e03SGordon Ross 
49728162916SGordon Ross 	return (0);
49802d09e03SGordon Ross }
49902d09e03SGordon Ross 
50002d09e03SGordon Ross 
50102d09e03SGordon Ross /*
50202d09e03SGordon Ross  * Convert SMB over the wire attributes to vnode form.
50302d09e03SGordon Ross  * Returns 0 for success, error if failed (overflow, etc).
50402d09e03SGordon Ross  * From NFS: nattr_to_vattr()
50502d09e03SGordon Ross  */
50628162916SGordon Ross void
50702d09e03SGordon Ross smbfattr_to_vattr(vnode_t *vp, struct smbfattr *fa, struct vattr *vap)
50802d09e03SGordon Ross {
50902d09e03SGordon Ross 	struct smbnode *np = VTOSMB(vp);
51002d09e03SGordon Ross 
51102d09e03SGordon Ross 	/*
51202d09e03SGordon Ross 	 * Take type, mode, uid, gid from the smbfs node,
51302d09e03SGordon Ross 	 * which has have been updated by _getattr_otw.
51402d09e03SGordon Ross 	 */
51502d09e03SGordon Ross 	vap->va_type = vp->v_type;
51602d09e03SGordon Ross 	vap->va_mode = np->n_mode;
51702d09e03SGordon Ross 
51802d09e03SGordon Ross 	vap->va_uid = np->n_uid;
51902d09e03SGordon Ross 	vap->va_gid = np->n_gid;
52002d09e03SGordon Ross 
52102d09e03SGordon Ross 	vap->va_fsid = vp->v_vfsp->vfs_dev;
52202d09e03SGordon Ross 	vap->va_nodeid = np->n_ino;
52302d09e03SGordon Ross 	vap->va_nlink = 1;
52402d09e03SGordon Ross 
52502d09e03SGordon Ross 	/*
52602d09e03SGordon Ross 	 * Difference from NFS here:  We cache attributes as
52702d09e03SGordon Ross 	 * reported by the server, so r_attr.fa_size is the
52802d09e03SGordon Ross 	 * server's idea of the file size.  This is called
52902d09e03SGordon Ross 	 * for getattr, so we want to return the client's
53002d09e03SGordon Ross 	 * idea of the file size.  NFS deals with that in
53102d09e03SGordon Ross 	 * nfsgetattr(), the equivalent of our caller.
53202d09e03SGordon Ross 	 */
53302d09e03SGordon Ross 	vap->va_size = np->r_size;
53402d09e03SGordon Ross 
53502d09e03SGordon Ross 	/*
53602d09e03SGordon Ross 	 * Times.  Note, already converted from NT to
53702d09e03SGordon Ross 	 * Unix form (in the unmarshalling code).
53802d09e03SGordon Ross 	 */
53902d09e03SGordon Ross 	vap->va_atime = fa->fa_atime;
54002d09e03SGordon Ross 	vap->va_mtime = fa->fa_mtime;
54102d09e03SGordon Ross 	vap->va_ctime = fa->fa_ctime;
54202d09e03SGordon Ross 
54302d09e03SGordon Ross 	/*
54402d09e03SGordon Ross 	 * rdev, blksize, seq are made up.
54502d09e03SGordon Ross 	 * va_nblocks is 512 byte blocks.
54602d09e03SGordon Ross 	 */
54702d09e03SGordon Ross 	vap->va_rdev = vp->v_rdev;
54802d09e03SGordon Ross 	vap->va_blksize = MAXBSIZE;
54902d09e03SGordon Ross 	vap->va_nblocks = (fsblkcnt64_t)btod(np->r_attr.fa_allocsz);
55002d09e03SGordon Ross 	vap->va_seq = 0;
55102d09e03SGordon Ross }
55202d09e03SGordon Ross 
55328162916SGordon Ross /*
55428162916SGordon Ross  * smbfattr_to_xvattr: like smbfattr_to_vattr but for
55528162916SGordon Ross  * Extensible system attributes (PSARC 2007/315)
55628162916SGordon Ross  */
55728162916SGordon Ross static void
55828162916SGordon Ross smbfattr_to_xvattr(struct smbfattr *fa, struct vattr *vap)
55928162916SGordon Ross {
56028162916SGordon Ross 	xvattr_t *xvap = (xvattr_t *)vap;	/* *vap may be xvattr_t */
56128162916SGordon Ross 	xoptattr_t *xoap = NULL;
56228162916SGordon Ross 
56328162916SGordon Ross 	if ((xoap = xva_getxoptattr(xvap)) == NULL)
56428162916SGordon Ross 		return;
56528162916SGordon Ross 
56628162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
56728162916SGordon Ross 		xoap->xoa_createtime = fa->fa_createtime;
56828162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_CREATETIME);
56928162916SGordon Ross 	}
57028162916SGordon Ross 
57128162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
57228162916SGordon Ross 		xoap->xoa_archive =
57328162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_ARCHIVE) != 0);
57428162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_ARCHIVE);
57528162916SGordon Ross 	}
57628162916SGordon Ross 
57728162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
57828162916SGordon Ross 		xoap->xoa_system =
57928162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_SYSTEM) != 0);
58028162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_SYSTEM);
58128162916SGordon Ross 	}
58228162916SGordon Ross 
58328162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
58428162916SGordon Ross 		xoap->xoa_readonly =
58528162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_RDONLY) != 0);
58628162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_READONLY);
58728162916SGordon Ross 	}
58828162916SGordon Ross 
58928162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
59028162916SGordon Ross 		xoap->xoa_hidden =
59128162916SGordon Ross 		    ((fa->fa_attr & SMB_FA_HIDDEN) != 0);
59228162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_HIDDEN);
59328162916SGordon Ross 	}
59428162916SGordon Ross }
59502d09e03SGordon Ross 
59602d09e03SGordon Ross /*
597*5f4fc069Sjilinxpd  * Here NFS has:
598*5f4fc069Sjilinxpd  *	nfs_async_... stuff
599*5f4fc069Sjilinxpd  * which we're not using (no async I/O), and:
600*5f4fc069Sjilinxpd  *	writerp(),
601*5f4fc069Sjilinxpd  *	nfs_putpages()
602*5f4fc069Sjilinxpd  *	nfs_invalidate_pages()
603*5f4fc069Sjilinxpd  * which we have in smbfs_vnops.c, and
604*5f4fc069Sjilinxpd  *	nfs_printfhandle()
605*5f4fc069Sjilinxpd  *	nfs_write_error()
606*5f4fc069Sjilinxpd  * not needed here.
607*5f4fc069Sjilinxpd  */
608*5f4fc069Sjilinxpd 
609*5f4fc069Sjilinxpd /*
610*5f4fc069Sjilinxpd  * Helper function for smbfs_sync
611*5f4fc069Sjilinxpd  *
612*5f4fc069Sjilinxpd  * Walk the per-zone list of smbfs mounts, calling smbfs_rflush
613*5f4fc069Sjilinxpd  * on each one.  This is a little tricky because we need to exit
614*5f4fc069Sjilinxpd  * the list mutex before each _rflush call and then try to resume
615*5f4fc069Sjilinxpd  * where we were in the list after re-entering the mutex.
616*5f4fc069Sjilinxpd  */
617*5f4fc069Sjilinxpd void
618*5f4fc069Sjilinxpd smbfs_flushall(cred_t *cr)
619*5f4fc069Sjilinxpd {
620*5f4fc069Sjilinxpd 	smi_globals_t *smg;
621*5f4fc069Sjilinxpd 	smbmntinfo_t *tmp_smi, *cur_smi, *next_smi;
622*5f4fc069Sjilinxpd 
623*5f4fc069Sjilinxpd 	smg = zone_getspecific(smi_list_key, crgetzone(cr));
624*5f4fc069Sjilinxpd 	ASSERT(smg != NULL);
625*5f4fc069Sjilinxpd 
626*5f4fc069Sjilinxpd 	mutex_enter(&smg->smg_lock);
627*5f4fc069Sjilinxpd 	cur_smi = list_head(&smg->smg_list);
628*5f4fc069Sjilinxpd 	if (cur_smi == NULL) {
629*5f4fc069Sjilinxpd 		mutex_exit(&smg->smg_lock);
630*5f4fc069Sjilinxpd 		return;
631*5f4fc069Sjilinxpd 	}
632*5f4fc069Sjilinxpd 	VFS_HOLD(cur_smi->smi_vfsp);
633*5f4fc069Sjilinxpd 	mutex_exit(&smg->smg_lock);
634*5f4fc069Sjilinxpd 
635*5f4fc069Sjilinxpd flush:
636*5f4fc069Sjilinxpd 	smbfs_rflush(cur_smi->smi_vfsp, cr);
637*5f4fc069Sjilinxpd 
638*5f4fc069Sjilinxpd 	mutex_enter(&smg->smg_lock);
639*5f4fc069Sjilinxpd 	/*
640*5f4fc069Sjilinxpd 	 * Resume after cur_smi if that's still on the list,
641*5f4fc069Sjilinxpd 	 * otherwise restart at the head.
642*5f4fc069Sjilinxpd 	 */
643*5f4fc069Sjilinxpd 	for (tmp_smi = list_head(&smg->smg_list);
644*5f4fc069Sjilinxpd 	    tmp_smi != NULL;
645*5f4fc069Sjilinxpd 	    tmp_smi = list_next(&smg->smg_list, tmp_smi))
646*5f4fc069Sjilinxpd 		if (tmp_smi == cur_smi)
647*5f4fc069Sjilinxpd 			break;
648*5f4fc069Sjilinxpd 	if (tmp_smi != NULL)
649*5f4fc069Sjilinxpd 		next_smi = list_next(&smg->smg_list, tmp_smi);
650*5f4fc069Sjilinxpd 	else
651*5f4fc069Sjilinxpd 		next_smi = list_head(&smg->smg_list);
652*5f4fc069Sjilinxpd 
653*5f4fc069Sjilinxpd 	if (next_smi != NULL)
654*5f4fc069Sjilinxpd 		VFS_HOLD(next_smi->smi_vfsp);
655*5f4fc069Sjilinxpd 	VFS_RELE(cur_smi->smi_vfsp);
656*5f4fc069Sjilinxpd 
657*5f4fc069Sjilinxpd 	mutex_exit(&smg->smg_lock);
658*5f4fc069Sjilinxpd 
659*5f4fc069Sjilinxpd 	if (next_smi != NULL) {
660*5f4fc069Sjilinxpd 		cur_smi = next_smi;
661*5f4fc069Sjilinxpd 		goto flush;
662*5f4fc069Sjilinxpd 	}
663*5f4fc069Sjilinxpd }
664*5f4fc069Sjilinxpd 
665*5f4fc069Sjilinxpd /*
66602d09e03SGordon Ross  * SMB Client initialization and cleanup.
66702d09e03SGordon Ross  * Much of it is per-zone now.
66802d09e03SGordon Ross  */
66902d09e03SGordon Ross 
67002d09e03SGordon Ross 
6714bff34e3Sthurlow /* ARGSUSED */
6724bff34e3Sthurlow static void *
6734bff34e3Sthurlow smbfs_zone_init(zoneid_t zoneid)
6744bff34e3Sthurlow {
6754bff34e3Sthurlow 	smi_globals_t *smg;
6764bff34e3Sthurlow 
6774bff34e3Sthurlow 	smg = kmem_alloc(sizeof (*smg), KM_SLEEP);
6784bff34e3Sthurlow 	mutex_init(&smg->smg_lock, NULL, MUTEX_DEFAULT, NULL);
6794bff34e3Sthurlow 	list_create(&smg->smg_list, sizeof (smbmntinfo_t),
6804bff34e3Sthurlow 	    offsetof(smbmntinfo_t, smi_zone_node));
6814bff34e3Sthurlow 	smg->smg_destructor_called = B_FALSE;
6824bff34e3Sthurlow 	return (smg);
6834bff34e3Sthurlow }
6844bff34e3Sthurlow 
6854bff34e3Sthurlow /*
6864bff34e3Sthurlow  * Callback routine to tell all SMBFS mounts in the zone to stop creating new
6874bff34e3Sthurlow  * threads.  Existing threads should exit.
6884bff34e3Sthurlow  */
6894bff34e3Sthurlow /* ARGSUSED */
6904bff34e3Sthurlow static void
6914bff34e3Sthurlow smbfs_zone_shutdown(zoneid_t zoneid, void *data)
6924bff34e3Sthurlow {
6934bff34e3Sthurlow 	smi_globals_t *smg = data;
6944bff34e3Sthurlow 	smbmntinfo_t *smi;
6954bff34e3Sthurlow 
6964bff34e3Sthurlow 	ASSERT(smg != NULL);
6974bff34e3Sthurlow again:
6984bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
6994bff34e3Sthurlow 	for (smi = list_head(&smg->smg_list); smi != NULL;
7004bff34e3Sthurlow 	    smi = list_next(&smg->smg_list, smi)) {
7014bff34e3Sthurlow 
7024bff34e3Sthurlow 		/*
7034bff34e3Sthurlow 		 * If we've done the shutdown work for this FS, skip.
7044bff34e3Sthurlow 		 * Once we go off the end of the list, we're done.
7054bff34e3Sthurlow 		 */
7064bff34e3Sthurlow 		if (smi->smi_flags & SMI_DEAD)
7074bff34e3Sthurlow 			continue;
7084bff34e3Sthurlow 
7094bff34e3Sthurlow 		/*
7104bff34e3Sthurlow 		 * We will do work, so not done.  Get a hold on the FS.
7114bff34e3Sthurlow 		 */
7124bff34e3Sthurlow 		VFS_HOLD(smi->smi_vfsp);
7134bff34e3Sthurlow 
7144bff34e3Sthurlow 		mutex_enter(&smi->smi_lock);
7154bff34e3Sthurlow 		smi->smi_flags |= SMI_DEAD;
7164bff34e3Sthurlow 		mutex_exit(&smi->smi_lock);
7174bff34e3Sthurlow 
7184bff34e3Sthurlow 		/*
7194bff34e3Sthurlow 		 * Drop lock and release FS, which may change list, then repeat.
7204bff34e3Sthurlow 		 * We're done when every mi has been done or the list is empty.
7214bff34e3Sthurlow 		 */
7224bff34e3Sthurlow 		mutex_exit(&smg->smg_lock);
7234bff34e3Sthurlow 		VFS_RELE(smi->smi_vfsp);
7244bff34e3Sthurlow 		goto again;
7254bff34e3Sthurlow 	}
7264bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
7274bff34e3Sthurlow }
7284bff34e3Sthurlow 
7294bff34e3Sthurlow static void
7304bff34e3Sthurlow smbfs_zone_free_globals(smi_globals_t *smg)
7314bff34e3Sthurlow {
7324bff34e3Sthurlow 	list_destroy(&smg->smg_list);	/* makes sure the list is empty */
7334bff34e3Sthurlow 	mutex_destroy(&smg->smg_lock);
7344bff34e3Sthurlow 	kmem_free(smg, sizeof (*smg));
7354bff34e3Sthurlow 
7364bff34e3Sthurlow }
7374bff34e3Sthurlow 
7384bff34e3Sthurlow /* ARGSUSED */
7394bff34e3Sthurlow static void
7404bff34e3Sthurlow smbfs_zone_destroy(zoneid_t zoneid, void *data)
7414bff34e3Sthurlow {
7424bff34e3Sthurlow 	smi_globals_t *smg = data;
7434bff34e3Sthurlow 
7444bff34e3Sthurlow 	ASSERT(smg != NULL);
7454bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7464bff34e3Sthurlow 	if (list_head(&smg->smg_list) != NULL) {
7474bff34e3Sthurlow 		/* Still waiting for VFS_FREEVFS() */
7484bff34e3Sthurlow 		smg->smg_destructor_called = B_TRUE;
7494bff34e3Sthurlow 		mutex_exit(&smg->smg_lock);
7504bff34e3Sthurlow 		return;
7514bff34e3Sthurlow 	}
7524bff34e3Sthurlow 	smbfs_zone_free_globals(smg);
7534bff34e3Sthurlow }
7544bff34e3Sthurlow 
7554bff34e3Sthurlow /*
7564bff34e3Sthurlow  * Add an SMBFS mount to the per-zone list of SMBFS mounts.
7574bff34e3Sthurlow  */
7584bff34e3Sthurlow void
7594bff34e3Sthurlow smbfs_zonelist_add(smbmntinfo_t *smi)
7604bff34e3Sthurlow {
7614bff34e3Sthurlow 	smi_globals_t *smg;
7624bff34e3Sthurlow 
763a19609f8Sjv227347 	smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone);
7644bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7654bff34e3Sthurlow 	list_insert_head(&smg->smg_list, smi);
7664bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
7674bff34e3Sthurlow }
7684bff34e3Sthurlow 
7694bff34e3Sthurlow /*
7704bff34e3Sthurlow  * Remove an SMBFS mount from the per-zone list of SMBFS mounts.
7714bff34e3Sthurlow  */
7724bff34e3Sthurlow void
7734bff34e3Sthurlow smbfs_zonelist_remove(smbmntinfo_t *smi)
7744bff34e3Sthurlow {
7754bff34e3Sthurlow 	smi_globals_t *smg;
7764bff34e3Sthurlow 
777a19609f8Sjv227347 	smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone);
7784bff34e3Sthurlow 	mutex_enter(&smg->smg_lock);
7794bff34e3Sthurlow 	list_remove(&smg->smg_list, smi);
7804bff34e3Sthurlow 	/*
7814bff34e3Sthurlow 	 * We can be called asynchronously by VFS_FREEVFS() after the zone
7824bff34e3Sthurlow 	 * shutdown/destroy callbacks have executed; if so, clean up the zone's
7834bff34e3Sthurlow 	 * smi_globals.
7844bff34e3Sthurlow 	 */
7854bff34e3Sthurlow 	if (list_head(&smg->smg_list) == NULL &&
7864bff34e3Sthurlow 	    smg->smg_destructor_called == B_TRUE) {
7874bff34e3Sthurlow 		smbfs_zone_free_globals(smg);
7884bff34e3Sthurlow 		return;
7894bff34e3Sthurlow 	}
7904bff34e3Sthurlow 	mutex_exit(&smg->smg_lock);
7914bff34e3Sthurlow }
7924bff34e3Sthurlow 
793613a2f6bSGordon Ross #ifdef	lint
794613a2f6bSGordon Ross #define	NEED_SMBFS_CALLBACKS	1
795613a2f6bSGordon Ross #endif
7964bff34e3Sthurlow 
7974bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
7984bff34e3Sthurlow /*
7994bff34e3Sthurlow  * Call-back hooks for netsmb, in case we want them.
8004bff34e3Sthurlow  * Apple's VFS wants them.  We may not need them.
8014bff34e3Sthurlow  */
802613a2f6bSGordon Ross /*ARGSUSED*/
8034bff34e3Sthurlow static void smbfs_dead(smb_share_t *ssp)
8044bff34e3Sthurlow {
805613a2f6bSGordon Ross 	/*
806613a2f6bSGordon Ross 	 * Walk the mount list, finding all mounts
807613a2f6bSGordon Ross 	 * using this share...
808613a2f6bSGordon Ross 	 */
8094bff34e3Sthurlow }
8104bff34e3Sthurlow 
811613a2f6bSGordon Ross /*ARGSUSED*/
812613a2f6bSGordon Ross static void smbfs_cb_nop(smb_share_t *ss)
8134bff34e3Sthurlow {
8144bff34e3Sthurlow 	/* no-op */
8154bff34e3Sthurlow }
8164bff34e3Sthurlow 
8174bff34e3Sthurlow smb_fscb_t smbfs_cb = {
818613a2f6bSGordon Ross 	.fscb_disconn	= smbfs_dead,
819613a2f6bSGordon Ross 	.fscb_connect	= smbfs_cb_nop,
820613a2f6bSGordon Ross 	.fscb_down	= smbfs_cb_nop,
821613a2f6bSGordon Ross 	.fscb_up	= smbfs_cb_nop };
8224bff34e3Sthurlow 
8234bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8244bff34e3Sthurlow 
8254bff34e3Sthurlow /*
8264bff34e3Sthurlow  * SMBFS Client initialization routine.  This routine should only be called
8274bff34e3Sthurlow  * once.  It performs the following tasks:
8284bff34e3Sthurlow  *      - Initalize all global locks
8294bff34e3Sthurlow  *      - Call sub-initialization routines (localize access to variables)
8304bff34e3Sthurlow  */
8314bff34e3Sthurlow int
8324bff34e3Sthurlow smbfs_clntinit(void)
8334bff34e3Sthurlow {
8344bff34e3Sthurlow 
8354bff34e3Sthurlow 	zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown,
8364bff34e3Sthurlow 	    smbfs_zone_destroy);
8374bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
838c1374a13SSurya Prakki 	(void) smb_fscb_set(&smbfs_cb);
8394bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8404bff34e3Sthurlow 	return (0);
8414bff34e3Sthurlow }
8424bff34e3Sthurlow 
8434bff34e3Sthurlow /*
8444bff34e3Sthurlow  * This routine is called when the modunload is called. This will cleanup
8454bff34e3Sthurlow  * the previously allocated/initialized nodes.
8464bff34e3Sthurlow  */
8474bff34e3Sthurlow void
8484bff34e3Sthurlow smbfs_clntfini(void)
8494bff34e3Sthurlow {
8504bff34e3Sthurlow #ifdef NEED_SMBFS_CALLBACKS
851c1374a13SSurya Prakki 	(void) smb_fscb_set(NULL);
8524bff34e3Sthurlow #endif /* NEED_SMBFS_CALLBACKS */
8534bff34e3Sthurlow 	(void) zone_key_delete(smi_list_key);
8544bff34e3Sthurlow }
855