xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 8fd04b8338ed5093ec2d1e668fa620b7de44c177)
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 2010 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_kproto.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_notify_parent(smb_node_t *);
140 static void smb_node_delete_on_close(smb_node_t *);
141 static void smb_node_create_audit_buf(smb_node_t *, int);
142 static void smb_node_destroy_audit_buf(smb_node_t *);
143 static void smb_node_audit(smb_node_t *);
144 static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
145 static void smb_node_free(smb_node_t *);
146 static int smb_node_constructor(void *, void *, int);
147 static void smb_node_destructor(void *, void *);
148 static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
149 
150 static void smb_node_init_cached_data(smb_node_t *);
151 static void smb_node_clear_cached_data(smb_node_t *);
152 
153 static void smb_node_init_cached_timestamps(smb_node_t *, smb_attr_t *);
154 static void smb_node_clear_cached_timestamps(smb_node_t *);
155 static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *);
156 static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *);
157 
158 static void smb_node_init_cached_allocsz(smb_node_t *, smb_attr_t *);
159 static void smb_node_clear_cached_allocsz(smb_node_t *);
160 static void smb_node_get_cached_allocsz(smb_node_t *, smb_attr_t *);
161 static void smb_node_set_cached_allocsz(smb_node_t *, smb_attr_t *);
162 
163 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
164     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
165     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
166     ASSERT((_dir_)->n_dnode != (_node_));
167 
168 /* round sz to DEV_BSIZE block */
169 #define	SMB_ALLOCSZ(sz)	(((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
170 
171 static kmem_cache_t	*smb_node_cache = NULL;
172 static boolean_t	smb_node_initialized = B_FALSE;
173 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
174 
175 /*
176  * smb_node_init
177  *
178  * Initialization of the SMB node layer.
179  *
180  * This function is not multi-thread safe. The caller must make sure only one
181  * thread makes the call.
182  */
183 int
184 smb_node_init(void)
185 {
186 	int	i;
187 
188 	if (smb_node_initialized)
189 		return (0);
190 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
191 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
192 	    NULL, NULL, NULL, 0);
193 
194 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
195 		smb_llist_constructor(&smb_node_hash_table[i],
196 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
197 	}
198 	smb_node_initialized = B_TRUE;
199 	return (0);
200 }
201 
202 /*
203  * smb_node_fini
204  *
205  * This function is not multi-thread safe. The caller must make sure only one
206  * thread makes the call.
207  */
208 void
209 smb_node_fini(void)
210 {
211 	int	i;
212 
213 	if (!smb_node_initialized)
214 		return;
215 
216 #ifdef DEBUG
217 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
218 		smb_node_t	*node;
219 
220 		/*
221 		 * The following sequence is just intended for sanity check.
222 		 * This will have to be modified when the code goes into
223 		 * production.
224 		 *
225 		 * The SMB node hash table should be emtpy at this point. If the
226 		 * hash table is not empty a panic will be triggered.
227 		 *
228 		 * The reason why SMB nodes are still remaining in the hash
229 		 * table is problably due to a mismatch between calls to
230 		 * smb_node_lookup() and smb_node_release(). You must track that
231 		 * down.
232 		 */
233 		node = smb_llist_head(&smb_node_hash_table[i]);
234 		ASSERT(node == NULL);
235 	}
236 #endif
237 
238 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
239 		smb_llist_destructor(&smb_node_hash_table[i]);
240 	}
241 	kmem_cache_destroy(smb_node_cache);
242 	smb_node_cache = NULL;
243 	smb_node_initialized = B_FALSE;
244 }
245 
246 /*
247  * smb_node_lookup()
248  *
249  * NOTE: This routine should only be called by the file system interface layer,
250  * and not by SMB.
251  *
252  * smb_node_lookup() is called upon successful lookup, mkdir, and create
253  * (for both non-streams and streams).  In each of these cases, a held vnode is
254  * passed into this routine.  If a new smb_node is created it will take its
255  * own hold on the vnode.  The caller's hold therefore still belongs to, and
256  * should be released by, the caller.
257  *
258  * A reference is taken on the smb_node whether found in the hash table
259  * or newly created.
260  *
261  * If an smb_node needs to be created, a reference is also taken on the
262  * dnode (if passed in).
263  *
264  * See smb_node_release() for details on the release of these references.
265  */
266 
267 /*ARGSUSED*/
268 smb_node_t *
269 smb_node_lookup(
270     struct smb_request	*sr,
271     struct open_param	*op,
272     cred_t		*cred,
273     vnode_t		*vp,
274     char		*od_name,
275     smb_node_t		*dnode,
276     smb_node_t		*unode)
277 {
278 	smb_llist_t		*node_hdr;
279 	smb_node_t		*node;
280 	smb_attr_t		attr;
281 	uint32_t		hashkey = 0;
282 	fsid_t			fsid;
283 	int			error;
284 	krw_t			lock_mode;
285 	vnode_t			*unnamed_vp = NULL;
286 
287 	/*
288 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
289 	 * because the node may not yet exist.  We also do not want to call
290 	 * it with the list lock held.
291 	 */
292 
293 	if (unode)
294 		unnamed_vp = unode->vp;
295 
296 	/*
297 	 * This getattr is performed on behalf of the server
298 	 * that's why kcred is used not the user's cred
299 	 */
300 	attr.sa_mask = SMB_AT_ALL;
301 	error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, kcred);
302 	if (error)
303 		return (NULL);
304 
305 	if (sr && sr->tid_tree) {
306 		/*
307 		 * The fsid for a file is that of the tree, even
308 		 * if the file resides in a different mountpoint
309 		 * under the share.
310 		 */
311 		fsid = SMB_TREE_FSID(sr->tid_tree);
312 	} else {
313 		/*
314 		 * This should be getting executed only for the
315 		 * tree root smb_node.
316 		 */
317 		fsid = vp->v_vfsp->vfs_fsid;
318 	}
319 
320 	node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
321 	lock_mode = RW_READER;
322 
323 	smb_llist_enter(node_hdr, lock_mode);
324 	for (;;) {
325 		node = list_head(&node_hdr->ll_list);
326 		while (node) {
327 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
328 			ASSERT(node->n_hash_bucket == node_hdr);
329 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
330 				mutex_enter(&node->n_mutex);
331 				DTRACE_PROBE1(smb_node_lookup_hit,
332 				    smb_node_t *, node);
333 				switch (node->n_state) {
334 				case SMB_NODE_STATE_OPLOCK_GRANTED:
335 				case SMB_NODE_STATE_OPLOCK_BREAKING:
336 				case SMB_NODE_STATE_AVAILABLE:
337 					/* The node was found. */
338 					node->n_refcnt++;
339 					if ((node->n_dnode == NULL) &&
340 					    (dnode != NULL) &&
341 					    (node != dnode) &&
342 					    (strcmp(od_name, "..") != 0) &&
343 					    (strcmp(od_name, ".") != 0)) {
344 						VALIDATE_DIR_NODE(dnode, node);
345 						node->n_dnode = dnode;
346 						smb_node_ref(dnode);
347 					}
348 
349 					smb_node_audit(node);
350 					mutex_exit(&node->n_mutex);
351 					smb_llist_exit(node_hdr);
352 					return (node);
353 
354 				case SMB_NODE_STATE_DESTROYING:
355 					/*
356 					 * Although the node exists it is about
357 					 * to be destroyed. We act as it hasn't
358 					 * been found.
359 					 */
360 					mutex_exit(&node->n_mutex);
361 					break;
362 				default:
363 					/*
364 					 * Although the node exists it is in an
365 					 * unknown state. We act as it hasn't
366 					 * been found.
367 					 */
368 					ASSERT(0);
369 					mutex_exit(&node->n_mutex);
370 					break;
371 				}
372 			}
373 			node = smb_llist_next(node_hdr, node);
374 		}
375 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
376 			lock_mode = RW_WRITER;
377 			continue;
378 		}
379 		break;
380 	}
381 	node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
382 	node->n_orig_uid = crgetuid(sr->user_cr);
383 
384 	if (op)
385 		node->flags |= smb_is_executable(op->fqi.fq_last_comp);
386 
387 	if (dnode) {
388 		smb_node_ref(dnode);
389 		node->n_dnode = dnode;
390 		ASSERT(dnode->n_dnode != node);
391 		ASSERT((dnode->vp->v_xattrdir) ||
392 		    (dnode->vp->v_type == VDIR));
393 	}
394 
395 	if (unode) {
396 		smb_node_ref(unode);
397 		node->n_unode = unode;
398 	}
399 
400 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
401 	smb_node_audit(node);
402 	smb_llist_insert_head(node_hdr, node);
403 	smb_llist_exit(node_hdr);
404 	return (node);
405 }
406 
407 /*
408  * smb_stream_node_lookup()
409  *
410  * Note: stream_name (the name that will be stored in the "od_name" field
411  * of a stream's smb_node) is the same as the on-disk name for the stream
412  * except that it does not have SMB_STREAM_PREFIX prepended.
413  */
414 
415 smb_node_t *
416 smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
417     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
418 {
419 	smb_node_t	*xattrdir_node;
420 	smb_node_t	*snode;
421 
422 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
423 	    fnode, NULL);
424 
425 	if (xattrdir_node == NULL)
426 		return (NULL);
427 
428 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
429 	    fnode);
430 
431 	(void) smb_node_release(xattrdir_node);
432 	return (snode);
433 }
434 
435 
436 /*
437  * This function should be called whenever a reference is needed on an
438  * smb_node pointer.  The copy of an smb_node pointer from one non-local
439  * data structure to another requires a reference to be taken on the smb_node
440  * (unless the usage is localized).  Each data structure deallocation routine
441  * will call smb_node_release() on its smb_node pointers.
442  *
443  * In general, an smb_node pointer residing in a structure should never be
444  * stale.  A node pointer may be NULL, however, and care should be taken
445  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
446  * Care also needs to be taken with respect to racing deallocations of a
447  * structure.
448  */
449 void
450 smb_node_ref(smb_node_t *node)
451 {
452 	SMB_NODE_VALID(node);
453 
454 	mutex_enter(&node->n_mutex);
455 	switch (node->n_state) {
456 	case SMB_NODE_STATE_AVAILABLE:
457 	case SMB_NODE_STATE_OPLOCK_GRANTED:
458 	case SMB_NODE_STATE_OPLOCK_BREAKING:
459 		node->n_refcnt++;
460 		ASSERT(node->n_refcnt);
461 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
462 		smb_node_audit(node);
463 		break;
464 	default:
465 		SMB_PANIC();
466 	}
467 	mutex_exit(&node->n_mutex);
468 }
469 
470 /*
471  * smb_node_lookup() takes a hold on an smb_node, whether found in the
472  * hash table or newly created.  This hold is expected to be released
473  * in the following manner.
474  *
475  * smb_node_lookup() takes an address of an smb_node pointer.  This should
476  * be getting passed down via a lookup (whether path name or component), mkdir,
477  * create.  If the original smb_node pointer resides in a data structure, then
478  * the deallocation routine for the data structure is responsible for calling
479  * smb_node_release() on the smb_node pointer.  Alternatively,
480  * smb_node_release() can be called as soon as the smb_node pointer is no longer
481  * needed.  In this case, callers are responsible for setting an embedded
482  * pointer to NULL if it is known that the last reference is being released.
483  *
484  * If the passed-in address of the smb_node pointer belongs to a local variable,
485  * then the caller with the local variable should call smb_node_release()
486  * directly.
487  *
488  * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
489  * as smb_node_lookup() takes a hold on dnode.
490  */
491 void
492 smb_node_release(smb_node_t *node)
493 {
494 	SMB_NODE_VALID(node);
495 
496 	mutex_enter(&node->n_mutex);
497 	ASSERT(node->n_refcnt);
498 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
499 	if (--node->n_refcnt == 0) {
500 		switch (node->n_state) {
501 
502 		case SMB_NODE_STATE_AVAILABLE:
503 			node->n_state = SMB_NODE_STATE_DESTROYING;
504 			mutex_exit(&node->n_mutex);
505 
506 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
507 			smb_llist_remove(node->n_hash_bucket, node);
508 			smb_llist_exit(node->n_hash_bucket);
509 
510 			/*
511 			 * Check if the file was deleted
512 			 */
513 			smb_node_delete_on_close(node);
514 
515 			if (node->n_dnode) {
516 				ASSERT(node->n_dnode->n_magic ==
517 				    SMB_NODE_MAGIC);
518 				smb_node_release(node->n_dnode);
519 			}
520 
521 			if (node->n_unode) {
522 				ASSERT(node->n_unode->n_magic ==
523 				    SMB_NODE_MAGIC);
524 				smb_node_release(node->n_unode);
525 			}
526 
527 			smb_node_free(node);
528 			return;
529 
530 		default:
531 			SMB_PANIC();
532 		}
533 	}
534 	smb_node_audit(node);
535 	mutex_exit(&node->n_mutex);
536 }
537 
538 static void
539 smb_node_delete_on_close(smb_node_t *node)
540 {
541 	smb_node_t	*d_snode;
542 	int		rc = 0;
543 	uint32_t	flags = 0;
544 
545 	d_snode = node->n_dnode;
546 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
547 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
548 		flags = node->n_delete_on_close_flags;
549 		ASSERT(node->od_name != NULL);
550 
551 		if (node->vp->v_type == VDIR)
552 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
553 			    d_snode, node->od_name, flags);
554 		else
555 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
556 			    d_snode, node->od_name, flags);
557 		smb_cred_rele(node->delete_on_close_cred);
558 	}
559 	if (rc != 0)
560 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
561 		    node->od_name, rc);
562 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
563 }
564 
565 /*
566  * smb_node_rename()
567  *
568  */
569 void
570 smb_node_rename(
571     smb_node_t	*from_dnode,
572     smb_node_t	*ret_node,
573     smb_node_t	*to_dnode,
574     char	*to_name)
575 {
576 	SMB_NODE_VALID(from_dnode);
577 	SMB_NODE_VALID(to_dnode);
578 	SMB_NODE_VALID(ret_node);
579 
580 	smb_node_ref(to_dnode);
581 	mutex_enter(&ret_node->n_mutex);
582 	switch (ret_node->n_state) {
583 	case SMB_NODE_STATE_AVAILABLE:
584 	case SMB_NODE_STATE_OPLOCK_GRANTED:
585 	case SMB_NODE_STATE_OPLOCK_BREAKING:
586 		ret_node->n_dnode = to_dnode;
587 		mutex_exit(&ret_node->n_mutex);
588 		ASSERT(to_dnode->n_dnode != ret_node);
589 		ASSERT((to_dnode->vp->v_xattrdir) ||
590 		    (to_dnode->vp->v_type == VDIR));
591 		smb_node_release(from_dnode);
592 		(void) strcpy(ret_node->od_name, to_name);
593 		/*
594 		 * XXX Need to update attributes?
595 		 */
596 		break;
597 	default:
598 		SMB_PANIC();
599 	}
600 }
601 
602 int
603 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
604 {
605 	smb_attr_t	attr;
606 	int		error;
607 	uint32_t	hashkey;
608 	smb_llist_t	*node_hdr;
609 	smb_node_t	*node;
610 
611 	attr.sa_mask = SMB_AT_ALL;
612 	error = smb_vop_getattr(vp, NULL, &attr, 0, kcred);
613 	if (error) {
614 		VN_RELE(vp);
615 		return (error);
616 	}
617 
618 	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &attr, &hashkey);
619 
620 	node = smb_node_alloc(ROOTVOL, vp, node_hdr, hashkey);
621 
622 	sv->si_root_smb_node = node;
623 	smb_node_audit(node);
624 	smb_llist_enter(node_hdr, RW_WRITER);
625 	smb_llist_insert_head(node_hdr, node);
626 	smb_llist_exit(node_hdr);
627 	*root = node;
628 	return (0);
629 }
630 
631 /*
632  * When DeleteOnClose is set on an smb_node, the common open code will
633  * reject subsequent open requests for the file. Observation of Windows
634  * 2000 indicates that subsequent opens should be allowed (assuming
635  * there would be no sharing violation) until the file is closed using
636  * the fid on which the DeleteOnClose was requested.
637  *
638  * If there are multiple opens with delete-on-close create options,
639  * whichever the first file handle is closed will trigger the node to be
640  * marked as delete-on-close. The credentials of that ofile will be used
641  * as the delete-on-close credentials of the node.
642  */
643 int
644 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
645 {
646 	int rc = 0;
647 	smb_attr_t attr;
648 
649 	if (node->readonly_creator)
650 		return (-1);
651 
652 	bzero(&attr, sizeof (smb_attr_t));
653 	attr.sa_mask = SMB_AT_DOSATTR;
654 	rc = smb_fsop_getattr(NULL, kcred, node, &attr);
655 	if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
656 		return (-1);
657 	}
658 
659 	mutex_enter(&node->n_mutex);
660 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
661 		rc = -1;
662 	} else {
663 		crhold(cr);
664 		node->delete_on_close_cred = cr;
665 		node->n_delete_on_close_flags = flags;
666 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
667 		rc = 0;
668 	}
669 	mutex_exit(&node->n_mutex);
670 	return (rc);
671 }
672 
673 void
674 smb_node_reset_delete_on_close(smb_node_t *node)
675 {
676 	mutex_enter(&node->n_mutex);
677 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
678 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
679 		crfree(node->delete_on_close_cred);
680 		node->delete_on_close_cred = NULL;
681 		node->n_delete_on_close_flags = 0;
682 	}
683 	mutex_exit(&node->n_mutex);
684 }
685 
686 /*
687  * smb_node_open_check
688  *
689  * check file sharing rules for current open request
690  * against all existing opens for a file.
691  *
692  * Returns NT_STATUS_SHARING_VIOLATION if there is any
693  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
694  */
695 uint32_t
696 smb_node_open_check(
697     smb_node_t	*node,
698     cred_t	*cr,
699     uint32_t	desired_access,
700     uint32_t	share_access)
701 {
702 	smb_ofile_t *of;
703 	uint32_t status;
704 
705 	SMB_NODE_VALID(node);
706 
707 	smb_llist_enter(&node->n_ofile_list, RW_READER);
708 	of = smb_llist_head(&node->n_ofile_list);
709 	while (of) {
710 		status = smb_ofile_open_check(of, cr, desired_access,
711 		    share_access);
712 
713 		switch (status) {
714 		case NT_STATUS_INVALID_HANDLE:
715 		case NT_STATUS_SUCCESS:
716 			of = smb_llist_next(&node->n_ofile_list, of);
717 			break;
718 		default:
719 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
720 			smb_llist_exit(&node->n_ofile_list);
721 			return (status);
722 		}
723 	}
724 
725 	smb_llist_exit(&node->n_ofile_list);
726 	return (NT_STATUS_SUCCESS);
727 }
728 
729 uint32_t
730 smb_node_rename_check(smb_node_t *node)
731 {
732 	smb_ofile_t	*of;
733 	uint32_t	status;
734 
735 	SMB_NODE_VALID(node);
736 
737 	/*
738 	 * Intra-CIFS check
739 	 */
740 	smb_llist_enter(&node->n_ofile_list, RW_READER);
741 	of = smb_llist_head(&node->n_ofile_list);
742 	while (of) {
743 		status = smb_ofile_rename_check(of);
744 
745 		switch (status) {
746 		case NT_STATUS_INVALID_HANDLE:
747 		case NT_STATUS_SUCCESS:
748 			of = smb_llist_next(&node->n_ofile_list, of);
749 			break;
750 		default:
751 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
752 			smb_llist_exit(&node->n_ofile_list);
753 			return (status);
754 		}
755 	}
756 	smb_llist_exit(&node->n_ofile_list);
757 
758 	/*
759 	 * system-wide share check
760 	 */
761 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
762 		return (NT_STATUS_SHARING_VIOLATION);
763 	else
764 		return (NT_STATUS_SUCCESS);
765 }
766 
767 uint32_t
768 smb_node_delete_check(smb_node_t *node)
769 {
770 	smb_ofile_t	*of;
771 	uint32_t	status;
772 
773 	SMB_NODE_VALID(node);
774 
775 	if (node->vp->v_type == VDIR)
776 		return (NT_STATUS_SUCCESS);
777 
778 	/*
779 	 * intra-CIFS check
780 	 */
781 	smb_llist_enter(&node->n_ofile_list, RW_READER);
782 	of = smb_llist_head(&node->n_ofile_list);
783 	while (of) {
784 		status = smb_ofile_delete_check(of);
785 
786 		switch (status) {
787 		case NT_STATUS_INVALID_HANDLE:
788 		case NT_STATUS_SUCCESS:
789 			of = smb_llist_next(&node->n_ofile_list, of);
790 			break;
791 		default:
792 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
793 			smb_llist_exit(&node->n_ofile_list);
794 			return (status);
795 		}
796 	}
797 	smb_llist_exit(&node->n_ofile_list);
798 
799 	/*
800 	 * system-wide share check
801 	 */
802 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
803 		return (NT_STATUS_SHARING_VIOLATION);
804 	else
805 		return (NT_STATUS_SUCCESS);
806 }
807 
808 void
809 smb_node_notify_change(smb_node_t *node)
810 {
811 	SMB_NODE_VALID(node);
812 
813 	if (node->flags & NODE_FLAGS_NOTIFY_CHANGE) {
814 		node->flags |= NODE_FLAGS_CHANGED;
815 		smb_process_node_notify_change_queue(node);
816 	}
817 }
818 
819 static void
820 smb_node_notify_parent(smb_node_t *node)
821 {
822 	SMB_NODE_VALID(node);
823 
824 	if (node->n_dnode != NULL)
825 		smb_node_notify_change(node->n_dnode);
826 }
827 
828 /*
829  * smb_node_start_crit()
830  *
831  * Enter critical region for share reservations.
832  * See comments above smb_fsop_shrlock().
833  */
834 
835 void
836 smb_node_start_crit(smb_node_t *node, krw_t mode)
837 {
838 	rw_enter(&node->n_lock, mode);
839 	nbl_start_crit(node->vp, mode);
840 }
841 
842 /*
843  * smb_node_end_crit()
844  *
845  * Exit critical region for share reservations.
846  */
847 
848 void
849 smb_node_end_crit(smb_node_t *node)
850 {
851 	nbl_end_crit(node->vp);
852 	rw_exit(&node->n_lock);
853 }
854 
855 int
856 smb_node_in_crit(smb_node_t *node)
857 {
858 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
859 }
860 
861 void
862 smb_node_rdlock(smb_node_t *node)
863 {
864 	rw_enter(&node->n_lock, RW_READER);
865 }
866 
867 void
868 smb_node_wrlock(smb_node_t *node)
869 {
870 	rw_enter(&node->n_lock, RW_WRITER);
871 }
872 
873 void
874 smb_node_unlock(smb_node_t *node)
875 {
876 	rw_exit(&node->n_lock);
877 }
878 
879 uint32_t
880 smb_node_get_ofile_count(smb_node_t *node)
881 {
882 	uint32_t	cntr;
883 
884 	SMB_NODE_VALID(node);
885 
886 	smb_llist_enter(&node->n_ofile_list, RW_READER);
887 	cntr = smb_llist_get_count(&node->n_ofile_list);
888 	smb_llist_exit(&node->n_ofile_list);
889 	return (cntr);
890 }
891 
892 void
893 smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
894 {
895 	SMB_NODE_VALID(node);
896 
897 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
898 	smb_llist_insert_tail(&node->n_ofile_list, of);
899 	smb_llist_exit(&node->n_ofile_list);
900 }
901 
902 void
903 smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
904 {
905 	SMB_NODE_VALID(node);
906 
907 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
908 	smb_llist_remove(&node->n_ofile_list, of);
909 	smb_llist_exit(&node->n_ofile_list);
910 }
911 
912 /*
913  * smb_node_inc_open_ofiles
914  */
915 void
916 smb_node_inc_open_ofiles(smb_node_t *node)
917 {
918 	SMB_NODE_VALID(node);
919 
920 	mutex_enter(&node->n_mutex);
921 	node->n_open_count++;
922 	mutex_exit(&node->n_mutex);
923 
924 	smb_node_init_cached_data(node);
925 }
926 
927 /*
928  * smb_node_dec_open_ofiles
929  */
930 void
931 smb_node_dec_open_ofiles(smb_node_t *node)
932 {
933 	SMB_NODE_VALID(node);
934 
935 	mutex_enter(&node->n_mutex);
936 	node->n_open_count--;
937 	mutex_exit(&node->n_mutex);
938 
939 	smb_node_clear_cached_data(node);
940 }
941 
942 uint32_t
943 smb_node_get_open_ofiles(smb_node_t *node)
944 {
945 	uint32_t	cnt;
946 
947 	SMB_NODE_VALID(node);
948 
949 	mutex_enter(&node->n_mutex);
950 	cnt = node->n_open_count;
951 	mutex_exit(&node->n_mutex);
952 	return (cnt);
953 }
954 
955 /*
956  * smb_node_alloc
957  */
958 static smb_node_t *
959 smb_node_alloc(
960     char	*od_name,
961     vnode_t	*vp,
962     smb_llist_t	*bucket,
963     uint32_t	hashkey)
964 {
965 	smb_node_t	*node;
966 
967 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
968 
969 	if (node->n_audit_buf != NULL)
970 		node->n_audit_buf->anb_index = 0;
971 
972 	node->flags = 0;
973 	VN_HOLD(vp);
974 	node->vp = vp;
975 	node->n_refcnt = 1;
976 	node->n_hash_bucket = bucket;
977 	node->n_hashkey = hashkey;
978 	node->n_orig_uid = 0;
979 	node->readonly_creator = NULL;
980 	node->waiting_event = 0;
981 	node->n_open_count = 0;
982 	node->n_dnode = NULL;
983 	node->n_unode = NULL;
984 	node->delete_on_close_cred = NULL;
985 	node->n_delete_on_close_flags = 0;
986 
987 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
988 	if (strcmp(od_name, XATTR_DIR) == 0)
989 		node->flags |= NODE_XATTR_DIR;
990 
991 	node->n_state = SMB_NODE_STATE_AVAILABLE;
992 	node->n_magic = SMB_NODE_MAGIC;
993 	return (node);
994 }
995 
996 /*
997  * smb_node_free
998  */
999 static void
1000 smb_node_free(smb_node_t *node)
1001 {
1002 	SMB_NODE_VALID(node);
1003 
1004 	node->n_magic = 0;
1005 	VERIFY(!list_link_active(&node->n_lnd));
1006 	VERIFY(node->n_lock_list.ll_count == 0);
1007 	VERIFY(node->n_ofile_list.ll_count == 0);
1008 	VERIFY(node->n_oplock.ol_xthread == NULL);
1009 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
1010 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
1011 	VN_RELE(node->vp);
1012 	kmem_cache_free(smb_node_cache, node);
1013 }
1014 
1015 /*
1016  * smb_node_constructor
1017  */
1018 static int
1019 smb_node_constructor(void *buf, void *un, int kmflags)
1020 {
1021 	_NOTE(ARGUNUSED(kmflags, un))
1022 
1023 	smb_node_t	*node = (smb_node_t *)buf;
1024 
1025 	bzero(node, sizeof (smb_node_t));
1026 
1027 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1028 	    offsetof(smb_ofile_t, f_nnd));
1029 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
1030 	    offsetof(smb_lock_t, l_lnd));
1031 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
1032 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
1033 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
1034 	smb_node_create_audit_buf(node, kmflags);
1035 	return (0);
1036 }
1037 
1038 /*
1039  * smb_node_destructor
1040  */
1041 static void
1042 smb_node_destructor(void *buf, void *un)
1043 {
1044 	_NOTE(ARGUNUSED(un))
1045 
1046 	smb_node_t	*node = (smb_node_t *)buf;
1047 
1048 	smb_node_destroy_audit_buf(node);
1049 	mutex_destroy(&node->n_mutex);
1050 	rw_destroy(&node->n_lock);
1051 	cv_destroy(&node->n_oplock.ol_cv);
1052 	smb_llist_destructor(&node->n_lock_list);
1053 	smb_llist_destructor(&node->n_ofile_list);
1054 }
1055 
1056 /*
1057  * smb_node_create_audit_buf
1058  */
1059 static void
1060 smb_node_create_audit_buf(smb_node_t *node, int kmflags)
1061 {
1062 	smb_audit_buf_node_t	*abn;
1063 
1064 	if (smb_audit_flags & SMB_AUDIT_NODE) {
1065 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
1066 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
1067 		node->n_audit_buf = abn;
1068 	}
1069 }
1070 
1071 /*
1072  * smb_node_destroy_audit_buf
1073  */
1074 static void
1075 smb_node_destroy_audit_buf(smb_node_t *node)
1076 {
1077 	if (node->n_audit_buf != NULL) {
1078 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
1079 		node->n_audit_buf = NULL;
1080 	}
1081 }
1082 
1083 /*
1084  * smb_node_audit
1085  *
1086  * This function saves the calling stack in the audit buffer of the node passed
1087  * in.
1088  */
1089 static void
1090 smb_node_audit(smb_node_t *node)
1091 {
1092 	smb_audit_buf_node_t	*abn;
1093 	smb_audit_record_node_t	*anr;
1094 
1095 	if (node->n_audit_buf) {
1096 		abn = node->n_audit_buf;
1097 		anr = abn->anb_records;
1098 		anr += abn->anb_index;
1099 		abn->anb_index++;
1100 		abn->anb_index &= abn->anb_max_index;
1101 		anr->anr_refcnt = node->n_refcnt;
1102 		anr->anr_depth = getpcstack(anr->anr_stack,
1103 		    SMB_AUDIT_STACK_DEPTH);
1104 	}
1105 }
1106 
1107 static smb_llist_t *
1108 smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
1109 {
1110 	uint32_t	hashkey;
1111 
1112 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
1113 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1114 	*phashkey = hashkey;
1115 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1116 }
1117 
1118 boolean_t
1119 smb_node_is_dir(smb_node_t *node)
1120 {
1121 	SMB_NODE_VALID(node);
1122 	return (node->vp->v_type == VDIR);
1123 }
1124 
1125 boolean_t
1126 smb_node_is_link(smb_node_t *node)
1127 {
1128 	SMB_NODE_VALID(node);
1129 	return (node->vp->v_type == VLNK);
1130 }
1131 
1132 /*
1133  * smb_node_file_is_readonly
1134  *
1135  * Checks if the file (which node represents) is marked readonly
1136  * in the filesystem. No account is taken of any pending readonly
1137  * in the node, which must be handled by the callers.
1138  * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY)
1139  */
1140 boolean_t
1141 smb_node_file_is_readonly(smb_node_t *node)
1142 {
1143 	smb_attr_t attr;
1144 
1145 	if (node == NULL)
1146 		return (B_FALSE);
1147 
1148 	bzero(&attr, sizeof (smb_attr_t));
1149 	attr.sa_mask = SMB_AT_DOSATTR;
1150 	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
1151 	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
1152 }
1153 
1154 /*
1155  * smb_node_setattr
1156  *
1157  * The sr may be NULL, for example when closing an ofile.
1158  * The ofile may be NULL, for example when a client request
1159  * specifies the file by pathname.
1160  *
1161  * Timestamps
1162  * When attributes are set on an ofile, any pending timestamps
1163  * from a write request on the ofile are implicitly set to "now".
1164  * For compatibility with windows the following timestamps are
1165  * also implicitly set to now:
1166  * - if any attribute is being explicitly set, set ctime to now
1167  * - if file size is being explicitly set, set atime & ctime to now
1168  *
1169  * Any timestamp that is being explicitly set, or has previously
1170  * been explicitly set on the ofile, is excluded from implicit
1171  * (now) setting.
1172  *
1173  * Updates the node's cached timestamp values.
1174  * Updates the ofile's explicit times flag.
1175  *
1176  * File allocation size
1177  * When the file allocation size is set it is first rounded up
1178  * to block size. If the file size is smaller than the allocation
1179  * size the file is truncated by setting the filesize to allocsz.
1180  * If there are open ofiles, the allocsz is cached on the node.
1181  *
1182  * Updates the node's cached allocsz value.
1183  *
1184  * Returns: errno
1185  */
1186 int
1187 smb_node_setattr(smb_request_t *sr, smb_node_t *node,
1188     cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
1189 {
1190 	int rc;
1191 	uint32_t pending_times = 0;
1192 	uint32_t explicit_times = 0;
1193 	timestruc_t now;
1194 	smb_attr_t tmp_attr;
1195 
1196 	ASSERT(attr);
1197 	SMB_NODE_VALID(node);
1198 
1199 	/* set attributes specified in attr */
1200 	if (attr->sa_mask != 0) {
1201 		/* if allocation size is < file size, truncate the file */
1202 		if (attr->sa_mask & SMB_AT_ALLOCSZ) {
1203 			attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
1204 
1205 			bzero(&tmp_attr, sizeof (smb_attr_t));
1206 			tmp_attr.sa_mask = SMB_AT_SIZE;
1207 			(void) smb_fsop_getattr(NULL, kcred, node, &tmp_attr);
1208 
1209 			if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) {
1210 				attr->sa_vattr.va_size = attr->sa_allocsz;
1211 				attr->sa_mask |= SMB_AT_SIZE;
1212 			}
1213 		}
1214 
1215 		rc = smb_fsop_setattr(sr, cr, node, attr);
1216 		if (rc != 0)
1217 			return (rc);
1218 
1219 		smb_node_set_cached_allocsz(node, attr);
1220 		smb_node_set_cached_timestamps(node, attr);
1221 		if (of) {
1222 			smb_ofile_set_explicit_times(of,
1223 			    (attr->sa_mask & SMB_AT_TIMES));
1224 		}
1225 	}
1226 
1227 	/*
1228 	 * Determine which timestamps to implicitly set to "now".
1229 	 * Don't overwrite timestamps already explicitly set.
1230 	 */
1231 	bzero(&tmp_attr, sizeof (smb_attr_t));
1232 	gethrestime(&now);
1233 	tmp_attr.sa_vattr.va_atime = now;
1234 	tmp_attr.sa_vattr.va_mtime = now;
1235 	tmp_attr.sa_vattr.va_ctime = now;
1236 
1237 	/* pending write timestamps */
1238 	if (of) {
1239 		if (smb_ofile_write_time_pending(of)) {
1240 			pending_times |=
1241 			    (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
1242 		}
1243 		explicit_times |= (smb_ofile_explicit_times(of));
1244 	}
1245 	explicit_times |= (attr->sa_mask & SMB_AT_TIMES);
1246 	pending_times &= ~explicit_times;
1247 
1248 	if (pending_times) {
1249 		tmp_attr.sa_mask = pending_times;
1250 		(void) smb_fsop_setattr(NULL, kcred, node, &tmp_attr);
1251 	}
1252 
1253 	/* additional timestamps to update in cache */
1254 	if (attr->sa_mask)
1255 		tmp_attr.sa_mask |= SMB_AT_CTIME;
1256 	if (attr->sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ))
1257 		tmp_attr.sa_mask |= SMB_AT_MTIME;
1258 	tmp_attr.sa_mask &= ~explicit_times;
1259 
1260 	if (tmp_attr.sa_mask)
1261 		smb_node_set_cached_timestamps(node, &tmp_attr);
1262 
1263 	if (tmp_attr.sa_mask & SMB_AT_MTIME || explicit_times & SMB_AT_MTIME)
1264 		smb_node_notify_parent(node);
1265 
1266 	return (0);
1267 }
1268 
1269 /*
1270  * smb_node_getattr
1271  *
1272  * Get attributes from the file system and apply any smb-specific
1273  * overrides for size, dos attributes and timestamps
1274  *
1275  * node->readonly_creator reflects whether a readonly set is pending
1276  * from a readonly create. The readonly attribute should be visible to
1277  * all clients even though the readonly creator fid is immune to the
1278  * readonly bit until close.
1279  *
1280  * Returns: errno
1281  */
1282 int
1283 smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
1284 {
1285 	int rc;
1286 
1287 	SMB_NODE_VALID(node);
1288 
1289 	bzero(attr, sizeof (smb_attr_t));
1290 	attr->sa_mask = SMB_AT_ALL;
1291 	rc = smb_fsop_getattr(sr, kcred, node, attr);
1292 	if (rc != 0)
1293 		return (rc);
1294 
1295 	mutex_enter(&node->n_mutex);
1296 
1297 	if (node->vp->v_type == VDIR) {
1298 		attr->sa_vattr.va_size = 0;
1299 		attr->sa_allocsz = 0;
1300 		attr->sa_vattr.va_nlink = 1;
1301 	}
1302 
1303 	if (node->readonly_creator)
1304 		attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
1305 	if (attr->sa_dosattr == 0)
1306 		attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
1307 
1308 
1309 	mutex_exit(&node->n_mutex);
1310 
1311 	smb_node_get_cached_allocsz(node, attr);
1312 	smb_node_get_cached_timestamps(node, attr);
1313 
1314 	return (0);
1315 }
1316 
1317 /*
1318  * smb_node_init_cached_data
1319  */
1320 static void
1321 smb_node_init_cached_data(smb_node_t *node)
1322 {
1323 	smb_attr_t attr;
1324 
1325 	bzero(&attr, sizeof (smb_attr_t));
1326 	attr.sa_mask = SMB_AT_ALL;
1327 	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
1328 
1329 	smb_node_init_cached_allocsz(node, &attr);
1330 	smb_node_init_cached_timestamps(node, &attr);
1331 }
1332 
1333 /*
1334  * smb_node_clear_cached_data
1335  */
1336 static void
1337 smb_node_clear_cached_data(smb_node_t *node)
1338 {
1339 	smb_node_clear_cached_allocsz(node);
1340 	smb_node_clear_cached_timestamps(node);
1341 }
1342 
1343 /*
1344  * File allocation size (allocsz) caching
1345  *
1346  * When there are open ofiles on the node, the file allocsz is cached.
1347  * The cached value (n_allocsz) is initialized when the first ofile is
1348  * opened and cleared when the last is closed. Allocsz calculated from
1349  * the filesize (rounded up to block size).
1350  * When the allocation size is queried, if the cached allocsz is less
1351  * than the filesize, it is recalculated from the filesize.
1352  */
1353 
1354 /*
1355  * smb_node_init_cached_allocsz
1356  *
1357  * If there are open ofiles, cache the allocsz in the node.
1358  * Calculate the allocsz from the filesizes.
1359  * block size).
1360  */
1361 static void
1362 smb_node_init_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
1363 {
1364 	mutex_enter(&node->n_mutex);
1365 	if (node->n_open_count == 1)
1366 		node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
1367 	mutex_exit(&node->n_mutex);
1368 }
1369 
1370 /*
1371  * smb_node_clear_cached_allocsz
1372  */
1373 static void
1374 smb_node_clear_cached_allocsz(smb_node_t *node)
1375 {
1376 	mutex_enter(&node->n_mutex);
1377 	if (node->n_open_count == 0)
1378 		node->n_allocsz = 0;
1379 	mutex_exit(&node->n_mutex);
1380 }
1381 
1382 /*
1383  * smb_node_get_cached_allocsz
1384  *
1385  * If there is no cached allocsz (no open files), calculate
1386  * allocsz from the filesize.
1387  * If the allocsz is cached but is smaller than the filesize
1388  * recalculate the cached allocsz from the filesize.
1389  *
1390  * Return allocs in attr->sa_allocsz.
1391  */
1392 static void
1393 smb_node_get_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
1394 {
1395 	if (node->vp->v_type == VDIR)
1396 		return;
1397 
1398 	mutex_enter(&node->n_mutex);
1399 	if (node->n_open_count == 0) {
1400 		attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
1401 	} else {
1402 		if (node->n_allocsz < attr->sa_vattr.va_size)
1403 			node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
1404 		attr->sa_allocsz = node->n_allocsz;
1405 	}
1406 	mutex_exit(&node->n_mutex);
1407 }
1408 
1409 /*
1410  * smb_node_set_cached_allocsz
1411  *
1412  * attr->sa_allocsz has already been rounded to block size by
1413  * the caller.
1414  */
1415 static void
1416 smb_node_set_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
1417 {
1418 	mutex_enter(&node->n_mutex);
1419 	if (attr->sa_mask & SMB_AT_ALLOCSZ) {
1420 		if (node->n_open_count > 0)
1421 			node->n_allocsz = attr->sa_allocsz;
1422 	}
1423 	mutex_exit(&node->n_mutex);
1424 }
1425 
1426 
1427 /*
1428  * Timestamp caching
1429  *
1430  * Solaris file systems handle timestamps different from NTFS. For
1431  * example when file data is written NTFS doesn't update the timestamps
1432  * until the file is closed, and then only if they haven't been explicity
1433  * set via a set attribute request. In order to provide a more similar
1434  * view of an open file's timestamps, we cache the timestamps in the
1435  * node and manipulate them in a manner more consistent with windows.
1436  * (See handling of explicit times and pending timestamps from a write
1437  * request in smb_node_getattr and smb_node_setattr above.)
1438  * Timestamps remain cached while there are open ofiles for the node.
1439  * This includes open ofiles for named streams.
1440  * n_open_ofiles cannot be used as this doesn't include ofiles opened
1441  * for the node's named streams. Thus n_timestamps contains a count
1442  * of open ofiles (t_open_ofiles), including named streams' ofiles,
1443  * to be used to control timestamp caching.
1444  *
1445  * If a node represents a named stream the associated unnamed streams
1446  * cached timestamps are used instead.
1447  */
1448 
1449 /*
1450  * smb_node_init_cached_timestamps
1451  *
1452  * Increment count of open ofiles which are using the cached timestamps.
1453  * If this is the first open ofile, init the cached timestamps from the
1454  * file system values.
1455  */
1456 static void
1457 smb_node_init_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
1458 {
1459 	smb_node_t *unode;
1460 
1461 	if ((unode = SMB_IS_STREAM(node)) != NULL)
1462 		node = unode;
1463 
1464 	mutex_enter(&node->n_mutex);
1465 	++(node->n_timestamps.t_open_ofiles);
1466 	if (node->n_timestamps.t_open_ofiles == 1) {
1467 		node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
1468 		node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
1469 		node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
1470 		node->n_timestamps.t_crtime = attr->sa_crtime;
1471 		node->n_timestamps.t_cached = B_TRUE;
1472 	}
1473 	mutex_exit(&node->n_mutex);
1474 }
1475 
1476 /*
1477  * smb_node_clear_cached_timestamps
1478  *
1479  * Decrement count of open ofiles using the cached timestamps.
1480  * If the decremented count is zero, clear the cached timestamps.
1481  */
1482 static void
1483 smb_node_clear_cached_timestamps(smb_node_t *node)
1484 {
1485 	smb_node_t *unode;
1486 
1487 	if ((unode = SMB_IS_STREAM(node)) != NULL)
1488 		node = unode;
1489 
1490 	mutex_enter(&node->n_mutex);
1491 	ASSERT(node->n_timestamps.t_open_ofiles > 0);
1492 	--(node->n_timestamps.t_open_ofiles);
1493 	if (node->n_timestamps.t_open_ofiles == 0)
1494 		bzero(&node->n_timestamps, sizeof (smb_times_t));
1495 	mutex_exit(&node->n_mutex);
1496 }
1497 
1498 /*
1499  * smb_node_get_cached_timestamps
1500  *
1501  * Overwrite timestamps in attr with those cached in node.
1502  */
1503 static void
1504 smb_node_get_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
1505 {
1506 	smb_node_t *unode;
1507 
1508 	if ((unode = SMB_IS_STREAM(node)) != NULL)
1509 		node = unode;
1510 
1511 	mutex_enter(&node->n_mutex);
1512 	if (node->n_timestamps.t_cached) {
1513 		attr->sa_vattr.va_mtime = node->n_timestamps.t_mtime;
1514 		attr->sa_vattr.va_atime = node->n_timestamps.t_atime;
1515 		attr->sa_vattr.va_ctime = node->n_timestamps.t_ctime;
1516 		attr->sa_crtime = node->n_timestamps.t_crtime;
1517 	}
1518 	mutex_exit(&node->n_mutex);
1519 }
1520 
1521 /*
1522  * smb_node_set_cached_timestamps
1523  *
1524  * Update the node's cached timestamps with values from attr.
1525  */
1526 static void
1527 smb_node_set_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
1528 {
1529 	smb_node_t *unode;
1530 
1531 	if ((unode = SMB_IS_STREAM(node)) != NULL)
1532 		node = unode;
1533 
1534 	mutex_enter(&node->n_mutex);
1535 	if (node->n_timestamps.t_cached) {
1536 		if (attr->sa_mask & SMB_AT_MTIME)
1537 			node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
1538 		if (attr->sa_mask & SMB_AT_ATIME)
1539 			node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
1540 		if (attr->sa_mask & SMB_AT_CTIME)
1541 			node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
1542 		if (attr->sa_mask & SMB_AT_CRTIME)
1543 			node->n_timestamps.t_crtime = attr->sa_crtime;
1544 	}
1545 	mutex_exit(&node->n_mutex);
1546 }
1547