xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 337180d8810735987b8c349b70f3bf8dac99c273)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * SMB Node State Machine
30  * ----------------------
31  *
32  *    +----------------------------+	 T0
33  *    |  SMB_NODE_STATE_AVAILABLE  |<----------- Creation/Allocation
34  *    +----------------------------+
35  *		    |
36  *		    | T1
37  *		    |
38  *		    v
39  *    +-----------------------------+    T2
40  *    |  SMB_NODE_STATE_DESTROYING  |----------> Deletion/Free
41  *    +-----------------------------+
42  *
43  * Transition T0
44  *
45  *    This transition occurs in smb_node_lookup(). If the node looked for is
46  *    not found in the has table a new node is created. The reference count is
47  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
48  *
49  * Transition T1
50  *
51  *    This transition occurs in smb_node_release(). If the reference count
52  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
53  *    reference count will be given out for that node.
54  *
55  * Transition T2
56  *
57  *    This transition occurs in smb_node_release(). The structure is deleted.
58  *
59  * Comments
60  * --------
61  *
62  *    The reason the smb node has 2 states is the following synchronization
63  *    rule:
64  *
65  *    There's a mutex embedded in the node used to protect its fields and
66  *    there's a lock embedded in the bucket of the hash table the node belongs
67  *    to. To increment or to decrement the reference count the mutex must be
68  *    entered. To insert the node into the bucket and to remove it from the
69  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
70  *    lock) have to be entered, the lock has always to be entered first then
71  *    the mutex. This prevents a deadlock between smb_node_lookup() and
72  *    smb_node_release() from occurring. However, in smb_node_release() when the
73  *    reference count drops to zero and triggers the deletion of the node, the
74  *    mutex has to be released before entering the lock of the bucket (to
75  *    remove the node). This creates a window during which the node that is
76  *    about to be freed could be given out by smb_node_lookup(). To close that
77  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
78  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
79  *    state will indicate that the node should be treated as non existent (of
80  *    course the state of the node should be tested/updated under the
81  *    protection of the mutex).
82  */
83 #include <smbsrv/smb_incl.h>
84 #include <smbsrv/smb_fsops.h>
85 #include <sys/pathname.h>
86 #include <sys/sdt.h>
87 #include <sys/nbmlock.h>
88 
89 uint32_t smb_is_executable(char *path);
90 static void smb_node_delete_on_close(smb_node_t *node);
91 
92 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
93     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
94     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
95     ASSERT((_dir_)->dir_snode != (_node_));
96 
97 static boolean_t	smb_node_initialized = B_FALSE;
98 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
99 
100 /*
101  * smb_node_init
102  *
103  * Initialization of the SMB node layer.
104  *
105  * This function is not multi-thread safe. The caller must make sure only one
106  * thread makes the call.
107  */
108 int
109 smb_node_init(void)
110 {
111 	int	i;
112 
113 	if (smb_node_initialized)
114 		return (0);
115 
116 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
117 		smb_llist_constructor(&smb_node_hash_table[i],
118 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
119 	}
120 	smb_node_initialized = B_TRUE;
121 	return (0);
122 }
123 
124 /*
125  * smb_node_fini
126  *
127  * This function is not multi-thread safe. The caller must make sure only one
128  * thread makes the call.
129  */
130 void
131 smb_node_fini(void)
132 {
133 	int	i;
134 
135 	if (!smb_node_initialized)
136 		return;
137 
138 #ifdef DEBUG
139 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
140 		smb_node_t	*node;
141 
142 		/*
143 		 * The following sequence is just intended for sanity check.
144 		 * This will have to be modified when the code goes into
145 		 * production.
146 		 *
147 		 * The SMB node hash table should be emtpy at this point. If the
148 		 * hash table is not empty a panic will be triggered.
149 		 *
150 		 * The reason why SMB nodes are still remaining in the hash
151 		 * table is problably due to a mismatch between calls to
152 		 * smb_node_lookup() and smb_node_release(). You must track that
153 		 * down.
154 		 */
155 		node = smb_llist_head(&smb_node_hash_table[i]);
156 		ASSERT(node == NULL);
157 	}
158 #endif
159 
160 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
161 		smb_llist_destructor(&smb_node_hash_table[i]);
162 	}
163 	smb_node_initialized = B_FALSE;
164 }
165 
166 /*
167  * smb_node_lookup()
168  *
169  * NOTE: This routine should only be called by the file system interface layer,
170  * and not by SMB.
171  *
172  * smb_node_lookup() is called upon successful lookup, mkdir, and create
173  * (for both non-streams and streams).  In each of these cases, a held vnode is
174  * passed into this routine.  If an smb_node already exists for this vnode,
175  * the vp is released.  Otherwise, a new smb_node will be created and the
176  * reference will be held until the refcnt on the node goes to 0 (see
177  * smb_node_release()).
178  *
179  * A reference is taken on the smb_node whether found in the hash table
180  * or newly created.
181  *
182  * If an smb_node needs to be created, a reference is also taken on the
183  * dir_snode (if passed in).
184  *
185  * See smb_node_release() for details on the release of these references.
186  */
187 
188 /*ARGSUSED*/
189 smb_node_t *
190 smb_node_lookup(
191     struct smb_request	*sr,
192     struct open_param	*op,
193     cred_t		*cred,
194     vnode_t		*vp,
195     char		*od_name,
196     smb_node_t		*dir_snode,
197     smb_node_t		*unnamed_node,
198     smb_attr_t		*attr)
199 {
200 	smb_llist_t		*node_hdr;
201 	smb_node_t		*node;
202 	uint32_t		hashkey = 0;
203 	fs_desc_t		fsd;
204 	int			error;
205 	krw_t			lock_mode;
206 	vnode_t			*unnamed_vp = NULL;
207 
208 	/*
209 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
210 	 * because the node may not yet exist.  We also do not want to call
211 	 * it with the list lock held.
212 	 */
213 
214 	if (unnamed_node)
215 		unnamed_vp = unnamed_node->vp;
216 
217 	/*
218 	 * This getattr is performed on behalf of the server
219 	 * that's why kcred is used not the user's cred
220 	 */
221 	attr->sa_mask = SMB_AT_ALL;
222 	error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred);
223 	if (error)
224 		return (NULL);
225 
226 	if (sr) {
227 		if (sr->tid_tree) {
228 			/*
229 			 * The fsd for a file is that of the tree, even
230 			 * if the file resides in a different mountpoint
231 			 * under the share.
232 			 */
233 			fsd = sr->tid_tree->t_fsd;
234 		} else {
235 			/*
236 			 * This should be getting executed only for the
237 			 * tree's root smb_node.
238 			 */
239 			fsd = vp->v_vfsp->vfs_fsid;
240 		}
241 	} else {
242 		fsd = vp->v_vfsp->vfs_fsid;
243 	}
244 
245 	hashkey = fsd.val[0] + attr->sa_vattr.va_nodeid;
246 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
247 	node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)];
248 	lock_mode = RW_READER;
249 
250 	smb_llist_enter(node_hdr, lock_mode);
251 	for (;;) {
252 		node = list_head(&node_hdr->ll_list);
253 		while (node) {
254 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
255 			ASSERT(node->n_hash_bucket == node_hdr);
256 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
257 				smb_rwx_xenter(&node->n_lock);
258 				DTRACE_PROBE1(smb_node_lookup_hit,
259 				    smb_node_t *, node);
260 				switch (node->n_state) {
261 				case SMB_NODE_STATE_AVAILABLE:
262 					/* The node was found. */
263 					node->n_refcnt++;
264 					if ((node->dir_snode == NULL) &&
265 					    (dir_snode != NULL) &&
266 					    (strcmp(od_name, "..") != 0) &&
267 					    (strcmp(od_name, ".") != 0)) {
268 						VALIDATE_DIR_NODE(dir_snode,
269 						    node);
270 						node->dir_snode = dir_snode;
271 						smb_node_ref(dir_snode);
272 					}
273 					node->attr = *attr;
274 					node->n_size = attr->sa_vattr.va_size;
275 
276 					smb_audit_node(node);
277 					smb_rwx_xexit(&node->n_lock);
278 					smb_llist_exit(node_hdr);
279 					VN_RELE(vp);
280 					return (node);
281 
282 				case SMB_NODE_STATE_DESTROYING:
283 					/*
284 					 * Although the node exists it is about
285 					 * to be destroyed. We act as it hasn't
286 					 * been found.
287 					 */
288 					smb_rwx_xexit(&node->n_lock);
289 					break;
290 				default:
291 					/*
292 					 * Although the node exists it is in an
293 					 * unknown state. We act as it hasn't
294 					 * been found.
295 					 */
296 					ASSERT(0);
297 					smb_rwx_xexit(&node->n_lock);
298 					break;
299 				}
300 			}
301 			node = smb_llist_next(node_hdr, node);
302 		}
303 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
304 			lock_mode = RW_WRITER;
305 			continue;
306 		}
307 		break;
308 	}
309 	node = kmem_cache_alloc(sr->sr_server->si_cache_node, KM_SLEEP);
310 	bzero(node, sizeof (smb_node_t));
311 
312 	node->n_state = SMB_NODE_STATE_AVAILABLE;
313 	node->n_hash_bucket = node_hdr;
314 	node->n_sr = sr;
315 	node->vp = vp;
316 	node->n_hashkey = hashkey;
317 	node->n_refcnt = 1;
318 	node->tree_fsd = vp->v_vfsp->vfs_fsid;
319 	node->attr = *attr;
320 	node->flags |= NODE_FLAGS_ATTR_VALID;
321 	node->n_size = node->attr.sa_vattr.va_size;
322 	node->n_orig_session_id = sr->session->s_kid;
323 	node->n_orig_uid = crgetuid(sr->user_cr);
324 	node->n_cache = sr->sr_server->si_cache_node;
325 
326 	ASSERT(od_name);
327 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
328 
329 	if (fsd_chkcap(&vp->v_vfsp->vfs_fsid, FSOLF_READONLY) > 0)
330 		node->flags |= NODE_READ_ONLY;
331 
332 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
333 	    offsetof(smb_ofile_t, f_nnd));
334 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
335 	    offsetof(smb_lock_t, l_lnd));
336 
337 
338 	if (strcmp(od_name, XATTR_DIR) == 0)
339 		node->flags |= NODE_XATTR_DIR;
340 	if (op)
341 		node->flags |= smb_is_executable(op->fqi.last_comp);
342 
343 	if (dir_snode) {
344 		smb_node_ref(dir_snode);
345 		node->dir_snode = dir_snode;
346 		ASSERT(dir_snode->dir_snode != node);
347 		ASSERT((dir_snode->vp->v_xattrdir) ||
348 		    (dir_snode->vp->v_type == VDIR));
349 	}
350 
351 	if (unnamed_node) {
352 		smb_node_ref(unnamed_node);
353 		node->unnamed_stream_node = unnamed_node;
354 	}
355 
356 	smb_rwx_init(&node->n_lock);
357 	node->n_magic = SMB_NODE_MAGIC;
358 	smb_audit_buf_node_create(node);
359 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
360 	smb_audit_node(node);
361 	smb_llist_insert_head(node_hdr, node);
362 
363 	smb_llist_exit(node_hdr);
364 	return (node);
365 }
366 
367 /*
368  * smb_stream_node_lookup()
369  *
370  * Note: stream_name (the name that will be stored in the "od_name" field
371  * of a stream's smb_node) is the same as the on-disk name for the stream
372  * except that it does not have SMB_STREAM_PREFIX prepended.
373  */
374 
375 smb_node_t *
376 smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
377     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
378 {
379 	smb_node_t	*xattrdir_node;
380 	smb_node_t	*snode;
381 	smb_attr_t	tmp_attr;
382 
383 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
384 	    fnode, NULL, &tmp_attr);
385 
386 	if (xattrdir_node == NULL)
387 		return (NULL);
388 
389 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
390 	    fnode, ret_attr);
391 
392 	/*
393 	 * The following VN_HOLD is necessary because the caller will VN_RELE
394 	 * xattrdirvp in the case of an error.  (xattrdir_node has the original
395 	 * hold on the vnode, which the smb_node_release() call below will
396 	 * release.)
397 	 */
398 	if (snode == NULL) {
399 		VN_HOLD(xattrdirvp);
400 	}
401 	(void) smb_node_release(xattrdir_node);
402 	return (snode);
403 }
404 
405 
406 /*
407  * This function should be called whenever a reference is needed on an
408  * smb_node pointer.  The copy of an smb_node pointer from one non-local
409  * data structure to another requires a reference to be taken on the smb_node
410  * (unless the usage is localized).  Each data structure deallocation routine
411  * will call smb_node_release() on its smb_node pointers.
412  *
413  * In general, an smb_node pointer residing in a structure should never be
414  * stale.  A node pointer may be NULL, however, and care should be taken
415  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
416  * Care also needs to be taken with respect to racing deallocations of a
417  * structure.
418  */
419 
420 void
421 smb_node_ref(smb_node_t *node)
422 {
423 	ASSERT(node);
424 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
425 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
426 
427 	smb_rwx_xenter(&node->n_lock);
428 	node->n_refcnt++;
429 	ASSERT(node->n_refcnt);
430 	DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
431 	smb_audit_node(node);
432 	smb_rwx_xexit(&node->n_lock);
433 }
434 
435 /*
436  * smb_node_lookup() takes a hold on an smb_node, whether found in the
437  * hash table or newly created.  This hold is expected to be released
438  * in the following manner.
439  *
440  * smb_node_lookup() takes an address of an smb_node pointer.  This should
441  * be getting passed down via a lookup (whether path name or component), mkdir,
442  * create.  If the original smb_node pointer resides in a data structure, then
443  * the deallocation routine for the data structure is responsible for calling
444  * smb_node_release() on the smb_node pointer.  Alternatively,
445  * smb_node_release() can be called as soon as the smb_node pointer is no longer
446  * needed.  In this case, callers are responsible for setting an embedded
447  * pointer to NULL if it is known that the last reference is being released.
448  *
449  * If the passed-in address of the smb_node pointer belongs to a local variable,
450  * then the caller with the local variable should call smb_node_release()
451  * directly.
452  *
453  * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
454  * as smb_node_lookup() takes a hold on dir_snode.
455  */
456 void
457 smb_node_release(smb_node_t *node)
458 {
459 	ASSERT(node);
460 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
461 
462 	smb_rwx_xenter(&node->n_lock);
463 	ASSERT(node->n_refcnt);
464 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
465 	if (--node->n_refcnt == 0) {
466 		switch (node->n_state) {
467 
468 		case SMB_NODE_STATE_AVAILABLE:
469 			node->n_state = SMB_NODE_STATE_DESTROYING;
470 			smb_rwx_xexit(&node->n_lock);
471 
472 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
473 			smb_llist_remove(node->n_hash_bucket, node);
474 			smb_llist_exit(node->n_hash_bucket);
475 
476 			/*
477 			 * Check if the file was deleted
478 			 */
479 			smb_node_delete_on_close(node);
480 			node->n_magic = (uint32_t)~SMB_NODE_MAGIC;
481 
482 			/* These lists should be empty. */
483 			smb_llist_destructor(&node->n_ofile_list);
484 			smb_llist_destructor(&node->n_lock_list);
485 
486 			if (node->dir_snode) {
487 				ASSERT(node->dir_snode->n_magic ==
488 				    SMB_NODE_MAGIC);
489 				smb_node_release(node->dir_snode);
490 			}
491 
492 			if (node->unnamed_stream_node) {
493 				ASSERT(node->unnamed_stream_node->n_magic ==
494 				    SMB_NODE_MAGIC);
495 				smb_node_release(node->unnamed_stream_node);
496 			}
497 
498 			ASSERT(node->vp);
499 			VN_RELE(node->vp);
500 
501 			smb_audit_buf_node_destroy(node);
502 			smb_rwx_destroy(&node->n_lock);
503 			kmem_cache_free(node->n_cache, node);
504 			return;
505 
506 		default:
507 			ASSERT(0);
508 			break;
509 		}
510 	}
511 	smb_audit_node(node);
512 	smb_rwx_xexit(&node->n_lock);
513 }
514 
515 static void
516 smb_node_delete_on_close(smb_node_t *node)
517 {
518 	smb_node_t	*d_snode;
519 	int		rc = 0;
520 
521 	d_snode = node->dir_snode;
522 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
523 
524 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
525 		ASSERT(node->od_name != NULL);
526 		if (node->attr.sa_vattr.va_type == VDIR)
527 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
528 			    d_snode, node->od_name, 1);
529 		else
530 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
531 			    d_snode, node->od_name, 1);
532 		smb_cred_rele(node->delete_on_close_cred);
533 	}
534 	if (rc != 0)
535 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
536 		    node->od_name, rc);
537 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
538 }
539 
540 /*
541  * smb_node_rename()
542  *
543  */
544 int
545 smb_node_rename(
546     smb_node_t	*from_dir_snode,
547     smb_node_t	*ret_snode,
548     smb_node_t	*to_dir_snode,
549     char	*to_name)
550 {
551 	ASSERT(from_dir_snode);
552 	ASSERT(to_dir_snode);
553 	ASSERT(ret_snode);
554 	ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC);
555 	ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC);
556 	ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC);
557 	ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
558 	ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
559 	ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE);
560 
561 	smb_node_ref(to_dir_snode);
562 	smb_rwx_xenter(&ret_snode->n_lock);
563 	ret_snode->dir_snode = to_dir_snode;
564 	smb_rwx_xexit(&ret_snode->n_lock);
565 	ASSERT(to_dir_snode->dir_snode != ret_snode);
566 	ASSERT((to_dir_snode->vp->v_xattrdir) ||
567 	    (to_dir_snode->vp->v_type == VDIR));
568 	smb_node_release(from_dir_snode);
569 
570 	(void) strcpy(ret_snode->od_name, to_name);
571 
572 	/*
573 	 * XXX Need to update attributes?
574 	 */
575 
576 	return (0);
577 }
578 
579 int
580 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
581 {
582 	smb_attr_t	va;
583 	int		error;
584 	uint32_t	hashkey;
585 	smb_llist_t	*node_hdr;
586 	smb_node_t	*node;
587 
588 	/*
589 	 * Take an explicit hold on rootdir.  This goes with the
590 	 * corresponding release in smb_node_root_fini()/smb_node_release().
591 	 */
592 	VN_HOLD(vp);
593 
594 	va.sa_mask = SMB_AT_ALL;
595 	error = smb_vop_getattr(vp, NULL, &va, 0, kcred);
596 	if (error) {
597 		VN_RELE(vp);
598 		return (error);
599 	}
600 
601 	hashkey = vp->v_vfsp->vfs_fsid.val[0] + va.sa_vattr.va_nodeid;
602 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
603 	node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)];
604 
605 	node = kmem_cache_alloc(sv->si_cache_node, KM_SLEEP);
606 	bzero(node, sizeof (smb_node_t));
607 
608 	node->n_state = SMB_NODE_STATE_AVAILABLE;
609 	node->n_hash_bucket = node_hdr;
610 	node->vp = vp;
611 	node->n_hashkey = hashkey;
612 	node->n_refcnt = 1;
613 	node->tree_fsd = vp->v_vfsp->vfs_fsid;
614 	node->attr = va;
615 	node->flags |= NODE_FLAGS_ATTR_VALID;
616 	node->n_size = node->attr.sa_vattr.va_size;
617 	node->n_cache = sv->si_cache_node;
618 	(void) strlcpy(node->od_name, ROOTVOL, sizeof (node->od_name));
619 
620 	if (fsd_chkcap(&vp->v_vfsp->vfs_fsid, FSOLF_READONLY) > 0)
621 		node->flags |= NODE_READ_ONLY;
622 
623 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
624 	    offsetof(smb_ofile_t, f_nnd));
625 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
626 	    offsetof(smb_lock_t, l_lnd));
627 
628 	smb_rwx_init(&node->n_lock);
629 	node->n_magic = SMB_NODE_MAGIC;
630 	smb_audit_buf_node_create(node);
631 
632 	sv->si_root_smb_node = node;
633 
634 	smb_audit_node(node);
635 	smb_llist_enter(node_hdr, RW_WRITER);
636 	smb_llist_insert_head(node_hdr, node);
637 	smb_llist_exit(node_hdr);
638 
639 	*root = node;
640 
641 	return (0);
642 }
643 
644 /*
645  * smb_node_get_size
646  */
647 u_offset_t
648 smb_node_get_size(smb_node_t *node, smb_attr_t *attr)
649 {
650 	u_offset_t size;
651 
652 	if (attr->sa_vattr.va_type == VDIR)
653 		return (0);
654 
655 	smb_rwx_xenter(&node->n_lock);
656 	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
657 		size = node->n_size;
658 	else
659 		size = attr->sa_vattr.va_size;
660 	smb_rwx_xexit(&node->n_lock);
661 	return (size);
662 }
663 
664 static int
665 timeval_cmp(timestruc_t *a, timestruc_t *b)
666 {
667 	if (a->tv_sec < b->tv_sec)
668 		return (-1);
669 	if (a->tv_sec > b->tv_sec)
670 		return (1);
671 	/* Seconds are equal compare tv_nsec */
672 	if (a->tv_nsec < b->tv_nsec)
673 		return (-1);
674 	return (a->tv_nsec > b->tv_nsec);
675 }
676 
677 /*
678  * smb_node_set_time
679  *
680  * This function will update the time stored in the node and
681  * set the appropriate flags. If there is nothing to update
682  * or the node is readonly, the function would return without
683  * any updates. The update is only in the node level and the
684  * attribute in the file system will be updated when client
685  * close the file.
686  */
687 void
688 smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
689     struct timestruc *mtime, struct timestruc *atime,
690     struct timestruc *ctime, unsigned int what)
691 {
692 	smb_rwx_xenter(&node->n_lock);
693 	if (node->flags & NODE_READ_ONLY || what == 0) {
694 		smb_rwx_xexit(&node->n_lock);
695 		return;
696 	}
697 
698 	if ((what & SMB_AT_CRTIME && crtime == 0) ||
699 	    (what & SMB_AT_MTIME && mtime == 0) ||
700 	    (what & SMB_AT_ATIME && atime == 0) ||
701 	    (what & SMB_AT_CTIME && ctime == 0)) {
702 		smb_rwx_xexit(&node->n_lock);
703 		return;
704 	}
705 
706 	if ((what & SMB_AT_CRTIME) &&
707 	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
708 	    crtime) != 0) {
709 		node->what |= SMB_AT_CRTIME;
710 		node->attr.sa_crtime = *((timestruc_t *)crtime);
711 	}
712 
713 	if ((what & SMB_AT_MTIME) &&
714 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
715 	    mtime) != 0) {
716 		node->what |= SMB_AT_MTIME;
717 		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
718 	}
719 
720 	if ((what & SMB_AT_ATIME) &&
721 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
722 	    atime) != 0) {
723 			node->what |= SMB_AT_ATIME;
724 			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
725 	}
726 
727 	/*
728 	 * The ctime handling is trickier. It has three scenarios.
729 	 * 1. Only ctime need to be set and it is the same as the ctime
730 	 *    stored in the node. (update not necessary)
731 	 * 2. The ctime is the same as the ctime stored in the node but
732 	 *    is not the only time need to be set. (update required)
733 	 * 3. The ctime need to be set and is not the same as the ctime
734 	 *    stored in the node. (update required)
735 	 * Unlike other time setting, the ctime needs to be set even when
736 	 * it is the same as the ctime in the node if there are other time
737 	 * needs to be set (#2). This will ensure the ctime not being
738 	 * updated when other times are being updated in the file system.
739 	 *
740 	 * Retained file rules:
741 	 *
742 	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
743 	 *    request will be rejected by filesystem
744 	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
745 	 *    any request for changing ctime on these files should have
746 	 *    been already rejected
747 	 */
748 	node->what |= SMB_AT_CTIME;
749 	if (what & SMB_AT_CTIME) {
750 		if ((what == SMB_AT_CTIME) &&
751 		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
752 		    ctime) == 0) {
753 			node->what &= ~SMB_AT_CTIME;
754 		} else {
755 			gethrestime(&node->attr.sa_vattr.va_ctime);
756 		}
757 	} else {
758 		gethrestime(&node->attr.sa_vattr.va_ctime);
759 	}
760 	smb_rwx_xexit(&node->n_lock);
761 }
762 
763 
764 timestruc_t *
765 smb_node_get_crtime(smb_node_t *node)
766 {
767 	return ((timestruc_t *)&node->attr.sa_crtime);
768 }
769 
770 timestruc_t *
771 smb_node_get_atime(smb_node_t *node)
772 {
773 	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
774 }
775 
776 timestruc_t *
777 smb_node_get_ctime(smb_node_t *node)
778 {
779 	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
780 }
781 
782 timestruc_t *
783 smb_node_get_mtime(smb_node_t *node)
784 {
785 	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
786 }
787 
788 /*
789  * smb_node_set_dosattr
790  *
791  * Parse the specified DOS attributes and, if they have been modified,
792  * update the node cache. This call should be followed by a
793  * smb_sync_fsattr() call to write the attribute changes to filesystem.
794  */
795 void
796 smb_node_set_dosattr(smb_node_t *node, uint32_t dos_attr)
797 {
798 	unsigned int mode;  /* New mode */
799 
800 	mode = 0;
801 
802 	/* Handle the archive bit */
803 	if (dos_attr & SMB_FA_ARCHIVE)
804 		mode |= FILE_ATTRIBUTE_ARCHIVE;
805 
806 	/* Handle the readonly bit */
807 	if (dos_attr & SMB_FA_READONLY)
808 		mode |= FILE_ATTRIBUTE_READONLY;
809 
810 	/* Handle the hidden bit */
811 	if (dos_attr & SMB_FA_HIDDEN)
812 		mode |= FILE_ATTRIBUTE_HIDDEN;
813 
814 	/* Handle the system bit */
815 	if (dos_attr & SMB_FA_SYSTEM)
816 		mode |= FILE_ATTRIBUTE_SYSTEM;
817 
818 	smb_rwx_xenter(&node->n_lock);
819 	if (node->attr.sa_dosattr != mode) {
820 		node->attr.sa_dosattr = mode;
821 		node->what |= SMB_AT_DOSATTR;
822 	}
823 	smb_rwx_xexit(&node->n_lock);
824 }
825 
826 /*
827  * smb_node_get_dosattr
828  *
829  * This function will get dos attribute using the node.
830  */
831 uint32_t
832 smb_node_get_dosattr(smb_node_t *node)
833 {
834 	return (smb_mode_to_dos_attributes(&node->attr));
835 }
836 
837 int
838 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
839 {
840 	int	rc = -1;
841 
842 	smb_rwx_xenter(&node->n_lock);
843 	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
844 	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
845 		crhold(cr);
846 		node->delete_on_close_cred = cr;
847 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
848 		rc = 0;
849 	}
850 	smb_rwx_xexit(&node->n_lock);
851 	return (rc);
852 }
853 
854 void
855 smb_node_reset_delete_on_close(smb_node_t *node)
856 {
857 	smb_rwx_xenter(&node->n_lock);
858 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
859 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
860 		crfree(node->delete_on_close_cred);
861 		node->delete_on_close_cred = NULL;
862 	}
863 	smb_rwx_xexit(&node->n_lock);
864 }
865 
866 /*
867  * smb_node_open_check
868  *
869  * check file sharing rules for current open request
870  * against all existing opens for a file.
871  *
872  * Returns NT_STATUS_SHARING_VIOLATION if there is any
873  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
874  */
875 uint32_t
876 smb_node_open_check(struct smb_node *node, cred_t *cr,
877     uint32_t desired_access, uint32_t share_access)
878 {
879 	smb_ofile_t *of;
880 	uint32_t status;
881 
882 	ASSERT(node);
883 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
884 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
885 
886 	smb_llist_enter(&node->n_ofile_list, RW_READER);
887 	of = smb_llist_head(&node->n_ofile_list);
888 	while (of) {
889 		status = smb_ofile_open_check(of, cr, desired_access,
890 		    share_access);
891 
892 		switch (status) {
893 		case NT_STATUS_INVALID_HANDLE:
894 		case NT_STATUS_SUCCESS:
895 			of = smb_llist_next(&node->n_ofile_list, of);
896 			break;
897 		default:
898 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
899 			smb_llist_exit(&node->n_ofile_list);
900 			return (status);
901 		}
902 	}
903 
904 	smb_llist_exit(&node->n_ofile_list);
905 	return (NT_STATUS_SUCCESS);
906 }
907 
908 uint32_t
909 smb_node_rename_check(struct smb_node *node)
910 {
911 	struct smb_ofile *of;
912 	uint32_t status;
913 
914 	ASSERT(node);
915 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
916 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
917 
918 	/*
919 	 * Intra-CIFS check
920 	 */
921 
922 	smb_llist_enter(&node->n_ofile_list, RW_READER);
923 	of = smb_llist_head(&node->n_ofile_list);
924 	while (of) {
925 		status = smb_ofile_rename_check(of);
926 
927 		switch (status) {
928 		case NT_STATUS_INVALID_HANDLE:
929 		case NT_STATUS_SUCCESS:
930 			of = smb_llist_next(&node->n_ofile_list, of);
931 			break;
932 		default:
933 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
934 			smb_llist_exit(&node->n_ofile_list);
935 			return (status);
936 		}
937 	}
938 	smb_llist_exit(&node->n_ofile_list);
939 
940 	/*
941 	 * system-wide share check
942 	 */
943 
944 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
945 		return (NT_STATUS_SHARING_VIOLATION);
946 	else
947 		return (NT_STATUS_SUCCESS);
948 }
949 
950 uint32_t
951 smb_node_delete_check(smb_node_t *node)
952 {
953 	smb_ofile_t *of;
954 	uint32_t status;
955 
956 	ASSERT(node);
957 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
958 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
959 
960 	if (node->attr.sa_vattr.va_type == VDIR)
961 		return (NT_STATUS_SUCCESS);
962 
963 	/*
964 	 * intra-CIFS check
965 	 */
966 
967 	smb_llist_enter(&node->n_ofile_list, RW_READER);
968 	of = smb_llist_head(&node->n_ofile_list);
969 	while (of) {
970 		status = smb_ofile_delete_check(of);
971 
972 		switch (status) {
973 		case NT_STATUS_INVALID_HANDLE:
974 		case NT_STATUS_SUCCESS:
975 			of = smb_llist_next(&node->n_ofile_list, of);
976 			break;
977 		default:
978 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
979 			smb_llist_exit(&node->n_ofile_list);
980 			return (status);
981 		}
982 	}
983 	smb_llist_exit(&node->n_ofile_list);
984 
985 	/*
986 	 * system-wide share check
987 	 */
988 
989 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
990 		return (NT_STATUS_SHARING_VIOLATION);
991 	else
992 		return (NT_STATUS_SUCCESS);
993 }
994 
995 /*
996  * smb_node_start_crit()
997  *
998  * Enter critical region for share reservations.
999  * See comments above smb_fsop_shrlock().
1000  */
1001 
1002 void
1003 smb_node_start_crit(smb_node_t *node, krw_t mode)
1004 {
1005 	rw_enter(&node->n_share_lock, mode);
1006 	nbl_start_crit(node->vp, mode);
1007 }
1008 
1009 /*
1010  * smb_node_end_crit()
1011  *
1012  * Exit critical region for share reservations.
1013  */
1014 
1015 void
1016 smb_node_end_crit(smb_node_t *node)
1017 {
1018 	nbl_end_crit(node->vp);
1019 	rw_exit(&node->n_share_lock);
1020 }
1021 
1022 int
1023 smb_node_in_crit(smb_node_t *node)
1024 {
1025 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock));
1026 }
1027