xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /*
26  * SMB Node State Machine
27  * ----------------------
28  *
29  *
30  *		    +----------- Creation/Allocation
31  *		    |
32  *		    | T0
33  *		    |
34  *		    v
35  *    +----------------------------+        T1
36  *    |  SMB_NODE_STATE_AVAILABLE  |--------------------+
37  *    +----------------------------+			|
38  *		    |	     ^				|
39  *		    |	     |				v
40  *		    |	     |	  T2	+-------------------------------+
41  *		    |	     |<---------| SMB_NODE_STATE_OPLOCK_GRANTED |
42  *		    |	     |		+-------------------------------+
43  *		    | T5     |				|
44  *		    |	     |				| T3
45  *		    |	     |				v
46  *		    |	     |	  T4	+--------------------------------+
47  *		    |	     +----------| SMB_NODE_STATE_OPLOCK_BREAKING |
48  *		    |			+--------------------------------+
49  *		    |
50  *		    v
51  *    +-----------------------------+
52  *    |  SMB_NODE_STATE_DESTROYING  |
53  *    +-----------------------------+
54  *		    |
55  *		    |
56  *		    | T6
57  *		    |
58  *		    +----------> Deletion/Free
59  *
60  * Transition T0
61  *
62  *    This transition occurs in smb_node_lookup(). If the node looked for is
63  *    not found in the has table a new node is created. The reference count is
64  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
65  *
66  * Transition T1
67  *
68  *    This transition occurs smb_oplock_acquire() during an OPEN.
69  *
70  * Transition T2
71  *
72  *    This transition occurs in smb_oplock_release(). The events triggering
73  *    it are:
74  *
75  *	- LockingAndX sent by the client that was granted the oplock.
76  *	- Closing of the file.
77  *
78  * Transition T3
79  *
80  *    This transition occurs in smb_oplock_break(). The events triggering
81  *    it are:
82  *
83  *	- Another client wants to open the file.
84  *	- A client is trying to delete the file.
85  *	- A client is trying to rename the file.
86  *	- A client is trying to set/modify  the file attributes.
87  *
88  * Transition T4
89  *
90  *    This transition occurs in smb_oplock_release or smb_oplock_break(). The
91  *    events triggering it are:
92  *
93  *	- The client that was granting the oplock releases it (close or
94  *	  LockingAndx).
95  *	- The time alloted to release the oplock expired.
96  *
97  * Transition T5
98  *
99  *    This transition occurs in smb_node_release(). If the reference count
100  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
101  *    reference count will be given out for that node.
102  *
103  * Transition T6
104  *
105  *    This transition occurs in smb_node_release(). The structure is deleted.
106  *
107  * Comments
108  * --------
109  *
110  *    The reason the smb node has 2 states is the following synchronization
111  *    rule:
112  *
113  *    There's a mutex embedded in the node used to protect its fields and
114  *    there's a lock embedded in the bucket of the hash table the node belongs
115  *    to. To increment or to decrement the reference count the mutex must be
116  *    entered. To insert the node into the bucket and to remove it from the
117  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
118  *    lock) have to be entered, the lock has always to be entered first then
119  *    the mutex. This prevents a deadlock between smb_node_lookup() and
120  *    smb_node_release() from occurring. However, in smb_node_release() when the
121  *    reference count drops to zero and triggers the deletion of the node, the
122  *    mutex has to be released before entering the lock of the bucket (to
123  *    remove the node). This creates a window during which the node that is
124  *    about to be freed could be given out by smb_node_lookup(). To close that
125  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
126  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
127  *    state will indicate that the node should be treated as non existent (of
128  *    course the state of the node should be tested/updated under the
129  *    protection of the mutex).
130  */
131 #include <smbsrv/smb_incl.h>
132 #include <smbsrv/smb_fsops.h>
133 #include <smbsrv/smb_kstat.h>
134 #include <sys/pathname.h>
135 #include <sys/sdt.h>
136 #include <sys/nbmlock.h>
137 
138 uint32_t smb_is_executable(char *);
139 static void smb_node_delete_on_close(smb_node_t *);
140 static void smb_node_create_audit_buf(smb_node_t *, int);
141 static void smb_node_destroy_audit_buf(smb_node_t *);
142 static void smb_node_audit(smb_node_t *);
143 static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
144 static void smb_node_free(smb_node_t *);
145 static int smb_node_constructor(void *, void *, int);
146 static void smb_node_destructor(void *, void *);
147 static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
148 static void smb_node_init_cached_timestamps(smb_node_t *);
149 static void smb_node_clear_cached_timestamps(smb_node_t *);
150 static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *);
151 static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *);
152 
153 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
154     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
155     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
156     ASSERT((_dir_)->n_dnode != (_node_));
157 
158 static kmem_cache_t	*smb_node_cache = NULL;
159 static boolean_t	smb_node_initialized = B_FALSE;
160 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
161 
162 /*
163  * smb_node_init
164  *
165  * Initialization of the SMB node layer.
166  *
167  * This function is not multi-thread safe. The caller must make sure only one
168  * thread makes the call.
169  */
170 int
171 smb_node_init(void)
172 {
173 	int	i;
174 
175 	if (smb_node_initialized)
176 		return (0);
177 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
178 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
179 	    NULL, NULL, NULL, 0);
180 
181 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
182 		smb_llist_constructor(&smb_node_hash_table[i],
183 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
184 	}
185 	smb_node_initialized = B_TRUE;
186 	return (0);
187 }
188 
189 /*
190  * smb_node_fini
191  *
192  * This function is not multi-thread safe. The caller must make sure only one
193  * thread makes the call.
194  */
195 void
196 smb_node_fini(void)
197 {
198 	int	i;
199 
200 	if (!smb_node_initialized)
201 		return;
202 
203 #ifdef DEBUG
204 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
205 		smb_node_t	*node;
206 
207 		/*
208 		 * The following sequence is just intended for sanity check.
209 		 * This will have to be modified when the code goes into
210 		 * production.
211 		 *
212 		 * The SMB node hash table should be emtpy at this point. If the
213 		 * hash table is not empty a panic will be triggered.
214 		 *
215 		 * The reason why SMB nodes are still remaining in the hash
216 		 * table is problably due to a mismatch between calls to
217 		 * smb_node_lookup() and smb_node_release(). You must track that
218 		 * down.
219 		 */
220 		node = smb_llist_head(&smb_node_hash_table[i]);
221 		ASSERT(node == NULL);
222 	}
223 #endif
224 
225 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
226 		smb_llist_destructor(&smb_node_hash_table[i]);
227 	}
228 	kmem_cache_destroy(smb_node_cache);
229 	smb_node_cache = NULL;
230 	smb_node_initialized = B_FALSE;
231 }
232 
233 /*
234  * smb_node_lookup()
235  *
236  * NOTE: This routine should only be called by the file system interface layer,
237  * and not by SMB.
238  *
239  * smb_node_lookup() is called upon successful lookup, mkdir, and create
240  * (for both non-streams and streams).  In each of these cases, a held vnode is
241  * passed into this routine.  If a new smb_node is created it will take its
242  * own hold on the vnode.  The caller's hold therefore still belongs to, and
243  * should be released by, the caller.
244  *
245  * A reference is taken on the smb_node whether found in the hash table
246  * or newly created.
247  *
248  * If an smb_node needs to be created, a reference is also taken on the
249  * dnode (if passed in).
250  *
251  * See smb_node_release() for details on the release of these references.
252  */
253 
254 /*ARGSUSED*/
255 smb_node_t *
256 smb_node_lookup(
257     struct smb_request	*sr,
258     struct open_param	*op,
259     cred_t		*cred,
260     vnode_t		*vp,
261     char		*od_name,
262     smb_node_t		*dnode,
263     smb_node_t		*unode)
264 {
265 	smb_llist_t		*node_hdr;
266 	smb_node_t		*node;
267 	smb_attr_t		attr;
268 	uint32_t		hashkey = 0;
269 	fsid_t			fsid;
270 	int			error;
271 	krw_t			lock_mode;
272 	vnode_t			*unnamed_vp = NULL;
273 
274 	/*
275 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
276 	 * because the node may not yet exist.  We also do not want to call
277 	 * it with the list lock held.
278 	 */
279 
280 	if (unode)
281 		unnamed_vp = unode->vp;
282 
283 	/*
284 	 * This getattr is performed on behalf of the server
285 	 * that's why kcred is used not the user's cred
286 	 */
287 	attr.sa_mask = SMB_AT_ALL;
288 	error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, kcred);
289 	if (error)
290 		return (NULL);
291 
292 	if (sr && sr->tid_tree) {
293 		/*
294 		 * The fsid for a file is that of the tree, even
295 		 * if the file resides in a different mountpoint
296 		 * under the share.
297 		 */
298 		fsid = SMB_TREE_FSID(sr->tid_tree);
299 	} else {
300 		/*
301 		 * This should be getting executed only for the
302 		 * tree root smb_node.
303 		 */
304 		fsid = vp->v_vfsp->vfs_fsid;
305 	}
306 
307 	node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
308 	lock_mode = RW_READER;
309 
310 	smb_llist_enter(node_hdr, lock_mode);
311 	for (;;) {
312 		node = list_head(&node_hdr->ll_list);
313 		while (node) {
314 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
315 			ASSERT(node->n_hash_bucket == node_hdr);
316 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
317 				mutex_enter(&node->n_mutex);
318 				DTRACE_PROBE1(smb_node_lookup_hit,
319 				    smb_node_t *, node);
320 				switch (node->n_state) {
321 				case SMB_NODE_STATE_OPLOCK_GRANTED:
322 				case SMB_NODE_STATE_OPLOCK_BREAKING:
323 				case SMB_NODE_STATE_AVAILABLE:
324 					/* The node was found. */
325 					node->n_refcnt++;
326 					if ((node->n_dnode == NULL) &&
327 					    (dnode != NULL) &&
328 					    (strcmp(od_name, "..") != 0) &&
329 					    (strcmp(od_name, ".") != 0)) {
330 						VALIDATE_DIR_NODE(dnode, node);
331 						node->n_dnode = dnode;
332 						smb_node_ref(dnode);
333 					}
334 
335 					smb_node_audit(node);
336 					mutex_exit(&node->n_mutex);
337 					smb_llist_exit(node_hdr);
338 					return (node);
339 
340 				case SMB_NODE_STATE_DESTROYING:
341 					/*
342 					 * Although the node exists it is about
343 					 * to be destroyed. We act as it hasn't
344 					 * been found.
345 					 */
346 					mutex_exit(&node->n_mutex);
347 					break;
348 				default:
349 					/*
350 					 * Although the node exists it is in an
351 					 * unknown state. We act as it hasn't
352 					 * been found.
353 					 */
354 					ASSERT(0);
355 					mutex_exit(&node->n_mutex);
356 					break;
357 				}
358 			}
359 			node = smb_llist_next(node_hdr, node);
360 		}
361 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
362 			lock_mode = RW_WRITER;
363 			continue;
364 		}
365 		break;
366 	}
367 	node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
368 	node->n_orig_uid = crgetuid(sr->user_cr);
369 
370 	if (op)
371 		node->flags |= smb_is_executable(op->fqi.fq_last_comp);
372 
373 	if (dnode) {
374 		smb_node_ref(dnode);
375 		node->n_dnode = dnode;
376 		ASSERT(dnode->n_dnode != node);
377 		ASSERT((dnode->vp->v_xattrdir) ||
378 		    (dnode->vp->v_type == VDIR));
379 	}
380 
381 	if (unode) {
382 		smb_node_ref(unode);
383 		node->n_unode = unode;
384 	}
385 
386 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
387 	smb_node_audit(node);
388 	smb_llist_insert_head(node_hdr, node);
389 	smb_llist_exit(node_hdr);
390 	return (node);
391 }
392 
393 /*
394  * smb_stream_node_lookup()
395  *
396  * Note: stream_name (the name that will be stored in the "od_name" field
397  * of a stream's smb_node) is the same as the on-disk name for the stream
398  * except that it does not have SMB_STREAM_PREFIX prepended.
399  */
400 
401 smb_node_t *
402 smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
403     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
404 {
405 	smb_node_t	*xattrdir_node;
406 	smb_node_t	*snode;
407 
408 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
409 	    fnode, NULL);
410 
411 	if (xattrdir_node == NULL)
412 		return (NULL);
413 
414 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
415 	    fnode);
416 
417 	(void) smb_node_release(xattrdir_node);
418 	return (snode);
419 }
420 
421 
422 /*
423  * This function should be called whenever a reference is needed on an
424  * smb_node pointer.  The copy of an smb_node pointer from one non-local
425  * data structure to another requires a reference to be taken on the smb_node
426  * (unless the usage is localized).  Each data structure deallocation routine
427  * will call smb_node_release() on its smb_node pointers.
428  *
429  * In general, an smb_node pointer residing in a structure should never be
430  * stale.  A node pointer may be NULL, however, and care should be taken
431  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
432  * Care also needs to be taken with respect to racing deallocations of a
433  * structure.
434  */
435 void
436 smb_node_ref(smb_node_t *node)
437 {
438 	SMB_NODE_VALID(node);
439 
440 	mutex_enter(&node->n_mutex);
441 	switch (node->n_state) {
442 	case SMB_NODE_STATE_AVAILABLE:
443 	case SMB_NODE_STATE_OPLOCK_GRANTED:
444 	case SMB_NODE_STATE_OPLOCK_BREAKING:
445 		node->n_refcnt++;
446 		ASSERT(node->n_refcnt);
447 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
448 		smb_node_audit(node);
449 		break;
450 	default:
451 		SMB_PANIC();
452 	}
453 	mutex_exit(&node->n_mutex);
454 }
455 
456 /*
457  * smb_node_lookup() takes a hold on an smb_node, whether found in the
458  * hash table or newly created.  This hold is expected to be released
459  * in the following manner.
460  *
461  * smb_node_lookup() takes an address of an smb_node pointer.  This should
462  * be getting passed down via a lookup (whether path name or component), mkdir,
463  * create.  If the original smb_node pointer resides in a data structure, then
464  * the deallocation routine for the data structure is responsible for calling
465  * smb_node_release() on the smb_node pointer.  Alternatively,
466  * smb_node_release() can be called as soon as the smb_node pointer is no longer
467  * needed.  In this case, callers are responsible for setting an embedded
468  * pointer to NULL if it is known that the last reference is being released.
469  *
470  * If the passed-in address of the smb_node pointer belongs to a local variable,
471  * then the caller with the local variable should call smb_node_release()
472  * directly.
473  *
474  * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
475  * as smb_node_lookup() takes a hold on dnode.
476  */
477 void
478 smb_node_release(smb_node_t *node)
479 {
480 	SMB_NODE_VALID(node);
481 
482 	mutex_enter(&node->n_mutex);
483 	ASSERT(node->n_refcnt);
484 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
485 	if (--node->n_refcnt == 0) {
486 		switch (node->n_state) {
487 
488 		case SMB_NODE_STATE_AVAILABLE:
489 			node->n_state = SMB_NODE_STATE_DESTROYING;
490 			mutex_exit(&node->n_mutex);
491 
492 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
493 			smb_llist_remove(node->n_hash_bucket, node);
494 			smb_llist_exit(node->n_hash_bucket);
495 
496 			/*
497 			 * Check if the file was deleted
498 			 */
499 			smb_node_delete_on_close(node);
500 
501 			if (node->n_dnode) {
502 				ASSERT(node->n_dnode->n_magic ==
503 				    SMB_NODE_MAGIC);
504 				smb_node_release(node->n_dnode);
505 			}
506 
507 			if (node->n_unode) {
508 				ASSERT(node->n_unode->n_magic ==
509 				    SMB_NODE_MAGIC);
510 				smb_node_release(node->n_unode);
511 			}
512 
513 			smb_node_free(node);
514 			return;
515 
516 		default:
517 			SMB_PANIC();
518 		}
519 	}
520 	smb_node_audit(node);
521 	mutex_exit(&node->n_mutex);
522 }
523 
524 static void
525 smb_node_delete_on_close(smb_node_t *node)
526 {
527 	smb_node_t	*d_snode;
528 	int		rc = 0;
529 	uint32_t	flags = 0;
530 
531 	d_snode = node->n_dnode;
532 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
533 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
534 		flags = node->n_delete_on_close_flags;
535 		ASSERT(node->od_name != NULL);
536 
537 		if (node->vp->v_type == VDIR)
538 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
539 			    d_snode, node->od_name, flags);
540 		else
541 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
542 			    d_snode, node->od_name, flags);
543 		smb_cred_rele(node->delete_on_close_cred);
544 	}
545 	if (rc != 0)
546 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
547 		    node->od_name, rc);
548 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
549 }
550 
551 /*
552  * smb_node_rename()
553  *
554  */
555 void
556 smb_node_rename(
557     smb_node_t	*from_dnode,
558     smb_node_t	*ret_node,
559     smb_node_t	*to_dnode,
560     char	*to_name)
561 {
562 	SMB_NODE_VALID(from_dnode);
563 	SMB_NODE_VALID(to_dnode);
564 	SMB_NODE_VALID(ret_node);
565 
566 	smb_node_ref(to_dnode);
567 	mutex_enter(&ret_node->n_mutex);
568 	switch (ret_node->n_state) {
569 	case SMB_NODE_STATE_AVAILABLE:
570 	case SMB_NODE_STATE_OPLOCK_GRANTED:
571 	case SMB_NODE_STATE_OPLOCK_BREAKING:
572 		ret_node->n_dnode = to_dnode;
573 		mutex_exit(&ret_node->n_mutex);
574 		ASSERT(to_dnode->n_dnode != ret_node);
575 		ASSERT((to_dnode->vp->v_xattrdir) ||
576 		    (to_dnode->vp->v_type == VDIR));
577 		smb_node_release(from_dnode);
578 		(void) strcpy(ret_node->od_name, to_name);
579 		/*
580 		 * XXX Need to update attributes?
581 		 */
582 		break;
583 	default:
584 		SMB_PANIC();
585 	}
586 }
587 
588 int
589 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
590 {
591 	smb_attr_t	attr;
592 	int		error;
593 	uint32_t	hashkey;
594 	smb_llist_t	*node_hdr;
595 	smb_node_t	*node;
596 
597 	attr.sa_mask = SMB_AT_ALL;
598 	error = smb_vop_getattr(vp, NULL, &attr, 0, kcred);
599 	if (error) {
600 		VN_RELE(vp);
601 		return (error);
602 	}
603 
604 	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &attr, &hashkey);
605 
606 	node = smb_node_alloc(ROOTVOL, vp, node_hdr, hashkey);
607 
608 	sv->si_root_smb_node = node;
609 	smb_node_audit(node);
610 	smb_llist_enter(node_hdr, RW_WRITER);
611 	smb_llist_insert_head(node_hdr, node);
612 	smb_llist_exit(node_hdr);
613 	*root = node;
614 	return (0);
615 }
616 
617 /*
618  * When DeleteOnClose is set on an smb_node, the common open code will
619  * reject subsequent open requests for the file. Observation of Windows
620  * 2000 indicates that subsequent opens should be allowed (assuming
621  * there would be no sharing violation) until the file is closed using
622  * the fid on which the DeleteOnClose was requested.
623  *
624  * If there are multiple opens with delete-on-close create options,
625  * whichever the first file handle is closed will trigger the node to be
626  * marked as delete-on-close. The credentials of that ofile will be used
627  * as the delete-on-close credentials of the node.
628  */
629 int
630 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
631 {
632 	int rc;
633 	smb_attr_t attr;
634 
635 	mutex_enter(&node->n_mutex);
636 
637 	if ((node->flags & NODE_FLAGS_DELETE_ON_CLOSE) ||
638 	    (node->readonly_creator)) {
639 		mutex_exit(&node->n_mutex);
640 		return (-1);
641 	}
642 
643 	bzero(&attr, sizeof (smb_attr_t));
644 	attr.sa_mask = SMB_AT_DOSATTR;
645 	rc = smb_fsop_getattr(NULL, kcred, node, &attr);
646 	if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
647 		mutex_exit(&node->n_mutex);
648 		return (-1);
649 	}
650 
651 	crhold(cr);
652 	node->delete_on_close_cred = cr;
653 	node->n_delete_on_close_flags = flags;
654 	node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
655 	mutex_exit(&node->n_mutex);
656 	return (0);
657 }
658 
659 void
660 smb_node_reset_delete_on_close(smb_node_t *node)
661 {
662 	mutex_enter(&node->n_mutex);
663 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
664 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
665 		crfree(node->delete_on_close_cred);
666 		node->delete_on_close_cred = NULL;
667 		node->n_delete_on_close_flags = 0;
668 	}
669 	mutex_exit(&node->n_mutex);
670 }
671 
672 /*
673  * smb_node_open_check
674  *
675  * check file sharing rules for current open request
676  * against all existing opens for a file.
677  *
678  * Returns NT_STATUS_SHARING_VIOLATION if there is any
679  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
680  */
681 uint32_t
682 smb_node_open_check(
683     smb_node_t	*node,
684     cred_t	*cr,
685     uint32_t	desired_access,
686     uint32_t	share_access)
687 {
688 	smb_ofile_t *of;
689 	uint32_t status;
690 
691 	SMB_NODE_VALID(node);
692 
693 	smb_llist_enter(&node->n_ofile_list, RW_READER);
694 	of = smb_llist_head(&node->n_ofile_list);
695 	while (of) {
696 		status = smb_ofile_open_check(of, cr, desired_access,
697 		    share_access);
698 
699 		switch (status) {
700 		case NT_STATUS_INVALID_HANDLE:
701 		case NT_STATUS_SUCCESS:
702 			of = smb_llist_next(&node->n_ofile_list, of);
703 			break;
704 		default:
705 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
706 			smb_llist_exit(&node->n_ofile_list);
707 			return (status);
708 		}
709 	}
710 
711 	smb_llist_exit(&node->n_ofile_list);
712 	return (NT_STATUS_SUCCESS);
713 }
714 
715 uint32_t
716 smb_node_rename_check(smb_node_t *node)
717 {
718 	smb_ofile_t	*of;
719 	uint32_t	status;
720 
721 	SMB_NODE_VALID(node);
722 
723 	/*
724 	 * Intra-CIFS check
725 	 */
726 	smb_llist_enter(&node->n_ofile_list, RW_READER);
727 	of = smb_llist_head(&node->n_ofile_list);
728 	while (of) {
729 		status = smb_ofile_rename_check(of);
730 
731 		switch (status) {
732 		case NT_STATUS_INVALID_HANDLE:
733 		case NT_STATUS_SUCCESS:
734 			of = smb_llist_next(&node->n_ofile_list, of);
735 			break;
736 		default:
737 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
738 			smb_llist_exit(&node->n_ofile_list);
739 			return (status);
740 		}
741 	}
742 	smb_llist_exit(&node->n_ofile_list);
743 
744 	/*
745 	 * system-wide share check
746 	 */
747 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
748 		return (NT_STATUS_SHARING_VIOLATION);
749 	else
750 		return (NT_STATUS_SUCCESS);
751 }
752 
753 uint32_t
754 smb_node_delete_check(smb_node_t *node)
755 {
756 	smb_ofile_t	*of;
757 	uint32_t	status;
758 
759 	SMB_NODE_VALID(node);
760 
761 	if (node->vp->v_type == VDIR)
762 		return (NT_STATUS_SUCCESS);
763 
764 	/*
765 	 * intra-CIFS check
766 	 */
767 	smb_llist_enter(&node->n_ofile_list, RW_READER);
768 	of = smb_llist_head(&node->n_ofile_list);
769 	while (of) {
770 		status = smb_ofile_delete_check(of);
771 
772 		switch (status) {
773 		case NT_STATUS_INVALID_HANDLE:
774 		case NT_STATUS_SUCCESS:
775 			of = smb_llist_next(&node->n_ofile_list, of);
776 			break;
777 		default:
778 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
779 			smb_llist_exit(&node->n_ofile_list);
780 			return (status);
781 		}
782 	}
783 	smb_llist_exit(&node->n_ofile_list);
784 
785 	/*
786 	 * system-wide share check
787 	 */
788 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
789 		return (NT_STATUS_SHARING_VIOLATION);
790 	else
791 		return (NT_STATUS_SUCCESS);
792 }
793 
794 void
795 smb_node_notify_change(smb_node_t *node)
796 {
797 	SMB_NODE_VALID(node);
798 
799 	if (node->flags & NODE_FLAGS_NOTIFY_CHANGE) {
800 		node->flags |= NODE_FLAGS_CHANGED;
801 		smb_process_node_notify_change_queue(node);
802 	}
803 }
804 
805 /*
806  * smb_node_start_crit()
807  *
808  * Enter critical region for share reservations.
809  * See comments above smb_fsop_shrlock().
810  */
811 
812 void
813 smb_node_start_crit(smb_node_t *node, krw_t mode)
814 {
815 	rw_enter(&node->n_lock, mode);
816 	nbl_start_crit(node->vp, mode);
817 }
818 
819 /*
820  * smb_node_end_crit()
821  *
822  * Exit critical region for share reservations.
823  */
824 
825 void
826 smb_node_end_crit(smb_node_t *node)
827 {
828 	nbl_end_crit(node->vp);
829 	rw_exit(&node->n_lock);
830 }
831 
832 int
833 smb_node_in_crit(smb_node_t *node)
834 {
835 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
836 }
837 
838 void
839 smb_node_rdlock(smb_node_t *node)
840 {
841 	rw_enter(&node->n_lock, RW_READER);
842 }
843 
844 void
845 smb_node_wrlock(smb_node_t *node)
846 {
847 	rw_enter(&node->n_lock, RW_WRITER);
848 }
849 
850 void
851 smb_node_unlock(smb_node_t *node)
852 {
853 	rw_exit(&node->n_lock);
854 }
855 
856 uint32_t
857 smb_node_get_ofile_count(smb_node_t *node)
858 {
859 	uint32_t	cntr;
860 
861 	SMB_NODE_VALID(node);
862 
863 	smb_llist_enter(&node->n_ofile_list, RW_READER);
864 	cntr = smb_llist_get_count(&node->n_ofile_list);
865 	smb_llist_exit(&node->n_ofile_list);
866 	return (cntr);
867 }
868 
869 void
870 smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
871 {
872 	SMB_NODE_VALID(node);
873 
874 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
875 	smb_llist_insert_tail(&node->n_ofile_list, of);
876 	smb_llist_exit(&node->n_ofile_list);
877 }
878 
879 void
880 smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
881 {
882 	SMB_NODE_VALID(node);
883 
884 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
885 	smb_llist_remove(&node->n_ofile_list, of);
886 	smb_llist_exit(&node->n_ofile_list);
887 }
888 
889 /*
890  * smb_node_inc_open_ofiles
891  */
892 void
893 smb_node_inc_open_ofiles(smb_node_t *node)
894 {
895 	SMB_NODE_VALID(node);
896 
897 	mutex_enter(&node->n_mutex);
898 	node->n_open_count++;
899 	mutex_exit(&node->n_mutex);
900 
901 	smb_node_init_cached_timestamps(node);
902 }
903 
904 /*
905  * smb_node_dec_open_ofiles
906  */
907 void
908 smb_node_dec_open_ofiles(smb_node_t *node)
909 {
910 	SMB_NODE_VALID(node);
911 
912 	mutex_enter(&node->n_mutex);
913 	node->n_open_count--;
914 	mutex_exit(&node->n_mutex);
915 
916 	smb_node_clear_cached_timestamps(node);
917 }
918 
919 uint32_t
920 smb_node_get_open_ofiles(smb_node_t *node)
921 {
922 	uint32_t	cnt;
923 
924 	SMB_NODE_VALID(node);
925 
926 	mutex_enter(&node->n_mutex);
927 	cnt = node->n_open_count;
928 	mutex_exit(&node->n_mutex);
929 	return (cnt);
930 }
931 
932 /*
933  * smb_node_alloc
934  */
935 static smb_node_t *
936 smb_node_alloc(
937     char	*od_name,
938     vnode_t	*vp,
939     smb_llist_t	*bucket,
940     uint32_t	hashkey)
941 {
942 	smb_node_t	*node;
943 
944 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
945 
946 	if (node->n_audit_buf != NULL)
947 		node->n_audit_buf->anb_index = 0;
948 
949 	node->flags = 0;
950 	VN_HOLD(vp);
951 	node->vp = vp;
952 	node->n_refcnt = 1;
953 	node->n_hash_bucket = bucket;
954 	node->n_hashkey = hashkey;
955 	node->n_orig_uid = 0;
956 	node->readonly_creator = NULL;
957 	node->waiting_event = 0;
958 	node->n_open_count = 0;
959 	node->n_dnode = NULL;
960 	node->n_unode = NULL;
961 	node->delete_on_close_cred = NULL;
962 	node->n_delete_on_close_flags = 0;
963 
964 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
965 	if (strcmp(od_name, XATTR_DIR) == 0)
966 		node->flags |= NODE_XATTR_DIR;
967 
968 	node->n_state = SMB_NODE_STATE_AVAILABLE;
969 	node->n_magic = SMB_NODE_MAGIC;
970 	return (node);
971 }
972 
973 /*
974  * smb_node_free
975  */
976 static void
977 smb_node_free(smb_node_t *node)
978 {
979 	SMB_NODE_VALID(node);
980 
981 	node->n_magic = 0;
982 	VERIFY(!list_link_active(&node->n_lnd));
983 	VERIFY(node->n_lock_list.ll_count == 0);
984 	VERIFY(node->n_ofile_list.ll_count == 0);
985 	VERIFY(node->n_oplock.ol_xthread == NULL);
986 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
987 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
988 	VN_RELE(node->vp);
989 	kmem_cache_free(smb_node_cache, node);
990 }
991 
992 /*
993  * smb_node_constructor
994  */
995 static int
996 smb_node_constructor(void *buf, void *un, int kmflags)
997 {
998 	_NOTE(ARGUNUSED(kmflags, un))
999 
1000 	smb_node_t	*node = (smb_node_t *)buf;
1001 
1002 	bzero(node, sizeof (smb_node_t));
1003 
1004 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1005 	    offsetof(smb_ofile_t, f_nnd));
1006 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
1007 	    offsetof(smb_lock_t, l_lnd));
1008 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
1009 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
1010 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
1011 	smb_node_create_audit_buf(node, kmflags);
1012 	return (0);
1013 }
1014 
1015 /*
1016  * smb_node_destructor
1017  */
1018 static void
1019 smb_node_destructor(void *buf, void *un)
1020 {
1021 	_NOTE(ARGUNUSED(un))
1022 
1023 	smb_node_t	*node = (smb_node_t *)buf;
1024 
1025 	smb_node_destroy_audit_buf(node);
1026 	mutex_destroy(&node->n_mutex);
1027 	rw_destroy(&node->n_lock);
1028 	cv_destroy(&node->n_oplock.ol_cv);
1029 	smb_llist_destructor(&node->n_lock_list);
1030 	smb_llist_destructor(&node->n_ofile_list);
1031 }
1032 
1033 /*
1034  * smb_node_create_audit_buf
1035  */
1036 static void
1037 smb_node_create_audit_buf(smb_node_t *node, int kmflags)
1038 {
1039 	smb_audit_buf_node_t	*abn;
1040 
1041 	if (smb_audit_flags & SMB_AUDIT_NODE) {
1042 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
1043 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
1044 		node->n_audit_buf = abn;
1045 	}
1046 }
1047 
1048 /*
1049  * smb_node_destroy_audit_buf
1050  */
1051 static void
1052 smb_node_destroy_audit_buf(smb_node_t *node)
1053 {
1054 	if (node->n_audit_buf != NULL) {
1055 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
1056 		node->n_audit_buf = NULL;
1057 	}
1058 }
1059 
1060 /*
1061  * smb_node_audit
1062  *
1063  * This function saves the calling stack in the audit buffer of the node passed
1064  * in.
1065  */
1066 static void
1067 smb_node_audit(smb_node_t *node)
1068 {
1069 	smb_audit_buf_node_t	*abn;
1070 	smb_audit_record_node_t	*anr;
1071 
1072 	if (node->n_audit_buf) {
1073 		abn = node->n_audit_buf;
1074 		anr = abn->anb_records;
1075 		anr += abn->anb_index;
1076 		abn->anb_index++;
1077 		abn->anb_index &= abn->anb_max_index;
1078 		anr->anr_refcnt = node->n_refcnt;
1079 		anr->anr_depth = getpcstack(anr->anr_stack,
1080 		    SMB_AUDIT_STACK_DEPTH);
1081 	}
1082 }
1083 
1084 static smb_llist_t *
1085 smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
1086 {
1087 	uint32_t	hashkey;
1088 
1089 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
1090 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1091 	*phashkey = hashkey;
1092 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1093 }
1094 
1095 boolean_t
1096 smb_node_is_dir(smb_node_t *node)
1097 {
1098 	SMB_NODE_VALID(node);
1099 	return (node->vp->v_type == VDIR);
1100 }
1101 
1102 boolean_t
1103 smb_node_is_link(smb_node_t *node)
1104 {
1105 	SMB_NODE_VALID(node);
1106 	return (node->vp->v_type == VLNK);
1107 }
1108 
1109 /*
1110  * smb_node_file_is_readonly
1111  *
1112  * Checks if the file (which node represents) is marked readonly
1113  * in the filesystem. No account is taken of any pending readonly
1114  * in the node, which must be handled by the callers.
1115  * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY)
1116  */
1117 boolean_t
1118 smb_node_file_is_readonly(smb_node_t *node)
1119 {
1120 	smb_attr_t attr;
1121 
1122 	if (node == NULL)
1123 		return (B_FALSE);
1124 
1125 	bzero(&attr, sizeof (smb_attr_t));
1126 	attr.sa_mask = SMB_AT_DOSATTR;
1127 	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
1128 	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
1129 }
1130 
1131 /*
1132  * smb_node_setattr
1133  *
1134  * The sr may be NULL, for example when closing an ofile.
1135  * The ofile may be NULL, for example when a client request
1136  * specifies the file by pathname.
1137  *
1138  * When attributes are set on an ofile, any pending timestamps
1139  * from a write request on the ofile are implicitly set to "now".
1140  * For compatibility with windows the following timestamps are
1141  * also implicitly set to now:
1142  * - if any attribute is being explicitly set, set ctime to now
1143  * - if file size is being explicitly set, set atime & ctime to now
1144  *
1145  * Any attribute that is being explicitly set, or has previously
1146  * been explicitly set on the ofile, is excluded from implicit
1147  * (now) setting.
1148  *
1149  * Updates the node's cached timestamp values.
1150  * Updates the ofile's explicit times flag.
1151  *
1152  * Returns: errno
1153  */
1154 int
1155 smb_node_setattr(smb_request_t *sr, smb_node_t *node,
1156     cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
1157 {
1158 	int rc;
1159 	uint32_t what;
1160 	uint32_t now_times = 0;
1161 	timestruc_t now;
1162 
1163 	ASSERT(attr);
1164 	SMB_NODE_VALID(node);
1165 
1166 	what = attr->sa_mask;
1167 
1168 	/* determine which timestamps to implicitly set to "now" */
1169 	if (what)
1170 		now_times |= SMB_AT_CTIME;
1171 	if (what & SMB_AT_SIZE)
1172 		now_times |= (SMB_AT_MTIME | SMB_AT_CTIME);
1173 	if (of) {
1174 		if (smb_ofile_write_time_pending(of))
1175 			now_times |=
1176 			    (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
1177 		now_times &= ~(smb_ofile_explicit_times(of));
1178 	}
1179 	now_times &= ~what;
1180 
1181 	if (now_times) {
1182 		gethrestime(&now);
1183 
1184 		if (now_times & SMB_AT_ATIME) {
1185 			attr->sa_vattr.va_atime = now;
1186 			attr->sa_mask |= SMB_AT_ATIME;
1187 		}
1188 		if (now_times & SMB_AT_MTIME) {
1189 			attr->sa_vattr.va_mtime = now;
1190 			attr->sa_mask |= SMB_AT_MTIME;
1191 		}
1192 		if (now_times & SMB_AT_CTIME) {
1193 			attr->sa_vattr.va_ctime = now;
1194 			attr->sa_mask |= SMB_AT_CTIME;
1195 		}
1196 	}
1197 
1198 	if (attr->sa_mask == 0)
1199 		return (0);
1200 
1201 	rc = smb_fsop_setattr(sr, cr, node, attr);
1202 	if (rc != 0)
1203 		return (rc);
1204 
1205 	smb_node_set_cached_timestamps(node, attr);
1206 
1207 	if (of)
1208 		smb_ofile_set_explicit_times(of, (what & SMB_AT_TIMES));
1209 
1210 	return (0);
1211 }
1212 
1213 /*
1214  * smb_node_getattr
1215  *
1216  * Get attributes from the file system and apply any smb-specific
1217  * overrides for size, dos attributes and timestamps
1218  *
1219  * node->readonly_creator reflects whether a readonly set is pending
1220  * from a readonly create. The readonly attribute should be visible to
1221  * all clients even though the readonly creator fid is immune to the
1222  * readonly bit until close.
1223  *
1224  * Returns: errno
1225  */
1226 int
1227 smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
1228 {
1229 	int rc;
1230 
1231 	SMB_NODE_VALID(node);
1232 
1233 	bzero(attr, sizeof (smb_attr_t));
1234 	attr->sa_mask = SMB_AT_ALL;
1235 	rc = smb_fsop_getattr(sr, kcred, node, attr);
1236 	if (rc != 0)
1237 		return (rc);
1238 
1239 	mutex_enter(&node->n_mutex);
1240 
1241 	if (node->vp->v_type == VDIR)
1242 		attr->sa_vattr.va_size = 0;
1243 
1244 	if (node->readonly_creator)
1245 		attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
1246 	if (attr->sa_dosattr == 0)
1247 		attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
1248 
1249 	mutex_exit(&node->n_mutex);
1250 
1251 	smb_node_get_cached_timestamps(node, attr);
1252 	return (0);
1253 }
1254 
1255 /*
1256  * Timestamp caching
1257  *
1258  * Solaris file systems handle timestamps different from NTFS. For
1259  * example when file data is written NTFS doesn't update the timestamps
1260  * until the file is closed, and then only if they haven't been explicity
1261  * set via a set attribute request. In order to provide a more similar
1262  * view of an open file's timestamps, we cache the timestamps in the
1263  * node and manipulate them in a manner more consistent with windows.
1264  * (See handling of explicit times and pending timestamps from a write
1265  * request in smb_node_getattr and smb_node_setattr above.)
1266  * Timestamps remain cached while there are open ofiles for the node.
1267  * This includes open ofiles for named streams.
1268  * n_open_ofiles cannot be used as this doesn't include ofiles opened
1269  * for the node's named streams. Thus n_timestamps contains a count
1270  * of open ofiles (t_open_ofiles), including named streams' ofiles,
1271  * to be used to control timestamp caching.
1272  *
1273  * If a node represents a named stream the associated unnamed streams
1274  * cached timestamps are used instead.
1275  */
1276 
1277 /*
1278  * smb_node_init_cached_timestamps
1279  *
1280  * Increment count of open ofiles which are using the cached timestamps.
1281  * If this is the first open ofile, init the cached timestamps from the
1282  * file system values.
1283  */
1284 static void
1285 smb_node_init_cached_timestamps(smb_node_t *node)
1286 {
1287 	smb_node_t *unode;
1288 	smb_attr_t attr;
1289 
1290 	if ((unode = SMB_IS_STREAM(node)) != NULL)
1291 		node = unode;
1292 
1293 	mutex_enter(&node->n_mutex);
1294 	++(node->n_timestamps.t_open_ofiles);
1295 	if (node->n_timestamps.t_open_ofiles == 1) {
1296 		bzero(&attr, sizeof (smb_attr_t));
1297 		attr.sa_mask = SMB_AT_TIMES;
1298 		(void) smb_fsop_getattr(NULL, kcred, node, &attr);
1299 		node->n_timestamps.t_mtime = attr.sa_vattr.va_mtime;
1300 		node->n_timestamps.t_atime = attr.sa_vattr.va_atime;
1301 		node->n_timestamps.t_ctime = attr.sa_vattr.va_ctime;
1302 		node->n_timestamps.t_crtime = attr.sa_crtime;
1303 		node->n_timestamps.t_cached = B_TRUE;
1304 	}
1305 	mutex_exit(&node->n_mutex);
1306 }
1307 
1308 /*
1309  * smb_node_clear_cached_timestamps
1310  *
1311  * Decrement count of open ofiles using the cached timestamps.
1312  * If the decremented count is zero, clear the cached timestamps.
1313  */
1314 static void
1315 smb_node_clear_cached_timestamps(smb_node_t *node)
1316 {
1317 	smb_node_t *unode;
1318 
1319 	if ((unode = SMB_IS_STREAM(node)) != NULL)
1320 		node = unode;
1321 
1322 	mutex_enter(&node->n_mutex);
1323 	ASSERT(node->n_timestamps.t_open_ofiles > 0);
1324 	--(node->n_timestamps.t_open_ofiles);
1325 	if (node->n_timestamps.t_open_ofiles == 0)
1326 		bzero(&node->n_timestamps, sizeof (smb_times_t));
1327 	mutex_exit(&node->n_mutex);
1328 }
1329 
1330 /*
1331  * smb_node_get_cached_timestamps
1332  *
1333  * Overwrite timestamps in attr with those cached in node.
1334  */
1335 static void
1336 smb_node_get_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
1337 {
1338 	smb_node_t *unode;
1339 
1340 	if ((unode = SMB_IS_STREAM(node)) != NULL)
1341 		node = unode;
1342 
1343 	mutex_enter(&node->n_mutex);
1344 	if (node->n_timestamps.t_cached) {
1345 		attr->sa_vattr.va_mtime = node->n_timestamps.t_mtime;
1346 		attr->sa_vattr.va_atime = node->n_timestamps.t_atime;
1347 		attr->sa_vattr.va_ctime = node->n_timestamps.t_ctime;
1348 		attr->sa_crtime = node->n_timestamps.t_crtime;
1349 	}
1350 	mutex_exit(&node->n_mutex);
1351 }
1352 
1353 /*
1354  * smb_node_set_cached_timestamps
1355  *
1356  * Update the node's cached timestamps with values from attr.
1357  */
1358 static void
1359 smb_node_set_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
1360 {
1361 	smb_node_t *unode;
1362 
1363 	if ((unode = SMB_IS_STREAM(node)) != NULL)
1364 		node = unode;
1365 
1366 	mutex_enter(&node->n_mutex);
1367 	if (node->n_timestamps.t_cached) {
1368 		if (attr->sa_mask & SMB_AT_MTIME)
1369 			node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
1370 		if (attr->sa_mask & SMB_AT_ATIME)
1371 			node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
1372 		if (attr->sa_mask & SMB_AT_CTIME)
1373 			node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
1374 		if (attr->sa_mask & SMB_AT_CRTIME)
1375 			node->n_timestamps.t_crtime = attr->sa_crtime;
1376 	}
1377 	mutex_exit(&node->n_mutex);
1378 }
1379