xref: /titanic_52/usr/src/uts/common/fs/smbsrv/smb_node.c (revision bbec428e3a4860f4c1dd3a128c6b10c5bcd81ca4)
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 uint64_t
648 smb_node_get_size(
649     smb_node_t		*node,
650     smb_attr_t		*attr)
651 {
652 	uint64_t	size;
653 
654 	if (attr->sa_vattr.va_type == VDIR)
655 		return (0);
656 
657 	smb_rwx_xenter(&node->n_lock);
658 	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
659 		size = node->n_size;
660 	else
661 		size = attr->sa_vattr.va_size;
662 	smb_rwx_xexit(&node->n_lock);
663 	return (size);
664 }
665 
666 static int
667 timeval_cmp(timestruc_t *a, timestruc_t *b)
668 {
669 	if (a->tv_sec < b->tv_sec)
670 		return (-1);
671 	if (a->tv_sec > b->tv_sec)
672 		return (1);
673 	/* Seconds are equal compare tv_nsec */
674 	if (a->tv_nsec < b->tv_nsec)
675 		return (-1);
676 	return (a->tv_nsec > b->tv_nsec);
677 }
678 
679 /*
680  * smb_node_set_time
681  *
682  * This function will update the time stored in the node and
683  * set the appropriate flags. If there is nothing to update
684  * or the node is readonly, the function would return without
685  * any updates. The update is only in the node level and the
686  * attribute in the file system will be updated when client
687  * close the file.
688  */
689 void
690 smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
691     struct timestruc *mtime, struct timestruc *atime,
692     struct timestruc *ctime, unsigned int what)
693 {
694 	smb_rwx_xenter(&node->n_lock);
695 	if (node->flags & NODE_READ_ONLY || what == 0) {
696 		smb_rwx_xexit(&node->n_lock);
697 		return;
698 	}
699 
700 	if ((what & SMB_AT_CRTIME && crtime == 0) ||
701 	    (what & SMB_AT_MTIME && mtime == 0) ||
702 	    (what & SMB_AT_ATIME && atime == 0) ||
703 	    (what & SMB_AT_CTIME && ctime == 0)) {
704 		smb_rwx_xexit(&node->n_lock);
705 		return;
706 	}
707 
708 	if ((what & SMB_AT_CRTIME) &&
709 	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
710 	    crtime) != 0) {
711 		node->what |= SMB_AT_CRTIME;
712 		node->attr.sa_crtime = *((timestruc_t *)crtime);
713 	}
714 
715 	if ((what & SMB_AT_MTIME) &&
716 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
717 	    mtime) != 0) {
718 		node->what |= SMB_AT_MTIME;
719 		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
720 	}
721 
722 	if ((what & SMB_AT_ATIME) &&
723 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
724 	    atime) != 0) {
725 			node->what |= SMB_AT_ATIME;
726 			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
727 	}
728 
729 	/*
730 	 * The ctime handling is trickier. It has three scenarios.
731 	 * 1. Only ctime need to be set and it is the same as the ctime
732 	 *    stored in the node. (update not necessary)
733 	 * 2. The ctime is the same as the ctime stored in the node but
734 	 *    is not the only time need to be set. (update required)
735 	 * 3. The ctime need to be set and is not the same as the ctime
736 	 *    stored in the node. (update required)
737 	 * Unlike other time setting, the ctime needs to be set even when
738 	 * it is the same as the ctime in the node if there are other time
739 	 * needs to be set (#2). This will ensure the ctime not being
740 	 * updated when other times are being updated in the file system.
741 	 *
742 	 * Retained file rules:
743 	 *
744 	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
745 	 *    request will be rejected by filesystem
746 	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
747 	 *    any request for changing ctime on these files should have
748 	 *    been already rejected
749 	 */
750 	node->what |= SMB_AT_CTIME;
751 	if (what & SMB_AT_CTIME) {
752 		if ((what == SMB_AT_CTIME) &&
753 		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
754 		    ctime) == 0) {
755 			node->what &= ~SMB_AT_CTIME;
756 		} else {
757 			gethrestime(&node->attr.sa_vattr.va_ctime);
758 		}
759 	} else {
760 		gethrestime(&node->attr.sa_vattr.va_ctime);
761 	}
762 	smb_rwx_xexit(&node->n_lock);
763 }
764 
765 
766 timestruc_t *
767 smb_node_get_crtime(smb_node_t *node)
768 {
769 	return ((timestruc_t *)&node->attr.sa_crtime);
770 }
771 
772 timestruc_t *
773 smb_node_get_atime(smb_node_t *node)
774 {
775 	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
776 }
777 
778 timestruc_t *
779 smb_node_get_ctime(smb_node_t *node)
780 {
781 	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
782 }
783 
784 timestruc_t *
785 smb_node_get_mtime(smb_node_t *node)
786 {
787 	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
788 }
789 
790 /*
791  * smb_node_set_dosattr
792  *
793  * Parse the specified DOS attributes and, if they have been modified,
794  * update the node cache. This call should be followed by a
795  * smb_sync_fsattr() call to write the attribute changes to filesystem.
796  */
797 void
798 smb_node_set_dosattr(smb_node_t *node, uint32_t dos_attr)
799 {
800 	unsigned int mode;  /* New mode */
801 
802 	mode = 0;
803 
804 	/* Handle the archive bit */
805 	if (dos_attr & SMB_FA_ARCHIVE)
806 		mode |= FILE_ATTRIBUTE_ARCHIVE;
807 
808 	/* Handle the readonly bit */
809 	if (dos_attr & SMB_FA_READONLY)
810 		mode |= FILE_ATTRIBUTE_READONLY;
811 
812 	/* Handle the hidden bit */
813 	if (dos_attr & SMB_FA_HIDDEN)
814 		mode |= FILE_ATTRIBUTE_HIDDEN;
815 
816 	/* Handle the system bit */
817 	if (dos_attr & SMB_FA_SYSTEM)
818 		mode |= FILE_ATTRIBUTE_SYSTEM;
819 
820 	smb_rwx_xenter(&node->n_lock);
821 	if (node->attr.sa_dosattr != mode) {
822 		node->attr.sa_dosattr = mode;
823 		node->what |= SMB_AT_DOSATTR;
824 	}
825 	smb_rwx_xexit(&node->n_lock);
826 }
827 
828 /*
829  * smb_node_get_dosattr
830  *
831  * This function will get dos attribute using the node.
832  */
833 uint32_t
834 smb_node_get_dosattr(smb_node_t *node)
835 {
836 	return (smb_mode_to_dos_attributes(&node->attr));
837 }
838 
839 int
840 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
841 {
842 	int	rc = -1;
843 
844 	smb_rwx_xenter(&node->n_lock);
845 	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
846 	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
847 		crhold(cr);
848 		node->delete_on_close_cred = cr;
849 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
850 		rc = 0;
851 	}
852 	smb_rwx_xexit(&node->n_lock);
853 	return (rc);
854 }
855 
856 void
857 smb_node_reset_delete_on_close(smb_node_t *node)
858 {
859 	smb_rwx_xenter(&node->n_lock);
860 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
861 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
862 		crfree(node->delete_on_close_cred);
863 		node->delete_on_close_cred = NULL;
864 	}
865 	smb_rwx_xexit(&node->n_lock);
866 }
867 
868 /*
869  * smb_node_share_check
870  *
871  * check file sharing rules for current open request
872  * against all existing opens for a file.
873  *
874  * Returns NT_STATUS_SHARING_VIOLATION if there is any
875  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
876  */
877 uint32_t
878 smb_node_open_check(struct smb_node *node, cred_t *cr,
879     uint32_t desired_access, uint32_t share_access)
880 {
881 	smb_ofile_t *of;
882 	uint32_t status;
883 
884 	ASSERT(node);
885 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
886 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
887 
888 	smb_llist_enter(&node->n_ofile_list, RW_READER);
889 	of = smb_llist_head(&node->n_ofile_list);
890 	while (of) {
891 		status = smb_node_share_check(node, cr, desired_access,
892 		    share_access, of);
893 		if (status == NT_STATUS_SHARING_VIOLATION) {
894 			smb_llist_exit(&node->n_ofile_list);
895 			return (status);
896 		}
897 		of = smb_llist_next(&node->n_ofile_list, of);
898 	}
899 	smb_llist_exit(&node->n_ofile_list);
900 
901 	return (NT_STATUS_SUCCESS);
902 }
903 
904 /*
905  * smb_open_share_check
906  *
907  * check file sharing rules for current open request
908  * against the given existing open.
909  *
910  * Returns NT_STATUS_SHARING_VIOLATION if there is any
911  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
912  */
913 uint32_t
914 smb_node_share_check(
915     struct smb_node *node,
916     cred_t *cr,
917     uint32_t desired_access,
918     uint32_t share_access,
919     smb_ofile_t *of)
920 {
921 	/*
922 	 * It appears that share modes are not relevant to
923 	 * directories, but this check will remain as it is not
924 	 * clear whether it was originally put here for a reason.
925 	 */
926 	if (node->attr.sa_vattr.va_type == VDIR) {
927 		if (SMB_DENY_RW(of->f_share_access) &&
928 		    (node->n_orig_uid != crgetuid(cr))) {
929 			return (NT_STATUS_SHARING_VIOLATION);
930 		}
931 
932 		return (NT_STATUS_SUCCESS);
933 	}
934 
935 	/* if it's just meta data */
936 	if ((of->f_granted_access & FILE_DATA_ALL) == 0)
937 		return (NT_STATUS_SUCCESS);
938 
939 	/*
940 	 * Check requested share access against the
941 	 * open granted (desired) access
942 	 */
943 	if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE))
944 		return (NT_STATUS_SHARING_VIOLATION);
945 
946 	if (SMB_DENY_READ(share_access) &&
947 	    (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE)))
948 		return (NT_STATUS_SHARING_VIOLATION);
949 
950 	if (SMB_DENY_WRITE(share_access) &&
951 	    (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
952 		return (NT_STATUS_SHARING_VIOLATION);
953 
954 	/* check requested desired access against the open share access */
955 	if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE))
956 		return (NT_STATUS_SHARING_VIOLATION);
957 
958 	if (SMB_DENY_READ(of->f_share_access) &&
959 	    (desired_access & (FILE_READ_DATA | FILE_EXECUTE)))
960 		return (NT_STATUS_SHARING_VIOLATION);
961 
962 	if (SMB_DENY_WRITE(of->f_share_access) &&
963 	    (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
964 		return (NT_STATUS_SHARING_VIOLATION);
965 
966 	return (NT_STATUS_SUCCESS);
967 }
968 
969 /*
970  * smb_rename_share_check
971  *
972  * An open file can be renamed if
973  *
974  *  1. isn't opened for data writing or deleting
975  *
976  *  2. Opened with "Deny Delete" share mode
977  *         But not opened for data reading or executing
978  *         (opened for accessing meta data)
979  */
980 
981 DWORD
982 smb_node_rename_check(struct smb_node *node)
983 {
984 	struct smb_ofile *open;
985 
986 	ASSERT(node);
987 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
988 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
989 
990 	/*
991 	 * Intra-CIFS check
992 	 */
993 
994 	smb_llist_enter(&node->n_ofile_list, RW_READER);
995 	open = smb_llist_head(&node->n_ofile_list);
996 	while (open) {
997 		if (open->f_granted_access &
998 		    (FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE)) {
999 			smb_llist_exit(&node->n_ofile_list);
1000 			return (NT_STATUS_SHARING_VIOLATION);
1001 		}
1002 
1003 		if ((open->f_share_access & FILE_SHARE_DELETE) == 0) {
1004 			if (open->f_granted_access &
1005 			    (FILE_READ_DATA | FILE_EXECUTE)) {
1006 				smb_llist_exit(&node->n_ofile_list);
1007 				return (NT_STATUS_SHARING_VIOLATION);
1008 			}
1009 		}
1010 		open = smb_llist_next(&node->n_ofile_list, open);
1011 	}
1012 	smb_llist_exit(&node->n_ofile_list);
1013 
1014 	/*
1015 	 * system-wide share check
1016 	 */
1017 
1018 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
1019 		return (NT_STATUS_SHARING_VIOLATION);
1020 	else
1021 		return (NT_STATUS_SUCCESS);
1022 }
1023 
1024 /*
1025  * smb_node_delete_check
1026  *
1027  * An open file can be deleted only if opened for
1028  * accessing meta data. Share modes aren't important
1029  * in this case.
1030  *
1031  * NOTE: there is another mechanism for deleting an
1032  * open file that NT clients usually use.
1033  * That's setting "Delete on close" flag for an open
1034  * file.  In this way the file will be deleted after
1035  * last close. This flag can be set by SmbTrans2SetFileInfo
1036  * with FILE_DISPOSITION_INFO information level.
1037  * For setting this flag, the file should be opened by
1038  * DELETE access in the FID that is passed in the Trans2
1039  * request.
1040  */
1041 DWORD
1042 smb_node_delete_check(smb_node_t *node)
1043 {
1044 	smb_ofile_t *file;
1045 
1046 	ASSERT(node);
1047 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
1048 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
1049 
1050 	if (node->attr.sa_vattr.va_type == VDIR)
1051 		return (NT_STATUS_SUCCESS);
1052 
1053 	/*
1054 	 * intra-CIFS check
1055 	 */
1056 
1057 	smb_llist_enter(&node->n_ofile_list, RW_READER);
1058 	file = smb_llist_head(&node->n_ofile_list);
1059 	while (file) {
1060 		ASSERT(file->f_magic == SMB_OFILE_MAGIC);
1061 		if (file->f_granted_access &
1062 		    (FILE_READ_DATA |
1063 		    FILE_WRITE_DATA |
1064 		    FILE_APPEND_DATA |
1065 		    FILE_EXECUTE |
1066 		    DELETE)) {
1067 			smb_llist_exit(&node->n_ofile_list);
1068 			return (NT_STATUS_SHARING_VIOLATION);
1069 		}
1070 		file = smb_llist_next(&node->n_ofile_list, file);
1071 	}
1072 	smb_llist_exit(&node->n_ofile_list);
1073 
1074 	/*
1075 	 * system-wide share check
1076 	 */
1077 
1078 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
1079 		return (NT_STATUS_SHARING_VIOLATION);
1080 	else
1081 		return (NT_STATUS_SUCCESS);
1082 }
1083 
1084 /*
1085  * smb_node_start_crit()
1086  *
1087  * Enter critical region for share reservations.
1088  * See comments above smb_fsop_shrlock().
1089  */
1090 
1091 void
1092 smb_node_start_crit(smb_node_t *node, krw_t mode)
1093 {
1094 	rw_enter(&node->n_share_lock, mode);
1095 	nbl_start_crit(node->vp, mode);
1096 }
1097 
1098 /*
1099  * smb_node_end_crit()
1100  *
1101  * Exit critical region for share reservations.
1102  */
1103 
1104 void
1105 smb_node_end_crit(smb_node_t *node)
1106 {
1107 	nbl_end_crit(node->vp);
1108 	rw_exit(&node->n_share_lock);
1109 }
1110 
1111 int
1112 smb_node_in_crit(smb_node_t *node)
1113 {
1114 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock));
1115 }
1116