xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 8934:8ff6afa44187)
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  *
295331Samw  *    +----------------------------+	 T0
305331Samw  *    |  SMB_NODE_STATE_AVAILABLE  |<----------- Creation/Allocation
315331Samw  *    +----------------------------+
325331Samw  *		    |
335331Samw  *		    | T1
345331Samw  *		    |
355331Samw  *		    v
365331Samw  *    +-----------------------------+    T2
375331Samw  *    |  SMB_NODE_STATE_DESTROYING  |----------> Deletion/Free
385331Samw  *    +-----------------------------+
395331Samw  *
405331Samw  * Transition T0
415331Samw  *
425331Samw  *    This transition occurs in smb_node_lookup(). If the node looked for is
435331Samw  *    not found in the has table a new node is created. The reference count is
445331Samw  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
455331Samw  *
465331Samw  * Transition T1
475331Samw  *
485331Samw  *    This transition occurs in smb_node_release(). If the reference count
495331Samw  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
505331Samw  *    reference count will be given out for that node.
515331Samw  *
525331Samw  * Transition T2
535331Samw  *
545331Samw  *    This transition occurs in smb_node_release(). The structure is deleted.
555331Samw  *
565331Samw  * Comments
575331Samw  * --------
585331Samw  *
595331Samw  *    The reason the smb node has 2 states is the following synchronization
605331Samw  *    rule:
615331Samw  *
625331Samw  *    There's a mutex embedded in the node used to protect its fields and
635331Samw  *    there's a lock embedded in the bucket of the hash table the node belongs
645331Samw  *    to. To increment or to decrement the reference count the mutex must be
655331Samw  *    entered. To insert the node into the bucket and to remove it from the
665331Samw  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
675331Samw  *    lock) have to be entered, the lock has always to be entered first then
685331Samw  *    the mutex. This prevents a deadlock between smb_node_lookup() and
695331Samw  *    smb_node_release() from occurring. However, in smb_node_release() when the
705331Samw  *    reference count drops to zero and triggers the deletion of the node, the
715331Samw  *    mutex has to be released before entering the lock of the bucket (to
725331Samw  *    remove the node). This creates a window during which the node that is
735331Samw  *    about to be freed could be given out by smb_node_lookup(). To close that
745331Samw  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
755331Samw  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
765331Samw  *    state will indicate that the node should be treated as non existent (of
775331Samw  *    course the state of the node should be tested/updated under the
785331Samw  *    protection of the mutex).
795331Samw  */
805331Samw #include <smbsrv/smb_incl.h>
815331Samw #include <smbsrv/smb_fsops.h>
82*8934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h>
835331Samw #include <sys/pathname.h>
845331Samw #include <sys/sdt.h>
855772Sas200622 #include <sys/nbmlock.h>
865331Samw 
87*8934SJose.Borrego@Sun.COM uint32_t smb_is_executable(char *);
88*8934SJose.Borrego@Sun.COM static void smb_node_delete_on_close(smb_node_t *);
89*8934SJose.Borrego@Sun.COM static void smb_node_create_audit_buf(smb_node_t *, int);
90*8934SJose.Borrego@Sun.COM static void smb_node_destroy_audit_buf(smb_node_t *);
91*8934SJose.Borrego@Sun.COM static void smb_node_audit(smb_node_t *);
92*8934SJose.Borrego@Sun.COM static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_attr_t *,
93*8934SJose.Borrego@Sun.COM     smb_llist_t *bucket, uint32_t hashkey);
94*8934SJose.Borrego@Sun.COM static void smb_node_free(smb_node_t *);
95*8934SJose.Borrego@Sun.COM static int smb_node_constructor(void *, void *, int);
96*8934SJose.Borrego@Sun.COM static void smb_node_destructor(void *, void *);
97*8934SJose.Borrego@Sun.COM static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
985331Samw 
995331Samw #define	VALIDATE_DIR_NODE(_dir_, _node_) \
1005331Samw     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
1015331Samw     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
1025331Samw     ASSERT((_dir_)->dir_snode != (_node_));
1035331Samw 
104*8934SJose.Borrego@Sun.COM static kmem_cache_t	*smb_node_cache = NULL;
1056139Sjb150015 static boolean_t	smb_node_initialized = B_FALSE;
1066139Sjb150015 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
1076139Sjb150015 
1086139Sjb150015 /*
1096139Sjb150015  * smb_node_init
1106139Sjb150015  *
1116139Sjb150015  * Initialization of the SMB node layer.
1126139Sjb150015  *
1136139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1146139Sjb150015  * thread makes the call.
1156139Sjb150015  */
1166139Sjb150015 int
1176139Sjb150015 smb_node_init(void)
1186139Sjb150015 {
1196139Sjb150015 	int	i;
1206139Sjb150015 
1216139Sjb150015 	if (smb_node_initialized)
1226139Sjb150015 		return (0);
123*8934SJose.Borrego@Sun.COM 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
124*8934SJose.Borrego@Sun.COM 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
125*8934SJose.Borrego@Sun.COM 	    NULL, NULL, NULL, 0);
1266139Sjb150015 
1276139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
1286139Sjb150015 		smb_llist_constructor(&smb_node_hash_table[i],
1296139Sjb150015 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
1306139Sjb150015 	}
1316139Sjb150015 	smb_node_initialized = B_TRUE;
1326139Sjb150015 	return (0);
1336139Sjb150015 }
1346139Sjb150015 
1356139Sjb150015 /*
1366139Sjb150015  * smb_node_fini
1376139Sjb150015  *
1386139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1396139Sjb150015  * thread makes the call.
1406139Sjb150015  */
1416139Sjb150015 void
1426139Sjb150015 smb_node_fini(void)
1436139Sjb150015 {
1446139Sjb150015 	int	i;
1456139Sjb150015 
1466139Sjb150015 	if (!smb_node_initialized)
1476139Sjb150015 		return;
1486139Sjb150015 
1496139Sjb150015 #ifdef DEBUG
1506139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
1516139Sjb150015 		smb_node_t	*node;
1526139Sjb150015 
1536139Sjb150015 		/*
1546139Sjb150015 		 * The following sequence is just intended for sanity check.
1556139Sjb150015 		 * This will have to be modified when the code goes into
1566139Sjb150015 		 * production.
1576139Sjb150015 		 *
1586139Sjb150015 		 * The SMB node hash table should be emtpy at this point. If the
1596139Sjb150015 		 * hash table is not empty a panic will be triggered.
1606139Sjb150015 		 *
1616139Sjb150015 		 * The reason why SMB nodes are still remaining in the hash
1626139Sjb150015 		 * table is problably due to a mismatch between calls to
1636139Sjb150015 		 * smb_node_lookup() and smb_node_release(). You must track that
1646139Sjb150015 		 * down.
1656139Sjb150015 		 */
1666139Sjb150015 		node = smb_llist_head(&smb_node_hash_table[i]);
1676139Sjb150015 		ASSERT(node == NULL);
1686139Sjb150015 	}
1696139Sjb150015 #endif
1706139Sjb150015 
1716139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
1726139Sjb150015 		smb_llist_destructor(&smb_node_hash_table[i]);
1736139Sjb150015 	}
174*8934SJose.Borrego@Sun.COM 	kmem_cache_destroy(smb_node_cache);
175*8934SJose.Borrego@Sun.COM 	smb_node_cache = NULL;
1766139Sjb150015 	smb_node_initialized = B_FALSE;
1776139Sjb150015 }
1786139Sjb150015 
1795331Samw /*
1805331Samw  * smb_node_lookup()
1815331Samw  *
1825331Samw  * NOTE: This routine should only be called by the file system interface layer,
1835331Samw  * and not by SMB.
1845331Samw  *
1855331Samw  * smb_node_lookup() is called upon successful lookup, mkdir, and create
1865331Samw  * (for both non-streams and streams).  In each of these cases, a held vnode is
1878670SJose.Borrego@Sun.COM  * passed into this routine.  If a new smb_node is created it will take its
1888670SJose.Borrego@Sun.COM  * own hold on the vnode.  The caller's hold therefore still belongs to, and
1898670SJose.Borrego@Sun.COM  * should be released by, the caller.
1905331Samw  *
1915331Samw  * A reference is taken on the smb_node whether found in the hash table
1925331Samw  * or newly created.
1935331Samw  *
1945331Samw  * If an smb_node needs to be created, a reference is also taken on the
1955331Samw  * dir_snode (if passed in).
1965331Samw  *
1975331Samw  * See smb_node_release() for details on the release of these references.
1985331Samw  */
1995331Samw 
2005331Samw /*ARGSUSED*/
2015331Samw smb_node_t *
2025331Samw smb_node_lookup(
2035331Samw     struct smb_request	*sr,
2045331Samw     struct open_param	*op,
2055331Samw     cred_t		*cred,
2065331Samw     vnode_t		*vp,
2075331Samw     char		*od_name,
2085331Samw     smb_node_t		*dir_snode,
2095331Samw     smb_node_t		*unnamed_node,
2105331Samw     smb_attr_t		*attr)
2115331Samw {
2125331Samw 	smb_llist_t		*node_hdr;
2135331Samw 	smb_node_t		*node;
2145331Samw 	uint32_t		hashkey = 0;
2157348SJose.Borrego@Sun.COM 	fsid_t			fsid;
2165331Samw 	int			error;
2175331Samw 	krw_t			lock_mode;
2185331Samw 	vnode_t			*unnamed_vp = NULL;
2195331Samw 
2205331Samw 	/*
2215331Samw 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
2225331Samw 	 * because the node may not yet exist.  We also do not want to call
2235331Samw 	 * it with the list lock held.
2245331Samw 	 */
2255331Samw 
2265331Samw 	if (unnamed_node)
2275331Samw 		unnamed_vp = unnamed_node->vp;
2285331Samw 
2295331Samw 	/*
2305331Samw 	 * This getattr is performed on behalf of the server
2315331Samw 	 * that's why kcred is used not the user's cred
2325331Samw 	 */
2335331Samw 	attr->sa_mask = SMB_AT_ALL;
2345772Sas200622 	error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred);
2355331Samw 	if (error)
2365331Samw 		return (NULL);
2375331Samw 
2387348SJose.Borrego@Sun.COM 	if (sr && sr->tid_tree) {
2397348SJose.Borrego@Sun.COM 		/*
2407348SJose.Borrego@Sun.COM 		 * The fsid for a file is that of the tree, even
2417348SJose.Borrego@Sun.COM 		 * if the file resides in a different mountpoint
2427348SJose.Borrego@Sun.COM 		 * under the share.
2437348SJose.Borrego@Sun.COM 		 */
2447348SJose.Borrego@Sun.COM 		fsid = SMB_TREE_FSID(sr->tid_tree);
2455331Samw 	} else {
2467348SJose.Borrego@Sun.COM 		/*
2477348SJose.Borrego@Sun.COM 		 * This should be getting executed only for the
2487348SJose.Borrego@Sun.COM 		 * tree root smb_node.
2497348SJose.Borrego@Sun.COM 		 */
2507348SJose.Borrego@Sun.COM 		fsid = vp->v_vfsp->vfs_fsid;
2515331Samw 	}
2525331Samw 
253*8934SJose.Borrego@Sun.COM 	node_hdr = smb_node_get_hash(&fsid, attr, &hashkey);
2545331Samw 	lock_mode = RW_READER;
2555331Samw 
2565331Samw 	smb_llist_enter(node_hdr, lock_mode);
2575331Samw 	for (;;) {
2585331Samw 		node = list_head(&node_hdr->ll_list);
2595331Samw 		while (node) {
2605331Samw 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
2615331Samw 			ASSERT(node->n_hash_bucket == node_hdr);
2625331Samw 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
263*8934SJose.Borrego@Sun.COM 				mutex_enter(&node->n_mutex);
2645331Samw 				DTRACE_PROBE1(smb_node_lookup_hit,
2655331Samw 				    smb_node_t *, node);
2665331Samw 				switch (node->n_state) {
267*8934SJose.Borrego@Sun.COM 				case SMB_NODE_STATE_OPLOCK_GRANTED:
268*8934SJose.Borrego@Sun.COM 				case SMB_NODE_STATE_OPLOCK_BREAKING:
2695331Samw 				case SMB_NODE_STATE_AVAILABLE:
2705331Samw 					/* The node was found. */
2715331Samw 					node->n_refcnt++;
2725331Samw 					if ((node->dir_snode == NULL) &&
2735331Samw 					    (dir_snode != NULL) &&
2745331Samw 					    (strcmp(od_name, "..") != 0) &&
2755331Samw 					    (strcmp(od_name, ".") != 0)) {
2765331Samw 						VALIDATE_DIR_NODE(dir_snode,
2775331Samw 						    node);
2785331Samw 						node->dir_snode = dir_snode;
2795331Samw 						smb_node_ref(dir_snode);
2805331Samw 					}
2815331Samw 					node->attr = *attr;
2825772Sas200622 					node->n_size = attr->sa_vattr.va_size;
2835331Samw 
284*8934SJose.Borrego@Sun.COM 					smb_node_audit(node);
285*8934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
2865331Samw 					smb_llist_exit(node_hdr);
2875331Samw 					return (node);
2885331Samw 
2895331Samw 				case SMB_NODE_STATE_DESTROYING:
2905331Samw 					/*
2915331Samw 					 * Although the node exists it is about
2925331Samw 					 * to be destroyed. We act as it hasn't
2935331Samw 					 * been found.
2945331Samw 					 */
295*8934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
2965331Samw 					break;
2975331Samw 				default:
2985331Samw 					/*
2995331Samw 					 * Although the node exists it is in an
3005331Samw 					 * unknown state. We act as it hasn't
3015331Samw 					 * been found.
3025331Samw 					 */
3035331Samw 					ASSERT(0);
304*8934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3055331Samw 					break;
3065331Samw 				}
3075331Samw 			}
3085331Samw 			node = smb_llist_next(node_hdr, node);
3095331Samw 		}
3105331Samw 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
3115331Samw 			lock_mode = RW_WRITER;
3125331Samw 			continue;
3135331Samw 		}
3145331Samw 		break;
3155331Samw 	}
316*8934SJose.Borrego@Sun.COM 	node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey);
317*8934SJose.Borrego@Sun.COM 	node->n_orig_uid = crgetuid(sr->user_cr);
3185331Samw 
3195331Samw 	if (op)
3205331Samw 		node->flags |= smb_is_executable(op->fqi.last_comp);
3215331Samw 
3225331Samw 	if (dir_snode) {
3235331Samw 		smb_node_ref(dir_snode);
3245331Samw 		node->dir_snode = dir_snode;
3255331Samw 		ASSERT(dir_snode->dir_snode != node);
3265331Samw 		ASSERT((dir_snode->vp->v_xattrdir) ||
3275331Samw 		    (dir_snode->vp->v_type == VDIR));
3285331Samw 	}
3295331Samw 
3305331Samw 	if (unnamed_node) {
3315331Samw 		smb_node_ref(unnamed_node);
3325331Samw 		node->unnamed_stream_node = unnamed_node;
3335331Samw 	}
3345331Samw 
3355331Samw 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
336*8934SJose.Borrego@Sun.COM 	smb_node_audit(node);
3375331Samw 	smb_llist_insert_head(node_hdr, node);
3385331Samw 	smb_llist_exit(node_hdr);
3395331Samw 	return (node);
3405331Samw }
3415331Samw 
3425331Samw /*
3435331Samw  * smb_stream_node_lookup()
3445331Samw  *
3455331Samw  * Note: stream_name (the name that will be stored in the "od_name" field
3465331Samw  * of a stream's smb_node) is the same as the on-disk name for the stream
3475331Samw  * except that it does not have SMB_STREAM_PREFIX prepended.
3485331Samw  */
3495331Samw 
3505331Samw smb_node_t *
351*8934SJose.Borrego@Sun.COM smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
3525331Samw     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
3535331Samw {
3545331Samw 	smb_node_t	*xattrdir_node;
3555331Samw 	smb_node_t	*snode;
3565331Samw 	smb_attr_t	tmp_attr;
3575331Samw 
3585331Samw 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
3595331Samw 	    fnode, NULL, &tmp_attr);
3605331Samw 
3615331Samw 	if (xattrdir_node == NULL)
3625331Samw 		return (NULL);
3635331Samw 
3645331Samw 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
3655331Samw 	    fnode, ret_attr);
3665331Samw 
3675331Samw 	(void) smb_node_release(xattrdir_node);
3685331Samw 	return (snode);
3695331Samw }
3705331Samw 
3715331Samw 
3725331Samw /*
3735331Samw  * This function should be called whenever a reference is needed on an
3745331Samw  * smb_node pointer.  The copy of an smb_node pointer from one non-local
3755331Samw  * data structure to another requires a reference to be taken on the smb_node
3765331Samw  * (unless the usage is localized).  Each data structure deallocation routine
3775331Samw  * will call smb_node_release() on its smb_node pointers.
3785331Samw  *
3795331Samw  * In general, an smb_node pointer residing in a structure should never be
3805331Samw  * stale.  A node pointer may be NULL, however, and care should be taken
3815331Samw  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
3825331Samw  * Care also needs to be taken with respect to racing deallocations of a
3835331Samw  * structure.
3845331Samw  */
3855331Samw void
3865331Samw smb_node_ref(smb_node_t *node)
3875331Samw {
388*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
3895331Samw 
390*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
391*8934SJose.Borrego@Sun.COM 	switch (node->n_state) {
392*8934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
393*8934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
394*8934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
395*8934SJose.Borrego@Sun.COM 		node->n_refcnt++;
396*8934SJose.Borrego@Sun.COM 		ASSERT(node->n_refcnt);
397*8934SJose.Borrego@Sun.COM 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
398*8934SJose.Borrego@Sun.COM 		smb_node_audit(node);
399*8934SJose.Borrego@Sun.COM 		break;
400*8934SJose.Borrego@Sun.COM 	default:
401*8934SJose.Borrego@Sun.COM 		SMB_PANIC();
402*8934SJose.Borrego@Sun.COM 	}
403*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
4045331Samw }
4055331Samw 
4065331Samw /*
4075331Samw  * smb_node_lookup() takes a hold on an smb_node, whether found in the
4085331Samw  * hash table or newly created.  This hold is expected to be released
4095331Samw  * in the following manner.
4105331Samw  *
4115331Samw  * smb_node_lookup() takes an address of an smb_node pointer.  This should
4125331Samw  * be getting passed down via a lookup (whether path name or component), mkdir,
4135331Samw  * create.  If the original smb_node pointer resides in a data structure, then
4145331Samw  * the deallocation routine for the data structure is responsible for calling
4155331Samw  * smb_node_release() on the smb_node pointer.  Alternatively,
4165331Samw  * smb_node_release() can be called as soon as the smb_node pointer is no longer
4175331Samw  * needed.  In this case, callers are responsible for setting an embedded
4185331Samw  * pointer to NULL if it is known that the last reference is being released.
4195331Samw  *
4205331Samw  * If the passed-in address of the smb_node pointer belongs to a local variable,
4215331Samw  * then the caller with the local variable should call smb_node_release()
4225331Samw  * directly.
4235331Samw  *
4245331Samw  * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
4255331Samw  * as smb_node_lookup() takes a hold on dir_snode.
4265331Samw  */
4275331Samw void
4285331Samw smb_node_release(smb_node_t *node)
4295331Samw {
430*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
4315331Samw 
432*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
4335331Samw 	ASSERT(node->n_refcnt);
4345331Samw 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
4355331Samw 	if (--node->n_refcnt == 0) {
4365331Samw 		switch (node->n_state) {
4375331Samw 
4385331Samw 		case SMB_NODE_STATE_AVAILABLE:
4395331Samw 			node->n_state = SMB_NODE_STATE_DESTROYING;
440*8934SJose.Borrego@Sun.COM 			mutex_exit(&node->n_mutex);
4415331Samw 
4425331Samw 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
4435331Samw 			smb_llist_remove(node->n_hash_bucket, node);
4445331Samw 			smb_llist_exit(node->n_hash_bucket);
4455331Samw 
4465331Samw 			/*
4475331Samw 			 * Check if the file was deleted
4485331Samw 			 */
4495331Samw 			smb_node_delete_on_close(node);
4505331Samw 
4515331Samw 			if (node->dir_snode) {
4525331Samw 				ASSERT(node->dir_snode->n_magic ==
4535331Samw 				    SMB_NODE_MAGIC);
4545331Samw 				smb_node_release(node->dir_snode);
4555331Samw 			}
4565331Samw 
4575331Samw 			if (node->unnamed_stream_node) {
4585331Samw 				ASSERT(node->unnamed_stream_node->n_magic ==
4595331Samw 				    SMB_NODE_MAGIC);
4605331Samw 				smb_node_release(node->unnamed_stream_node);
4615331Samw 			}
4625331Samw 
463*8934SJose.Borrego@Sun.COM 			smb_node_free(node);
4645331Samw 			return;
4655331Samw 
4665331Samw 		default:
467*8934SJose.Borrego@Sun.COM 			SMB_PANIC();
4685331Samw 		}
4695331Samw 	}
470*8934SJose.Borrego@Sun.COM 	smb_node_audit(node);
471*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
4725331Samw }
4735331Samw 
4745331Samw static void
4755331Samw smb_node_delete_on_close(smb_node_t *node)
4765331Samw {
4775331Samw 	smb_node_t	*d_snode;
4785331Samw 	int		rc = 0;
4795331Samw 
4805331Samw 	d_snode = node->dir_snode;
4815331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
4825331Samw 
4835331Samw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
4845331Samw 		ASSERT(node->od_name != NULL);
4855331Samw 		if (node->attr.sa_vattr.va_type == VDIR)
4865331Samw 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
4875331Samw 			    d_snode, node->od_name, 1);
4885331Samw 		else
4895331Samw 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
4905331Samw 			    d_snode, node->od_name, 1);
4915331Samw 		smb_cred_rele(node->delete_on_close_cred);
4925331Samw 	}
4935331Samw 	if (rc != 0)
4945331Samw 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
4955331Samw 		    node->od_name, rc);
4965331Samw 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
4975331Samw }
4985331Samw 
4995331Samw /*
5005331Samw  * smb_node_rename()
5015331Samw  *
5025331Samw  */
503*8934SJose.Borrego@Sun.COM void
5045331Samw smb_node_rename(
505*8934SJose.Borrego@Sun.COM     smb_node_t	*from_dnode,
506*8934SJose.Borrego@Sun.COM     smb_node_t	*ret_node,
507*8934SJose.Borrego@Sun.COM     smb_node_t	*to_dnode,
5085331Samw     char	*to_name)
5095331Samw {
510*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(from_dnode);
511*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(to_dnode);
512*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(ret_node);
5135331Samw 
514*8934SJose.Borrego@Sun.COM 	smb_node_ref(to_dnode);
515*8934SJose.Borrego@Sun.COM 	mutex_enter(&ret_node->n_mutex);
516*8934SJose.Borrego@Sun.COM 	switch (ret_node->n_state) {
517*8934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
518*8934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
519*8934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
520*8934SJose.Borrego@Sun.COM 		ret_node->dir_snode = to_dnode;
521*8934SJose.Borrego@Sun.COM 		mutex_exit(&ret_node->n_mutex);
522*8934SJose.Borrego@Sun.COM 		ASSERT(to_dnode->dir_snode != ret_node);
523*8934SJose.Borrego@Sun.COM 		ASSERT((to_dnode->vp->v_xattrdir) ||
524*8934SJose.Borrego@Sun.COM 		    (to_dnode->vp->v_type == VDIR));
525*8934SJose.Borrego@Sun.COM 		smb_node_release(from_dnode);
526*8934SJose.Borrego@Sun.COM 		(void) strcpy(ret_node->od_name, to_name);
527*8934SJose.Borrego@Sun.COM 		/*
528*8934SJose.Borrego@Sun.COM 		 * XXX Need to update attributes?
529*8934SJose.Borrego@Sun.COM 		 */
530*8934SJose.Borrego@Sun.COM 		break;
531*8934SJose.Borrego@Sun.COM 	default:
532*8934SJose.Borrego@Sun.COM 		SMB_PANIC();
533*8934SJose.Borrego@Sun.COM 	}
5345331Samw }
5355331Samw 
5365331Samw int
5376139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
5385331Samw {
5396139Sjb150015 	smb_attr_t	va;
5406139Sjb150015 	int		error;
5416139Sjb150015 	uint32_t	hashkey;
5426139Sjb150015 	smb_llist_t	*node_hdr;
5436139Sjb150015 	smb_node_t	*node;
5445331Samw 
5456139Sjb150015 	va.sa_mask = SMB_AT_ALL;
5466139Sjb150015 	error = smb_vop_getattr(vp, NULL, &va, 0, kcred);
5476139Sjb150015 	if (error) {
5486139Sjb150015 		VN_RELE(vp);
5496139Sjb150015 		return (error);
5506139Sjb150015 	}
5516139Sjb150015 
552*8934SJose.Borrego@Sun.COM 	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey);
5535331Samw 
554*8934SJose.Borrego@Sun.COM 	node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey);
5556139Sjb150015 
5566139Sjb150015 	sv->si_root_smb_node = node;
557*8934SJose.Borrego@Sun.COM 	smb_node_audit(node);
5586139Sjb150015 	smb_llist_enter(node_hdr, RW_WRITER);
5596139Sjb150015 	smb_llist_insert_head(node_hdr, node);
5606139Sjb150015 	smb_llist_exit(node_hdr);
5616139Sjb150015 	*root = node;
5626139Sjb150015 	return (0);
5635331Samw }
5645331Samw 
5655331Samw /*
5665331Samw  * smb_node_get_size
5675331Samw  */
5686432Sas200622 u_offset_t
5696432Sas200622 smb_node_get_size(smb_node_t *node, smb_attr_t *attr)
5705331Samw {
5716432Sas200622 	u_offset_t size;
5725331Samw 
5735331Samw 	if (attr->sa_vattr.va_type == VDIR)
5745331Samw 		return (0);
5755331Samw 
576*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
5775331Samw 	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
5785331Samw 		size = node->n_size;
5795331Samw 	else
5805331Samw 		size = attr->sa_vattr.va_size;
581*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
5825331Samw 	return (size);
5835331Samw }
5845331Samw 
5855331Samw static int
5865331Samw timeval_cmp(timestruc_t *a, timestruc_t *b)
5875331Samw {
5885331Samw 	if (a->tv_sec < b->tv_sec)
5895331Samw 		return (-1);
5905331Samw 	if (a->tv_sec > b->tv_sec)
5915331Samw 		return (1);
5925331Samw 	/* Seconds are equal compare tv_nsec */
5935331Samw 	if (a->tv_nsec < b->tv_nsec)
5945331Samw 		return (-1);
5955331Samw 	return (a->tv_nsec > b->tv_nsec);
5965331Samw }
5975331Samw 
5985331Samw /*
5995331Samw  * smb_node_set_time
6005331Samw  *
6015331Samw  * This function will update the time stored in the node and
6027348SJose.Borrego@Sun.COM  * set the appropriate flags. If there is nothing to update,
6037348SJose.Borrego@Sun.COM  * the function will return without any updates.  The update
6047348SJose.Borrego@Sun.COM  * is only in the node level and the attribute in the file system
6057348SJose.Borrego@Sun.COM  * will be updated when client close the file.
6065331Samw  */
6075331Samw void
608*8934SJose.Borrego@Sun.COM smb_node_set_time(
609*8934SJose.Borrego@Sun.COM     smb_node_t	*node,
610*8934SJose.Borrego@Sun.COM     timestruc_t	*crtime,
611*8934SJose.Borrego@Sun.COM     timestruc_t	*mtime,
612*8934SJose.Borrego@Sun.COM     timestruc_t	*atime,
613*8934SJose.Borrego@Sun.COM     timestruc_t	*ctime,
614*8934SJose.Borrego@Sun.COM     uint_t	what)
6155331Samw {
6167348SJose.Borrego@Sun.COM 	if (what == 0)
6175331Samw 		return;
6185331Samw 
6195331Samw 	if ((what & SMB_AT_CRTIME && crtime == 0) ||
6205331Samw 	    (what & SMB_AT_MTIME && mtime == 0) ||
6215331Samw 	    (what & SMB_AT_ATIME && atime == 0) ||
6227348SJose.Borrego@Sun.COM 	    (what & SMB_AT_CTIME && ctime == 0))
6235331Samw 		return;
6247348SJose.Borrego@Sun.COM 
625*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
6265331Samw 
6275331Samw 	if ((what & SMB_AT_CRTIME) &&
6285331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
6295331Samw 	    crtime) != 0) {
6305331Samw 		node->what |= SMB_AT_CRTIME;
6315331Samw 		node->attr.sa_crtime = *((timestruc_t *)crtime);
6325331Samw 	}
6335331Samw 
6345331Samw 	if ((what & SMB_AT_MTIME) &&
6355331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
6365331Samw 	    mtime) != 0) {
6375331Samw 		node->what |= SMB_AT_MTIME;
6385331Samw 		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
6395331Samw 	}
6405331Samw 
6415331Samw 	if ((what & SMB_AT_ATIME) &&
6425331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
6435331Samw 	    atime) != 0) {
6445331Samw 			node->what |= SMB_AT_ATIME;
6455331Samw 			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
6465331Samw 	}
6475331Samw 
6485331Samw 	/*
6495331Samw 	 * The ctime handling is trickier. It has three scenarios.
6505331Samw 	 * 1. Only ctime need to be set and it is the same as the ctime
6515331Samw 	 *    stored in the node. (update not necessary)
6525331Samw 	 * 2. The ctime is the same as the ctime stored in the node but
6535331Samw 	 *    is not the only time need to be set. (update required)
6545331Samw 	 * 3. The ctime need to be set and is not the same as the ctime
6555331Samw 	 *    stored in the node. (update required)
6565331Samw 	 * Unlike other time setting, the ctime needs to be set even when
6575331Samw 	 * it is the same as the ctime in the node if there are other time
6585331Samw 	 * needs to be set (#2). This will ensure the ctime not being
6595331Samw 	 * updated when other times are being updated in the file system.
6605331Samw 	 *
6615331Samw 	 * Retained file rules:
6625331Samw 	 *
6635331Samw 	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
6645331Samw 	 *    request will be rejected by filesystem
6655331Samw 	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
6665331Samw 	 *    any request for changing ctime on these files should have
6675331Samw 	 *    been already rejected
6685331Samw 	 */
6695331Samw 	node->what |= SMB_AT_CTIME;
6705331Samw 	if (what & SMB_AT_CTIME) {
6715331Samw 		if ((what == SMB_AT_CTIME) &&
6725331Samw 		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
6735331Samw 		    ctime) == 0) {
6745331Samw 			node->what &= ~SMB_AT_CTIME;
6755331Samw 		} else {
6765331Samw 			gethrestime(&node->attr.sa_vattr.va_ctime);
6775331Samw 		}
6785331Samw 	} else {
6795331Samw 		gethrestime(&node->attr.sa_vattr.va_ctime);
6805331Samw 	}
681*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
6825331Samw }
6835331Samw 
6845331Samw 
6855331Samw timestruc_t *
6865331Samw smb_node_get_crtime(smb_node_t *node)
6875331Samw {
6885331Samw 	return ((timestruc_t *)&node->attr.sa_crtime);
6895331Samw }
6905331Samw 
6915331Samw timestruc_t *
6925331Samw smb_node_get_atime(smb_node_t *node)
6935331Samw {
6945331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
6955331Samw }
6965331Samw 
6975331Samw timestruc_t *
6985331Samw smb_node_get_ctime(smb_node_t *node)
6995331Samw {
7005331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
7015331Samw }
7025331Samw 
7035331Samw timestruc_t *
7045331Samw smb_node_get_mtime(smb_node_t *node)
7055331Samw {
7065331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
7075331Samw }
7085331Samw 
7095331Samw /*
7105331Samw  * smb_node_set_dosattr
7115331Samw  *
7125331Samw  * Parse the specified DOS attributes and, if they have been modified,
7135331Samw  * update the node cache. This call should be followed by a
7145331Samw  * smb_sync_fsattr() call to write the attribute changes to filesystem.
7155331Samw  */
7165331Samw void
7177052Samw smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr)
7185331Samw {
7197052Samw 	uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE |
7207052Samw 	    FILE_ATTRIBUTE_READONLY |
7217052Samw 	    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
7225331Samw 
723*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
7245331Samw 	if (node->attr.sa_dosattr != mode) {
7255331Samw 		node->attr.sa_dosattr = mode;
7265331Samw 		node->what |= SMB_AT_DOSATTR;
7275331Samw 	}
728*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
7295331Samw }
7305331Samw 
7315331Samw /*
7327348SJose.Borrego@Sun.COM  * smb_node_get_dosattr()
7335331Samw  *
7347348SJose.Borrego@Sun.COM  * This function is used to provide clients with information as to whether
7357348SJose.Borrego@Sun.COM  * the readonly bit is set.  Hence both the node attribute cache (which
7367348SJose.Borrego@Sun.COM  * reflects the on-disk attributes) and node->readonly_creator (which
7377348SJose.Borrego@Sun.COM  * reflects whether a readonly set is pending from a readonly create) are
7387348SJose.Borrego@Sun.COM  * checked.  In the latter case, the readonly attribute should be visible to
7397348SJose.Borrego@Sun.COM  * all clients even though the readonly creator fid is immune to the readonly
7407348SJose.Borrego@Sun.COM  * bit until close.
7415331Samw  */
7427348SJose.Borrego@Sun.COM 
7435331Samw uint32_t
7445331Samw smb_node_get_dosattr(smb_node_t *node)
7455331Samw {
7467348SJose.Borrego@Sun.COM 	uint32_t dosattr = node->attr.sa_dosattr;
7477348SJose.Borrego@Sun.COM 
7487348SJose.Borrego@Sun.COM 	if (node->readonly_creator)
7497348SJose.Borrego@Sun.COM 		dosattr |= FILE_ATTRIBUTE_READONLY;
7507348SJose.Borrego@Sun.COM 
7517348SJose.Borrego@Sun.COM 	if (!dosattr)
7527348SJose.Borrego@Sun.COM 		dosattr = FILE_ATTRIBUTE_NORMAL;
7537348SJose.Borrego@Sun.COM 
7547348SJose.Borrego@Sun.COM 	return (dosattr);
7555331Samw }
7565331Samw 
7575331Samw int
7585331Samw smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
7595331Samw {
7605331Samw 	int	rc = -1;
7615331Samw 
762*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
7635331Samw 	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
7645331Samw 	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
7655331Samw 		crhold(cr);
7665331Samw 		node->delete_on_close_cred = cr;
7675331Samw 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
7685331Samw 		rc = 0;
7695331Samw 	}
770*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
7715331Samw 	return (rc);
7725331Samw }
7735331Samw 
7745331Samw void
7755331Samw smb_node_reset_delete_on_close(smb_node_t *node)
7765331Samw {
777*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
7785331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
7795331Samw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
7805331Samw 		crfree(node->delete_on_close_cred);
7815331Samw 		node->delete_on_close_cred = NULL;
7825331Samw 	}
783*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
7845331Samw }
7855772Sas200622 
7865772Sas200622 /*
7876771Sjb150015  * smb_node_open_check
7885772Sas200622  *
7895772Sas200622  * check file sharing rules for current open request
7905772Sas200622  * against all existing opens for a file.
7915772Sas200622  *
7925772Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
7935772Sas200622  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
7945772Sas200622  */
7955772Sas200622 uint32_t
796*8934SJose.Borrego@Sun.COM smb_node_open_check(
797*8934SJose.Borrego@Sun.COM     smb_node_t	*node,
798*8934SJose.Borrego@Sun.COM     cred_t	*cr,
799*8934SJose.Borrego@Sun.COM     uint32_t	desired_access,
800*8934SJose.Borrego@Sun.COM     uint32_t	share_access)
8015772Sas200622 {
8025772Sas200622 	smb_ofile_t *of;
8035772Sas200622 	uint32_t status;
8045772Sas200622 
805*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
8065772Sas200622 
8075772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
8085772Sas200622 	of = smb_llist_head(&node->n_ofile_list);
8095772Sas200622 	while (of) {
8106771Sjb150015 		status = smb_ofile_open_check(of, cr, desired_access,
8116771Sjb150015 		    share_access);
8126771Sjb150015 
8136771Sjb150015 		switch (status) {
8146771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
8156771Sjb150015 		case NT_STATUS_SUCCESS:
8166771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
8176771Sjb150015 			break;
8186771Sjb150015 		default:
8196771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
8205772Sas200622 			smb_llist_exit(&node->n_ofile_list);
8215772Sas200622 			return (status);
8225772Sas200622 		}
8235772Sas200622 	}
8246771Sjb150015 
8255772Sas200622 	smb_llist_exit(&node->n_ofile_list);
8265772Sas200622 	return (NT_STATUS_SUCCESS);
8275772Sas200622 }
8285772Sas200622 
8295772Sas200622 uint32_t
830*8934SJose.Borrego@Sun.COM smb_node_rename_check(smb_node_t *node)
8315772Sas200622 {
832*8934SJose.Borrego@Sun.COM 	smb_ofile_t	*of;
833*8934SJose.Borrego@Sun.COM 	uint32_t	status;
8345772Sas200622 
835*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
8365772Sas200622 
8375772Sas200622 	/*
8385772Sas200622 	 * Intra-CIFS check
8395772Sas200622 	 */
8405772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
8416771Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
8426771Sjb150015 	while (of) {
8436771Sjb150015 		status = smb_ofile_rename_check(of);
8445772Sas200622 
8456771Sjb150015 		switch (status) {
8466771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
8476771Sjb150015 		case NT_STATUS_SUCCESS:
8486771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
8496771Sjb150015 			break;
8506771Sjb150015 		default:
8516771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
8526771Sjb150015 			smb_llist_exit(&node->n_ofile_list);
8536771Sjb150015 			return (status);
8545772Sas200622 		}
8555772Sas200622 	}
8565772Sas200622 	smb_llist_exit(&node->n_ofile_list);
8575772Sas200622 
8585772Sas200622 	/*
8595772Sas200622 	 * system-wide share check
8605772Sas200622 	 */
8615772Sas200622 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
8625772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
8635772Sas200622 	else
8645772Sas200622 		return (NT_STATUS_SUCCESS);
8655772Sas200622 }
8665772Sas200622 
8676771Sjb150015 uint32_t
8685772Sas200622 smb_node_delete_check(smb_node_t *node)
8695772Sas200622 {
870*8934SJose.Borrego@Sun.COM 	smb_ofile_t	*of;
871*8934SJose.Borrego@Sun.COM 	uint32_t	status;
8725772Sas200622 
873*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
8745772Sas200622 
8755772Sas200622 	if (node->attr.sa_vattr.va_type == VDIR)
8765772Sas200622 		return (NT_STATUS_SUCCESS);
8775772Sas200622 
8785772Sas200622 	/*
8795772Sas200622 	 * intra-CIFS check
8805772Sas200622 	 */
8815772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
8826771Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
8836771Sjb150015 	while (of) {
8846771Sjb150015 		status = smb_ofile_delete_check(of);
8856771Sjb150015 
8866771Sjb150015 		switch (status) {
8876771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
8886771Sjb150015 		case NT_STATUS_SUCCESS:
8896771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
8906771Sjb150015 			break;
8916771Sjb150015 		default:
8926771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
8935772Sas200622 			smb_llist_exit(&node->n_ofile_list);
8946771Sjb150015 			return (status);
8955772Sas200622 		}
8965772Sas200622 	}
8975772Sas200622 	smb_llist_exit(&node->n_ofile_list);
8985772Sas200622 
8995772Sas200622 	/*
9005772Sas200622 	 * system-wide share check
9015772Sas200622 	 */
9025772Sas200622 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
9035772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
9045772Sas200622 	else
9055772Sas200622 		return (NT_STATUS_SUCCESS);
9065772Sas200622 }
9075772Sas200622 
9085772Sas200622 /*
9095772Sas200622  * smb_node_start_crit()
9105772Sas200622  *
9115772Sas200622  * Enter critical region for share reservations.
9125772Sas200622  * See comments above smb_fsop_shrlock().
9135772Sas200622  */
9145772Sas200622 
9155772Sas200622 void
9165772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode)
9175772Sas200622 {
918*8934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, mode);
9195772Sas200622 	nbl_start_crit(node->vp, mode);
9205772Sas200622 }
9215772Sas200622 
9225772Sas200622 /*
9235772Sas200622  * smb_node_end_crit()
9245772Sas200622  *
9255772Sas200622  * Exit critical region for share reservations.
9265772Sas200622  */
9275772Sas200622 
9285772Sas200622 void
9295772Sas200622 smb_node_end_crit(smb_node_t *node)
9305772Sas200622 {
9315772Sas200622 	nbl_end_crit(node->vp);
932*8934SJose.Borrego@Sun.COM 	rw_exit(&node->n_lock);
9335772Sas200622 }
9345772Sas200622 
9355772Sas200622 int
9365772Sas200622 smb_node_in_crit(smb_node_t *node)
9375772Sas200622 {
938*8934SJose.Borrego@Sun.COM 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
939*8934SJose.Borrego@Sun.COM }
940*8934SJose.Borrego@Sun.COM 
941*8934SJose.Borrego@Sun.COM void
942*8934SJose.Borrego@Sun.COM smb_node_rdlock(smb_node_t *node)
943*8934SJose.Borrego@Sun.COM {
944*8934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, RW_READER);
945*8934SJose.Borrego@Sun.COM }
946*8934SJose.Borrego@Sun.COM 
947*8934SJose.Borrego@Sun.COM void
948*8934SJose.Borrego@Sun.COM smb_node_wrlock(smb_node_t *node)
949*8934SJose.Borrego@Sun.COM {
950*8934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, RW_WRITER);
951*8934SJose.Borrego@Sun.COM }
952*8934SJose.Borrego@Sun.COM 
953*8934SJose.Borrego@Sun.COM void
954*8934SJose.Borrego@Sun.COM smb_node_unlock(smb_node_t *node)
955*8934SJose.Borrego@Sun.COM {
956*8934SJose.Borrego@Sun.COM 	rw_exit(&node->n_lock);
957*8934SJose.Borrego@Sun.COM }
958*8934SJose.Borrego@Sun.COM 
959*8934SJose.Borrego@Sun.COM uint32_t
960*8934SJose.Borrego@Sun.COM smb_node_get_ofile_count(smb_node_t *node)
961*8934SJose.Borrego@Sun.COM {
962*8934SJose.Borrego@Sun.COM 	uint32_t	cntr;
963*8934SJose.Borrego@Sun.COM 
964*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
965*8934SJose.Borrego@Sun.COM 
966*8934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_READER);
967*8934SJose.Borrego@Sun.COM 	cntr = smb_llist_get_count(&node->n_ofile_list);
968*8934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
969*8934SJose.Borrego@Sun.COM 	return (cntr);
970*8934SJose.Borrego@Sun.COM }
971*8934SJose.Borrego@Sun.COM 
972*8934SJose.Borrego@Sun.COM void
973*8934SJose.Borrego@Sun.COM smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
974*8934SJose.Borrego@Sun.COM {
975*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
976*8934SJose.Borrego@Sun.COM 
977*8934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
978*8934SJose.Borrego@Sun.COM 	smb_llist_insert_tail(&node->n_ofile_list, of);
979*8934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
980*8934SJose.Borrego@Sun.COM }
981*8934SJose.Borrego@Sun.COM 
982*8934SJose.Borrego@Sun.COM void
983*8934SJose.Borrego@Sun.COM smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
984*8934SJose.Borrego@Sun.COM {
985*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
986*8934SJose.Borrego@Sun.COM 
987*8934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
988*8934SJose.Borrego@Sun.COM 	smb_llist_remove(&node->n_ofile_list, of);
989*8934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
990*8934SJose.Borrego@Sun.COM }
991*8934SJose.Borrego@Sun.COM 
992*8934SJose.Borrego@Sun.COM void
993*8934SJose.Borrego@Sun.COM smb_node_inc_open_ofiles(smb_node_t *node)
994*8934SJose.Borrego@Sun.COM {
995*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
996*8934SJose.Borrego@Sun.COM 
997*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
998*8934SJose.Borrego@Sun.COM 	node->n_open_count++;
999*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
1000*8934SJose.Borrego@Sun.COM }
1001*8934SJose.Borrego@Sun.COM 
1002*8934SJose.Borrego@Sun.COM void
1003*8934SJose.Borrego@Sun.COM smb_node_dec_open_ofiles(smb_node_t *node)
1004*8934SJose.Borrego@Sun.COM {
1005*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
1006*8934SJose.Borrego@Sun.COM 
1007*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
1008*8934SJose.Borrego@Sun.COM 	node->n_open_count--;
1009*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
1010*8934SJose.Borrego@Sun.COM }
1011*8934SJose.Borrego@Sun.COM 
1012*8934SJose.Borrego@Sun.COM uint32_t
1013*8934SJose.Borrego@Sun.COM smb_node_get_open_ofiles(smb_node_t *node)
1014*8934SJose.Borrego@Sun.COM {
1015*8934SJose.Borrego@Sun.COM 	uint32_t	cnt;
1016*8934SJose.Borrego@Sun.COM 
1017*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
1018*8934SJose.Borrego@Sun.COM 
1019*8934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
1020*8934SJose.Borrego@Sun.COM 	cnt = node->n_open_count;
1021*8934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
1022*8934SJose.Borrego@Sun.COM 	return (cnt);
10235772Sas200622 }
1024*8934SJose.Borrego@Sun.COM 
1025*8934SJose.Borrego@Sun.COM /*
1026*8934SJose.Borrego@Sun.COM  * smb_node_alloc
1027*8934SJose.Borrego@Sun.COM  */
1028*8934SJose.Borrego@Sun.COM static smb_node_t *
1029*8934SJose.Borrego@Sun.COM smb_node_alloc(
1030*8934SJose.Borrego@Sun.COM     char	*od_name,
1031*8934SJose.Borrego@Sun.COM     vnode_t	*vp,
1032*8934SJose.Borrego@Sun.COM     smb_attr_t	*attr,
1033*8934SJose.Borrego@Sun.COM     smb_llist_t	*bucket,
1034*8934SJose.Borrego@Sun.COM     uint32_t	hashkey)
1035*8934SJose.Borrego@Sun.COM {
1036*8934SJose.Borrego@Sun.COM 	smb_node_t	*node;
1037*8934SJose.Borrego@Sun.COM 
1038*8934SJose.Borrego@Sun.COM 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
1039*8934SJose.Borrego@Sun.COM 
1040*8934SJose.Borrego@Sun.COM 	if (node->n_audit_buf != NULL)
1041*8934SJose.Borrego@Sun.COM 		node->n_audit_buf->anb_index = 0;
1042*8934SJose.Borrego@Sun.COM 
1043*8934SJose.Borrego@Sun.COM 	node->attr = *attr;
1044*8934SJose.Borrego@Sun.COM 	node->flags = NODE_FLAGS_ATTR_VALID;
1045*8934SJose.Borrego@Sun.COM 	node->n_size = node->attr.sa_vattr.va_size;
1046*8934SJose.Borrego@Sun.COM 	VN_HOLD(vp);
1047*8934SJose.Borrego@Sun.COM 	node->vp = vp;
1048*8934SJose.Borrego@Sun.COM 	node->n_refcnt = 1;
1049*8934SJose.Borrego@Sun.COM 	node->n_hash_bucket = bucket;
1050*8934SJose.Borrego@Sun.COM 	node->n_hashkey = hashkey;
1051*8934SJose.Borrego@Sun.COM 	node->n_orig_uid = 0;
1052*8934SJose.Borrego@Sun.COM 	node->readonly_creator = NULL;
1053*8934SJose.Borrego@Sun.COM 	node->waiting_event = 0;
1054*8934SJose.Borrego@Sun.COM 	node->what = 0;
1055*8934SJose.Borrego@Sun.COM 	node->n_open_count = 0;
1056*8934SJose.Borrego@Sun.COM 	node->dir_snode = NULL;
1057*8934SJose.Borrego@Sun.COM 	node->unnamed_stream_node = NULL;
1058*8934SJose.Borrego@Sun.COM 	node->delete_on_close_cred = NULL;
1059*8934SJose.Borrego@Sun.COM 
1060*8934SJose.Borrego@Sun.COM 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
1061*8934SJose.Borrego@Sun.COM 	if (strcmp(od_name, XATTR_DIR) == 0)
1062*8934SJose.Borrego@Sun.COM 		node->flags |= NODE_XATTR_DIR;
1063*8934SJose.Borrego@Sun.COM 
1064*8934SJose.Borrego@Sun.COM 	node->n_state = SMB_NODE_STATE_AVAILABLE;
1065*8934SJose.Borrego@Sun.COM 	node->n_magic = SMB_NODE_MAGIC;
1066*8934SJose.Borrego@Sun.COM 	return (node);
1067*8934SJose.Borrego@Sun.COM }
1068*8934SJose.Borrego@Sun.COM 
1069*8934SJose.Borrego@Sun.COM /*
1070*8934SJose.Borrego@Sun.COM  * smb_node_free
1071*8934SJose.Borrego@Sun.COM  */
1072*8934SJose.Borrego@Sun.COM static void
1073*8934SJose.Borrego@Sun.COM smb_node_free(smb_node_t *node)
1074*8934SJose.Borrego@Sun.COM {
1075*8934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
1076*8934SJose.Borrego@Sun.COM 
1077*8934SJose.Borrego@Sun.COM 	node->n_magic = 0;
1078*8934SJose.Borrego@Sun.COM 	VERIFY(!list_link_active(&node->n_lnd));
1079*8934SJose.Borrego@Sun.COM 	VERIFY(node->n_lock_list.ll_count == 0);
1080*8934SJose.Borrego@Sun.COM 	VERIFY(node->n_ofile_list.ll_count == 0);
1081*8934SJose.Borrego@Sun.COM 	VERIFY(node->n_oplock.ol_xthread == NULL);
1082*8934SJose.Borrego@Sun.COM 	VERIFY(node->n_oplock.ol_waiters_count == 0);
1083*8934SJose.Borrego@Sun.COM 	VN_RELE(node->vp);
1084*8934SJose.Borrego@Sun.COM 	kmem_cache_free(smb_node_cache, node);
1085*8934SJose.Borrego@Sun.COM }
1086*8934SJose.Borrego@Sun.COM 
1087*8934SJose.Borrego@Sun.COM /*
1088*8934SJose.Borrego@Sun.COM  * smb_node_constructor
1089*8934SJose.Borrego@Sun.COM  */
1090*8934SJose.Borrego@Sun.COM static int
1091*8934SJose.Borrego@Sun.COM smb_node_constructor(void *buf, void *un, int kmflags)
1092*8934SJose.Borrego@Sun.COM {
1093*8934SJose.Borrego@Sun.COM 	_NOTE(ARGUNUSED(kmflags, un))
1094*8934SJose.Borrego@Sun.COM 
1095*8934SJose.Borrego@Sun.COM 	smb_node_t	*node = (smb_node_t *)buf;
1096*8934SJose.Borrego@Sun.COM 
1097*8934SJose.Borrego@Sun.COM 	bzero(node, sizeof (smb_node_t));
1098*8934SJose.Borrego@Sun.COM 
1099*8934SJose.Borrego@Sun.COM 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1100*8934SJose.Borrego@Sun.COM 	    offsetof(smb_ofile_t, f_nnd));
1101*8934SJose.Borrego@Sun.COM 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
1102*8934SJose.Borrego@Sun.COM 	    offsetof(smb_lock_t, l_lnd));
1103*8934SJose.Borrego@Sun.COM 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
1104*8934SJose.Borrego@Sun.COM 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
1105*8934SJose.Borrego@Sun.COM 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
1106*8934SJose.Borrego@Sun.COM 	smb_node_create_audit_buf(node, kmflags);
1107*8934SJose.Borrego@Sun.COM 	return (0);
1108*8934SJose.Borrego@Sun.COM }
1109*8934SJose.Borrego@Sun.COM 
1110*8934SJose.Borrego@Sun.COM /*
1111*8934SJose.Borrego@Sun.COM  * smb_node_destructor
1112*8934SJose.Borrego@Sun.COM  */
1113*8934SJose.Borrego@Sun.COM static void
1114*8934SJose.Borrego@Sun.COM smb_node_destructor(void *buf, void *un)
1115*8934SJose.Borrego@Sun.COM {
1116*8934SJose.Borrego@Sun.COM 	_NOTE(ARGUNUSED(un))
1117*8934SJose.Borrego@Sun.COM 
1118*8934SJose.Borrego@Sun.COM 	smb_node_t	*node = (smb_node_t *)buf;
1119*8934SJose.Borrego@Sun.COM 
1120*8934SJose.Borrego@Sun.COM 	smb_node_destroy_audit_buf(node);
1121*8934SJose.Borrego@Sun.COM 	mutex_destroy(&node->n_mutex);
1122*8934SJose.Borrego@Sun.COM 	rw_destroy(&node->n_lock);
1123*8934SJose.Borrego@Sun.COM 	cv_destroy(&node->n_oplock.ol_cv);
1124*8934SJose.Borrego@Sun.COM 	smb_llist_destructor(&node->n_lock_list);
1125*8934SJose.Borrego@Sun.COM 	smb_llist_destructor(&node->n_ofile_list);
1126*8934SJose.Borrego@Sun.COM }
1127*8934SJose.Borrego@Sun.COM 
1128*8934SJose.Borrego@Sun.COM /*
1129*8934SJose.Borrego@Sun.COM  * smb_node_create_audit_buf
1130*8934SJose.Borrego@Sun.COM  */
1131*8934SJose.Borrego@Sun.COM static void
1132*8934SJose.Borrego@Sun.COM smb_node_create_audit_buf(smb_node_t *node, int kmflags)
1133*8934SJose.Borrego@Sun.COM {
1134*8934SJose.Borrego@Sun.COM 	smb_audit_buf_node_t	*abn;
1135*8934SJose.Borrego@Sun.COM 
1136*8934SJose.Borrego@Sun.COM 	if (smb_audit_flags & SMB_AUDIT_NODE) {
1137*8934SJose.Borrego@Sun.COM 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
1138*8934SJose.Borrego@Sun.COM 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
1139*8934SJose.Borrego@Sun.COM 		node->n_audit_buf = abn;
1140*8934SJose.Borrego@Sun.COM 	}
1141*8934SJose.Borrego@Sun.COM }
1142*8934SJose.Borrego@Sun.COM 
1143*8934SJose.Borrego@Sun.COM /*
1144*8934SJose.Borrego@Sun.COM  * smb_node_destroy_audit_buf
1145*8934SJose.Borrego@Sun.COM  */
1146*8934SJose.Borrego@Sun.COM static void
1147*8934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(smb_node_t *node)
1148*8934SJose.Borrego@Sun.COM {
1149*8934SJose.Borrego@Sun.COM 	if (node->n_audit_buf != NULL) {
1150*8934SJose.Borrego@Sun.COM 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
1151*8934SJose.Borrego@Sun.COM 		node->n_audit_buf = NULL;
1152*8934SJose.Borrego@Sun.COM 	}
1153*8934SJose.Borrego@Sun.COM }
1154*8934SJose.Borrego@Sun.COM 
1155*8934SJose.Borrego@Sun.COM /*
1156*8934SJose.Borrego@Sun.COM  * smb_node_audit
1157*8934SJose.Borrego@Sun.COM  *
1158*8934SJose.Borrego@Sun.COM  * This function saves the calling stack in the audit buffer of the node passed
1159*8934SJose.Borrego@Sun.COM  * in.
1160*8934SJose.Borrego@Sun.COM  */
1161*8934SJose.Borrego@Sun.COM static void
1162*8934SJose.Borrego@Sun.COM smb_node_audit(smb_node_t *node)
1163*8934SJose.Borrego@Sun.COM {
1164*8934SJose.Borrego@Sun.COM 	smb_audit_buf_node_t	*abn;
1165*8934SJose.Borrego@Sun.COM 	smb_audit_record_node_t	*anr;
1166*8934SJose.Borrego@Sun.COM 
1167*8934SJose.Borrego@Sun.COM 	if (node->n_audit_buf) {
1168*8934SJose.Borrego@Sun.COM 		abn = node->n_audit_buf;
1169*8934SJose.Borrego@Sun.COM 		anr = abn->anb_records;
1170*8934SJose.Borrego@Sun.COM 		anr += abn->anb_index;
1171*8934SJose.Borrego@Sun.COM 		abn->anb_index++;
1172*8934SJose.Borrego@Sun.COM 		abn->anb_index &= abn->anb_max_index;
1173*8934SJose.Borrego@Sun.COM 		anr->anr_refcnt = node->n_refcnt;
1174*8934SJose.Borrego@Sun.COM 		anr->anr_depth = getpcstack(anr->anr_stack,
1175*8934SJose.Borrego@Sun.COM 		    SMB_AUDIT_STACK_DEPTH);
1176*8934SJose.Borrego@Sun.COM 	}
1177*8934SJose.Borrego@Sun.COM }
1178*8934SJose.Borrego@Sun.COM 
1179*8934SJose.Borrego@Sun.COM static smb_llist_t *
1180*8934SJose.Borrego@Sun.COM smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
1181*8934SJose.Borrego@Sun.COM {
1182*8934SJose.Borrego@Sun.COM 	uint32_t	hashkey;
1183*8934SJose.Borrego@Sun.COM 
1184*8934SJose.Borrego@Sun.COM 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
1185*8934SJose.Borrego@Sun.COM 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1186*8934SJose.Borrego@Sun.COM 	*phashkey = hashkey;
1187*8934SJose.Borrego@Sun.COM 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1188*8934SJose.Borrego@Sun.COM }
1189