xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 9231:152b6e0d9b1a)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
228670SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw /*
265331Samw  * SMB Node State Machine
275331Samw  * ----------------------
285331Samw  *
299021Samw@Sun.COM  *
309021Samw@Sun.COM  *		    +----------- Creation/Allocation
315331Samw  *		    |
329021Samw@Sun.COM  *		    | T0
335331Samw  *		    |
345331Samw  *		    v
359021Samw@Sun.COM  *    +----------------------------+        T1
369021Samw@Sun.COM  *    |  SMB_NODE_STATE_AVAILABLE  |--------------------+
379021Samw@Sun.COM  *    +----------------------------+			|
389021Samw@Sun.COM  *		    |	     ^				|
399021Samw@Sun.COM  *		    |	     |				v
409021Samw@Sun.COM  *		    |	     |	  T2	+-------------------------------+
419021Samw@Sun.COM  *		    |	     |<---------| SMB_NODE_STATE_OPLOCK_GRANTED |
429021Samw@Sun.COM  *		    |	     |		+-------------------------------+
439021Samw@Sun.COM  *		    | T5     |				|
449021Samw@Sun.COM  *		    |	     |				| T3
459021Samw@Sun.COM  *		    |	     |				v
469021Samw@Sun.COM  *		    |	     |	  T4	+--------------------------------+
479021Samw@Sun.COM  *		    |	     +----------| SMB_NODE_STATE_OPLOCK_BREAKING |
489021Samw@Sun.COM  *		    |			+--------------------------------+
499021Samw@Sun.COM  *		    |
509021Samw@Sun.COM  *		    v
515331Samw  *    +-----------------------------+
529021Samw@Sun.COM  *    |  SMB_NODE_STATE_DESTROYING  |
539021Samw@Sun.COM  *    +-----------------------------+
549021Samw@Sun.COM  *		    |
559021Samw@Sun.COM  *		    |
569021Samw@Sun.COM  *		    | T6
579021Samw@Sun.COM  *		    |
589021Samw@Sun.COM  *		    +----------> Deletion/Free
595331Samw  *
605331Samw  * Transition T0
615331Samw  *
625331Samw  *    This transition occurs in smb_node_lookup(). If the node looked for is
635331Samw  *    not found in the has table a new node is created. The reference count is
645331Samw  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
655331Samw  *
665331Samw  * Transition T1
675331Samw  *
689021Samw@Sun.COM  *    This transition occurs smb_oplock_acquire() during an OPEN.
699021Samw@Sun.COM  *
709021Samw@Sun.COM  * Transition T2
719021Samw@Sun.COM  *
729021Samw@Sun.COM  *    This transition occurs in smb_oplock_release(). The events triggering
739021Samw@Sun.COM  *    it are:
749021Samw@Sun.COM  *
759021Samw@Sun.COM  *	- LockingAndX sent by the client that was granted the oplock.
769021Samw@Sun.COM  *	- Closing of the file.
779021Samw@Sun.COM  *
789021Samw@Sun.COM  * Transition T3
799021Samw@Sun.COM  *
809021Samw@Sun.COM  *    This transition occurs in smb_oplock_break(). The events triggering
819021Samw@Sun.COM  *    it are:
829021Samw@Sun.COM  *
839021Samw@Sun.COM  *	- Another client wants to open the file.
849021Samw@Sun.COM  *	- A client is trying to delete the file.
859021Samw@Sun.COM  *	- A client is trying to rename the file.
869021Samw@Sun.COM  *	- A client is trying to set/modify  the file attributes.
879021Samw@Sun.COM  *
889021Samw@Sun.COM  * Transition T4
899021Samw@Sun.COM  *
909021Samw@Sun.COM  *    This transition occurs in smb_oplock_release or smb_oplock_break(). The
919021Samw@Sun.COM  *    events triggering it are:
929021Samw@Sun.COM  *
939021Samw@Sun.COM  *	- The client that was granting the oplock releases it (close or
949021Samw@Sun.COM  *	  LockingAndx).
959021Samw@Sun.COM  *	- The time alloted to release the oplock expired.
969021Samw@Sun.COM  *
979021Samw@Sun.COM  * Transition T5
989021Samw@Sun.COM  *
995331Samw  *    This transition occurs in smb_node_release(). If the reference count
1005331Samw  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
1015331Samw  *    reference count will be given out for that node.
1025331Samw  *
1039021Samw@Sun.COM  * Transition T6
1045331Samw  *
1055331Samw  *    This transition occurs in smb_node_release(). The structure is deleted.
1065331Samw  *
1075331Samw  * Comments
1085331Samw  * --------
1095331Samw  *
1105331Samw  *    The reason the smb node has 2 states is the following synchronization
1115331Samw  *    rule:
1125331Samw  *
1135331Samw  *    There's a mutex embedded in the node used to protect its fields and
1145331Samw  *    there's a lock embedded in the bucket of the hash table the node belongs
1155331Samw  *    to. To increment or to decrement the reference count the mutex must be
1165331Samw  *    entered. To insert the node into the bucket and to remove it from the
1175331Samw  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
1185331Samw  *    lock) have to be entered, the lock has always to be entered first then
1195331Samw  *    the mutex. This prevents a deadlock between smb_node_lookup() and
1205331Samw  *    smb_node_release() from occurring. However, in smb_node_release() when the
1215331Samw  *    reference count drops to zero and triggers the deletion of the node, the
1225331Samw  *    mutex has to be released before entering the lock of the bucket (to
1235331Samw  *    remove the node). This creates a window during which the node that is
1245331Samw  *    about to be freed could be given out by smb_node_lookup(). To close that
1255331Samw  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
1265331Samw  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
1275331Samw  *    state will indicate that the node should be treated as non existent (of
1285331Samw  *    course the state of the node should be tested/updated under the
1295331Samw  *    protection of the mutex).
1305331Samw  */
1315331Samw #include <smbsrv/smb_incl.h>
1325331Samw #include <smbsrv/smb_fsops.h>
1338934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h>
1345331Samw #include <sys/pathname.h>
1355331Samw #include <sys/sdt.h>
1365772Sas200622 #include <sys/nbmlock.h>
1375331Samw 
1388934SJose.Borrego@Sun.COM uint32_t smb_is_executable(char *);
1398934SJose.Borrego@Sun.COM static void smb_node_delete_on_close(smb_node_t *);
1408934SJose.Borrego@Sun.COM static void smb_node_create_audit_buf(smb_node_t *, int);
1418934SJose.Borrego@Sun.COM static void smb_node_destroy_audit_buf(smb_node_t *);
1428934SJose.Borrego@Sun.COM static void smb_node_audit(smb_node_t *);
1438934SJose.Borrego@Sun.COM static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_attr_t *,
1448934SJose.Borrego@Sun.COM     smb_llist_t *bucket, uint32_t hashkey);
1458934SJose.Borrego@Sun.COM static void smb_node_free(smb_node_t *);
1468934SJose.Borrego@Sun.COM static int smb_node_constructor(void *, void *, int);
1478934SJose.Borrego@Sun.COM static void smb_node_destructor(void *, void *);
1488934SJose.Borrego@Sun.COM static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
1495331Samw 
1505331Samw #define	VALIDATE_DIR_NODE(_dir_, _node_) \
1515331Samw     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
1525331Samw     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
1535331Samw     ASSERT((_dir_)->dir_snode != (_node_));
1545331Samw 
1558934SJose.Borrego@Sun.COM static kmem_cache_t	*smb_node_cache = NULL;
1566139Sjb150015 static boolean_t	smb_node_initialized = B_FALSE;
1576139Sjb150015 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
1586139Sjb150015 
1596139Sjb150015 /*
1606139Sjb150015  * smb_node_init
1616139Sjb150015  *
1626139Sjb150015  * Initialization of the SMB node layer.
1636139Sjb150015  *
1646139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1656139Sjb150015  * thread makes the call.
1666139Sjb150015  */
1676139Sjb150015 int
1686139Sjb150015 smb_node_init(void)
1696139Sjb150015 {
1706139Sjb150015 	int	i;
1716139Sjb150015 
1726139Sjb150015 	if (smb_node_initialized)
1736139Sjb150015 		return (0);
1748934SJose.Borrego@Sun.COM 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
1758934SJose.Borrego@Sun.COM 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
1768934SJose.Borrego@Sun.COM 	    NULL, NULL, NULL, 0);
1776139Sjb150015 
1786139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
1796139Sjb150015 		smb_llist_constructor(&smb_node_hash_table[i],
1806139Sjb150015 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
1816139Sjb150015 	}
1826139Sjb150015 	smb_node_initialized = B_TRUE;
1836139Sjb150015 	return (0);
1846139Sjb150015 }
1856139Sjb150015 
1866139Sjb150015 /*
1876139Sjb150015  * smb_node_fini
1886139Sjb150015  *
1896139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1906139Sjb150015  * thread makes the call.
1916139Sjb150015  */
1926139Sjb150015 void
1936139Sjb150015 smb_node_fini(void)
1946139Sjb150015 {
1956139Sjb150015 	int	i;
1966139Sjb150015 
1976139Sjb150015 	if (!smb_node_initialized)
1986139Sjb150015 		return;
1996139Sjb150015 
2006139Sjb150015 #ifdef DEBUG
2016139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
2026139Sjb150015 		smb_node_t	*node;
2036139Sjb150015 
2046139Sjb150015 		/*
2056139Sjb150015 		 * The following sequence is just intended for sanity check.
2066139Sjb150015 		 * This will have to be modified when the code goes into
2076139Sjb150015 		 * production.
2086139Sjb150015 		 *
2096139Sjb150015 		 * The SMB node hash table should be emtpy at this point. If the
2106139Sjb150015 		 * hash table is not empty a panic will be triggered.
2116139Sjb150015 		 *
2126139Sjb150015 		 * The reason why SMB nodes are still remaining in the hash
2136139Sjb150015 		 * table is problably due to a mismatch between calls to
2146139Sjb150015 		 * smb_node_lookup() and smb_node_release(). You must track that
2156139Sjb150015 		 * down.
2166139Sjb150015 		 */
2176139Sjb150015 		node = smb_llist_head(&smb_node_hash_table[i]);
2186139Sjb150015 		ASSERT(node == NULL);
2196139Sjb150015 	}
2206139Sjb150015 #endif
2216139Sjb150015 
2226139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
2236139Sjb150015 		smb_llist_destructor(&smb_node_hash_table[i]);
2246139Sjb150015 	}
2258934SJose.Borrego@Sun.COM 	kmem_cache_destroy(smb_node_cache);
2268934SJose.Borrego@Sun.COM 	smb_node_cache = NULL;
2276139Sjb150015 	smb_node_initialized = B_FALSE;
2286139Sjb150015 }
2296139Sjb150015 
2305331Samw /*
2315331Samw  * smb_node_lookup()
2325331Samw  *
2335331Samw  * NOTE: This routine should only be called by the file system interface layer,
2345331Samw  * and not by SMB.
2355331Samw  *
2365331Samw  * smb_node_lookup() is called upon successful lookup, mkdir, and create
2375331Samw  * (for both non-streams and streams).  In each of these cases, a held vnode is
2388670SJose.Borrego@Sun.COM  * passed into this routine.  If a new smb_node is created it will take its
2398670SJose.Borrego@Sun.COM  * own hold on the vnode.  The caller's hold therefore still belongs to, and
2408670SJose.Borrego@Sun.COM  * should be released by, the caller.
2415331Samw  *
2425331Samw  * A reference is taken on the smb_node whether found in the hash table
2435331Samw  * or newly created.
2445331Samw  *
2455331Samw  * If an smb_node needs to be created, a reference is also taken on the
2465331Samw  * dir_snode (if passed in).
2475331Samw  *
2485331Samw  * See smb_node_release() for details on the release of these references.
2495331Samw  */
2505331Samw 
2515331Samw /*ARGSUSED*/
2525331Samw smb_node_t *
2535331Samw smb_node_lookup(
2545331Samw     struct smb_request	*sr,
2555331Samw     struct open_param	*op,
2565331Samw     cred_t		*cred,
2575331Samw     vnode_t		*vp,
2585331Samw     char		*od_name,
2595331Samw     smb_node_t		*dir_snode,
2605331Samw     smb_node_t		*unnamed_node,
2615331Samw     smb_attr_t		*attr)
2625331Samw {
2635331Samw 	smb_llist_t		*node_hdr;
2645331Samw 	smb_node_t		*node;
2655331Samw 	uint32_t		hashkey = 0;
2667348SJose.Borrego@Sun.COM 	fsid_t			fsid;
2675331Samw 	int			error;
2685331Samw 	krw_t			lock_mode;
2695331Samw 	vnode_t			*unnamed_vp = NULL;
2705331Samw 
2715331Samw 	/*
2725331Samw 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
2735331Samw 	 * because the node may not yet exist.  We also do not want to call
2745331Samw 	 * it with the list lock held.
2755331Samw 	 */
2765331Samw 
2775331Samw 	if (unnamed_node)
2785331Samw 		unnamed_vp = unnamed_node->vp;
2795331Samw 
2805331Samw 	/*
2815331Samw 	 * This getattr is performed on behalf of the server
2825331Samw 	 * that's why kcred is used not the user's cred
2835331Samw 	 */
2845331Samw 	attr->sa_mask = SMB_AT_ALL;
2855772Sas200622 	error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred);
2865331Samw 	if (error)
2875331Samw 		return (NULL);
2885331Samw 
2897348SJose.Borrego@Sun.COM 	if (sr && sr->tid_tree) {
2907348SJose.Borrego@Sun.COM 		/*
2917348SJose.Borrego@Sun.COM 		 * The fsid for a file is that of the tree, even
2927348SJose.Borrego@Sun.COM 		 * if the file resides in a different mountpoint
2937348SJose.Borrego@Sun.COM 		 * under the share.
2947348SJose.Borrego@Sun.COM 		 */
2957348SJose.Borrego@Sun.COM 		fsid = SMB_TREE_FSID(sr->tid_tree);
2965331Samw 	} else {
2977348SJose.Borrego@Sun.COM 		/*
2987348SJose.Borrego@Sun.COM 		 * This should be getting executed only for the
2997348SJose.Borrego@Sun.COM 		 * tree root smb_node.
3007348SJose.Borrego@Sun.COM 		 */
3017348SJose.Borrego@Sun.COM 		fsid = vp->v_vfsp->vfs_fsid;
3025331Samw 	}
3035331Samw 
3048934SJose.Borrego@Sun.COM 	node_hdr = smb_node_get_hash(&fsid, attr, &hashkey);
3055331Samw 	lock_mode = RW_READER;
3065331Samw 
3075331Samw 	smb_llist_enter(node_hdr, lock_mode);
3085331Samw 	for (;;) {
3095331Samw 		node = list_head(&node_hdr->ll_list);
3105331Samw 		while (node) {
3115331Samw 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
3125331Samw 			ASSERT(node->n_hash_bucket == node_hdr);
3135331Samw 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
3148934SJose.Borrego@Sun.COM 				mutex_enter(&node->n_mutex);
3155331Samw 				DTRACE_PROBE1(smb_node_lookup_hit,
3165331Samw 				    smb_node_t *, node);
3175331Samw 				switch (node->n_state) {
3188934SJose.Borrego@Sun.COM 				case SMB_NODE_STATE_OPLOCK_GRANTED:
3198934SJose.Borrego@Sun.COM 				case SMB_NODE_STATE_OPLOCK_BREAKING:
3205331Samw 				case SMB_NODE_STATE_AVAILABLE:
3215331Samw 					/* The node was found. */
3225331Samw 					node->n_refcnt++;
3235331Samw 					if ((node->dir_snode == NULL) &&
3245331Samw 					    (dir_snode != NULL) &&
3255331Samw 					    (strcmp(od_name, "..") != 0) &&
3265331Samw 					    (strcmp(od_name, ".") != 0)) {
3275331Samw 						VALIDATE_DIR_NODE(dir_snode,
3285331Samw 						    node);
3295331Samw 						node->dir_snode = dir_snode;
3305331Samw 						smb_node_ref(dir_snode);
3315331Samw 					}
3325331Samw 					node->attr = *attr;
3335772Sas200622 					node->n_size = attr->sa_vattr.va_size;
3345331Samw 
3358934SJose.Borrego@Sun.COM 					smb_node_audit(node);
3368934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3375331Samw 					smb_llist_exit(node_hdr);
3385331Samw 					return (node);
3395331Samw 
3405331Samw 				case SMB_NODE_STATE_DESTROYING:
3415331Samw 					/*
3425331Samw 					 * Although the node exists it is about
3435331Samw 					 * to be destroyed. We act as it hasn't
3445331Samw 					 * been found.
3455331Samw 					 */
3468934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3475331Samw 					break;
3485331Samw 				default:
3495331Samw 					/*
3505331Samw 					 * Although the node exists it is in an
3515331Samw 					 * unknown state. We act as it hasn't
3525331Samw 					 * been found.
3535331Samw 					 */
3545331Samw 					ASSERT(0);
3558934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3565331Samw 					break;
3575331Samw 				}
3585331Samw 			}
3595331Samw 			node = smb_llist_next(node_hdr, node);
3605331Samw 		}
3615331Samw 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
3625331Samw 			lock_mode = RW_WRITER;
3635331Samw 			continue;
3645331Samw 		}
3655331Samw 		break;
3665331Samw 	}
3678934SJose.Borrego@Sun.COM 	node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey);
3688934SJose.Borrego@Sun.COM 	node->n_orig_uid = crgetuid(sr->user_cr);
3695331Samw 
3705331Samw 	if (op)
3715331Samw 		node->flags |= smb_is_executable(op->fqi.last_comp);
3725331Samw 
3735331Samw 	if (dir_snode) {
3745331Samw 		smb_node_ref(dir_snode);
3755331Samw 		node->dir_snode = dir_snode;
3765331Samw 		ASSERT(dir_snode->dir_snode != node);
3775331Samw 		ASSERT((dir_snode->vp->v_xattrdir) ||
3785331Samw 		    (dir_snode->vp->v_type == VDIR));
3795331Samw 	}
3805331Samw 
3815331Samw 	if (unnamed_node) {
3825331Samw 		smb_node_ref(unnamed_node);
3835331Samw 		node->unnamed_stream_node = unnamed_node;
3845331Samw 	}
3855331Samw 
3865331Samw 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
3878934SJose.Borrego@Sun.COM 	smb_node_audit(node);
3885331Samw 	smb_llist_insert_head(node_hdr, node);
3895331Samw 	smb_llist_exit(node_hdr);
3905331Samw 	return (node);
3915331Samw }
3925331Samw 
3935331Samw /*
3945331Samw  * smb_stream_node_lookup()
3955331Samw  *
3965331Samw  * Note: stream_name (the name that will be stored in the "od_name" field
3975331Samw  * of a stream's smb_node) is the same as the on-disk name for the stream
3985331Samw  * except that it does not have SMB_STREAM_PREFIX prepended.
3995331Samw  */
4005331Samw 
4015331Samw smb_node_t *
4028934SJose.Borrego@Sun.COM smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
4035331Samw     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
4045331Samw {
4055331Samw 	smb_node_t	*xattrdir_node;
4065331Samw 	smb_node_t	*snode;
4075331Samw 	smb_attr_t	tmp_attr;
4085331Samw 
4095331Samw 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
4105331Samw 	    fnode, NULL, &tmp_attr);
4115331Samw 
4125331Samw 	if (xattrdir_node == NULL)
4135331Samw 		return (NULL);
4145331Samw 
4155331Samw 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
4165331Samw 	    fnode, ret_attr);
4175331Samw 
4185331Samw 	(void) smb_node_release(xattrdir_node);
4195331Samw 	return (snode);
4205331Samw }
4215331Samw 
4225331Samw 
4235331Samw /*
4245331Samw  * This function should be called whenever a reference is needed on an
4255331Samw  * smb_node pointer.  The copy of an smb_node pointer from one non-local
4265331Samw  * data structure to another requires a reference to be taken on the smb_node
4275331Samw  * (unless the usage is localized).  Each data structure deallocation routine
4285331Samw  * will call smb_node_release() on its smb_node pointers.
4295331Samw  *
4305331Samw  * In general, an smb_node pointer residing in a structure should never be
4315331Samw  * stale.  A node pointer may be NULL, however, and care should be taken
4325331Samw  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
4335331Samw  * Care also needs to be taken with respect to racing deallocations of a
4345331Samw  * structure.
4355331Samw  */
4365331Samw void
4375331Samw smb_node_ref(smb_node_t *node)
4385331Samw {
4398934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
4405331Samw 
4418934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
4428934SJose.Borrego@Sun.COM 	switch (node->n_state) {
4438934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
4448934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
4458934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
4468934SJose.Borrego@Sun.COM 		node->n_refcnt++;
4478934SJose.Borrego@Sun.COM 		ASSERT(node->n_refcnt);
4488934SJose.Borrego@Sun.COM 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
4498934SJose.Borrego@Sun.COM 		smb_node_audit(node);
4508934SJose.Borrego@Sun.COM 		break;
4518934SJose.Borrego@Sun.COM 	default:
4528934SJose.Borrego@Sun.COM 		SMB_PANIC();
4538934SJose.Borrego@Sun.COM 	}
4548934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
4555331Samw }
4565331Samw 
4575331Samw /*
4585331Samw  * smb_node_lookup() takes a hold on an smb_node, whether found in the
4595331Samw  * hash table or newly created.  This hold is expected to be released
4605331Samw  * in the following manner.
4615331Samw  *
4625331Samw  * smb_node_lookup() takes an address of an smb_node pointer.  This should
4635331Samw  * be getting passed down via a lookup (whether path name or component), mkdir,
4645331Samw  * create.  If the original smb_node pointer resides in a data structure, then
4655331Samw  * the deallocation routine for the data structure is responsible for calling
4665331Samw  * smb_node_release() on the smb_node pointer.  Alternatively,
4675331Samw  * smb_node_release() can be called as soon as the smb_node pointer is no longer
4685331Samw  * needed.  In this case, callers are responsible for setting an embedded
4695331Samw  * pointer to NULL if it is known that the last reference is being released.
4705331Samw  *
4715331Samw  * If the passed-in address of the smb_node pointer belongs to a local variable,
4725331Samw  * then the caller with the local variable should call smb_node_release()
4735331Samw  * directly.
4745331Samw  *
4755331Samw  * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
4765331Samw  * as smb_node_lookup() takes a hold on dir_snode.
4775331Samw  */
4785331Samw void
4795331Samw smb_node_release(smb_node_t *node)
4805331Samw {
4818934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
4825331Samw 
4838934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
4845331Samw 	ASSERT(node->n_refcnt);
4855331Samw 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
4865331Samw 	if (--node->n_refcnt == 0) {
4875331Samw 		switch (node->n_state) {
4885331Samw 
4895331Samw 		case SMB_NODE_STATE_AVAILABLE:
4905331Samw 			node->n_state = SMB_NODE_STATE_DESTROYING;
4918934SJose.Borrego@Sun.COM 			mutex_exit(&node->n_mutex);
4925331Samw 
4935331Samw 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
4945331Samw 			smb_llist_remove(node->n_hash_bucket, node);
4955331Samw 			smb_llist_exit(node->n_hash_bucket);
4965331Samw 
4975331Samw 			/*
4985331Samw 			 * Check if the file was deleted
4995331Samw 			 */
5005331Samw 			smb_node_delete_on_close(node);
5015331Samw 
5025331Samw 			if (node->dir_snode) {
5035331Samw 				ASSERT(node->dir_snode->n_magic ==
5045331Samw 				    SMB_NODE_MAGIC);
5055331Samw 				smb_node_release(node->dir_snode);
5065331Samw 			}
5075331Samw 
5085331Samw 			if (node->unnamed_stream_node) {
5095331Samw 				ASSERT(node->unnamed_stream_node->n_magic ==
5105331Samw 				    SMB_NODE_MAGIC);
5115331Samw 				smb_node_release(node->unnamed_stream_node);
5125331Samw 			}
5135331Samw 
5148934SJose.Borrego@Sun.COM 			smb_node_free(node);
5155331Samw 			return;
5165331Samw 
5175331Samw 		default:
5188934SJose.Borrego@Sun.COM 			SMB_PANIC();
5195331Samw 		}
5205331Samw 	}
5218934SJose.Borrego@Sun.COM 	smb_node_audit(node);
5228934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
5235331Samw }
5245331Samw 
5255331Samw static void
5265331Samw smb_node_delete_on_close(smb_node_t *node)
5275331Samw {
5285331Samw 	smb_node_t	*d_snode;
5295331Samw 	int		rc = 0;
530*9231SAfshin.Ardakani@Sun.COM 	uint32_t	flags = 0;
5315331Samw 
5325331Samw 	d_snode = node->dir_snode;
5335331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
534*9231SAfshin.Ardakani@Sun.COM 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
535*9231SAfshin.Ardakani@Sun.COM 		flags = node->n_delete_on_close_flags;
536*9231SAfshin.Ardakani@Sun.COM 		ASSERT(node->od_name != NULL);
5375331Samw 
5385331Samw 		if (node->attr.sa_vattr.va_type == VDIR)
5395331Samw 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
540*9231SAfshin.Ardakani@Sun.COM 			    d_snode, node->od_name, flags);
5415331Samw 		else
5425331Samw 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
543*9231SAfshin.Ardakani@Sun.COM 			    d_snode, node->od_name, flags);
5445331Samw 		smb_cred_rele(node->delete_on_close_cred);
5455331Samw 	}
5465331Samw 	if (rc != 0)
5475331Samw 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
5485331Samw 		    node->od_name, rc);
5495331Samw 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
5505331Samw }
5515331Samw 
5525331Samw /*
5535331Samw  * smb_node_rename()
5545331Samw  *
5555331Samw  */
5568934SJose.Borrego@Sun.COM void
5575331Samw smb_node_rename(
5588934SJose.Borrego@Sun.COM     smb_node_t	*from_dnode,
5598934SJose.Borrego@Sun.COM     smb_node_t	*ret_node,
5608934SJose.Borrego@Sun.COM     smb_node_t	*to_dnode,
5615331Samw     char	*to_name)
5625331Samw {
5638934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(from_dnode);
5648934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(to_dnode);
5658934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(ret_node);
5665331Samw 
5678934SJose.Borrego@Sun.COM 	smb_node_ref(to_dnode);
5688934SJose.Borrego@Sun.COM 	mutex_enter(&ret_node->n_mutex);
5698934SJose.Borrego@Sun.COM 	switch (ret_node->n_state) {
5708934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
5718934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
5728934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
5738934SJose.Borrego@Sun.COM 		ret_node->dir_snode = to_dnode;
5748934SJose.Borrego@Sun.COM 		mutex_exit(&ret_node->n_mutex);
5758934SJose.Borrego@Sun.COM 		ASSERT(to_dnode->dir_snode != ret_node);
5768934SJose.Borrego@Sun.COM 		ASSERT((to_dnode->vp->v_xattrdir) ||
5778934SJose.Borrego@Sun.COM 		    (to_dnode->vp->v_type == VDIR));
5788934SJose.Borrego@Sun.COM 		smb_node_release(from_dnode);
5798934SJose.Borrego@Sun.COM 		(void) strcpy(ret_node->od_name, to_name);
5808934SJose.Borrego@Sun.COM 		/*
5818934SJose.Borrego@Sun.COM 		 * XXX Need to update attributes?
5828934SJose.Borrego@Sun.COM 		 */
5838934SJose.Borrego@Sun.COM 		break;
5848934SJose.Borrego@Sun.COM 	default:
5858934SJose.Borrego@Sun.COM 		SMB_PANIC();
5868934SJose.Borrego@Sun.COM 	}
5875331Samw }
5885331Samw 
5895331Samw int
5906139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
5915331Samw {
5926139Sjb150015 	smb_attr_t	va;
5936139Sjb150015 	int		error;
5946139Sjb150015 	uint32_t	hashkey;
5956139Sjb150015 	smb_llist_t	*node_hdr;
5966139Sjb150015 	smb_node_t	*node;
5975331Samw 
5986139Sjb150015 	va.sa_mask = SMB_AT_ALL;
5996139Sjb150015 	error = smb_vop_getattr(vp, NULL, &va, 0, kcred);
6006139Sjb150015 	if (error) {
6016139Sjb150015 		VN_RELE(vp);
6026139Sjb150015 		return (error);
6036139Sjb150015 	}
6046139Sjb150015 
6058934SJose.Borrego@Sun.COM 	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey);
6065331Samw 
6078934SJose.Borrego@Sun.COM 	node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey);
6086139Sjb150015 
6096139Sjb150015 	sv->si_root_smb_node = node;
6108934SJose.Borrego@Sun.COM 	smb_node_audit(node);
6116139Sjb150015 	smb_llist_enter(node_hdr, RW_WRITER);
6126139Sjb150015 	smb_llist_insert_head(node_hdr, node);
6136139Sjb150015 	smb_llist_exit(node_hdr);
6146139Sjb150015 	*root = node;
6156139Sjb150015 	return (0);
6165331Samw }
6175331Samw 
6185331Samw /*
6195331Samw  * smb_node_get_size
6205331Samw  */
6216432Sas200622 u_offset_t
6226432Sas200622 smb_node_get_size(smb_node_t *node, smb_attr_t *attr)
6235331Samw {
6246432Sas200622 	u_offset_t size;
6255331Samw 
6265331Samw 	if (attr->sa_vattr.va_type == VDIR)
6275331Samw 		return (0);
6285331Samw 
6298934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
6305331Samw 	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
6315331Samw 		size = node->n_size;
6325331Samw 	else
6335331Samw 		size = attr->sa_vattr.va_size;
6348934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
6355331Samw 	return (size);
6365331Samw }
6375331Samw 
6385331Samw static int
6395331Samw timeval_cmp(timestruc_t *a, timestruc_t *b)
6405331Samw {
6415331Samw 	if (a->tv_sec < b->tv_sec)
6425331Samw 		return (-1);
6435331Samw 	if (a->tv_sec > b->tv_sec)
6445331Samw 		return (1);
6455331Samw 	/* Seconds are equal compare tv_nsec */
6465331Samw 	if (a->tv_nsec < b->tv_nsec)
6475331Samw 		return (-1);
6485331Samw 	return (a->tv_nsec > b->tv_nsec);
6495331Samw }
6505331Samw 
6515331Samw /*
6525331Samw  * smb_node_set_time
6535331Samw  *
6545331Samw  * This function will update the time stored in the node and
6557348SJose.Borrego@Sun.COM  * set the appropriate flags. If there is nothing to update,
6567348SJose.Borrego@Sun.COM  * the function will return without any updates.  The update
6577348SJose.Borrego@Sun.COM  * is only in the node level and the attribute in the file system
6587348SJose.Borrego@Sun.COM  * will be updated when client close the file.
6595331Samw  */
6605331Samw void
6618934SJose.Borrego@Sun.COM smb_node_set_time(
6628934SJose.Borrego@Sun.COM     smb_node_t	*node,
6638934SJose.Borrego@Sun.COM     timestruc_t	*crtime,
6648934SJose.Borrego@Sun.COM     timestruc_t	*mtime,
6658934SJose.Borrego@Sun.COM     timestruc_t	*atime,
6668934SJose.Borrego@Sun.COM     timestruc_t	*ctime,
6678934SJose.Borrego@Sun.COM     uint_t	what)
6685331Samw {
6697348SJose.Borrego@Sun.COM 	if (what == 0)
6705331Samw 		return;
6715331Samw 
6725331Samw 	if ((what & SMB_AT_CRTIME && crtime == 0) ||
6735331Samw 	    (what & SMB_AT_MTIME && mtime == 0) ||
6745331Samw 	    (what & SMB_AT_ATIME && atime == 0) ||
6757348SJose.Borrego@Sun.COM 	    (what & SMB_AT_CTIME && ctime == 0))
6765331Samw 		return;
6777348SJose.Borrego@Sun.COM 
6788934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
6795331Samw 
6805331Samw 	if ((what & SMB_AT_CRTIME) &&
6815331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
6825331Samw 	    crtime) != 0) {
6835331Samw 		node->what |= SMB_AT_CRTIME;
6845331Samw 		node->attr.sa_crtime = *((timestruc_t *)crtime);
6855331Samw 	}
6865331Samw 
6875331Samw 	if ((what & SMB_AT_MTIME) &&
6885331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
6895331Samw 	    mtime) != 0) {
6905331Samw 		node->what |= SMB_AT_MTIME;
6915331Samw 		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
6925331Samw 	}
6935331Samw 
6945331Samw 	if ((what & SMB_AT_ATIME) &&
6955331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
6965331Samw 	    atime) != 0) {
6975331Samw 			node->what |= SMB_AT_ATIME;
6985331Samw 			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
6995331Samw 	}
7005331Samw 
7015331Samw 	/*
7025331Samw 	 * The ctime handling is trickier. It has three scenarios.
7035331Samw 	 * 1. Only ctime need to be set and it is the same as the ctime
7045331Samw 	 *    stored in the node. (update not necessary)
7055331Samw 	 * 2. The ctime is the same as the ctime stored in the node but
7065331Samw 	 *    is not the only time need to be set. (update required)
7075331Samw 	 * 3. The ctime need to be set and is not the same as the ctime
7085331Samw 	 *    stored in the node. (update required)
7095331Samw 	 * Unlike other time setting, the ctime needs to be set even when
7105331Samw 	 * it is the same as the ctime in the node if there are other time
7115331Samw 	 * needs to be set (#2). This will ensure the ctime not being
7125331Samw 	 * updated when other times are being updated in the file system.
7135331Samw 	 *
7145331Samw 	 * Retained file rules:
7155331Samw 	 *
7165331Samw 	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
7175331Samw 	 *    request will be rejected by filesystem
7185331Samw 	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
7195331Samw 	 *    any request for changing ctime on these files should have
7205331Samw 	 *    been already rejected
7215331Samw 	 */
7225331Samw 	node->what |= SMB_AT_CTIME;
7235331Samw 	if (what & SMB_AT_CTIME) {
7245331Samw 		if ((what == SMB_AT_CTIME) &&
7255331Samw 		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
7265331Samw 		    ctime) == 0) {
7275331Samw 			node->what &= ~SMB_AT_CTIME;
7285331Samw 		} else {
7295331Samw 			gethrestime(&node->attr.sa_vattr.va_ctime);
7305331Samw 		}
7315331Samw 	} else {
7325331Samw 		gethrestime(&node->attr.sa_vattr.va_ctime);
7335331Samw 	}
7348934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
7355331Samw }
7365331Samw 
7375331Samw 
7385331Samw timestruc_t *
7395331Samw smb_node_get_crtime(smb_node_t *node)
7405331Samw {
7415331Samw 	return ((timestruc_t *)&node->attr.sa_crtime);
7425331Samw }
7435331Samw 
7445331Samw timestruc_t *
7455331Samw smb_node_get_atime(smb_node_t *node)
7465331Samw {
7475331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
7485331Samw }
7495331Samw 
7505331Samw timestruc_t *
7515331Samw smb_node_get_ctime(smb_node_t *node)
7525331Samw {
7535331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
7545331Samw }
7555331Samw 
7565331Samw timestruc_t *
7575331Samw smb_node_get_mtime(smb_node_t *node)
7585331Samw {
7595331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
7605331Samw }
7615331Samw 
7625331Samw /*
7635331Samw  * smb_node_set_dosattr
7645331Samw  *
7655331Samw  * Parse the specified DOS attributes and, if they have been modified,
7665331Samw  * update the node cache. This call should be followed by a
7675331Samw  * smb_sync_fsattr() call to write the attribute changes to filesystem.
7685331Samw  */
7695331Samw void
7707052Samw smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr)
7715331Samw {
7727052Samw 	uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE |
7737052Samw 	    FILE_ATTRIBUTE_READONLY |
7747052Samw 	    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
7755331Samw 
7768934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
7775331Samw 	if (node->attr.sa_dosattr != mode) {
7785331Samw 		node->attr.sa_dosattr = mode;
7795331Samw 		node->what |= SMB_AT_DOSATTR;
7805331Samw 	}
7818934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
7825331Samw }
7835331Samw 
7845331Samw /*
7857348SJose.Borrego@Sun.COM  * smb_node_get_dosattr()
7865331Samw  *
7877348SJose.Borrego@Sun.COM  * This function is used to provide clients with information as to whether
7887348SJose.Borrego@Sun.COM  * the readonly bit is set.  Hence both the node attribute cache (which
7897348SJose.Borrego@Sun.COM  * reflects the on-disk attributes) and node->readonly_creator (which
7907348SJose.Borrego@Sun.COM  * reflects whether a readonly set is pending from a readonly create) are
7917348SJose.Borrego@Sun.COM  * checked.  In the latter case, the readonly attribute should be visible to
7927348SJose.Borrego@Sun.COM  * all clients even though the readonly creator fid is immune to the readonly
7937348SJose.Borrego@Sun.COM  * bit until close.
7945331Samw  */
7957348SJose.Borrego@Sun.COM 
7965331Samw uint32_t
7975331Samw smb_node_get_dosattr(smb_node_t *node)
7985331Samw {
7997348SJose.Borrego@Sun.COM 	uint32_t dosattr = node->attr.sa_dosattr;
8007348SJose.Borrego@Sun.COM 
8017348SJose.Borrego@Sun.COM 	if (node->readonly_creator)
8027348SJose.Borrego@Sun.COM 		dosattr |= FILE_ATTRIBUTE_READONLY;
8037348SJose.Borrego@Sun.COM 
8047348SJose.Borrego@Sun.COM 	if (!dosattr)
8057348SJose.Borrego@Sun.COM 		dosattr = FILE_ATTRIBUTE_NORMAL;
8067348SJose.Borrego@Sun.COM 
8077348SJose.Borrego@Sun.COM 	return (dosattr);
8085331Samw }
8095331Samw 
810*9231SAfshin.Ardakani@Sun.COM /*
811*9231SAfshin.Ardakani@Sun.COM  * When DeleteOnClose is set on an smb_node, the common open code will
812*9231SAfshin.Ardakani@Sun.COM  * reject subsequent open requests for the file. Observation of Windows
813*9231SAfshin.Ardakani@Sun.COM  * 2000 indicates that subsequent opens should be allowed (assuming
814*9231SAfshin.Ardakani@Sun.COM  * there would be no sharing violation) until the file is closed using
815*9231SAfshin.Ardakani@Sun.COM  * the fid on which the DeleteOnClose was requested.
816*9231SAfshin.Ardakani@Sun.COM  *
817*9231SAfshin.Ardakani@Sun.COM  * If there are multiple opens with delete-on-close create options,
818*9231SAfshin.Ardakani@Sun.COM  * whichever the first file handle is closed will trigger the node to be
819*9231SAfshin.Ardakani@Sun.COM  * marked as delete-on-close. The credentials of that ofile will be used
820*9231SAfshin.Ardakani@Sun.COM  * as the delete-on-close credentials of the node.
821*9231SAfshin.Ardakani@Sun.COM  */
8225331Samw int
823*9231SAfshin.Ardakani@Sun.COM smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
8245331Samw {
8255331Samw 	int	rc = -1;
8265331Samw 
8278934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
8285331Samw 	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
8295331Samw 	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
8305331Samw 		crhold(cr);
8315331Samw 		node->delete_on_close_cred = cr;
832*9231SAfshin.Ardakani@Sun.COM 		node->n_delete_on_close_flags = flags;
8335331Samw 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
8345331Samw 		rc = 0;
8355331Samw 	}
8368934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
8375331Samw 	return (rc);
8385331Samw }
8395331Samw 
8405331Samw void
8415331Samw smb_node_reset_delete_on_close(smb_node_t *node)
8425331Samw {
8438934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
8445331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
8455331Samw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
8465331Samw 		crfree(node->delete_on_close_cred);
8475331Samw 		node->delete_on_close_cred = NULL;
848*9231SAfshin.Ardakani@Sun.COM 		node->n_delete_on_close_flags = 0;
8495331Samw 	}
8508934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
8515331Samw }
8525772Sas200622 
8535772Sas200622 /*
8546771Sjb150015  * smb_node_open_check
8555772Sas200622  *
8565772Sas200622  * check file sharing rules for current open request
8575772Sas200622  * against all existing opens for a file.
8585772Sas200622  *
8595772Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
8605772Sas200622  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
8615772Sas200622  */
8625772Sas200622 uint32_t
8638934SJose.Borrego@Sun.COM smb_node_open_check(
8648934SJose.Borrego@Sun.COM     smb_node_t	*node,
8658934SJose.Borrego@Sun.COM     cred_t	*cr,
8668934SJose.Borrego@Sun.COM     uint32_t	desired_access,
8678934SJose.Borrego@Sun.COM     uint32_t	share_access)
8685772Sas200622 {
8695772Sas200622 	smb_ofile_t *of;
8705772Sas200622 	uint32_t status;
8715772Sas200622 
8728934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
8735772Sas200622 
8745772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
8755772Sas200622 	of = smb_llist_head(&node->n_ofile_list);
8765772Sas200622 	while (of) {
8776771Sjb150015 		status = smb_ofile_open_check(of, cr, desired_access,
8786771Sjb150015 		    share_access);
8796771Sjb150015 
8806771Sjb150015 		switch (status) {
8816771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
8826771Sjb150015 		case NT_STATUS_SUCCESS:
8836771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
8846771Sjb150015 			break;
8856771Sjb150015 		default:
8866771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
8875772Sas200622 			smb_llist_exit(&node->n_ofile_list);
8885772Sas200622 			return (status);
8895772Sas200622 		}
8905772Sas200622 	}
8916771Sjb150015 
8925772Sas200622 	smb_llist_exit(&node->n_ofile_list);
8935772Sas200622 	return (NT_STATUS_SUCCESS);
8945772Sas200622 }
8955772Sas200622 
8965772Sas200622 uint32_t
8978934SJose.Borrego@Sun.COM smb_node_rename_check(smb_node_t *node)
8985772Sas200622 {
8998934SJose.Borrego@Sun.COM 	smb_ofile_t	*of;
9008934SJose.Borrego@Sun.COM 	uint32_t	status;
9015772Sas200622 
9028934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9035772Sas200622 
9045772Sas200622 	/*
9055772Sas200622 	 * Intra-CIFS check
9065772Sas200622 	 */
9075772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
9086771Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
9096771Sjb150015 	while (of) {
9106771Sjb150015 		status = smb_ofile_rename_check(of);
9115772Sas200622 
9126771Sjb150015 		switch (status) {
9136771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
9146771Sjb150015 		case NT_STATUS_SUCCESS:
9156771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
9166771Sjb150015 			break;
9176771Sjb150015 		default:
9186771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
9196771Sjb150015 			smb_llist_exit(&node->n_ofile_list);
9206771Sjb150015 			return (status);
9215772Sas200622 		}
9225772Sas200622 	}
9235772Sas200622 	smb_llist_exit(&node->n_ofile_list);
9245772Sas200622 
9255772Sas200622 	/*
9265772Sas200622 	 * system-wide share check
9275772Sas200622 	 */
9285772Sas200622 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
9295772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
9305772Sas200622 	else
9315772Sas200622 		return (NT_STATUS_SUCCESS);
9325772Sas200622 }
9335772Sas200622 
9346771Sjb150015 uint32_t
9355772Sas200622 smb_node_delete_check(smb_node_t *node)
9365772Sas200622 {
9378934SJose.Borrego@Sun.COM 	smb_ofile_t	*of;
9388934SJose.Borrego@Sun.COM 	uint32_t	status;
9395772Sas200622 
9408934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9415772Sas200622 
9425772Sas200622 	if (node->attr.sa_vattr.va_type == VDIR)
9435772Sas200622 		return (NT_STATUS_SUCCESS);
9445772Sas200622 
9455772Sas200622 	/*
9465772Sas200622 	 * intra-CIFS check
9475772Sas200622 	 */
9485772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
9496771Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
9506771Sjb150015 	while (of) {
9516771Sjb150015 		status = smb_ofile_delete_check(of);
9526771Sjb150015 
9536771Sjb150015 		switch (status) {
9546771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
9556771Sjb150015 		case NT_STATUS_SUCCESS:
9566771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
9576771Sjb150015 			break;
9586771Sjb150015 		default:
9596771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
9605772Sas200622 			smb_llist_exit(&node->n_ofile_list);
9616771Sjb150015 			return (status);
9625772Sas200622 		}
9635772Sas200622 	}
9645772Sas200622 	smb_llist_exit(&node->n_ofile_list);
9655772Sas200622 
9665772Sas200622 	/*
9675772Sas200622 	 * system-wide share check
9685772Sas200622 	 */
9695772Sas200622 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
9705772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
9715772Sas200622 	else
9725772Sas200622 		return (NT_STATUS_SUCCESS);
9735772Sas200622 }
9745772Sas200622 
9755772Sas200622 /*
9765772Sas200622  * smb_node_start_crit()
9775772Sas200622  *
9785772Sas200622  * Enter critical region for share reservations.
9795772Sas200622  * See comments above smb_fsop_shrlock().
9805772Sas200622  */
9815772Sas200622 
9825772Sas200622 void
9835772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode)
9845772Sas200622 {
9858934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, mode);
9865772Sas200622 	nbl_start_crit(node->vp, mode);
9875772Sas200622 }
9885772Sas200622 
9895772Sas200622 /*
9905772Sas200622  * smb_node_end_crit()
9915772Sas200622  *
9925772Sas200622  * Exit critical region for share reservations.
9935772Sas200622  */
9945772Sas200622 
9955772Sas200622 void
9965772Sas200622 smb_node_end_crit(smb_node_t *node)
9975772Sas200622 {
9985772Sas200622 	nbl_end_crit(node->vp);
9998934SJose.Borrego@Sun.COM 	rw_exit(&node->n_lock);
10005772Sas200622 }
10015772Sas200622 
10025772Sas200622 int
10035772Sas200622 smb_node_in_crit(smb_node_t *node)
10045772Sas200622 {
10058934SJose.Borrego@Sun.COM 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
10068934SJose.Borrego@Sun.COM }
10078934SJose.Borrego@Sun.COM 
10088934SJose.Borrego@Sun.COM void
10098934SJose.Borrego@Sun.COM smb_node_rdlock(smb_node_t *node)
10108934SJose.Borrego@Sun.COM {
10118934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, RW_READER);
10128934SJose.Borrego@Sun.COM }
10138934SJose.Borrego@Sun.COM 
10148934SJose.Borrego@Sun.COM void
10158934SJose.Borrego@Sun.COM smb_node_wrlock(smb_node_t *node)
10168934SJose.Borrego@Sun.COM {
10178934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, RW_WRITER);
10188934SJose.Borrego@Sun.COM }
10198934SJose.Borrego@Sun.COM 
10208934SJose.Borrego@Sun.COM void
10218934SJose.Borrego@Sun.COM smb_node_unlock(smb_node_t *node)
10228934SJose.Borrego@Sun.COM {
10238934SJose.Borrego@Sun.COM 	rw_exit(&node->n_lock);
10248934SJose.Borrego@Sun.COM }
10258934SJose.Borrego@Sun.COM 
10268934SJose.Borrego@Sun.COM uint32_t
10278934SJose.Borrego@Sun.COM smb_node_get_ofile_count(smb_node_t *node)
10288934SJose.Borrego@Sun.COM {
10298934SJose.Borrego@Sun.COM 	uint32_t	cntr;
10308934SJose.Borrego@Sun.COM 
10318934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
10328934SJose.Borrego@Sun.COM 
10338934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_READER);
10348934SJose.Borrego@Sun.COM 	cntr = smb_llist_get_count(&node->n_ofile_list);
10358934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
10368934SJose.Borrego@Sun.COM 	return (cntr);
10378934SJose.Borrego@Sun.COM }
10388934SJose.Borrego@Sun.COM 
10398934SJose.Borrego@Sun.COM void
10408934SJose.Borrego@Sun.COM smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
10418934SJose.Borrego@Sun.COM {
10428934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
10438934SJose.Borrego@Sun.COM 
10448934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
10458934SJose.Borrego@Sun.COM 	smb_llist_insert_tail(&node->n_ofile_list, of);
10468934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
10478934SJose.Borrego@Sun.COM }
10488934SJose.Borrego@Sun.COM 
10498934SJose.Borrego@Sun.COM void
10508934SJose.Borrego@Sun.COM smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
10518934SJose.Borrego@Sun.COM {
10528934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
10538934SJose.Borrego@Sun.COM 
10548934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
10558934SJose.Borrego@Sun.COM 	smb_llist_remove(&node->n_ofile_list, of);
10568934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
10578934SJose.Borrego@Sun.COM }
10588934SJose.Borrego@Sun.COM 
10598934SJose.Borrego@Sun.COM void
10608934SJose.Borrego@Sun.COM smb_node_inc_open_ofiles(smb_node_t *node)
10618934SJose.Borrego@Sun.COM {
10628934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
10638934SJose.Borrego@Sun.COM 
10648934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
10658934SJose.Borrego@Sun.COM 	node->n_open_count++;
10668934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
10678934SJose.Borrego@Sun.COM }
10688934SJose.Borrego@Sun.COM 
10698934SJose.Borrego@Sun.COM void
10708934SJose.Borrego@Sun.COM smb_node_dec_open_ofiles(smb_node_t *node)
10718934SJose.Borrego@Sun.COM {
10728934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
10738934SJose.Borrego@Sun.COM 
10748934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
10758934SJose.Borrego@Sun.COM 	node->n_open_count--;
10768934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
10778934SJose.Borrego@Sun.COM }
10788934SJose.Borrego@Sun.COM 
10798934SJose.Borrego@Sun.COM uint32_t
10808934SJose.Borrego@Sun.COM smb_node_get_open_ofiles(smb_node_t *node)
10818934SJose.Borrego@Sun.COM {
10828934SJose.Borrego@Sun.COM 	uint32_t	cnt;
10838934SJose.Borrego@Sun.COM 
10848934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
10858934SJose.Borrego@Sun.COM 
10868934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
10878934SJose.Borrego@Sun.COM 	cnt = node->n_open_count;
10888934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
10898934SJose.Borrego@Sun.COM 	return (cnt);
10905772Sas200622 }
10918934SJose.Borrego@Sun.COM 
10928934SJose.Borrego@Sun.COM /*
10938934SJose.Borrego@Sun.COM  * smb_node_alloc
10948934SJose.Borrego@Sun.COM  */
10958934SJose.Borrego@Sun.COM static smb_node_t *
10968934SJose.Borrego@Sun.COM smb_node_alloc(
10978934SJose.Borrego@Sun.COM     char	*od_name,
10988934SJose.Borrego@Sun.COM     vnode_t	*vp,
10998934SJose.Borrego@Sun.COM     smb_attr_t	*attr,
11008934SJose.Borrego@Sun.COM     smb_llist_t	*bucket,
11018934SJose.Borrego@Sun.COM     uint32_t	hashkey)
11028934SJose.Borrego@Sun.COM {
11038934SJose.Borrego@Sun.COM 	smb_node_t	*node;
11048934SJose.Borrego@Sun.COM 
11058934SJose.Borrego@Sun.COM 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
11068934SJose.Borrego@Sun.COM 
11078934SJose.Borrego@Sun.COM 	if (node->n_audit_buf != NULL)
11088934SJose.Borrego@Sun.COM 		node->n_audit_buf->anb_index = 0;
11098934SJose.Borrego@Sun.COM 
11108934SJose.Borrego@Sun.COM 	node->attr = *attr;
11118934SJose.Borrego@Sun.COM 	node->flags = NODE_FLAGS_ATTR_VALID;
11128934SJose.Borrego@Sun.COM 	node->n_size = node->attr.sa_vattr.va_size;
11138934SJose.Borrego@Sun.COM 	VN_HOLD(vp);
11148934SJose.Borrego@Sun.COM 	node->vp = vp;
11158934SJose.Borrego@Sun.COM 	node->n_refcnt = 1;
11168934SJose.Borrego@Sun.COM 	node->n_hash_bucket = bucket;
11178934SJose.Borrego@Sun.COM 	node->n_hashkey = hashkey;
11188934SJose.Borrego@Sun.COM 	node->n_orig_uid = 0;
11198934SJose.Borrego@Sun.COM 	node->readonly_creator = NULL;
11208934SJose.Borrego@Sun.COM 	node->waiting_event = 0;
11218934SJose.Borrego@Sun.COM 	node->what = 0;
11228934SJose.Borrego@Sun.COM 	node->n_open_count = 0;
11238934SJose.Borrego@Sun.COM 	node->dir_snode = NULL;
11248934SJose.Borrego@Sun.COM 	node->unnamed_stream_node = NULL;
11258934SJose.Borrego@Sun.COM 	node->delete_on_close_cred = NULL;
1126*9231SAfshin.Ardakani@Sun.COM 	node->n_delete_on_close_flags = 0;
11278934SJose.Borrego@Sun.COM 
11288934SJose.Borrego@Sun.COM 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
11298934SJose.Borrego@Sun.COM 	if (strcmp(od_name, XATTR_DIR) == 0)
11308934SJose.Borrego@Sun.COM 		node->flags |= NODE_XATTR_DIR;
11318934SJose.Borrego@Sun.COM 
11328934SJose.Borrego@Sun.COM 	node->n_state = SMB_NODE_STATE_AVAILABLE;
11338934SJose.Borrego@Sun.COM 	node->n_magic = SMB_NODE_MAGIC;
11348934SJose.Borrego@Sun.COM 	return (node);
11358934SJose.Borrego@Sun.COM }
11368934SJose.Borrego@Sun.COM 
11378934SJose.Borrego@Sun.COM /*
11388934SJose.Borrego@Sun.COM  * smb_node_free
11398934SJose.Borrego@Sun.COM  */
11408934SJose.Borrego@Sun.COM static void
11418934SJose.Borrego@Sun.COM smb_node_free(smb_node_t *node)
11428934SJose.Borrego@Sun.COM {
11438934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
11448934SJose.Borrego@Sun.COM 
11458934SJose.Borrego@Sun.COM 	node->n_magic = 0;
11468934SJose.Borrego@Sun.COM 	VERIFY(!list_link_active(&node->n_lnd));
11478934SJose.Borrego@Sun.COM 	VERIFY(node->n_lock_list.ll_count == 0);
11488934SJose.Borrego@Sun.COM 	VERIFY(node->n_ofile_list.ll_count == 0);
11498934SJose.Borrego@Sun.COM 	VERIFY(node->n_oplock.ol_xthread == NULL);
11509021Samw@Sun.COM 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
11519021Samw@Sun.COM 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
11528934SJose.Borrego@Sun.COM 	VN_RELE(node->vp);
11538934SJose.Borrego@Sun.COM 	kmem_cache_free(smb_node_cache, node);
11548934SJose.Borrego@Sun.COM }
11558934SJose.Borrego@Sun.COM 
11568934SJose.Borrego@Sun.COM /*
11578934SJose.Borrego@Sun.COM  * smb_node_constructor
11588934SJose.Borrego@Sun.COM  */
11598934SJose.Borrego@Sun.COM static int
11608934SJose.Borrego@Sun.COM smb_node_constructor(void *buf, void *un, int kmflags)
11618934SJose.Borrego@Sun.COM {
11628934SJose.Borrego@Sun.COM 	_NOTE(ARGUNUSED(kmflags, un))
11638934SJose.Borrego@Sun.COM 
11648934SJose.Borrego@Sun.COM 	smb_node_t	*node = (smb_node_t *)buf;
11658934SJose.Borrego@Sun.COM 
11668934SJose.Borrego@Sun.COM 	bzero(node, sizeof (smb_node_t));
11678934SJose.Borrego@Sun.COM 
11688934SJose.Borrego@Sun.COM 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
11698934SJose.Borrego@Sun.COM 	    offsetof(smb_ofile_t, f_nnd));
11708934SJose.Borrego@Sun.COM 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
11718934SJose.Borrego@Sun.COM 	    offsetof(smb_lock_t, l_lnd));
11728934SJose.Borrego@Sun.COM 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
11738934SJose.Borrego@Sun.COM 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
11748934SJose.Borrego@Sun.COM 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
11758934SJose.Borrego@Sun.COM 	smb_node_create_audit_buf(node, kmflags);
11768934SJose.Borrego@Sun.COM 	return (0);
11778934SJose.Borrego@Sun.COM }
11788934SJose.Borrego@Sun.COM 
11798934SJose.Borrego@Sun.COM /*
11808934SJose.Borrego@Sun.COM  * smb_node_destructor
11818934SJose.Borrego@Sun.COM  */
11828934SJose.Borrego@Sun.COM static void
11838934SJose.Borrego@Sun.COM smb_node_destructor(void *buf, void *un)
11848934SJose.Borrego@Sun.COM {
11858934SJose.Borrego@Sun.COM 	_NOTE(ARGUNUSED(un))
11868934SJose.Borrego@Sun.COM 
11878934SJose.Borrego@Sun.COM 	smb_node_t	*node = (smb_node_t *)buf;
11888934SJose.Borrego@Sun.COM 
11898934SJose.Borrego@Sun.COM 	smb_node_destroy_audit_buf(node);
11908934SJose.Borrego@Sun.COM 	mutex_destroy(&node->n_mutex);
11918934SJose.Borrego@Sun.COM 	rw_destroy(&node->n_lock);
11928934SJose.Borrego@Sun.COM 	cv_destroy(&node->n_oplock.ol_cv);
11938934SJose.Borrego@Sun.COM 	smb_llist_destructor(&node->n_lock_list);
11948934SJose.Borrego@Sun.COM 	smb_llist_destructor(&node->n_ofile_list);
11958934SJose.Borrego@Sun.COM }
11968934SJose.Borrego@Sun.COM 
11978934SJose.Borrego@Sun.COM /*
11988934SJose.Borrego@Sun.COM  * smb_node_create_audit_buf
11998934SJose.Borrego@Sun.COM  */
12008934SJose.Borrego@Sun.COM static void
12018934SJose.Borrego@Sun.COM smb_node_create_audit_buf(smb_node_t *node, int kmflags)
12028934SJose.Borrego@Sun.COM {
12038934SJose.Borrego@Sun.COM 	smb_audit_buf_node_t	*abn;
12048934SJose.Borrego@Sun.COM 
12058934SJose.Borrego@Sun.COM 	if (smb_audit_flags & SMB_AUDIT_NODE) {
12068934SJose.Borrego@Sun.COM 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
12078934SJose.Borrego@Sun.COM 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
12088934SJose.Borrego@Sun.COM 		node->n_audit_buf = abn;
12098934SJose.Borrego@Sun.COM 	}
12108934SJose.Borrego@Sun.COM }
12118934SJose.Borrego@Sun.COM 
12128934SJose.Borrego@Sun.COM /*
12138934SJose.Borrego@Sun.COM  * smb_node_destroy_audit_buf
12148934SJose.Borrego@Sun.COM  */
12158934SJose.Borrego@Sun.COM static void
12168934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(smb_node_t *node)
12178934SJose.Borrego@Sun.COM {
12188934SJose.Borrego@Sun.COM 	if (node->n_audit_buf != NULL) {
12198934SJose.Borrego@Sun.COM 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
12208934SJose.Borrego@Sun.COM 		node->n_audit_buf = NULL;
12218934SJose.Borrego@Sun.COM 	}
12228934SJose.Borrego@Sun.COM }
12238934SJose.Borrego@Sun.COM 
12248934SJose.Borrego@Sun.COM /*
12258934SJose.Borrego@Sun.COM  * smb_node_audit
12268934SJose.Borrego@Sun.COM  *
12278934SJose.Borrego@Sun.COM  * This function saves the calling stack in the audit buffer of the node passed
12288934SJose.Borrego@Sun.COM  * in.
12298934SJose.Borrego@Sun.COM  */
12308934SJose.Borrego@Sun.COM static void
12318934SJose.Borrego@Sun.COM smb_node_audit(smb_node_t *node)
12328934SJose.Borrego@Sun.COM {
12338934SJose.Borrego@Sun.COM 	smb_audit_buf_node_t	*abn;
12348934SJose.Borrego@Sun.COM 	smb_audit_record_node_t	*anr;
12358934SJose.Borrego@Sun.COM 
12368934SJose.Borrego@Sun.COM 	if (node->n_audit_buf) {
12378934SJose.Borrego@Sun.COM 		abn = node->n_audit_buf;
12388934SJose.Borrego@Sun.COM 		anr = abn->anb_records;
12398934SJose.Borrego@Sun.COM 		anr += abn->anb_index;
12408934SJose.Borrego@Sun.COM 		abn->anb_index++;
12418934SJose.Borrego@Sun.COM 		abn->anb_index &= abn->anb_max_index;
12428934SJose.Borrego@Sun.COM 		anr->anr_refcnt = node->n_refcnt;
12438934SJose.Borrego@Sun.COM 		anr->anr_depth = getpcstack(anr->anr_stack,
12448934SJose.Borrego@Sun.COM 		    SMB_AUDIT_STACK_DEPTH);
12458934SJose.Borrego@Sun.COM 	}
12468934SJose.Borrego@Sun.COM }
12478934SJose.Borrego@Sun.COM 
12488934SJose.Borrego@Sun.COM static smb_llist_t *
12498934SJose.Borrego@Sun.COM smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
12508934SJose.Borrego@Sun.COM {
12518934SJose.Borrego@Sun.COM 	uint32_t	hashkey;
12528934SJose.Borrego@Sun.COM 
12538934SJose.Borrego@Sun.COM 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
12548934SJose.Borrego@Sun.COM 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
12558934SJose.Borrego@Sun.COM 	*phashkey = hashkey;
12568934SJose.Borrego@Sun.COM 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
12578934SJose.Borrego@Sun.COM }
1258