xref: /titanic_50/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 45179f4335d029f1129eb7283f8087740f0395f1)
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_attr_t *,
144     smb_llist_t *bucket, uint32_t hashkey);
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 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
151     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
152     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
153     ASSERT((_dir_)->dir_snode != (_node_));
154 
155 static kmem_cache_t	*smb_node_cache = NULL;
156 static boolean_t	smb_node_initialized = B_FALSE;
157 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
158 
159 /*
160  * smb_node_init
161  *
162  * Initialization of the SMB node layer.
163  *
164  * This function is not multi-thread safe. The caller must make sure only one
165  * thread makes the call.
166  */
167 int
168 smb_node_init(void)
169 {
170 	int	i;
171 
172 	if (smb_node_initialized)
173 		return (0);
174 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
175 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
176 	    NULL, NULL, NULL, 0);
177 
178 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
179 		smb_llist_constructor(&smb_node_hash_table[i],
180 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
181 	}
182 	smb_node_initialized = B_TRUE;
183 	return (0);
184 }
185 
186 /*
187  * smb_node_fini
188  *
189  * This function is not multi-thread safe. The caller must make sure only one
190  * thread makes the call.
191  */
192 void
193 smb_node_fini(void)
194 {
195 	int	i;
196 
197 	if (!smb_node_initialized)
198 		return;
199 
200 #ifdef DEBUG
201 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
202 		smb_node_t	*node;
203 
204 		/*
205 		 * The following sequence is just intended for sanity check.
206 		 * This will have to be modified when the code goes into
207 		 * production.
208 		 *
209 		 * The SMB node hash table should be emtpy at this point. If the
210 		 * hash table is not empty a panic will be triggered.
211 		 *
212 		 * The reason why SMB nodes are still remaining in the hash
213 		 * table is problably due to a mismatch between calls to
214 		 * smb_node_lookup() and smb_node_release(). You must track that
215 		 * down.
216 		 */
217 		node = smb_llist_head(&smb_node_hash_table[i]);
218 		ASSERT(node == NULL);
219 	}
220 #endif
221 
222 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
223 		smb_llist_destructor(&smb_node_hash_table[i]);
224 	}
225 	kmem_cache_destroy(smb_node_cache);
226 	smb_node_cache = NULL;
227 	smb_node_initialized = B_FALSE;
228 }
229 
230 /*
231  * smb_node_lookup()
232  *
233  * NOTE: This routine should only be called by the file system interface layer,
234  * and not by SMB.
235  *
236  * smb_node_lookup() is called upon successful lookup, mkdir, and create
237  * (for both non-streams and streams).  In each of these cases, a held vnode is
238  * passed into this routine.  If a new smb_node is created it will take its
239  * own hold on the vnode.  The caller's hold therefore still belongs to, and
240  * should be released by, the caller.
241  *
242  * A reference is taken on the smb_node whether found in the hash table
243  * or newly created.
244  *
245  * If an smb_node needs to be created, a reference is also taken on the
246  * dir_snode (if passed in).
247  *
248  * See smb_node_release() for details on the release of these references.
249  */
250 
251 /*ARGSUSED*/
252 smb_node_t *
253 smb_node_lookup(
254     struct smb_request	*sr,
255     struct open_param	*op,
256     cred_t		*cred,
257     vnode_t		*vp,
258     char		*od_name,
259     smb_node_t		*dir_snode,
260     smb_node_t		*unnamed_node,
261     smb_attr_t		*attr)
262 {
263 	smb_llist_t		*node_hdr;
264 	smb_node_t		*node;
265 	uint32_t		hashkey = 0;
266 	fsid_t			fsid;
267 	int			error;
268 	krw_t			lock_mode;
269 	vnode_t			*unnamed_vp = NULL;
270 
271 	/*
272 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
273 	 * because the node may not yet exist.  We also do not want to call
274 	 * it with the list lock held.
275 	 */
276 
277 	if (unnamed_node)
278 		unnamed_vp = unnamed_node->vp;
279 
280 	/*
281 	 * This getattr is performed on behalf of the server
282 	 * that's why kcred is used not the user's cred
283 	 */
284 	attr->sa_mask = SMB_AT_ALL;
285 	error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred);
286 	if (error)
287 		return (NULL);
288 
289 	if (sr && sr->tid_tree) {
290 		/*
291 		 * The fsid for a file is that of the tree, even
292 		 * if the file resides in a different mountpoint
293 		 * under the share.
294 		 */
295 		fsid = SMB_TREE_FSID(sr->tid_tree);
296 	} else {
297 		/*
298 		 * This should be getting executed only for the
299 		 * tree root smb_node.
300 		 */
301 		fsid = vp->v_vfsp->vfs_fsid;
302 	}
303 
304 	node_hdr = smb_node_get_hash(&fsid, attr, &hashkey);
305 	lock_mode = RW_READER;
306 
307 	smb_llist_enter(node_hdr, lock_mode);
308 	for (;;) {
309 		node = list_head(&node_hdr->ll_list);
310 		while (node) {
311 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
312 			ASSERT(node->n_hash_bucket == node_hdr);
313 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
314 				mutex_enter(&node->n_mutex);
315 				DTRACE_PROBE1(smb_node_lookup_hit,
316 				    smb_node_t *, node);
317 				switch (node->n_state) {
318 				case SMB_NODE_STATE_OPLOCK_GRANTED:
319 				case SMB_NODE_STATE_OPLOCK_BREAKING:
320 				case SMB_NODE_STATE_AVAILABLE:
321 					/* The node was found. */
322 					node->n_refcnt++;
323 					if ((node->dir_snode == NULL) &&
324 					    (dir_snode != NULL) &&
325 					    (strcmp(od_name, "..") != 0) &&
326 					    (strcmp(od_name, ".") != 0)) {
327 						VALIDATE_DIR_NODE(dir_snode,
328 						    node);
329 						node->dir_snode = dir_snode;
330 						smb_node_ref(dir_snode);
331 					}
332 					node->attr = *attr;
333 					node->n_size = attr->sa_vattr.va_size;
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, attr, 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 (dir_snode) {
374 		smb_node_ref(dir_snode);
375 		node->dir_snode = dir_snode;
376 		ASSERT(dir_snode->dir_snode != node);
377 		ASSERT((dir_snode->vp->v_xattrdir) ||
378 		    (dir_snode->vp->v_type == VDIR));
379 	}
380 
381 	if (unnamed_node) {
382 		smb_node_ref(unnamed_node);
383 		node->unnamed_stream_node = unnamed_node;
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, smb_attr_t *ret_attr)
404 {
405 	smb_node_t	*xattrdir_node;
406 	smb_node_t	*snode;
407 	smb_attr_t	tmp_attr;
408 
409 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
410 	    fnode, NULL, &tmp_attr);
411 
412 	if (xattrdir_node == NULL)
413 		return (NULL);
414 
415 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
416 	    fnode, ret_attr);
417 
418 	(void) smb_node_release(xattrdir_node);
419 	return (snode);
420 }
421 
422 
423 /*
424  * This function should be called whenever a reference is needed on an
425  * smb_node pointer.  The copy of an smb_node pointer from one non-local
426  * data structure to another requires a reference to be taken on the smb_node
427  * (unless the usage is localized).  Each data structure deallocation routine
428  * will call smb_node_release() on its smb_node pointers.
429  *
430  * In general, an smb_node pointer residing in a structure should never be
431  * stale.  A node pointer may be NULL, however, and care should be taken
432  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
433  * Care also needs to be taken with respect to racing deallocations of a
434  * structure.
435  */
436 void
437 smb_node_ref(smb_node_t *node)
438 {
439 	SMB_NODE_VALID(node);
440 
441 	mutex_enter(&node->n_mutex);
442 	switch (node->n_state) {
443 	case SMB_NODE_STATE_AVAILABLE:
444 	case SMB_NODE_STATE_OPLOCK_GRANTED:
445 	case SMB_NODE_STATE_OPLOCK_BREAKING:
446 		node->n_refcnt++;
447 		ASSERT(node->n_refcnt);
448 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
449 		smb_node_audit(node);
450 		break;
451 	default:
452 		SMB_PANIC();
453 	}
454 	mutex_exit(&node->n_mutex);
455 }
456 
457 /*
458  * smb_node_lookup() takes a hold on an smb_node, whether found in the
459  * hash table or newly created.  This hold is expected to be released
460  * in the following manner.
461  *
462  * smb_node_lookup() takes an address of an smb_node pointer.  This should
463  * be getting passed down via a lookup (whether path name or component), mkdir,
464  * create.  If the original smb_node pointer resides in a data structure, then
465  * the deallocation routine for the data structure is responsible for calling
466  * smb_node_release() on the smb_node pointer.  Alternatively,
467  * smb_node_release() can be called as soon as the smb_node pointer is no longer
468  * needed.  In this case, callers are responsible for setting an embedded
469  * pointer to NULL if it is known that the last reference is being released.
470  *
471  * If the passed-in address of the smb_node pointer belongs to a local variable,
472  * then the caller with the local variable should call smb_node_release()
473  * directly.
474  *
475  * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
476  * as smb_node_lookup() takes a hold on dir_snode.
477  */
478 void
479 smb_node_release(smb_node_t *node)
480 {
481 	SMB_NODE_VALID(node);
482 
483 	mutex_enter(&node->n_mutex);
484 	ASSERT(node->n_refcnt);
485 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
486 	if (--node->n_refcnt == 0) {
487 		switch (node->n_state) {
488 
489 		case SMB_NODE_STATE_AVAILABLE:
490 			node->n_state = SMB_NODE_STATE_DESTROYING;
491 			mutex_exit(&node->n_mutex);
492 
493 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
494 			smb_llist_remove(node->n_hash_bucket, node);
495 			smb_llist_exit(node->n_hash_bucket);
496 
497 			/*
498 			 * Check if the file was deleted
499 			 */
500 			smb_node_delete_on_close(node);
501 
502 			if (node->dir_snode) {
503 				ASSERT(node->dir_snode->n_magic ==
504 				    SMB_NODE_MAGIC);
505 				smb_node_release(node->dir_snode);
506 			}
507 
508 			if (node->unnamed_stream_node) {
509 				ASSERT(node->unnamed_stream_node->n_magic ==
510 				    SMB_NODE_MAGIC);
511 				smb_node_release(node->unnamed_stream_node);
512 			}
513 
514 			smb_node_free(node);
515 			return;
516 
517 		default:
518 			SMB_PANIC();
519 		}
520 	}
521 	smb_node_audit(node);
522 	mutex_exit(&node->n_mutex);
523 }
524 
525 static void
526 smb_node_delete_on_close(smb_node_t *node)
527 {
528 	smb_node_t	*d_snode;
529 	int		rc = 0;
530 	uint32_t	flags = 0;
531 
532 	d_snode = node->dir_snode;
533 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
534 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
535 		flags = node->n_delete_on_close_flags;
536 		ASSERT(node->od_name != NULL);
537 
538 		if (node->attr.sa_vattr.va_type == VDIR)
539 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
540 			    d_snode, node->od_name, flags);
541 		else
542 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
543 			    d_snode, node->od_name, flags);
544 		smb_cred_rele(node->delete_on_close_cred);
545 	}
546 	if (rc != 0)
547 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
548 		    node->od_name, rc);
549 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
550 }
551 
552 /*
553  * smb_node_rename()
554  *
555  */
556 void
557 smb_node_rename(
558     smb_node_t	*from_dnode,
559     smb_node_t	*ret_node,
560     smb_node_t	*to_dnode,
561     char	*to_name)
562 {
563 	SMB_NODE_VALID(from_dnode);
564 	SMB_NODE_VALID(to_dnode);
565 	SMB_NODE_VALID(ret_node);
566 
567 	smb_node_ref(to_dnode);
568 	mutex_enter(&ret_node->n_mutex);
569 	switch (ret_node->n_state) {
570 	case SMB_NODE_STATE_AVAILABLE:
571 	case SMB_NODE_STATE_OPLOCK_GRANTED:
572 	case SMB_NODE_STATE_OPLOCK_BREAKING:
573 		ret_node->dir_snode = to_dnode;
574 		mutex_exit(&ret_node->n_mutex);
575 		ASSERT(to_dnode->dir_snode != ret_node);
576 		ASSERT((to_dnode->vp->v_xattrdir) ||
577 		    (to_dnode->vp->v_type == VDIR));
578 		smb_node_release(from_dnode);
579 		(void) strcpy(ret_node->od_name, to_name);
580 		/*
581 		 * XXX Need to update attributes?
582 		 */
583 		break;
584 	default:
585 		SMB_PANIC();
586 	}
587 }
588 
589 int
590 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
591 {
592 	smb_attr_t	va;
593 	int		error;
594 	uint32_t	hashkey;
595 	smb_llist_t	*node_hdr;
596 	smb_node_t	*node;
597 
598 	va.sa_mask = SMB_AT_ALL;
599 	error = smb_vop_getattr(vp, NULL, &va, 0, kcred);
600 	if (error) {
601 		VN_RELE(vp);
602 		return (error);
603 	}
604 
605 	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey);
606 
607 	node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey);
608 
609 	sv->si_root_smb_node = node;
610 	smb_node_audit(node);
611 	smb_llist_enter(node_hdr, RW_WRITER);
612 	smb_llist_insert_head(node_hdr, node);
613 	smb_llist_exit(node_hdr);
614 	*root = node;
615 	return (0);
616 }
617 
618 /*
619  * smb_node_get_size
620  */
621 u_offset_t
622 smb_node_get_size(smb_node_t *node, smb_attr_t *attr)
623 {
624 	u_offset_t size;
625 
626 	if (attr->sa_vattr.va_type == VDIR)
627 		return (0);
628 
629 	mutex_enter(&node->n_mutex);
630 	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
631 		size = node->n_size;
632 	else
633 		size = attr->sa_vattr.va_size;
634 	mutex_exit(&node->n_mutex);
635 	return (size);
636 }
637 
638 static int
639 timeval_cmp(timestruc_t *a, timestruc_t *b)
640 {
641 	if (a->tv_sec < b->tv_sec)
642 		return (-1);
643 	if (a->tv_sec > b->tv_sec)
644 		return (1);
645 	/* Seconds are equal compare tv_nsec */
646 	if (a->tv_nsec < b->tv_nsec)
647 		return (-1);
648 	return (a->tv_nsec > b->tv_nsec);
649 }
650 
651 /*
652  * smb_node_set_time
653  *
654  * This function will update the time stored in the node and
655  * set the appropriate flags. If there is nothing to update,
656  * the function will return without any updates.  The update
657  * is only in the node level and the attribute in the file system
658  * will be updated when client close the file.
659  */
660 void
661 smb_node_set_time(
662     smb_node_t	*node,
663     timestruc_t	*crtime,
664     timestruc_t	*mtime,
665     timestruc_t	*atime,
666     timestruc_t	*ctime,
667     uint_t	what)
668 {
669 	if (what == 0)
670 		return;
671 
672 	if ((what & SMB_AT_CRTIME && crtime == 0) ||
673 	    (what & SMB_AT_MTIME && mtime == 0) ||
674 	    (what & SMB_AT_ATIME && atime == 0) ||
675 	    (what & SMB_AT_CTIME && ctime == 0))
676 		return;
677 
678 	mutex_enter(&node->n_mutex);
679 
680 	if ((what & SMB_AT_CRTIME) &&
681 	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
682 	    crtime) != 0) {
683 		node->what |= SMB_AT_CRTIME;
684 		node->attr.sa_crtime = *((timestruc_t *)crtime);
685 	}
686 
687 	if ((what & SMB_AT_MTIME) &&
688 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
689 	    mtime) != 0) {
690 		node->what |= SMB_AT_MTIME;
691 		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
692 	}
693 
694 	if ((what & SMB_AT_ATIME) &&
695 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
696 	    atime) != 0) {
697 			node->what |= SMB_AT_ATIME;
698 			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
699 	}
700 
701 	/*
702 	 * The ctime handling is trickier. It has three scenarios.
703 	 * 1. Only ctime need to be set and it is the same as the ctime
704 	 *    stored in the node. (update not necessary)
705 	 * 2. The ctime is the same as the ctime stored in the node but
706 	 *    is not the only time need to be set. (update required)
707 	 * 3. The ctime need to be set and is not the same as the ctime
708 	 *    stored in the node. (update required)
709 	 * Unlike other time setting, the ctime needs to be set even when
710 	 * it is the same as the ctime in the node if there are other time
711 	 * needs to be set (#2). This will ensure the ctime not being
712 	 * updated when other times are being updated in the file system.
713 	 *
714 	 * Retained file rules:
715 	 *
716 	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
717 	 *    request will be rejected by filesystem
718 	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
719 	 *    any request for changing ctime on these files should have
720 	 *    been already rejected
721 	 */
722 	node->what |= SMB_AT_CTIME;
723 	if (what & SMB_AT_CTIME) {
724 		if ((what == SMB_AT_CTIME) &&
725 		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
726 		    ctime) == 0) {
727 			node->what &= ~SMB_AT_CTIME;
728 		} else {
729 			gethrestime(&node->attr.sa_vattr.va_ctime);
730 		}
731 	} else {
732 		gethrestime(&node->attr.sa_vattr.va_ctime);
733 	}
734 	mutex_exit(&node->n_mutex);
735 }
736 
737 
738 timestruc_t *
739 smb_node_get_crtime(smb_node_t *node)
740 {
741 	return ((timestruc_t *)&node->attr.sa_crtime);
742 }
743 
744 timestruc_t *
745 smb_node_get_atime(smb_node_t *node)
746 {
747 	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
748 }
749 
750 timestruc_t *
751 smb_node_get_ctime(smb_node_t *node)
752 {
753 	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
754 }
755 
756 timestruc_t *
757 smb_node_get_mtime(smb_node_t *node)
758 {
759 	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
760 }
761 
762 /*
763  * smb_node_set_dosattr
764  *
765  * Parse the specified DOS attributes and, if they have been modified,
766  * update the node cache. This call should be followed by a
767  * smb_sync_fsattr() call to write the attribute changes to filesystem.
768  */
769 void
770 smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr)
771 {
772 	uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE |
773 	    FILE_ATTRIBUTE_READONLY |
774 	    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
775 
776 	mutex_enter(&node->n_mutex);
777 	if (node->attr.sa_dosattr != mode) {
778 		node->attr.sa_dosattr = mode;
779 		node->what |= SMB_AT_DOSATTR;
780 	}
781 	mutex_exit(&node->n_mutex);
782 }
783 
784 /*
785  * smb_node_get_dosattr()
786  *
787  * This function is used to provide clients with information as to whether
788  * the readonly bit is set.  Hence both the node attribute cache (which
789  * reflects the on-disk attributes) and node->readonly_creator (which
790  * reflects whether a readonly set is pending from a readonly create) are
791  * checked.  In the latter case, the readonly attribute should be visible to
792  * all clients even though the readonly creator fid is immune to the readonly
793  * bit until close.
794  */
795 
796 uint32_t
797 smb_node_get_dosattr(smb_node_t *node)
798 {
799 	uint32_t dosattr = node->attr.sa_dosattr;
800 
801 	if (node->readonly_creator)
802 		dosattr |= FILE_ATTRIBUTE_READONLY;
803 
804 	if (!dosattr)
805 		dosattr = FILE_ATTRIBUTE_NORMAL;
806 
807 	return (dosattr);
808 }
809 
810 /*
811  * When DeleteOnClose is set on an smb_node, the common open code will
812  * reject subsequent open requests for the file. Observation of Windows
813  * 2000 indicates that subsequent opens should be allowed (assuming
814  * there would be no sharing violation) until the file is closed using
815  * the fid on which the DeleteOnClose was requested.
816  *
817  * If there are multiple opens with delete-on-close create options,
818  * whichever the first file handle is closed will trigger the node to be
819  * marked as delete-on-close. The credentials of that ofile will be used
820  * as the delete-on-close credentials of the node.
821  */
822 int
823 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
824 {
825 	int	rc = -1;
826 
827 	mutex_enter(&node->n_mutex);
828 	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
829 	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
830 		crhold(cr);
831 		node->delete_on_close_cred = cr;
832 		node->n_delete_on_close_flags = flags;
833 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
834 		rc = 0;
835 	}
836 	mutex_exit(&node->n_mutex);
837 	return (rc);
838 }
839 
840 void
841 smb_node_reset_delete_on_close(smb_node_t *node)
842 {
843 	mutex_enter(&node->n_mutex);
844 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
845 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
846 		crfree(node->delete_on_close_cred);
847 		node->delete_on_close_cred = NULL;
848 		node->n_delete_on_close_flags = 0;
849 	}
850 	mutex_exit(&node->n_mutex);
851 }
852 
853 /*
854  * smb_node_open_check
855  *
856  * check file sharing rules for current open request
857  * against all existing opens for a file.
858  *
859  * Returns NT_STATUS_SHARING_VIOLATION if there is any
860  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
861  */
862 uint32_t
863 smb_node_open_check(
864     smb_node_t	*node,
865     cred_t	*cr,
866     uint32_t	desired_access,
867     uint32_t	share_access)
868 {
869 	smb_ofile_t *of;
870 	uint32_t status;
871 
872 	SMB_NODE_VALID(node);
873 
874 	smb_llist_enter(&node->n_ofile_list, RW_READER);
875 	of = smb_llist_head(&node->n_ofile_list);
876 	while (of) {
877 		status = smb_ofile_open_check(of, cr, desired_access,
878 		    share_access);
879 
880 		switch (status) {
881 		case NT_STATUS_INVALID_HANDLE:
882 		case NT_STATUS_SUCCESS:
883 			of = smb_llist_next(&node->n_ofile_list, of);
884 			break;
885 		default:
886 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
887 			smb_llist_exit(&node->n_ofile_list);
888 			return (status);
889 		}
890 	}
891 
892 	smb_llist_exit(&node->n_ofile_list);
893 	return (NT_STATUS_SUCCESS);
894 }
895 
896 uint32_t
897 smb_node_rename_check(smb_node_t *node)
898 {
899 	smb_ofile_t	*of;
900 	uint32_t	status;
901 
902 	SMB_NODE_VALID(node);
903 
904 	/*
905 	 * Intra-CIFS check
906 	 */
907 	smb_llist_enter(&node->n_ofile_list, RW_READER);
908 	of = smb_llist_head(&node->n_ofile_list);
909 	while (of) {
910 		status = smb_ofile_rename_check(of);
911 
912 		switch (status) {
913 		case NT_STATUS_INVALID_HANDLE:
914 		case NT_STATUS_SUCCESS:
915 			of = smb_llist_next(&node->n_ofile_list, of);
916 			break;
917 		default:
918 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
919 			smb_llist_exit(&node->n_ofile_list);
920 			return (status);
921 		}
922 	}
923 	smb_llist_exit(&node->n_ofile_list);
924 
925 	/*
926 	 * system-wide share check
927 	 */
928 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
929 		return (NT_STATUS_SHARING_VIOLATION);
930 	else
931 		return (NT_STATUS_SUCCESS);
932 }
933 
934 uint32_t
935 smb_node_delete_check(smb_node_t *node)
936 {
937 	smb_ofile_t	*of;
938 	uint32_t	status;
939 
940 	SMB_NODE_VALID(node);
941 
942 	if (node->attr.sa_vattr.va_type == VDIR)
943 		return (NT_STATUS_SUCCESS);
944 
945 	/*
946 	 * intra-CIFS check
947 	 */
948 	smb_llist_enter(&node->n_ofile_list, RW_READER);
949 	of = smb_llist_head(&node->n_ofile_list);
950 	while (of) {
951 		status = smb_ofile_delete_check(of);
952 
953 		switch (status) {
954 		case NT_STATUS_INVALID_HANDLE:
955 		case NT_STATUS_SUCCESS:
956 			of = smb_llist_next(&node->n_ofile_list, of);
957 			break;
958 		default:
959 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
960 			smb_llist_exit(&node->n_ofile_list);
961 			return (status);
962 		}
963 	}
964 	smb_llist_exit(&node->n_ofile_list);
965 
966 	/*
967 	 * system-wide share check
968 	 */
969 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
970 		return (NT_STATUS_SHARING_VIOLATION);
971 	else
972 		return (NT_STATUS_SUCCESS);
973 }
974 
975 void
976 smb_node_notify_change(smb_node_t *node)
977 {
978 	SMB_NODE_VALID(node);
979 
980 	if (node->flags & NODE_FLAGS_NOTIFY_CHANGE) {
981 		node->flags |= NODE_FLAGS_CHANGED;
982 		smb_process_node_notify_change_queue(node);
983 	}
984 }
985 
986 /*
987  * smb_node_start_crit()
988  *
989  * Enter critical region for share reservations.
990  * See comments above smb_fsop_shrlock().
991  */
992 
993 void
994 smb_node_start_crit(smb_node_t *node, krw_t mode)
995 {
996 	rw_enter(&node->n_lock, mode);
997 	nbl_start_crit(node->vp, mode);
998 }
999 
1000 /*
1001  * smb_node_end_crit()
1002  *
1003  * Exit critical region for share reservations.
1004  */
1005 
1006 void
1007 smb_node_end_crit(smb_node_t *node)
1008 {
1009 	nbl_end_crit(node->vp);
1010 	rw_exit(&node->n_lock);
1011 }
1012 
1013 int
1014 smb_node_in_crit(smb_node_t *node)
1015 {
1016 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
1017 }
1018 
1019 void
1020 smb_node_rdlock(smb_node_t *node)
1021 {
1022 	rw_enter(&node->n_lock, RW_READER);
1023 }
1024 
1025 void
1026 smb_node_wrlock(smb_node_t *node)
1027 {
1028 	rw_enter(&node->n_lock, RW_WRITER);
1029 }
1030 
1031 void
1032 smb_node_unlock(smb_node_t *node)
1033 {
1034 	rw_exit(&node->n_lock);
1035 }
1036 
1037 uint32_t
1038 smb_node_get_ofile_count(smb_node_t *node)
1039 {
1040 	uint32_t	cntr;
1041 
1042 	SMB_NODE_VALID(node);
1043 
1044 	smb_llist_enter(&node->n_ofile_list, RW_READER);
1045 	cntr = smb_llist_get_count(&node->n_ofile_list);
1046 	smb_llist_exit(&node->n_ofile_list);
1047 	return (cntr);
1048 }
1049 
1050 void
1051 smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
1052 {
1053 	SMB_NODE_VALID(node);
1054 
1055 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
1056 	smb_llist_insert_tail(&node->n_ofile_list, of);
1057 	smb_llist_exit(&node->n_ofile_list);
1058 }
1059 
1060 void
1061 smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
1062 {
1063 	SMB_NODE_VALID(node);
1064 
1065 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
1066 	smb_llist_remove(&node->n_ofile_list, of);
1067 	smb_llist_exit(&node->n_ofile_list);
1068 }
1069 
1070 void
1071 smb_node_inc_open_ofiles(smb_node_t *node)
1072 {
1073 	SMB_NODE_VALID(node);
1074 
1075 	mutex_enter(&node->n_mutex);
1076 	node->n_open_count++;
1077 	mutex_exit(&node->n_mutex);
1078 }
1079 
1080 void
1081 smb_node_dec_open_ofiles(smb_node_t *node)
1082 {
1083 	SMB_NODE_VALID(node);
1084 
1085 	mutex_enter(&node->n_mutex);
1086 	node->n_open_count--;
1087 	mutex_exit(&node->n_mutex);
1088 }
1089 
1090 uint32_t
1091 smb_node_get_open_ofiles(smb_node_t *node)
1092 {
1093 	uint32_t	cnt;
1094 
1095 	SMB_NODE_VALID(node);
1096 
1097 	mutex_enter(&node->n_mutex);
1098 	cnt = node->n_open_count;
1099 	mutex_exit(&node->n_mutex);
1100 	return (cnt);
1101 }
1102 
1103 /*
1104  * smb_node_alloc
1105  */
1106 static smb_node_t *
1107 smb_node_alloc(
1108     char	*od_name,
1109     vnode_t	*vp,
1110     smb_attr_t	*attr,
1111     smb_llist_t	*bucket,
1112     uint32_t	hashkey)
1113 {
1114 	smb_node_t	*node;
1115 
1116 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
1117 
1118 	if (node->n_audit_buf != NULL)
1119 		node->n_audit_buf->anb_index = 0;
1120 
1121 	node->attr = *attr;
1122 	node->flags = NODE_FLAGS_ATTR_VALID;
1123 	node->n_size = node->attr.sa_vattr.va_size;
1124 	VN_HOLD(vp);
1125 	node->vp = vp;
1126 	node->n_refcnt = 1;
1127 	node->n_hash_bucket = bucket;
1128 	node->n_hashkey = hashkey;
1129 	node->n_orig_uid = 0;
1130 	node->readonly_creator = NULL;
1131 	node->waiting_event = 0;
1132 	node->what = 0;
1133 	node->n_open_count = 0;
1134 	node->dir_snode = NULL;
1135 	node->unnamed_stream_node = NULL;
1136 	node->delete_on_close_cred = NULL;
1137 	node->n_delete_on_close_flags = 0;
1138 
1139 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
1140 	if (strcmp(od_name, XATTR_DIR) == 0)
1141 		node->flags |= NODE_XATTR_DIR;
1142 
1143 	node->n_state = SMB_NODE_STATE_AVAILABLE;
1144 	node->n_magic = SMB_NODE_MAGIC;
1145 	return (node);
1146 }
1147 
1148 /*
1149  * smb_node_free
1150  */
1151 static void
1152 smb_node_free(smb_node_t *node)
1153 {
1154 	SMB_NODE_VALID(node);
1155 
1156 	node->n_magic = 0;
1157 	VERIFY(!list_link_active(&node->n_lnd));
1158 	VERIFY(node->n_lock_list.ll_count == 0);
1159 	VERIFY(node->n_ofile_list.ll_count == 0);
1160 	VERIFY(node->n_oplock.ol_xthread == NULL);
1161 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
1162 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
1163 	VN_RELE(node->vp);
1164 	kmem_cache_free(smb_node_cache, node);
1165 }
1166 
1167 /*
1168  * smb_node_constructor
1169  */
1170 static int
1171 smb_node_constructor(void *buf, void *un, int kmflags)
1172 {
1173 	_NOTE(ARGUNUSED(kmflags, un))
1174 
1175 	smb_node_t	*node = (smb_node_t *)buf;
1176 
1177 	bzero(node, sizeof (smb_node_t));
1178 
1179 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1180 	    offsetof(smb_ofile_t, f_nnd));
1181 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
1182 	    offsetof(smb_lock_t, l_lnd));
1183 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
1184 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
1185 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
1186 	smb_node_create_audit_buf(node, kmflags);
1187 	return (0);
1188 }
1189 
1190 /*
1191  * smb_node_destructor
1192  */
1193 static void
1194 smb_node_destructor(void *buf, void *un)
1195 {
1196 	_NOTE(ARGUNUSED(un))
1197 
1198 	smb_node_t	*node = (smb_node_t *)buf;
1199 
1200 	smb_node_destroy_audit_buf(node);
1201 	mutex_destroy(&node->n_mutex);
1202 	rw_destroy(&node->n_lock);
1203 	cv_destroy(&node->n_oplock.ol_cv);
1204 	smb_llist_destructor(&node->n_lock_list);
1205 	smb_llist_destructor(&node->n_ofile_list);
1206 }
1207 
1208 /*
1209  * smb_node_create_audit_buf
1210  */
1211 static void
1212 smb_node_create_audit_buf(smb_node_t *node, int kmflags)
1213 {
1214 	smb_audit_buf_node_t	*abn;
1215 
1216 	if (smb_audit_flags & SMB_AUDIT_NODE) {
1217 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
1218 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
1219 		node->n_audit_buf = abn;
1220 	}
1221 }
1222 
1223 /*
1224  * smb_node_destroy_audit_buf
1225  */
1226 static void
1227 smb_node_destroy_audit_buf(smb_node_t *node)
1228 {
1229 	if (node->n_audit_buf != NULL) {
1230 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
1231 		node->n_audit_buf = NULL;
1232 	}
1233 }
1234 
1235 /*
1236  * smb_node_audit
1237  *
1238  * This function saves the calling stack in the audit buffer of the node passed
1239  * in.
1240  */
1241 static void
1242 smb_node_audit(smb_node_t *node)
1243 {
1244 	smb_audit_buf_node_t	*abn;
1245 	smb_audit_record_node_t	*anr;
1246 
1247 	if (node->n_audit_buf) {
1248 		abn = node->n_audit_buf;
1249 		anr = abn->anb_records;
1250 		anr += abn->anb_index;
1251 		abn->anb_index++;
1252 		abn->anb_index &= abn->anb_max_index;
1253 		anr->anr_refcnt = node->n_refcnt;
1254 		anr->anr_depth = getpcstack(anr->anr_stack,
1255 		    SMB_AUDIT_STACK_DEPTH);
1256 	}
1257 }
1258 
1259 static smb_llist_t *
1260 smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
1261 {
1262 	uint32_t	hashkey;
1263 
1264 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
1265 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1266 	*phashkey = hashkey;
1267 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1268 }
1269