xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 8b2cc8ac894f2d58f38cf2fb7c3ac778f4c57c09)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
227f667e74Sjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw /*
26da6c28aaSamw  * SMB Node State Machine
27da6c28aaSamw  * ----------------------
28da6c28aaSamw  *
29fc724630SAlan Wright  *
30fc724630SAlan Wright  *		    +----------- Creation/Allocation
31da6c28aaSamw  *		    |
32fc724630SAlan Wright  *		    | T0
33da6c28aaSamw  *		    |
34da6c28aaSamw  *		    v
35fc724630SAlan Wright  *    +----------------------------+        T1
36fc724630SAlan Wright  *    |  SMB_NODE_STATE_AVAILABLE  |--------------------+
37fc724630SAlan Wright  *    +----------------------------+			|
38fc724630SAlan Wright  *		    |	     ^				|
39fc724630SAlan Wright  *		    |	     |				v
40fc724630SAlan Wright  *		    |	     |	  T2	+-------------------------------+
41fc724630SAlan Wright  *		    |	     |<---------| SMB_NODE_STATE_OPLOCK_GRANTED |
42fc724630SAlan Wright  *		    |	     |		+-------------------------------+
43fc724630SAlan Wright  *		    | T5     |				|
44fc724630SAlan Wright  *		    |	     |				| T3
45fc724630SAlan Wright  *		    |	     |				v
46fc724630SAlan Wright  *		    |	     |	  T4	+--------------------------------+
47fc724630SAlan Wright  *		    |	     +----------| SMB_NODE_STATE_OPLOCK_BREAKING |
48fc724630SAlan Wright  *		    |			+--------------------------------+
49fc724630SAlan Wright  *		    |
50fc724630SAlan Wright  *		    v
51da6c28aaSamw  *    +-----------------------------+
52fc724630SAlan Wright  *    |  SMB_NODE_STATE_DESTROYING  |
53fc724630SAlan Wright  *    +-----------------------------+
54fc724630SAlan Wright  *		    |
55fc724630SAlan Wright  *		    |
56fc724630SAlan Wright  *		    | T6
57fc724630SAlan Wright  *		    |
58fc724630SAlan Wright  *		    +----------> Deletion/Free
59da6c28aaSamw  *
60da6c28aaSamw  * Transition T0
61da6c28aaSamw  *
62da6c28aaSamw  *    This transition occurs in smb_node_lookup(). If the node looked for is
63da6c28aaSamw  *    not found in the has table a new node is created. The reference count is
64da6c28aaSamw  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
65da6c28aaSamw  *
66da6c28aaSamw  * Transition T1
67da6c28aaSamw  *
68fc724630SAlan Wright  *    This transition occurs smb_oplock_acquire() during an OPEN.
69fc724630SAlan Wright  *
70fc724630SAlan Wright  * Transition T2
71fc724630SAlan Wright  *
72fc724630SAlan Wright  *    This transition occurs in smb_oplock_release(). The events triggering
73fc724630SAlan Wright  *    it are:
74fc724630SAlan Wright  *
75fc724630SAlan Wright  *	- LockingAndX sent by the client that was granted the oplock.
76fc724630SAlan Wright  *	- Closing of the file.
77fc724630SAlan Wright  *
78fc724630SAlan Wright  * Transition T3
79fc724630SAlan Wright  *
80fc724630SAlan Wright  *    This transition occurs in smb_oplock_break(). The events triggering
81fc724630SAlan Wright  *    it are:
82fc724630SAlan Wright  *
83fc724630SAlan Wright  *	- Another client wants to open the file.
84fc724630SAlan Wright  *	- A client is trying to delete the file.
85fc724630SAlan Wright  *	- A client is trying to rename the file.
86fc724630SAlan Wright  *	- A client is trying to set/modify  the file attributes.
87fc724630SAlan Wright  *
88fc724630SAlan Wright  * Transition T4
89fc724630SAlan Wright  *
90fc724630SAlan Wright  *    This transition occurs in smb_oplock_release or smb_oplock_break(). The
91fc724630SAlan Wright  *    events triggering it are:
92fc724630SAlan Wright  *
93fc724630SAlan Wright  *	- The client that was granting the oplock releases it (close or
94fc724630SAlan Wright  *	  LockingAndx).
95fc724630SAlan Wright  *	- The time alloted to release the oplock expired.
96fc724630SAlan Wright  *
97fc724630SAlan Wright  * Transition T5
98fc724630SAlan Wright  *
99da6c28aaSamw  *    This transition occurs in smb_node_release(). If the reference count
100da6c28aaSamw  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
101da6c28aaSamw  *    reference count will be given out for that node.
102da6c28aaSamw  *
103fc724630SAlan Wright  * Transition T6
104da6c28aaSamw  *
105da6c28aaSamw  *    This transition occurs in smb_node_release(). The structure is deleted.
106da6c28aaSamw  *
107da6c28aaSamw  * Comments
108da6c28aaSamw  * --------
109da6c28aaSamw  *
110da6c28aaSamw  *    The reason the smb node has 2 states is the following synchronization
111da6c28aaSamw  *    rule:
112da6c28aaSamw  *
113da6c28aaSamw  *    There's a mutex embedded in the node used to protect its fields and
114da6c28aaSamw  *    there's a lock embedded in the bucket of the hash table the node belongs
115da6c28aaSamw  *    to. To increment or to decrement the reference count the mutex must be
116da6c28aaSamw  *    entered. To insert the node into the bucket and to remove it from the
117da6c28aaSamw  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
118da6c28aaSamw  *    lock) have to be entered, the lock has always to be entered first then
119da6c28aaSamw  *    the mutex. This prevents a deadlock between smb_node_lookup() and
120da6c28aaSamw  *    smb_node_release() from occurring. However, in smb_node_release() when the
121da6c28aaSamw  *    reference count drops to zero and triggers the deletion of the node, the
122da6c28aaSamw  *    mutex has to be released before entering the lock of the bucket (to
123da6c28aaSamw  *    remove the node). This creates a window during which the node that is
124da6c28aaSamw  *    about to be freed could be given out by smb_node_lookup(). To close that
125da6c28aaSamw  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
126da6c28aaSamw  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
127da6c28aaSamw  *    state will indicate that the node should be treated as non existent (of
128da6c28aaSamw  *    course the state of the node should be tested/updated under the
129da6c28aaSamw  *    protection of the mutex).
130da6c28aaSamw  */
131da6c28aaSamw #include <smbsrv/smb_incl.h>
132da6c28aaSamw #include <smbsrv/smb_fsops.h>
1332c2961f8Sjose borrego #include <smbsrv/smb_kstat.h>
134da6c28aaSamw #include <sys/pathname.h>
135da6c28aaSamw #include <sys/sdt.h>
136dc20a302Sas200622 #include <sys/nbmlock.h>
137da6c28aaSamw 
1382c2961f8Sjose borrego uint32_t smb_is_executable(char *);
1392c2961f8Sjose borrego static void smb_node_delete_on_close(smb_node_t *);
1402c2961f8Sjose borrego static void smb_node_create_audit_buf(smb_node_t *, int);
1412c2961f8Sjose borrego static void smb_node_destroy_audit_buf(smb_node_t *);
1422c2961f8Sjose borrego static void smb_node_audit(smb_node_t *);
1432c2961f8Sjose borrego static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_attr_t *,
1442c2961f8Sjose borrego     smb_llist_t *bucket, uint32_t hashkey);
1452c2961f8Sjose borrego static void smb_node_free(smb_node_t *);
1462c2961f8Sjose borrego static int smb_node_constructor(void *, void *, int);
1472c2961f8Sjose borrego static void smb_node_destructor(void *, void *);
1482c2961f8Sjose borrego static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
149da6c28aaSamw 
150da6c28aaSamw #define	VALIDATE_DIR_NODE(_dir_, _node_) \
151da6c28aaSamw     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
152da6c28aaSamw     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
153da6c28aaSamw     ASSERT((_dir_)->dir_snode != (_node_));
154da6c28aaSamw 
1552c2961f8Sjose borrego static kmem_cache_t	*smb_node_cache = NULL;
156faa1795aSjb150015 static boolean_t	smb_node_initialized = B_FALSE;
157faa1795aSjb150015 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
158faa1795aSjb150015 
159faa1795aSjb150015 /*
160faa1795aSjb150015  * smb_node_init
161faa1795aSjb150015  *
162faa1795aSjb150015  * Initialization of the SMB node layer.
163faa1795aSjb150015  *
164faa1795aSjb150015  * This function is not multi-thread safe. The caller must make sure only one
165faa1795aSjb150015  * thread makes the call.
166faa1795aSjb150015  */
167faa1795aSjb150015 int
168faa1795aSjb150015 smb_node_init(void)
169faa1795aSjb150015 {
170faa1795aSjb150015 	int	i;
171faa1795aSjb150015 
172faa1795aSjb150015 	if (smb_node_initialized)
173faa1795aSjb150015 		return (0);
1742c2961f8Sjose borrego 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
1752c2961f8Sjose borrego 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
1762c2961f8Sjose borrego 	    NULL, NULL, NULL, 0);
177faa1795aSjb150015 
178faa1795aSjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
179faa1795aSjb150015 		smb_llist_constructor(&smb_node_hash_table[i],
180faa1795aSjb150015 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
181faa1795aSjb150015 	}
182faa1795aSjb150015 	smb_node_initialized = B_TRUE;
183faa1795aSjb150015 	return (0);
184faa1795aSjb150015 }
185faa1795aSjb150015 
186faa1795aSjb150015 /*
187faa1795aSjb150015  * smb_node_fini
188faa1795aSjb150015  *
189faa1795aSjb150015  * This function is not multi-thread safe. The caller must make sure only one
190faa1795aSjb150015  * thread makes the call.
191faa1795aSjb150015  */
192faa1795aSjb150015 void
193faa1795aSjb150015 smb_node_fini(void)
194faa1795aSjb150015 {
195faa1795aSjb150015 	int	i;
196faa1795aSjb150015 
197faa1795aSjb150015 	if (!smb_node_initialized)
198faa1795aSjb150015 		return;
199faa1795aSjb150015 
200faa1795aSjb150015 #ifdef DEBUG
201faa1795aSjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
202faa1795aSjb150015 		smb_node_t	*node;
203faa1795aSjb150015 
204faa1795aSjb150015 		/*
205faa1795aSjb150015 		 * The following sequence is just intended for sanity check.
206faa1795aSjb150015 		 * This will have to be modified when the code goes into
207faa1795aSjb150015 		 * production.
208faa1795aSjb150015 		 *
209faa1795aSjb150015 		 * The SMB node hash table should be emtpy at this point. If the
210faa1795aSjb150015 		 * hash table is not empty a panic will be triggered.
211faa1795aSjb150015 		 *
212faa1795aSjb150015 		 * The reason why SMB nodes are still remaining in the hash
213faa1795aSjb150015 		 * table is problably due to a mismatch between calls to
214faa1795aSjb150015 		 * smb_node_lookup() and smb_node_release(). You must track that
215faa1795aSjb150015 		 * down.
216faa1795aSjb150015 		 */
217faa1795aSjb150015 		node = smb_llist_head(&smb_node_hash_table[i]);
218faa1795aSjb150015 		ASSERT(node == NULL);
219faa1795aSjb150015 	}
220faa1795aSjb150015 #endif
221faa1795aSjb150015 
222faa1795aSjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
223faa1795aSjb150015 		smb_llist_destructor(&smb_node_hash_table[i]);
224faa1795aSjb150015 	}
2252c2961f8Sjose borrego 	kmem_cache_destroy(smb_node_cache);
2262c2961f8Sjose borrego 	smb_node_cache = NULL;
227faa1795aSjb150015 	smb_node_initialized = B_FALSE;
228faa1795aSjb150015 }
229faa1795aSjb150015 
230da6c28aaSamw /*
231da6c28aaSamw  * smb_node_lookup()
232da6c28aaSamw  *
233da6c28aaSamw  * NOTE: This routine should only be called by the file system interface layer,
234da6c28aaSamw  * and not by SMB.
235da6c28aaSamw  *
236da6c28aaSamw  * smb_node_lookup() is called upon successful lookup, mkdir, and create
237da6c28aaSamw  * (for both non-streams and streams).  In each of these cases, a held vnode is
2387f667e74Sjose borrego  * passed into this routine.  If a new smb_node is created it will take its
2397f667e74Sjose borrego  * own hold on the vnode.  The caller's hold therefore still belongs to, and
2407f667e74Sjose borrego  * should be released by, the caller.
241da6c28aaSamw  *
242da6c28aaSamw  * A reference is taken on the smb_node whether found in the hash table
243da6c28aaSamw  * or newly created.
244da6c28aaSamw  *
245da6c28aaSamw  * If an smb_node needs to be created, a reference is also taken on the
246da6c28aaSamw  * dir_snode (if passed in).
247da6c28aaSamw  *
248da6c28aaSamw  * See smb_node_release() for details on the release of these references.
249da6c28aaSamw  */
250da6c28aaSamw 
251da6c28aaSamw /*ARGSUSED*/
252da6c28aaSamw smb_node_t *
253da6c28aaSamw smb_node_lookup(
254da6c28aaSamw     struct smb_request	*sr,
255da6c28aaSamw     struct open_param	*op,
256da6c28aaSamw     cred_t		*cred,
257da6c28aaSamw     vnode_t		*vp,
258da6c28aaSamw     char		*od_name,
259da6c28aaSamw     smb_node_t		*dir_snode,
260da6c28aaSamw     smb_node_t		*unnamed_node,
261da6c28aaSamw     smb_attr_t		*attr)
262da6c28aaSamw {
263da6c28aaSamw 	smb_llist_t		*node_hdr;
264da6c28aaSamw 	smb_node_t		*node;
265da6c28aaSamw 	uint32_t		hashkey = 0;
266c8ec8eeaSjose borrego 	fsid_t			fsid;
267da6c28aaSamw 	int			error;
268da6c28aaSamw 	krw_t			lock_mode;
269da6c28aaSamw 	vnode_t			*unnamed_vp = NULL;
270da6c28aaSamw 
271da6c28aaSamw 	/*
272da6c28aaSamw 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
273da6c28aaSamw 	 * because the node may not yet exist.  We also do not want to call
274da6c28aaSamw 	 * it with the list lock held.
275da6c28aaSamw 	 */
276da6c28aaSamw 
277da6c28aaSamw 	if (unnamed_node)
278da6c28aaSamw 		unnamed_vp = unnamed_node->vp;
279da6c28aaSamw 
280da6c28aaSamw 	/*
281da6c28aaSamw 	 * This getattr is performed on behalf of the server
282da6c28aaSamw 	 * that's why kcred is used not the user's cred
283da6c28aaSamw 	 */
284da6c28aaSamw 	attr->sa_mask = SMB_AT_ALL;
285dc20a302Sas200622 	error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred);
286da6c28aaSamw 	if (error)
287da6c28aaSamw 		return (NULL);
288da6c28aaSamw 
289c8ec8eeaSjose borrego 	if (sr && sr->tid_tree) {
290da6c28aaSamw 		/*
291c8ec8eeaSjose borrego 		 * The fsid for a file is that of the tree, even
292da6c28aaSamw 		 * if the file resides in a different mountpoint
293da6c28aaSamw 		 * under the share.
294da6c28aaSamw 		 */
295c8ec8eeaSjose borrego 		fsid = SMB_TREE_FSID(sr->tid_tree);
296da6c28aaSamw 	} else {
297da6c28aaSamw 		/*
298da6c28aaSamw 		 * This should be getting executed only for the
299c8ec8eeaSjose borrego 		 * tree root smb_node.
300da6c28aaSamw 		 */
301c8ec8eeaSjose borrego 		fsid = vp->v_vfsp->vfs_fsid;
302da6c28aaSamw 	}
303da6c28aaSamw 
3042c2961f8Sjose borrego 	node_hdr = smb_node_get_hash(&fsid, attr, &hashkey);
305da6c28aaSamw 	lock_mode = RW_READER;
306da6c28aaSamw 
307da6c28aaSamw 	smb_llist_enter(node_hdr, lock_mode);
308da6c28aaSamw 	for (;;) {
309da6c28aaSamw 		node = list_head(&node_hdr->ll_list);
310da6c28aaSamw 		while (node) {
311da6c28aaSamw 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
312da6c28aaSamw 			ASSERT(node->n_hash_bucket == node_hdr);
313da6c28aaSamw 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
3142c2961f8Sjose borrego 				mutex_enter(&node->n_mutex);
315da6c28aaSamw 				DTRACE_PROBE1(smb_node_lookup_hit,
316da6c28aaSamw 				    smb_node_t *, node);
317da6c28aaSamw 				switch (node->n_state) {
3182c2961f8Sjose borrego 				case SMB_NODE_STATE_OPLOCK_GRANTED:
3192c2961f8Sjose borrego 				case SMB_NODE_STATE_OPLOCK_BREAKING:
320da6c28aaSamw 				case SMB_NODE_STATE_AVAILABLE:
321da6c28aaSamw 					/* The node was found. */
322da6c28aaSamw 					node->n_refcnt++;
323da6c28aaSamw 					if ((node->dir_snode == NULL) &&
324da6c28aaSamw 					    (dir_snode != NULL) &&
325da6c28aaSamw 					    (strcmp(od_name, "..") != 0) &&
326da6c28aaSamw 					    (strcmp(od_name, ".") != 0)) {
327da6c28aaSamw 						VALIDATE_DIR_NODE(dir_snode,
328da6c28aaSamw 						    node);
329da6c28aaSamw 						node->dir_snode = dir_snode;
330da6c28aaSamw 						smb_node_ref(dir_snode);
331da6c28aaSamw 					}
332da6c28aaSamw 					node->attr = *attr;
333dc20a302Sas200622 					node->n_size = attr->sa_vattr.va_size;
334da6c28aaSamw 
3352c2961f8Sjose borrego 					smb_node_audit(node);
3362c2961f8Sjose borrego 					mutex_exit(&node->n_mutex);
337da6c28aaSamw 					smb_llist_exit(node_hdr);
338da6c28aaSamw 					return (node);
339da6c28aaSamw 
340da6c28aaSamw 				case SMB_NODE_STATE_DESTROYING:
341da6c28aaSamw 					/*
342da6c28aaSamw 					 * Although the node exists it is about
343da6c28aaSamw 					 * to be destroyed. We act as it hasn't
344da6c28aaSamw 					 * been found.
345da6c28aaSamw 					 */
3462c2961f8Sjose borrego 					mutex_exit(&node->n_mutex);
347da6c28aaSamw 					break;
348da6c28aaSamw 				default:
349da6c28aaSamw 					/*
350da6c28aaSamw 					 * Although the node exists it is in an
351da6c28aaSamw 					 * unknown state. We act as it hasn't
352da6c28aaSamw 					 * been found.
353da6c28aaSamw 					 */
354da6c28aaSamw 					ASSERT(0);
3552c2961f8Sjose borrego 					mutex_exit(&node->n_mutex);
356da6c28aaSamw 					break;
357da6c28aaSamw 				}
358da6c28aaSamw 			}
359da6c28aaSamw 			node = smb_llist_next(node_hdr, node);
360da6c28aaSamw 		}
361da6c28aaSamw 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
362da6c28aaSamw 			lock_mode = RW_WRITER;
363da6c28aaSamw 			continue;
364da6c28aaSamw 		}
365da6c28aaSamw 		break;
366da6c28aaSamw 	}
3672c2961f8Sjose borrego 	node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey);
368faa1795aSjb150015 	node->n_orig_uid = crgetuid(sr->user_cr);
369da6c28aaSamw 
370da6c28aaSamw 	if (op)
371da6c28aaSamw 		node->flags |= smb_is_executable(op->fqi.last_comp);
372da6c28aaSamw 
373da6c28aaSamw 	if (dir_snode) {
374da6c28aaSamw 		smb_node_ref(dir_snode);
375da6c28aaSamw 		node->dir_snode = dir_snode;
376da6c28aaSamw 		ASSERT(dir_snode->dir_snode != node);
377da6c28aaSamw 		ASSERT((dir_snode->vp->v_xattrdir) ||
378da6c28aaSamw 		    (dir_snode->vp->v_type == VDIR));
379da6c28aaSamw 	}
380da6c28aaSamw 
381da6c28aaSamw 	if (unnamed_node) {
382da6c28aaSamw 		smb_node_ref(unnamed_node);
383da6c28aaSamw 		node->unnamed_stream_node = unnamed_node;
384da6c28aaSamw 	}
385da6c28aaSamw 
386da6c28aaSamw 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
3872c2961f8Sjose borrego 	smb_node_audit(node);
388da6c28aaSamw 	smb_llist_insert_head(node_hdr, node);
389da6c28aaSamw 	smb_llist_exit(node_hdr);
390da6c28aaSamw 	return (node);
391da6c28aaSamw }
392da6c28aaSamw 
393da6c28aaSamw /*
394da6c28aaSamw  * smb_stream_node_lookup()
395da6c28aaSamw  *
396da6c28aaSamw  * Note: stream_name (the name that will be stored in the "od_name" field
397da6c28aaSamw  * of a stream's smb_node) is the same as the on-disk name for the stream
398da6c28aaSamw  * except that it does not have SMB_STREAM_PREFIX prepended.
399da6c28aaSamw  */
400da6c28aaSamw 
401da6c28aaSamw smb_node_t *
4022c2961f8Sjose borrego smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
403da6c28aaSamw     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
404da6c28aaSamw {
405da6c28aaSamw 	smb_node_t	*xattrdir_node;
406da6c28aaSamw 	smb_node_t	*snode;
407da6c28aaSamw 	smb_attr_t	tmp_attr;
408da6c28aaSamw 
409da6c28aaSamw 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
410da6c28aaSamw 	    fnode, NULL, &tmp_attr);
411da6c28aaSamw 
412da6c28aaSamw 	if (xattrdir_node == NULL)
413da6c28aaSamw 		return (NULL);
414da6c28aaSamw 
415da6c28aaSamw 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
416da6c28aaSamw 	    fnode, ret_attr);
417da6c28aaSamw 
418da6c28aaSamw 	(void) smb_node_release(xattrdir_node);
419da6c28aaSamw 	return (snode);
420da6c28aaSamw }
421da6c28aaSamw 
422da6c28aaSamw 
423da6c28aaSamw /*
424da6c28aaSamw  * This function should be called whenever a reference is needed on an
425da6c28aaSamw  * smb_node pointer.  The copy of an smb_node pointer from one non-local
426da6c28aaSamw  * data structure to another requires a reference to be taken on the smb_node
427da6c28aaSamw  * (unless the usage is localized).  Each data structure deallocation routine
428da6c28aaSamw  * will call smb_node_release() on its smb_node pointers.
429da6c28aaSamw  *
430da6c28aaSamw  * In general, an smb_node pointer residing in a structure should never be
431da6c28aaSamw  * stale.  A node pointer may be NULL, however, and care should be taken
432da6c28aaSamw  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
433da6c28aaSamw  * Care also needs to be taken with respect to racing deallocations of a
434da6c28aaSamw  * structure.
435da6c28aaSamw  */
436da6c28aaSamw void
437da6c28aaSamw smb_node_ref(smb_node_t *node)
438da6c28aaSamw {
4392c2961f8Sjose borrego 	SMB_NODE_VALID(node);
440da6c28aaSamw 
4412c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
4422c2961f8Sjose borrego 	switch (node->n_state) {
4432c2961f8Sjose borrego 	case SMB_NODE_STATE_AVAILABLE:
4442c2961f8Sjose borrego 	case SMB_NODE_STATE_OPLOCK_GRANTED:
4452c2961f8Sjose borrego 	case SMB_NODE_STATE_OPLOCK_BREAKING:
446da6c28aaSamw 		node->n_refcnt++;
447da6c28aaSamw 		ASSERT(node->n_refcnt);
448da6c28aaSamw 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
4492c2961f8Sjose borrego 		smb_node_audit(node);
4502c2961f8Sjose borrego 		break;
4512c2961f8Sjose borrego 	default:
4522c2961f8Sjose borrego 		SMB_PANIC();
4532c2961f8Sjose borrego 	}
4542c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
455da6c28aaSamw }
456da6c28aaSamw 
457da6c28aaSamw /*
458da6c28aaSamw  * smb_node_lookup() takes a hold on an smb_node, whether found in the
459da6c28aaSamw  * hash table or newly created.  This hold is expected to be released
460da6c28aaSamw  * in the following manner.
461da6c28aaSamw  *
462da6c28aaSamw  * smb_node_lookup() takes an address of an smb_node pointer.  This should
463da6c28aaSamw  * be getting passed down via a lookup (whether path name or component), mkdir,
464da6c28aaSamw  * create.  If the original smb_node pointer resides in a data structure, then
465da6c28aaSamw  * the deallocation routine for the data structure is responsible for calling
466da6c28aaSamw  * smb_node_release() on the smb_node pointer.  Alternatively,
467da6c28aaSamw  * smb_node_release() can be called as soon as the smb_node pointer is no longer
468da6c28aaSamw  * needed.  In this case, callers are responsible for setting an embedded
469da6c28aaSamw  * pointer to NULL if it is known that the last reference is being released.
470da6c28aaSamw  *
471da6c28aaSamw  * If the passed-in address of the smb_node pointer belongs to a local variable,
472da6c28aaSamw  * then the caller with the local variable should call smb_node_release()
473da6c28aaSamw  * directly.
474da6c28aaSamw  *
475da6c28aaSamw  * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
476da6c28aaSamw  * as smb_node_lookup() takes a hold on dir_snode.
477da6c28aaSamw  */
478da6c28aaSamw void
479da6c28aaSamw smb_node_release(smb_node_t *node)
480da6c28aaSamw {
4812c2961f8Sjose borrego 	SMB_NODE_VALID(node);
482da6c28aaSamw 
4832c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
484da6c28aaSamw 	ASSERT(node->n_refcnt);
485da6c28aaSamw 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
486da6c28aaSamw 	if (--node->n_refcnt == 0) {
487da6c28aaSamw 		switch (node->n_state) {
488da6c28aaSamw 
489da6c28aaSamw 		case SMB_NODE_STATE_AVAILABLE:
490da6c28aaSamw 			node->n_state = SMB_NODE_STATE_DESTROYING;
4912c2961f8Sjose borrego 			mutex_exit(&node->n_mutex);
492da6c28aaSamw 
493da6c28aaSamw 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
494da6c28aaSamw 			smb_llist_remove(node->n_hash_bucket, node);
495da6c28aaSamw 			smb_llist_exit(node->n_hash_bucket);
496da6c28aaSamw 
497da6c28aaSamw 			/*
498da6c28aaSamw 			 * Check if the file was deleted
499da6c28aaSamw 			 */
500da6c28aaSamw 			smb_node_delete_on_close(node);
501da6c28aaSamw 
502da6c28aaSamw 			if (node->dir_snode) {
503da6c28aaSamw 				ASSERT(node->dir_snode->n_magic ==
504da6c28aaSamw 				    SMB_NODE_MAGIC);
505da6c28aaSamw 				smb_node_release(node->dir_snode);
506da6c28aaSamw 			}
507da6c28aaSamw 
508da6c28aaSamw 			if (node->unnamed_stream_node) {
509da6c28aaSamw 				ASSERT(node->unnamed_stream_node->n_magic ==
510da6c28aaSamw 				    SMB_NODE_MAGIC);
511da6c28aaSamw 				smb_node_release(node->unnamed_stream_node);
512da6c28aaSamw 			}
513da6c28aaSamw 
5142c2961f8Sjose borrego 			smb_node_free(node);
515da6c28aaSamw 			return;
516da6c28aaSamw 
517da6c28aaSamw 		default:
5182c2961f8Sjose borrego 			SMB_PANIC();
519da6c28aaSamw 		}
520da6c28aaSamw 	}
5212c2961f8Sjose borrego 	smb_node_audit(node);
5222c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
523da6c28aaSamw }
524da6c28aaSamw 
525da6c28aaSamw static void
526da6c28aaSamw smb_node_delete_on_close(smb_node_t *node)
527da6c28aaSamw {
528da6c28aaSamw 	smb_node_t	*d_snode;
529da6c28aaSamw 	int		rc = 0;
530*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	flags = 0;
531da6c28aaSamw 
532da6c28aaSamw 	d_snode = node->dir_snode;
533da6c28aaSamw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
534da6c28aaSamw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
535*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		flags = node->n_delete_on_close_flags;
536da6c28aaSamw 		ASSERT(node->od_name != NULL);
537*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
538da6c28aaSamw 		if (node->attr.sa_vattr.va_type == VDIR)
539da6c28aaSamw 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
540*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    d_snode, node->od_name, flags);
541da6c28aaSamw 		else
542da6c28aaSamw 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
543*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    d_snode, node->od_name, flags);
544da6c28aaSamw 		smb_cred_rele(node->delete_on_close_cred);
545da6c28aaSamw 	}
546da6c28aaSamw 	if (rc != 0)
547da6c28aaSamw 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
548da6c28aaSamw 		    node->od_name, rc);
549da6c28aaSamw 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
550da6c28aaSamw }
551da6c28aaSamw 
552da6c28aaSamw /*
553da6c28aaSamw  * smb_node_rename()
554da6c28aaSamw  *
555da6c28aaSamw  */
5562c2961f8Sjose borrego void
557da6c28aaSamw smb_node_rename(
5582c2961f8Sjose borrego     smb_node_t	*from_dnode,
5592c2961f8Sjose borrego     smb_node_t	*ret_node,
5602c2961f8Sjose borrego     smb_node_t	*to_dnode,
561da6c28aaSamw     char	*to_name)
562da6c28aaSamw {
5632c2961f8Sjose borrego 	SMB_NODE_VALID(from_dnode);
5642c2961f8Sjose borrego 	SMB_NODE_VALID(to_dnode);
5652c2961f8Sjose borrego 	SMB_NODE_VALID(ret_node);
566da6c28aaSamw 
5672c2961f8Sjose borrego 	smb_node_ref(to_dnode);
5682c2961f8Sjose borrego 	mutex_enter(&ret_node->n_mutex);
5692c2961f8Sjose borrego 	switch (ret_node->n_state) {
5702c2961f8Sjose borrego 	case SMB_NODE_STATE_AVAILABLE:
5712c2961f8Sjose borrego 	case SMB_NODE_STATE_OPLOCK_GRANTED:
5722c2961f8Sjose borrego 	case SMB_NODE_STATE_OPLOCK_BREAKING:
5732c2961f8Sjose borrego 		ret_node->dir_snode = to_dnode;
5742c2961f8Sjose borrego 		mutex_exit(&ret_node->n_mutex);
5752c2961f8Sjose borrego 		ASSERT(to_dnode->dir_snode != ret_node);
5762c2961f8Sjose borrego 		ASSERT((to_dnode->vp->v_xattrdir) ||
5772c2961f8Sjose borrego 		    (to_dnode->vp->v_type == VDIR));
5782c2961f8Sjose borrego 		smb_node_release(from_dnode);
5792c2961f8Sjose borrego 		(void) strcpy(ret_node->od_name, to_name);
580da6c28aaSamw 		/*
581da6c28aaSamw 		 * XXX Need to update attributes?
582da6c28aaSamw 		 */
5832c2961f8Sjose borrego 		break;
5842c2961f8Sjose borrego 	default:
5852c2961f8Sjose borrego 		SMB_PANIC();
5862c2961f8Sjose borrego 	}
587da6c28aaSamw }
588da6c28aaSamw 
589da6c28aaSamw int
590faa1795aSjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
591da6c28aaSamw {
592da6c28aaSamw 	smb_attr_t	va;
593faa1795aSjb150015 	int		error;
594faa1795aSjb150015 	uint32_t	hashkey;
595faa1795aSjb150015 	smb_llist_t	*node_hdr;
596faa1795aSjb150015 	smb_node_t	*node;
597da6c28aaSamw 
598faa1795aSjb150015 	va.sa_mask = SMB_AT_ALL;
599faa1795aSjb150015 	error = smb_vop_getattr(vp, NULL, &va, 0, kcred);
600faa1795aSjb150015 	if (error) {
601faa1795aSjb150015 		VN_RELE(vp);
602faa1795aSjb150015 		return (error);
603faa1795aSjb150015 	}
604da6c28aaSamw 
6052c2961f8Sjose borrego 	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey);
606faa1795aSjb150015 
6072c2961f8Sjose borrego 	node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey);
608faa1795aSjb150015 
609faa1795aSjb150015 	sv->si_root_smb_node = node;
6102c2961f8Sjose borrego 	smb_node_audit(node);
611faa1795aSjb150015 	smb_llist_enter(node_hdr, RW_WRITER);
612faa1795aSjb150015 	smb_llist_insert_head(node_hdr, node);
613faa1795aSjb150015 	smb_llist_exit(node_hdr);
614faa1795aSjb150015 	*root = node;
615da6c28aaSamw 	return (0);
616da6c28aaSamw }
617da6c28aaSamw 
618da6c28aaSamw /*
619da6c28aaSamw  * smb_node_get_size
620da6c28aaSamw  */
6216537f381Sas200622 u_offset_t
6226537f381Sas200622 smb_node_get_size(smb_node_t *node, smb_attr_t *attr)
623da6c28aaSamw {
6246537f381Sas200622 	u_offset_t size;
625da6c28aaSamw 
626da6c28aaSamw 	if (attr->sa_vattr.va_type == VDIR)
627da6c28aaSamw 		return (0);
628da6c28aaSamw 
6292c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
630da6c28aaSamw 	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
631da6c28aaSamw 		size = node->n_size;
632da6c28aaSamw 	else
633da6c28aaSamw 		size = attr->sa_vattr.va_size;
6342c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
635da6c28aaSamw 	return (size);
636da6c28aaSamw }
637da6c28aaSamw 
638da6c28aaSamw static int
639da6c28aaSamw timeval_cmp(timestruc_t *a, timestruc_t *b)
640da6c28aaSamw {
641da6c28aaSamw 	if (a->tv_sec < b->tv_sec)
642da6c28aaSamw 		return (-1);
643da6c28aaSamw 	if (a->tv_sec > b->tv_sec)
644da6c28aaSamw 		return (1);
645da6c28aaSamw 	/* Seconds are equal compare tv_nsec */
646da6c28aaSamw 	if (a->tv_nsec < b->tv_nsec)
647da6c28aaSamw 		return (-1);
648da6c28aaSamw 	return (a->tv_nsec > b->tv_nsec);
649da6c28aaSamw }
650da6c28aaSamw 
651da6c28aaSamw /*
652da6c28aaSamw  * smb_node_set_time
653da6c28aaSamw  *
654da6c28aaSamw  * This function will update the time stored in the node and
655c8ec8eeaSjose borrego  * set the appropriate flags. If there is nothing to update,
656c8ec8eeaSjose borrego  * the function will return without any updates.  The update
657c8ec8eeaSjose borrego  * is only in the node level and the attribute in the file system
658c8ec8eeaSjose borrego  * will be updated when client close the file.
659da6c28aaSamw  */
660da6c28aaSamw void
6612c2961f8Sjose borrego smb_node_set_time(
6622c2961f8Sjose borrego     smb_node_t	*node,
6632c2961f8Sjose borrego     timestruc_t	*crtime,
6642c2961f8Sjose borrego     timestruc_t	*mtime,
6652c2961f8Sjose borrego     timestruc_t	*atime,
6662c2961f8Sjose borrego     timestruc_t	*ctime,
6672c2961f8Sjose borrego     uint_t	what)
668da6c28aaSamw {
669c8ec8eeaSjose borrego 	if (what == 0)
670da6c28aaSamw 		return;
671da6c28aaSamw 
672da6c28aaSamw 	if ((what & SMB_AT_CRTIME && crtime == 0) ||
673da6c28aaSamw 	    (what & SMB_AT_MTIME && mtime == 0) ||
674da6c28aaSamw 	    (what & SMB_AT_ATIME && atime == 0) ||
675c8ec8eeaSjose borrego 	    (what & SMB_AT_CTIME && ctime == 0))
676da6c28aaSamw 		return;
677c8ec8eeaSjose borrego 
6782c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
679da6c28aaSamw 
680da6c28aaSamw 	if ((what & SMB_AT_CRTIME) &&
681da6c28aaSamw 	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
682da6c28aaSamw 	    crtime) != 0) {
683da6c28aaSamw 		node->what |= SMB_AT_CRTIME;
684da6c28aaSamw 		node->attr.sa_crtime = *((timestruc_t *)crtime);
685da6c28aaSamw 	}
686da6c28aaSamw 
687da6c28aaSamw 	if ((what & SMB_AT_MTIME) &&
688da6c28aaSamw 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
689da6c28aaSamw 	    mtime) != 0) {
690da6c28aaSamw 		node->what |= SMB_AT_MTIME;
691da6c28aaSamw 		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
692da6c28aaSamw 	}
693da6c28aaSamw 
694da6c28aaSamw 	if ((what & SMB_AT_ATIME) &&
695da6c28aaSamw 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
696da6c28aaSamw 	    atime) != 0) {
697da6c28aaSamw 			node->what |= SMB_AT_ATIME;
698da6c28aaSamw 			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
699da6c28aaSamw 	}
700da6c28aaSamw 
701da6c28aaSamw 	/*
702da6c28aaSamw 	 * The ctime handling is trickier. It has three scenarios.
703da6c28aaSamw 	 * 1. Only ctime need to be set and it is the same as the ctime
704da6c28aaSamw 	 *    stored in the node. (update not necessary)
705da6c28aaSamw 	 * 2. The ctime is the same as the ctime stored in the node but
706da6c28aaSamw 	 *    is not the only time need to be set. (update required)
707da6c28aaSamw 	 * 3. The ctime need to be set and is not the same as the ctime
708da6c28aaSamw 	 *    stored in the node. (update required)
709da6c28aaSamw 	 * Unlike other time setting, the ctime needs to be set even when
710da6c28aaSamw 	 * it is the same as the ctime in the node if there are other time
711da6c28aaSamw 	 * needs to be set (#2). This will ensure the ctime not being
712da6c28aaSamw 	 * updated when other times are being updated in the file system.
713da6c28aaSamw 	 *
714da6c28aaSamw 	 * Retained file rules:
715da6c28aaSamw 	 *
716da6c28aaSamw 	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
717da6c28aaSamw 	 *    request will be rejected by filesystem
718da6c28aaSamw 	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
719da6c28aaSamw 	 *    any request for changing ctime on these files should have
720da6c28aaSamw 	 *    been already rejected
721da6c28aaSamw 	 */
722da6c28aaSamw 	node->what |= SMB_AT_CTIME;
723da6c28aaSamw 	if (what & SMB_AT_CTIME) {
724da6c28aaSamw 		if ((what == SMB_AT_CTIME) &&
725da6c28aaSamw 		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
726da6c28aaSamw 		    ctime) == 0) {
727da6c28aaSamw 			node->what &= ~SMB_AT_CTIME;
728da6c28aaSamw 		} else {
729da6c28aaSamw 			gethrestime(&node->attr.sa_vattr.va_ctime);
730da6c28aaSamw 		}
731da6c28aaSamw 	} else {
732da6c28aaSamw 		gethrestime(&node->attr.sa_vattr.va_ctime);
733da6c28aaSamw 	}
7342c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
735da6c28aaSamw }
736da6c28aaSamw 
737da6c28aaSamw 
738da6c28aaSamw timestruc_t *
739da6c28aaSamw smb_node_get_crtime(smb_node_t *node)
740da6c28aaSamw {
741da6c28aaSamw 	return ((timestruc_t *)&node->attr.sa_crtime);
742da6c28aaSamw }
743da6c28aaSamw 
744da6c28aaSamw timestruc_t *
745da6c28aaSamw smb_node_get_atime(smb_node_t *node)
746da6c28aaSamw {
747da6c28aaSamw 	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
748da6c28aaSamw }
749da6c28aaSamw 
750da6c28aaSamw timestruc_t *
751da6c28aaSamw smb_node_get_ctime(smb_node_t *node)
752da6c28aaSamw {
753da6c28aaSamw 	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
754da6c28aaSamw }
755da6c28aaSamw 
756da6c28aaSamw timestruc_t *
757da6c28aaSamw smb_node_get_mtime(smb_node_t *node)
758da6c28aaSamw {
759da6c28aaSamw 	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
760da6c28aaSamw }
761da6c28aaSamw 
762da6c28aaSamw /*
763da6c28aaSamw  * smb_node_set_dosattr
764da6c28aaSamw  *
765da6c28aaSamw  * Parse the specified DOS attributes and, if they have been modified,
766da6c28aaSamw  * update the node cache. This call should be followed by a
767da6c28aaSamw  * smb_sync_fsattr() call to write the attribute changes to filesystem.
768da6c28aaSamw  */
769da6c28aaSamw void
7703db3f65cSamw smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr)
771da6c28aaSamw {
7723db3f65cSamw 	uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE |
7733db3f65cSamw 	    FILE_ATTRIBUTE_READONLY |
7743db3f65cSamw 	    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
775da6c28aaSamw 
7762c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
777da6c28aaSamw 	if (node->attr.sa_dosattr != mode) {
778da6c28aaSamw 		node->attr.sa_dosattr = mode;
779da6c28aaSamw 		node->what |= SMB_AT_DOSATTR;
780da6c28aaSamw 	}
7812c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
782da6c28aaSamw }
783da6c28aaSamw 
784da6c28aaSamw /*
785c8ec8eeaSjose borrego  * smb_node_get_dosattr()
786da6c28aaSamw  *
787c8ec8eeaSjose borrego  * This function is used to provide clients with information as to whether
788c8ec8eeaSjose borrego  * the readonly bit is set.  Hence both the node attribute cache (which
789c8ec8eeaSjose borrego  * reflects the on-disk attributes) and node->readonly_creator (which
790c8ec8eeaSjose borrego  * reflects whether a readonly set is pending from a readonly create) are
791c8ec8eeaSjose borrego  * checked.  In the latter case, the readonly attribute should be visible to
792c8ec8eeaSjose borrego  * all clients even though the readonly creator fid is immune to the readonly
793c8ec8eeaSjose borrego  * bit until close.
794da6c28aaSamw  */
795c8ec8eeaSjose borrego 
796da6c28aaSamw uint32_t
797da6c28aaSamw smb_node_get_dosattr(smb_node_t *node)
798da6c28aaSamw {
799c8ec8eeaSjose borrego 	uint32_t dosattr = node->attr.sa_dosattr;
800c8ec8eeaSjose borrego 
801c8ec8eeaSjose borrego 	if (node->readonly_creator)
802c8ec8eeaSjose borrego 		dosattr |= FILE_ATTRIBUTE_READONLY;
803c8ec8eeaSjose borrego 
804c8ec8eeaSjose borrego 	if (!dosattr)
805c8ec8eeaSjose borrego 		dosattr = FILE_ATTRIBUTE_NORMAL;
806c8ec8eeaSjose borrego 
807c8ec8eeaSjose borrego 	return (dosattr);
808da6c28aaSamw }
809da6c28aaSamw 
810*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /*
811*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * When DeleteOnClose is set on an smb_node, the common open code will
812*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * reject subsequent open requests for the file. Observation of Windows
813*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * 2000 indicates that subsequent opens should be allowed (assuming
814*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * there would be no sharing violation) until the file is closed using
815*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * the fid on which the DeleteOnClose was requested.
816*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *
817*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * If there are multiple opens with delete-on-close create options,
818*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * whichever the first file handle is closed will trigger the node to be
819*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * marked as delete-on-close. The credentials of that ofile will be used
820*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * as the delete-on-close credentials of the node.
821*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  */
822da6c28aaSamw int
823*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
824da6c28aaSamw {
825da6c28aaSamw 	int	rc = -1;
826da6c28aaSamw 
8272c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
828da6c28aaSamw 	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
829da6c28aaSamw 	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
830da6c28aaSamw 		crhold(cr);
831da6c28aaSamw 		node->delete_on_close_cred = cr;
832*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		node->n_delete_on_close_flags = flags;
833da6c28aaSamw 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
834da6c28aaSamw 		rc = 0;
835da6c28aaSamw 	}
8362c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
837da6c28aaSamw 	return (rc);
838da6c28aaSamw }
839da6c28aaSamw 
840da6c28aaSamw void
841da6c28aaSamw smb_node_reset_delete_on_close(smb_node_t *node)
842da6c28aaSamw {
8432c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
844da6c28aaSamw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
845da6c28aaSamw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
846da6c28aaSamw 		crfree(node->delete_on_close_cred);
847da6c28aaSamw 		node->delete_on_close_cred = NULL;
848*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		node->n_delete_on_close_flags = 0;
849da6c28aaSamw 	}
8502c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
851da6c28aaSamw }
852dc20a302Sas200622 
853dc20a302Sas200622 /*
8543ad684d6Sjb150015  * smb_node_open_check
855dc20a302Sas200622  *
856dc20a302Sas200622  * check file sharing rules for current open request
857dc20a302Sas200622  * against all existing opens for a file.
858dc20a302Sas200622  *
859dc20a302Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
860dc20a302Sas200622  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
861dc20a302Sas200622  */
862dc20a302Sas200622 uint32_t
8632c2961f8Sjose borrego smb_node_open_check(
8642c2961f8Sjose borrego     smb_node_t	*node,
8652c2961f8Sjose borrego     cred_t	*cr,
8662c2961f8Sjose borrego     uint32_t	desired_access,
8672c2961f8Sjose borrego     uint32_t	share_access)
868dc20a302Sas200622 {
869dc20a302Sas200622 	smb_ofile_t *of;
870dc20a302Sas200622 	uint32_t status;
871dc20a302Sas200622 
8722c2961f8Sjose borrego 	SMB_NODE_VALID(node);
873dc20a302Sas200622 
874dc20a302Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
875dc20a302Sas200622 	of = smb_llist_head(&node->n_ofile_list);
876dc20a302Sas200622 	while (of) {
8773ad684d6Sjb150015 		status = smb_ofile_open_check(of, cr, desired_access,
8783ad684d6Sjb150015 		    share_access);
8793ad684d6Sjb150015 
8803ad684d6Sjb150015 		switch (status) {
8813ad684d6Sjb150015 		case NT_STATUS_INVALID_HANDLE:
8823ad684d6Sjb150015 		case NT_STATUS_SUCCESS:
8833ad684d6Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
8843ad684d6Sjb150015 			break;
8853ad684d6Sjb150015 		default:
8863ad684d6Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
887dc20a302Sas200622 			smb_llist_exit(&node->n_ofile_list);
888dc20a302Sas200622 			return (status);
889dc20a302Sas200622 		}
890dc20a302Sas200622 	}
8913ad684d6Sjb150015 
892dc20a302Sas200622 	smb_llist_exit(&node->n_ofile_list);
893dc20a302Sas200622 	return (NT_STATUS_SUCCESS);
894dc20a302Sas200622 }
895dc20a302Sas200622 
896dc20a302Sas200622 uint32_t
8972c2961f8Sjose borrego smb_node_rename_check(smb_node_t *node)
898dc20a302Sas200622 {
8992c2961f8Sjose borrego 	smb_ofile_t	*of;
9003ad684d6Sjb150015 	uint32_t	status;
901dc20a302Sas200622 
9022c2961f8Sjose borrego 	SMB_NODE_VALID(node);
903dc20a302Sas200622 
904dc20a302Sas200622 	/*
905dc20a302Sas200622 	 * Intra-CIFS check
906dc20a302Sas200622 	 */
907dc20a302Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
9083ad684d6Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
9093ad684d6Sjb150015 	while (of) {
9103ad684d6Sjb150015 		status = smb_ofile_rename_check(of);
911dc20a302Sas200622 
9123ad684d6Sjb150015 		switch (status) {
9133ad684d6Sjb150015 		case NT_STATUS_INVALID_HANDLE:
9143ad684d6Sjb150015 		case NT_STATUS_SUCCESS:
9153ad684d6Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
9163ad684d6Sjb150015 			break;
9173ad684d6Sjb150015 		default:
9183ad684d6Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
919dc20a302Sas200622 			smb_llist_exit(&node->n_ofile_list);
9203ad684d6Sjb150015 			return (status);
921dc20a302Sas200622 		}
922dc20a302Sas200622 	}
923dc20a302Sas200622 	smb_llist_exit(&node->n_ofile_list);
924dc20a302Sas200622 
925dc20a302Sas200622 	/*
926dc20a302Sas200622 	 * system-wide share check
927dc20a302Sas200622 	 */
928dc20a302Sas200622 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
929dc20a302Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
930dc20a302Sas200622 	else
931dc20a302Sas200622 		return (NT_STATUS_SUCCESS);
932dc20a302Sas200622 }
933dc20a302Sas200622 
9343ad684d6Sjb150015 uint32_t
935dc20a302Sas200622 smb_node_delete_check(smb_node_t *node)
936dc20a302Sas200622 {
9373ad684d6Sjb150015 	smb_ofile_t	*of;
9383ad684d6Sjb150015 	uint32_t	status;
939dc20a302Sas200622 
9402c2961f8Sjose borrego 	SMB_NODE_VALID(node);
941dc20a302Sas200622 
942dc20a302Sas200622 	if (node->attr.sa_vattr.va_type == VDIR)
943dc20a302Sas200622 		return (NT_STATUS_SUCCESS);
944dc20a302Sas200622 
945dc20a302Sas200622 	/*
946dc20a302Sas200622 	 * intra-CIFS check
947dc20a302Sas200622 	 */
948dc20a302Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
9493ad684d6Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
9503ad684d6Sjb150015 	while (of) {
9513ad684d6Sjb150015 		status = smb_ofile_delete_check(of);
9523ad684d6Sjb150015 
9533ad684d6Sjb150015 		switch (status) {
9543ad684d6Sjb150015 		case NT_STATUS_INVALID_HANDLE:
9553ad684d6Sjb150015 		case NT_STATUS_SUCCESS:
9563ad684d6Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
9573ad684d6Sjb150015 			break;
9583ad684d6Sjb150015 		default:
9593ad684d6Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
960dc20a302Sas200622 			smb_llist_exit(&node->n_ofile_list);
9613ad684d6Sjb150015 			return (status);
962dc20a302Sas200622 		}
963dc20a302Sas200622 	}
964dc20a302Sas200622 	smb_llist_exit(&node->n_ofile_list);
965dc20a302Sas200622 
966dc20a302Sas200622 	/*
967dc20a302Sas200622 	 * system-wide share check
968dc20a302Sas200622 	 */
969dc20a302Sas200622 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
970dc20a302Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
971dc20a302Sas200622 	else
972dc20a302Sas200622 		return (NT_STATUS_SUCCESS);
973dc20a302Sas200622 }
974dc20a302Sas200622 
975dc20a302Sas200622 /*
976dc20a302Sas200622  * smb_node_start_crit()
977dc20a302Sas200622  *
978dc20a302Sas200622  * Enter critical region for share reservations.
979dc20a302Sas200622  * See comments above smb_fsop_shrlock().
980dc20a302Sas200622  */
981dc20a302Sas200622 
982dc20a302Sas200622 void
983dc20a302Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode)
984dc20a302Sas200622 {
9852c2961f8Sjose borrego 	rw_enter(&node->n_lock, mode);
986dc20a302Sas200622 	nbl_start_crit(node->vp, mode);
987dc20a302Sas200622 }
988dc20a302Sas200622 
989dc20a302Sas200622 /*
990dc20a302Sas200622  * smb_node_end_crit()
991dc20a302Sas200622  *
992dc20a302Sas200622  * Exit critical region for share reservations.
993dc20a302Sas200622  */
994dc20a302Sas200622 
995dc20a302Sas200622 void
996dc20a302Sas200622 smb_node_end_crit(smb_node_t *node)
997dc20a302Sas200622 {
998dc20a302Sas200622 	nbl_end_crit(node->vp);
9992c2961f8Sjose borrego 	rw_exit(&node->n_lock);
1000dc20a302Sas200622 }
1001dc20a302Sas200622 
1002dc20a302Sas200622 int
1003dc20a302Sas200622 smb_node_in_crit(smb_node_t *node)
1004dc20a302Sas200622 {
10052c2961f8Sjose borrego 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
10062c2961f8Sjose borrego }
10072c2961f8Sjose borrego 
10082c2961f8Sjose borrego void
10092c2961f8Sjose borrego smb_node_rdlock(smb_node_t *node)
10102c2961f8Sjose borrego {
10112c2961f8Sjose borrego 	rw_enter(&node->n_lock, RW_READER);
10122c2961f8Sjose borrego }
10132c2961f8Sjose borrego 
10142c2961f8Sjose borrego void
10152c2961f8Sjose borrego smb_node_wrlock(smb_node_t *node)
10162c2961f8Sjose borrego {
10172c2961f8Sjose borrego 	rw_enter(&node->n_lock, RW_WRITER);
10182c2961f8Sjose borrego }
10192c2961f8Sjose borrego 
10202c2961f8Sjose borrego void
10212c2961f8Sjose borrego smb_node_unlock(smb_node_t *node)
10222c2961f8Sjose borrego {
10232c2961f8Sjose borrego 	rw_exit(&node->n_lock);
10242c2961f8Sjose borrego }
10252c2961f8Sjose borrego 
10262c2961f8Sjose borrego uint32_t
10272c2961f8Sjose borrego smb_node_get_ofile_count(smb_node_t *node)
10282c2961f8Sjose borrego {
10292c2961f8Sjose borrego 	uint32_t	cntr;
10302c2961f8Sjose borrego 
10312c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10322c2961f8Sjose borrego 
10332c2961f8Sjose borrego 	smb_llist_enter(&node->n_ofile_list, RW_READER);
10342c2961f8Sjose borrego 	cntr = smb_llist_get_count(&node->n_ofile_list);
10352c2961f8Sjose borrego 	smb_llist_exit(&node->n_ofile_list);
10362c2961f8Sjose borrego 	return (cntr);
10372c2961f8Sjose borrego }
10382c2961f8Sjose borrego 
10392c2961f8Sjose borrego void
10402c2961f8Sjose borrego smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
10412c2961f8Sjose borrego {
10422c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10432c2961f8Sjose borrego 
10442c2961f8Sjose borrego 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
10452c2961f8Sjose borrego 	smb_llist_insert_tail(&node->n_ofile_list, of);
10462c2961f8Sjose borrego 	smb_llist_exit(&node->n_ofile_list);
10472c2961f8Sjose borrego }
10482c2961f8Sjose borrego 
10492c2961f8Sjose borrego void
10502c2961f8Sjose borrego smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
10512c2961f8Sjose borrego {
10522c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10532c2961f8Sjose borrego 
10542c2961f8Sjose borrego 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
10552c2961f8Sjose borrego 	smb_llist_remove(&node->n_ofile_list, of);
10562c2961f8Sjose borrego 	smb_llist_exit(&node->n_ofile_list);
10572c2961f8Sjose borrego }
10582c2961f8Sjose borrego 
10592c2961f8Sjose borrego void
10602c2961f8Sjose borrego smb_node_inc_open_ofiles(smb_node_t *node)
10612c2961f8Sjose borrego {
10622c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10632c2961f8Sjose borrego 
10642c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
10652c2961f8Sjose borrego 	node->n_open_count++;
10662c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
10672c2961f8Sjose borrego }
10682c2961f8Sjose borrego 
10692c2961f8Sjose borrego void
10702c2961f8Sjose borrego smb_node_dec_open_ofiles(smb_node_t *node)
10712c2961f8Sjose borrego {
10722c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10732c2961f8Sjose borrego 
10742c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
10752c2961f8Sjose borrego 	node->n_open_count--;
10762c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
10772c2961f8Sjose borrego }
10782c2961f8Sjose borrego 
10792c2961f8Sjose borrego uint32_t
10802c2961f8Sjose borrego smb_node_get_open_ofiles(smb_node_t *node)
10812c2961f8Sjose borrego {
10822c2961f8Sjose borrego 	uint32_t	cnt;
10832c2961f8Sjose borrego 
10842c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10852c2961f8Sjose borrego 
10862c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
10872c2961f8Sjose borrego 	cnt = node->n_open_count;
10882c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
10892c2961f8Sjose borrego 	return (cnt);
10902c2961f8Sjose borrego }
10912c2961f8Sjose borrego 
10922c2961f8Sjose borrego /*
10932c2961f8Sjose borrego  * smb_node_alloc
10942c2961f8Sjose borrego  */
10952c2961f8Sjose borrego static smb_node_t *
10962c2961f8Sjose borrego smb_node_alloc(
10972c2961f8Sjose borrego     char	*od_name,
10982c2961f8Sjose borrego     vnode_t	*vp,
10992c2961f8Sjose borrego     smb_attr_t	*attr,
11002c2961f8Sjose borrego     smb_llist_t	*bucket,
11012c2961f8Sjose borrego     uint32_t	hashkey)
11022c2961f8Sjose borrego {
11032c2961f8Sjose borrego 	smb_node_t	*node;
11042c2961f8Sjose borrego 
11052c2961f8Sjose borrego 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
11062c2961f8Sjose borrego 
11072c2961f8Sjose borrego 	if (node->n_audit_buf != NULL)
11082c2961f8Sjose borrego 		node->n_audit_buf->anb_index = 0;
11092c2961f8Sjose borrego 
11102c2961f8Sjose borrego 	node->attr = *attr;
11112c2961f8Sjose borrego 	node->flags = NODE_FLAGS_ATTR_VALID;
11122c2961f8Sjose borrego 	node->n_size = node->attr.sa_vattr.va_size;
11132c2961f8Sjose borrego 	VN_HOLD(vp);
11142c2961f8Sjose borrego 	node->vp = vp;
11152c2961f8Sjose borrego 	node->n_refcnt = 1;
11162c2961f8Sjose borrego 	node->n_hash_bucket = bucket;
11172c2961f8Sjose borrego 	node->n_hashkey = hashkey;
11182c2961f8Sjose borrego 	node->n_orig_uid = 0;
11192c2961f8Sjose borrego 	node->readonly_creator = NULL;
11202c2961f8Sjose borrego 	node->waiting_event = 0;
11212c2961f8Sjose borrego 	node->what = 0;
11222c2961f8Sjose borrego 	node->n_open_count = 0;
11232c2961f8Sjose borrego 	node->dir_snode = NULL;
11242c2961f8Sjose borrego 	node->unnamed_stream_node = NULL;
11252c2961f8Sjose borrego 	node->delete_on_close_cred = NULL;
1126*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	node->n_delete_on_close_flags = 0;
11272c2961f8Sjose borrego 
11282c2961f8Sjose borrego 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
11292c2961f8Sjose borrego 	if (strcmp(od_name, XATTR_DIR) == 0)
11302c2961f8Sjose borrego 		node->flags |= NODE_XATTR_DIR;
11312c2961f8Sjose borrego 
11322c2961f8Sjose borrego 	node->n_state = SMB_NODE_STATE_AVAILABLE;
11332c2961f8Sjose borrego 	node->n_magic = SMB_NODE_MAGIC;
11342c2961f8Sjose borrego 	return (node);
11352c2961f8Sjose borrego }
11362c2961f8Sjose borrego 
11372c2961f8Sjose borrego /*
11382c2961f8Sjose borrego  * smb_node_free
11392c2961f8Sjose borrego  */
11402c2961f8Sjose borrego static void
11412c2961f8Sjose borrego smb_node_free(smb_node_t *node)
11422c2961f8Sjose borrego {
11432c2961f8Sjose borrego 	SMB_NODE_VALID(node);
11442c2961f8Sjose borrego 
11452c2961f8Sjose borrego 	node->n_magic = 0;
11462c2961f8Sjose borrego 	VERIFY(!list_link_active(&node->n_lnd));
11472c2961f8Sjose borrego 	VERIFY(node->n_lock_list.ll_count == 0);
11482c2961f8Sjose borrego 	VERIFY(node->n_ofile_list.ll_count == 0);
11492c2961f8Sjose borrego 	VERIFY(node->n_oplock.ol_xthread == NULL);
1150fc724630SAlan Wright 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
1151fc724630SAlan Wright 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
11522c2961f8Sjose borrego 	VN_RELE(node->vp);
11532c2961f8Sjose borrego 	kmem_cache_free(smb_node_cache, node);
11542c2961f8Sjose borrego }
11552c2961f8Sjose borrego 
11562c2961f8Sjose borrego /*
11572c2961f8Sjose borrego  * smb_node_constructor
11582c2961f8Sjose borrego  */
11592c2961f8Sjose borrego static int
11602c2961f8Sjose borrego smb_node_constructor(void *buf, void *un, int kmflags)
11612c2961f8Sjose borrego {
11622c2961f8Sjose borrego 	_NOTE(ARGUNUSED(kmflags, un))
11632c2961f8Sjose borrego 
11642c2961f8Sjose borrego 	smb_node_t	*node = (smb_node_t *)buf;
11652c2961f8Sjose borrego 
11662c2961f8Sjose borrego 	bzero(node, sizeof (smb_node_t));
11672c2961f8Sjose borrego 
11682c2961f8Sjose borrego 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
11692c2961f8Sjose borrego 	    offsetof(smb_ofile_t, f_nnd));
11702c2961f8Sjose borrego 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
11712c2961f8Sjose borrego 	    offsetof(smb_lock_t, l_lnd));
11722c2961f8Sjose borrego 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
11732c2961f8Sjose borrego 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
11742c2961f8Sjose borrego 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
11752c2961f8Sjose borrego 	smb_node_create_audit_buf(node, kmflags);
11762c2961f8Sjose borrego 	return (0);
11772c2961f8Sjose borrego }
11782c2961f8Sjose borrego 
11792c2961f8Sjose borrego /*
11802c2961f8Sjose borrego  * smb_node_destructor
11812c2961f8Sjose borrego  */
11822c2961f8Sjose borrego static void
11832c2961f8Sjose borrego smb_node_destructor(void *buf, void *un)
11842c2961f8Sjose borrego {
11852c2961f8Sjose borrego 	_NOTE(ARGUNUSED(un))
11862c2961f8Sjose borrego 
11872c2961f8Sjose borrego 	smb_node_t	*node = (smb_node_t *)buf;
11882c2961f8Sjose borrego 
11892c2961f8Sjose borrego 	smb_node_destroy_audit_buf(node);
11902c2961f8Sjose borrego 	mutex_destroy(&node->n_mutex);
11912c2961f8Sjose borrego 	rw_destroy(&node->n_lock);
11922c2961f8Sjose borrego 	cv_destroy(&node->n_oplock.ol_cv);
11932c2961f8Sjose borrego 	smb_llist_destructor(&node->n_lock_list);
11942c2961f8Sjose borrego 	smb_llist_destructor(&node->n_ofile_list);
11952c2961f8Sjose borrego }
11962c2961f8Sjose borrego 
11972c2961f8Sjose borrego /*
11982c2961f8Sjose borrego  * smb_node_create_audit_buf
11992c2961f8Sjose borrego  */
12002c2961f8Sjose borrego static void
12012c2961f8Sjose borrego smb_node_create_audit_buf(smb_node_t *node, int kmflags)
12022c2961f8Sjose borrego {
12032c2961f8Sjose borrego 	smb_audit_buf_node_t	*abn;
12042c2961f8Sjose borrego 
12052c2961f8Sjose borrego 	if (smb_audit_flags & SMB_AUDIT_NODE) {
12062c2961f8Sjose borrego 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
12072c2961f8Sjose borrego 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
12082c2961f8Sjose borrego 		node->n_audit_buf = abn;
12092c2961f8Sjose borrego 	}
12102c2961f8Sjose borrego }
12112c2961f8Sjose borrego 
12122c2961f8Sjose borrego /*
12132c2961f8Sjose borrego  * smb_node_destroy_audit_buf
12142c2961f8Sjose borrego  */
12152c2961f8Sjose borrego static void
12162c2961f8Sjose borrego smb_node_destroy_audit_buf(smb_node_t *node)
12172c2961f8Sjose borrego {
12182c2961f8Sjose borrego 	if (node->n_audit_buf != NULL) {
12192c2961f8Sjose borrego 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
12202c2961f8Sjose borrego 		node->n_audit_buf = NULL;
12212c2961f8Sjose borrego 	}
12222c2961f8Sjose borrego }
12232c2961f8Sjose borrego 
12242c2961f8Sjose borrego /*
12252c2961f8Sjose borrego  * smb_node_audit
12262c2961f8Sjose borrego  *
12272c2961f8Sjose borrego  * This function saves the calling stack in the audit buffer of the node passed
12282c2961f8Sjose borrego  * in.
12292c2961f8Sjose borrego  */
12302c2961f8Sjose borrego static void
12312c2961f8Sjose borrego smb_node_audit(smb_node_t *node)
12322c2961f8Sjose borrego {
12332c2961f8Sjose borrego 	smb_audit_buf_node_t	*abn;
12342c2961f8Sjose borrego 	smb_audit_record_node_t	*anr;
12352c2961f8Sjose borrego 
12362c2961f8Sjose borrego 	if (node->n_audit_buf) {
12372c2961f8Sjose borrego 		abn = node->n_audit_buf;
12382c2961f8Sjose borrego 		anr = abn->anb_records;
12392c2961f8Sjose borrego 		anr += abn->anb_index;
12402c2961f8Sjose borrego 		abn->anb_index++;
12412c2961f8Sjose borrego 		abn->anb_index &= abn->anb_max_index;
12422c2961f8Sjose borrego 		anr->anr_refcnt = node->n_refcnt;
12432c2961f8Sjose borrego 		anr->anr_depth = getpcstack(anr->anr_stack,
12442c2961f8Sjose borrego 		    SMB_AUDIT_STACK_DEPTH);
12452c2961f8Sjose borrego 	}
12462c2961f8Sjose borrego }
12472c2961f8Sjose borrego 
12482c2961f8Sjose borrego static smb_llist_t *
12492c2961f8Sjose borrego smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
12502c2961f8Sjose borrego {
12512c2961f8Sjose borrego 	uint32_t	hashkey;
12522c2961f8Sjose borrego 
12532c2961f8Sjose borrego 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
12542c2961f8Sjose borrego 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
12552c2961f8Sjose borrego 	*phashkey = hashkey;
12562c2961f8Sjose borrego 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1257dc20a302Sas200622 }
1258