xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 5772:237ac22142fe)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
22*5772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
275331Samw 
285331Samw /*
295331Samw  * SMB Node State Machine
305331Samw  * ----------------------
315331Samw  *
325331Samw  *    +----------------------------+	 T0
335331Samw  *    |  SMB_NODE_STATE_AVAILABLE  |<----------- Creation/Allocation
345331Samw  *    +----------------------------+
355331Samw  *		    |
365331Samw  *		    | T1
375331Samw  *		    |
385331Samw  *		    v
395331Samw  *    +-----------------------------+    T2
405331Samw  *    |  SMB_NODE_STATE_DESTROYING  |----------> Deletion/Free
415331Samw  *    +-----------------------------+
425331Samw  *
435331Samw  * Transition T0
445331Samw  *
455331Samw  *    This transition occurs in smb_node_lookup(). If the node looked for is
465331Samw  *    not found in the has table a new node is created. The reference count is
475331Samw  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
485331Samw  *
495331Samw  * Transition T1
505331Samw  *
515331Samw  *    This transition occurs in smb_node_release(). If the reference count
525331Samw  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
535331Samw  *    reference count will be given out for that node.
545331Samw  *
555331Samw  * Transition T2
565331Samw  *
575331Samw  *    This transition occurs in smb_node_release(). The structure is deleted.
585331Samw  *
595331Samw  * Comments
605331Samw  * --------
615331Samw  *
625331Samw  *    The reason the smb node has 2 states is the following synchronization
635331Samw  *    rule:
645331Samw  *
655331Samw  *    There's a mutex embedded in the node used to protect its fields and
665331Samw  *    there's a lock embedded in the bucket of the hash table the node belongs
675331Samw  *    to. To increment or to decrement the reference count the mutex must be
685331Samw  *    entered. To insert the node into the bucket and to remove it from the
695331Samw  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
705331Samw  *    lock) have to be entered, the lock has always to be entered first then
715331Samw  *    the mutex. This prevents a deadlock between smb_node_lookup() and
725331Samw  *    smb_node_release() from occurring. However, in smb_node_release() when the
735331Samw  *    reference count drops to zero and triggers the deletion of the node, the
745331Samw  *    mutex has to be released before entering the lock of the bucket (to
755331Samw  *    remove the node). This creates a window during which the node that is
765331Samw  *    about to be freed could be given out by smb_node_lookup(). To close that
775331Samw  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
785331Samw  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
795331Samw  *    state will indicate that the node should be treated as non existent (of
805331Samw  *    course the state of the node should be tested/updated under the
815331Samw  *    protection of the mutex).
825331Samw  */
835331Samw #include <smbsrv/smb_incl.h>
845331Samw #include <smbsrv/smb_fsops.h>
855331Samw #include <sys/pathname.h>
865331Samw #include <sys/sdt.h>
87*5772Sas200622 #include <sys/nbmlock.h>
885331Samw 
895331Samw uint32_t smb_is_executable(char *path);
905331Samw static void smb_node_delete_on_close(smb_node_t *node);
915331Samw 
925331Samw uint32_t	smb_node_hit = 0;
935331Samw uint32_t	smb_node_miss = 0;
945331Samw uint32_t	smb_node_alloc = 0;
955331Samw uint32_t	smb_node_free = 0;
965331Samw 
975331Samw #define	VALIDATE_DIR_NODE(_dir_, _node_) \
985331Samw     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
995331Samw     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
1005331Samw     ASSERT((_dir_)->dir_snode != (_node_));
1015331Samw 
1025331Samw /*
1035331Samw  * smb_node_lookup()
1045331Samw  *
1055331Samw  * NOTE: This routine should only be called by the file system interface layer,
1065331Samw  * and not by SMB.
1075331Samw  *
1085331Samw  * smb_node_lookup() is called upon successful lookup, mkdir, and create
1095331Samw  * (for both non-streams and streams).  In each of these cases, a held vnode is
1105331Samw  * passed into this routine.  If an smb_node already exists for this vnode,
1115331Samw  * the vp is released.  Otherwise, a new smb_node will be created and the
1125331Samw  * reference will be held until the refcnt on the node goes to 0 (see
1135331Samw  * smb_node_release()).
1145331Samw  *
1155331Samw  * A reference is taken on the smb_node whether found in the hash table
1165331Samw  * or newly created.
1175331Samw  *
1185331Samw  * If an smb_node needs to be created, a reference is also taken on the
1195331Samw  * dir_snode (if passed in).
1205331Samw  *
1215331Samw  * See smb_node_release() for details on the release of these references.
1225331Samw  */
1235331Samw 
1245331Samw /*ARGSUSED*/
1255331Samw smb_node_t *
1265331Samw smb_node_lookup(
1275331Samw     struct smb_request	*sr,
1285331Samw     struct open_param	*op,
1295331Samw     cred_t		*cred,
1305331Samw     vnode_t		*vp,
1315331Samw     char		*od_name,
1325331Samw     smb_node_t		*dir_snode,
1335331Samw     smb_node_t		*unnamed_node,
1345331Samw     smb_attr_t		*attr)
1355331Samw {
1365331Samw 	smb_llist_t		*node_hdr;
1375331Samw 	smb_node_t		*node;
1385331Samw 	uint32_t		hashkey = 0;
1395331Samw 	fs_desc_t		fsd;
1405331Samw 	int			error;
1415331Samw 	krw_t			lock_mode;
1425331Samw 	vnode_t			*unnamed_vp = NULL;
1435331Samw 
1445331Samw 	/*
1455331Samw 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
1465331Samw 	 * because the node may not yet exist.  We also do not want to call
1475331Samw 	 * it with the list lock held.
1485331Samw 	 */
1495331Samw 
1505331Samw 	if (unnamed_node)
1515331Samw 		unnamed_vp = unnamed_node->vp;
1525331Samw 
1535331Samw 	/*
1545331Samw 	 * This getattr is performed on behalf of the server
1555331Samw 	 * that's why kcred is used not the user's cred
1565331Samw 	 */
1575331Samw 	attr->sa_mask = SMB_AT_ALL;
158*5772Sas200622 	error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred);
1595331Samw 	if (error)
1605331Samw 		return (NULL);
1615331Samw 
1625331Samw 	if (sr) {
1635331Samw 		if (sr->tid_tree) {
1645331Samw 			/*
1655331Samw 			 * The fsd for a file is that of the tree, even
1665331Samw 			 * if the file resides in a different mountpoint
1675331Samw 			 * under the share.
1685331Samw 			 */
1695331Samw 			fsd = sr->tid_tree->t_fsd;
1705331Samw 		} else {
1715331Samw 			/*
1725331Samw 			 * This should be getting executed only for the
1735331Samw 			 * tree's root smb_node.
1745331Samw 			 */
1755331Samw 			fsd = vp->v_vfsp->vfs_fsid;
1765331Samw 		}
1775331Samw 	} else {
1785331Samw 		fsd = vp->v_vfsp->vfs_fsid;
1795331Samw 	}
1805331Samw 
1815331Samw 	hashkey = fsd.val[0] + attr->sa_vattr.va_nodeid;
1825331Samw 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1835331Samw 	node_hdr = &smb_info.node_hash_table[(hashkey & SMBND_HASH_MASK)];
1845331Samw 	lock_mode = RW_READER;
1855331Samw 
1865331Samw 	smb_llist_enter(node_hdr, lock_mode);
1875331Samw 	for (;;) {
1885331Samw 		node = list_head(&node_hdr->ll_list);
1895331Samw 		while (node) {
1905331Samw 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
1915331Samw 			ASSERT(node->n_hash_bucket == node_hdr);
1925331Samw 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
1935331Samw 				smb_rwx_xenter(&node->n_lock);
1945331Samw 				DTRACE_PROBE1(smb_node_lookup_hit,
1955331Samw 				    smb_node_t *, node);
1965331Samw 				switch (node->n_state) {
1975331Samw 				case SMB_NODE_STATE_AVAILABLE:
1985331Samw 					/* The node was found. */
1995331Samw 					node->n_refcnt++;
2005331Samw 					if ((node->dir_snode == NULL) &&
2015331Samw 					    (dir_snode != NULL) &&
2025331Samw 					    (strcmp(od_name, "..") != 0) &&
2035331Samw 					    (strcmp(od_name, ".") != 0)) {
2045331Samw 						VALIDATE_DIR_NODE(dir_snode,
2055331Samw 						    node);
2065331Samw 						node->dir_snode = dir_snode;
2075331Samw 						smb_node_ref(dir_snode);
2085331Samw 					}
2095331Samw 					node->attr = *attr;
210*5772Sas200622 					node->n_size = attr->sa_vattr.va_size;
2115331Samw 
2125331Samw 					smb_audit_node(node);
2135331Samw 					smb_rwx_xexit(&node->n_lock);
2145331Samw 					smb_llist_exit(node_hdr);
2155331Samw 					VN_RELE(vp);
2165331Samw 					return (node);
2175331Samw 
2185331Samw 				case SMB_NODE_STATE_DESTROYING:
2195331Samw 					/*
2205331Samw 					 * Although the node exists it is about
2215331Samw 					 * to be destroyed. We act as it hasn't
2225331Samw 					 * been found.
2235331Samw 					 */
2245331Samw 					smb_rwx_xexit(&node->n_lock);
2255331Samw 					break;
2265331Samw 				default:
2275331Samw 					/*
2285331Samw 					 * Although the node exists it is in an
2295331Samw 					 * unknown state. We act as it hasn't
2305331Samw 					 * been found.
2315331Samw 					 */
2325331Samw 					ASSERT(0);
2335331Samw 					smb_rwx_xexit(&node->n_lock);
2345331Samw 					break;
2355331Samw 				}
2365331Samw 			}
2375331Samw 			node = smb_llist_next(node_hdr, node);
2385331Samw 		}
2395331Samw 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
2405331Samw 			lock_mode = RW_WRITER;
2415331Samw 			continue;
2425331Samw 		}
2435331Samw 		break;
2445331Samw 	}
2455331Samw 	node = kmem_cache_alloc(smb_info.si_cache_node, KM_SLEEP);
2465331Samw 	smb_node_alloc++;
2475331Samw 
2485331Samw 	bzero(node, sizeof (smb_node_t));
2495331Samw 
2505331Samw 	node->n_state = SMB_NODE_STATE_AVAILABLE;
2515331Samw 	node->n_hash_bucket = node_hdr;
2525331Samw 
2535331Samw 	if (fsd_chkcap(&fsd, FSOLF_READONLY) > 0) {
2545331Samw 		node->flags |= NODE_READ_ONLY;
2555331Samw 	}
2565331Samw 
2575331Samw 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
2585331Samw 	    offsetof(smb_ofile_t, f_nnd));
2595331Samw 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
2605331Samw 	    offsetof(smb_lock_t, l_lnd));
2615331Samw 	node->n_hashkey = hashkey;
2625331Samw 	node->n_refcnt = 1;
2635331Samw 
2645331Samw 	if (sr) {
2655331Samw 		node->n_orig_session_id = sr->session->s_kid;
2665331Samw 		node->n_orig_uid = crgetuid(sr->user_cr);
2675331Samw 	}
2685331Samw 
2695331Samw 	node->vp = vp;
2705331Samw 
2715331Samw 	ASSERT(od_name);
2725331Samw 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
2735331Samw 	node->tree_fsd = fsd;
2745331Samw 
2755331Samw 	if (op)
2765331Samw 		node->flags |= smb_is_executable(op->fqi.last_comp);
2775331Samw 
2785331Samw 	if (dir_snode) {
2795331Samw 		smb_node_ref(dir_snode);
2805331Samw 		node->dir_snode = dir_snode;
2815331Samw 		ASSERT(dir_snode->dir_snode != node);
2825331Samw 		ASSERT((dir_snode->vp->v_xattrdir) ||
2835331Samw 		    (dir_snode->vp->v_type == VDIR));
2845331Samw 	}
2855331Samw 
2865331Samw 	if (unnamed_node) {
2875331Samw 		smb_node_ref(unnamed_node);
2885331Samw 		node->unnamed_stream_node = unnamed_node;
2895331Samw 	}
2905331Samw 
2915331Samw 	node->attr = *attr;
2925331Samw 	node->flags |= NODE_FLAGS_ATTR_VALID;
2935331Samw 	node->n_size = node->attr.sa_vattr.va_size;
2945331Samw 
2955331Samw 	smb_rwx_init(&node->n_lock);
2965331Samw 	node->n_magic = SMB_NODE_MAGIC;
2975331Samw 	smb_audit_buf_node_create(node);
2985331Samw 
2995331Samw 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
3005331Samw 	smb_audit_node(node);
3015331Samw 	smb_llist_insert_head(node_hdr, node);
3025331Samw 	smb_llist_exit(node_hdr);
3035331Samw 	return (node);
3045331Samw }
3055331Samw 
3065331Samw /*
3075331Samw  * smb_stream_node_lookup()
3085331Samw  *
3095331Samw  * Note: stream_name (the name that will be stored in the "od_name" field
3105331Samw  * of a stream's smb_node) is the same as the on-disk name for the stream
3115331Samw  * except that it does not have SMB_STREAM_PREFIX prepended.
3125331Samw  */
3135331Samw 
3145331Samw smb_node_t *
3155331Samw smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
3165331Samw     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
3175331Samw {
3185331Samw 	smb_node_t	*xattrdir_node;
3195331Samw 	smb_node_t	*snode;
3205331Samw 	smb_attr_t	tmp_attr;
3215331Samw 
3225331Samw 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
3235331Samw 	    fnode, NULL, &tmp_attr);
3245331Samw 
3255331Samw 	if (xattrdir_node == NULL)
3265331Samw 		return (NULL);
3275331Samw 
3285331Samw 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
3295331Samw 	    fnode, ret_attr);
3305331Samw 
3315331Samw 	/*
3325331Samw 	 * The following VN_HOLD is necessary because the caller will VN_RELE
3335331Samw 	 * xattrdirvp in the case of an error.  (xattrdir_node has the original
3345331Samw 	 * hold on the vnode, which the smb_node_release() call below will
3355331Samw 	 * release.)
3365331Samw 	 */
3375331Samw 	if (snode == NULL) {
3385331Samw 		VN_HOLD(xattrdirvp);
3395331Samw 	}
3405331Samw 	(void) smb_node_release(xattrdir_node);
3415331Samw 	return (snode);
3425331Samw }
3435331Samw 
3445331Samw 
3455331Samw /*
3465331Samw  * This function should be called whenever a reference is needed on an
3475331Samw  * smb_node pointer.  The copy of an smb_node pointer from one non-local
3485331Samw  * data structure to another requires a reference to be taken on the smb_node
3495331Samw  * (unless the usage is localized).  Each data structure deallocation routine
3505331Samw  * will call smb_node_release() on its smb_node pointers.
3515331Samw  *
3525331Samw  * In general, an smb_node pointer residing in a structure should never be
3535331Samw  * stale.  A node pointer may be NULL, however, and care should be taken
3545331Samw  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
3555331Samw  * Care also needs to be taken with respect to racing deallocations of a
3565331Samw  * structure.
3575331Samw  */
3585331Samw 
3595331Samw void
3605331Samw smb_node_ref(smb_node_t *node)
3615331Samw {
3625331Samw 	ASSERT(node);
3635331Samw 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
3645331Samw 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
3655331Samw 
3665331Samw 	smb_rwx_xenter(&node->n_lock);
3675331Samw 	node->n_refcnt++;
3685331Samw 	ASSERT(node->n_refcnt);
3695331Samw 	DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
3705331Samw 	smb_audit_node(node);
3715331Samw 	smb_rwx_xexit(&node->n_lock);
3725331Samw }
3735331Samw 
3745331Samw /*
3755331Samw  * smb_node_lookup() takes a hold on an smb_node, whether found in the
3765331Samw  * hash table or newly created.  This hold is expected to be released
3775331Samw  * in the following manner.
3785331Samw  *
3795331Samw  * smb_node_lookup() takes an address of an smb_node pointer.  This should
3805331Samw  * be getting passed down via a lookup (whether path name or component), mkdir,
3815331Samw  * create.  If the original smb_node pointer resides in a data structure, then
3825331Samw  * the deallocation routine for the data structure is responsible for calling
3835331Samw  * smb_node_release() on the smb_node pointer.  Alternatively,
3845331Samw  * smb_node_release() can be called as soon as the smb_node pointer is no longer
3855331Samw  * needed.  In this case, callers are responsible for setting an embedded
3865331Samw  * pointer to NULL if it is known that the last reference is being released.
3875331Samw  *
3885331Samw  * If the passed-in address of the smb_node pointer belongs to a local variable,
3895331Samw  * then the caller with the local variable should call smb_node_release()
3905331Samw  * directly.
3915331Samw  *
3925331Samw  * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
3935331Samw  * as smb_node_lookup() takes a hold on dir_snode.
3945331Samw  */
3955331Samw 
3965331Samw void
3975331Samw smb_node_release(smb_node_t *node)
3985331Samw {
3995331Samw 	ASSERT(node);
4005331Samw 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
4015331Samw 
4025331Samw 	smb_rwx_xenter(&node->n_lock);
4035331Samw 	ASSERT(node->n_refcnt);
4045331Samw 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
4055331Samw 	if (--node->n_refcnt == 0) {
4065331Samw 		switch (node->n_state) {
4075331Samw 
4085331Samw 		case SMB_NODE_STATE_AVAILABLE:
4095331Samw 			node->n_state = SMB_NODE_STATE_DESTROYING;
4105331Samw 			smb_rwx_xexit(&node->n_lock);
4115331Samw 
4125331Samw 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
4135331Samw 			smb_llist_remove(node->n_hash_bucket, node);
4145331Samw 			smb_llist_exit(node->n_hash_bucket);
4155331Samw 
4165331Samw 			/*
4175331Samw 			 * Check if the file was deleted
4185331Samw 			 */
4195331Samw 			smb_node_delete_on_close(node);
4205331Samw 			node->n_magic = (uint32_t)~SMB_NODE_MAGIC;
4215331Samw 
4225331Samw 			/* These lists should be empty. */
4235331Samw 			smb_llist_destructor(&node->n_ofile_list);
4245331Samw 			smb_llist_destructor(&node->n_lock_list);
4255331Samw 
4265331Samw 			if (node->dir_snode) {
4275331Samw 				ASSERT(node->dir_snode->n_magic ==
4285331Samw 				    SMB_NODE_MAGIC);
4295331Samw 				smb_node_release(node->dir_snode);
4305331Samw 			}
4315331Samw 
4325331Samw 			if (node->unnamed_stream_node) {
4335331Samw 				ASSERT(node->unnamed_stream_node->n_magic ==
4345331Samw 				    SMB_NODE_MAGIC);
4355331Samw 				smb_node_release(node->unnamed_stream_node);
4365331Samw 			}
4375331Samw 
4385331Samw 			ASSERT(node->vp);
4395331Samw 			VN_RELE(node->vp);
4405331Samw 
4415331Samw 			smb_audit_buf_node_destroy(node);
4425331Samw 			smb_rwx_destroy(&node->n_lock);
4435331Samw 			kmem_cache_free(smb_info.si_cache_node, node);
4445331Samw 			++smb_node_free;
4455331Samw 			return;
4465331Samw 
4475331Samw 		default:
4485331Samw 			ASSERT(0);
4495331Samw 			break;
4505331Samw 		}
4515331Samw 	}
4525331Samw 	smb_audit_node(node);
4535331Samw 	smb_rwx_xexit(&node->n_lock);
4545331Samw }
4555331Samw 
4565331Samw static void
4575331Samw smb_node_delete_on_close(smb_node_t *node)
4585331Samw {
4595331Samw 	smb_node_t	*d_snode;
4605331Samw 	int		rc = 0;
4615331Samw 
4625331Samw 	d_snode = node->dir_snode;
4635331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
4645331Samw 
4655331Samw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
4665331Samw 		ASSERT(node->od_name != NULL);
4675331Samw 		if (node->attr.sa_vattr.va_type == VDIR)
4685331Samw 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
4695331Samw 			    d_snode, node->od_name, 1);
4705331Samw 		else
4715331Samw 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
4725331Samw 			    d_snode, node->od_name, 1);
4735331Samw 		smb_cred_rele(node->delete_on_close_cred);
4745331Samw 	}
4755331Samw 	if (rc != 0)
4765331Samw 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
4775331Samw 		    node->od_name, rc);
4785331Samw 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
4795331Samw }
4805331Samw 
4815331Samw /*
4825331Samw  * smb_node_rename()
4835331Samw  *
4845331Samw  */
4855331Samw int
4865331Samw smb_node_rename(
4875331Samw     smb_node_t	*from_dir_snode,
4885331Samw     smb_node_t	*ret_snode,
4895331Samw     smb_node_t	*to_dir_snode,
4905331Samw     char	*to_name)
4915331Samw {
4925331Samw 	ASSERT(from_dir_snode);
4935331Samw 	ASSERT(to_dir_snode);
4945331Samw 	ASSERT(ret_snode);
4955331Samw 	ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC);
4965331Samw 	ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC);
4975331Samw 	ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC);
4985331Samw 	ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
4995331Samw 	ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
5005331Samw 	ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE);
5015331Samw 
5025331Samw 	smb_node_ref(to_dir_snode);
5035331Samw 	smb_rwx_xenter(&ret_snode->n_lock);
5045331Samw 	ret_snode->dir_snode = to_dir_snode;
5055331Samw 	smb_rwx_xexit(&ret_snode->n_lock);
5065331Samw 	ASSERT(to_dir_snode->dir_snode != ret_snode);
5075331Samw 	ASSERT((to_dir_snode->vp->v_xattrdir) ||
5085331Samw 	    (to_dir_snode->vp->v_type == VDIR));
5095331Samw 	smb_node_release(from_dir_snode);
5105331Samw 
5115331Samw 	(void) strcpy(ret_snode->od_name, to_name);
5125331Samw 
5135331Samw 	/*
5145331Samw 	 * XXX Need to update attributes?
5155331Samw 	 */
5165331Samw 
5175331Samw 	return (0);
5185331Samw }
5195331Samw 
5205331Samw int
5215331Samw smb_node_root_init()
5225331Samw {
5235331Samw 	smb_attr_t va;
5245331Samw 
5255331Samw 	/*
5265331Samw 	 * Take an explicit hold on rootdir.  This goes with the
5275331Samw 	 * corresponding release in smb_node_root_fini()/smb_node_release().
5285331Samw 	 */
5295331Samw 
5305331Samw 	VN_HOLD(rootdir);
5315331Samw 
5325331Samw 	if ((smb_info.si_root_smb_node = smb_node_lookup(NULL, NULL, kcred,
5335331Samw 	    rootdir, ROOTVOL, NULL, NULL, &va)) == NULL)
5345331Samw 		return (-1);
5355331Samw 	else
5365331Samw 		return (0);
5375331Samw }
5385331Samw 
5395331Samw void
5405331Samw smb_node_root_fini()
5415331Samw {
5425331Samw 	if (smb_info.si_root_smb_node) {
5435331Samw 		smb_node_release(smb_info.si_root_smb_node);
5445331Samw 		smb_info.si_root_smb_node = NULL;
5455331Samw 	}
5465331Samw }
5475331Samw 
5485331Samw /*
5495331Samw  * smb_node_get_size
5505331Samw  */
5515331Samw uint64_t
5525331Samw smb_node_get_size(
5535331Samw     smb_node_t		*node,
5545331Samw     smb_attr_t		*attr)
5555331Samw {
5565331Samw 	uint64_t	size;
5575331Samw 
5585331Samw 	if (attr->sa_vattr.va_type == VDIR)
5595331Samw 		return (0);
5605331Samw 
5615331Samw 	smb_rwx_xenter(&node->n_lock);
5625331Samw 	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
5635331Samw 		size = node->n_size;
5645331Samw 	else
5655331Samw 		size = attr->sa_vattr.va_size;
5665331Samw 	smb_rwx_xexit(&node->n_lock);
5675331Samw 	return (size);
5685331Samw }
5695331Samw 
5705331Samw static int
5715331Samw timeval_cmp(timestruc_t *a, timestruc_t *b)
5725331Samw {
5735331Samw 	if (a->tv_sec < b->tv_sec)
5745331Samw 		return (-1);
5755331Samw 	if (a->tv_sec > b->tv_sec)
5765331Samw 		return (1);
5775331Samw 	/* Seconds are equal compare tv_nsec */
5785331Samw 	if (a->tv_nsec < b->tv_nsec)
5795331Samw 		return (-1);
5805331Samw 	return (a->tv_nsec > b->tv_nsec);
5815331Samw }
5825331Samw 
5835331Samw /*
5845331Samw  * smb_node_set_time
5855331Samw  *
5865331Samw  * This function will update the time stored in the node and
5875331Samw  * set the appropriate flags. If there is nothing to update
5885331Samw  * or the node is readonly, the function would return without
5895331Samw  * any updates. The update is only in the node level and the
5905331Samw  * attribute in the file system will be updated when client
5915331Samw  * close the file.
5925331Samw  */
5935331Samw void
5945331Samw smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
5955331Samw     struct timestruc *mtime, struct timestruc *atime,
5965331Samw     struct timestruc *ctime, unsigned int what)
5975331Samw {
5985331Samw 	smb_rwx_xenter(&node->n_lock);
5995331Samw 	if (node->flags & NODE_READ_ONLY || what == 0) {
6005331Samw 		smb_rwx_xexit(&node->n_lock);
6015331Samw 		return;
6025331Samw 	}
6035331Samw 
6045331Samw 	if ((what & SMB_AT_CRTIME && crtime == 0) ||
6055331Samw 	    (what & SMB_AT_MTIME && mtime == 0) ||
6065331Samw 	    (what & SMB_AT_ATIME && atime == 0) ||
6075331Samw 	    (what & SMB_AT_CTIME && ctime == 0)) {
6085331Samw 		smb_rwx_xexit(&node->n_lock);
6095331Samw 		return;
6105331Samw 	}
6115331Samw 
6125331Samw 	if ((what & SMB_AT_CRTIME) &&
6135331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
6145331Samw 	    crtime) != 0) {
6155331Samw 		node->what |= SMB_AT_CRTIME;
6165331Samw 		node->attr.sa_crtime = *((timestruc_t *)crtime);
6175331Samw 	}
6185331Samw 
6195331Samw 	if ((what & SMB_AT_MTIME) &&
6205331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
6215331Samw 	    mtime) != 0) {
6225331Samw 		node->what |= SMB_AT_MTIME;
6235331Samw 		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
6245331Samw 	}
6255331Samw 
6265331Samw 	if ((what & SMB_AT_ATIME) &&
6275331Samw 	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
6285331Samw 	    atime) != 0) {
6295331Samw 			node->what |= SMB_AT_ATIME;
6305331Samw 			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
6315331Samw 	}
6325331Samw 
6335331Samw 	/*
6345331Samw 	 * The ctime handling is trickier. It has three scenarios.
6355331Samw 	 * 1. Only ctime need to be set and it is the same as the ctime
6365331Samw 	 *    stored in the node. (update not necessary)
6375331Samw 	 * 2. The ctime is the same as the ctime stored in the node but
6385331Samw 	 *    is not the only time need to be set. (update required)
6395331Samw 	 * 3. The ctime need to be set and is not the same as the ctime
6405331Samw 	 *    stored in the node. (update required)
6415331Samw 	 * Unlike other time setting, the ctime needs to be set even when
6425331Samw 	 * it is the same as the ctime in the node if there are other time
6435331Samw 	 * needs to be set (#2). This will ensure the ctime not being
6445331Samw 	 * updated when other times are being updated in the file system.
6455331Samw 	 *
6465331Samw 	 * Retained file rules:
6475331Samw 	 *
6485331Samw 	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
6495331Samw 	 *    request will be rejected by filesystem
6505331Samw 	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
6515331Samw 	 *    any request for changing ctime on these files should have
6525331Samw 	 *    been already rejected
6535331Samw 	 */
6545331Samw 	node->what |= SMB_AT_CTIME;
6555331Samw 	if (what & SMB_AT_CTIME) {
6565331Samw 		if ((what == SMB_AT_CTIME) &&
6575331Samw 		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
6585331Samw 		    ctime) == 0) {
6595331Samw 			node->what &= ~SMB_AT_CTIME;
6605331Samw 		} else {
6615331Samw 			gethrestime(&node->attr.sa_vattr.va_ctime);
6625331Samw 		}
6635331Samw 	} else {
6645331Samw 		gethrestime(&node->attr.sa_vattr.va_ctime);
6655331Samw 	}
6665331Samw 	smb_rwx_xexit(&node->n_lock);
6675331Samw }
6685331Samw 
6695331Samw 
6705331Samw timestruc_t *
6715331Samw smb_node_get_crtime(smb_node_t *node)
6725331Samw {
6735331Samw 	return ((timestruc_t *)&node->attr.sa_crtime);
6745331Samw }
6755331Samw 
6765331Samw timestruc_t *
6775331Samw smb_node_get_atime(smb_node_t *node)
6785331Samw {
6795331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
6805331Samw }
6815331Samw 
6825331Samw timestruc_t *
6835331Samw smb_node_get_ctime(smb_node_t *node)
6845331Samw {
6855331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
6865331Samw }
6875331Samw 
6885331Samw timestruc_t *
6895331Samw smb_node_get_mtime(smb_node_t *node)
6905331Samw {
6915331Samw 	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
6925331Samw }
6935331Samw 
6945331Samw /*
6955331Samw  * smb_node_set_dosattr
6965331Samw  *
6975331Samw  * Parse the specified DOS attributes and, if they have been modified,
6985331Samw  * update the node cache. This call should be followed by a
6995331Samw  * smb_sync_fsattr() call to write the attribute changes to filesystem.
7005331Samw  */
7015331Samw void
7025331Samw smb_node_set_dosattr(smb_node_t *node, uint32_t dos_attr)
7035331Samw {
7045331Samw 	unsigned int mode;  /* New mode */
7055331Samw 
7065331Samw 	mode = 0;
7075331Samw 
7085331Samw 	/* Handle the archive bit */
7095331Samw 	if (dos_attr & SMB_FA_ARCHIVE)
7105331Samw 		mode |= FILE_ATTRIBUTE_ARCHIVE;
7115331Samw 
7125331Samw 	/* Handle the readonly bit */
7135331Samw 	if (dos_attr & SMB_FA_READONLY)
7145331Samw 		mode |= FILE_ATTRIBUTE_READONLY;
7155331Samw 
7165331Samw 	/* Handle the hidden bit */
7175331Samw 	if (dos_attr & SMB_FA_HIDDEN)
7185331Samw 		mode |= FILE_ATTRIBUTE_HIDDEN;
7195331Samw 
7205331Samw 	/* Handle the system bit */
7215331Samw 	if (dos_attr & SMB_FA_SYSTEM)
7225331Samw 		mode |= FILE_ATTRIBUTE_SYSTEM;
7235331Samw 
7245331Samw 	smb_rwx_xenter(&node->n_lock);
7255331Samw 	if (node->attr.sa_dosattr != mode) {
7265331Samw 		node->attr.sa_dosattr = mode;
7275331Samw 		node->what |= SMB_AT_DOSATTR;
7285331Samw 	}
7295331Samw 	smb_rwx_xexit(&node->n_lock);
7305331Samw }
7315331Samw 
7325331Samw /*
7335331Samw  * smb_node_get_dosattr
7345331Samw  *
7355331Samw  * This function will get dos attribute using the node.
7365331Samw  */
7375331Samw uint32_t
7385331Samw smb_node_get_dosattr(smb_node_t *node)
7395331Samw {
7405331Samw 	return (smb_mode_to_dos_attributes(&node->attr));
7415331Samw }
7425331Samw 
7435331Samw int
7445331Samw smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
7455331Samw {
7465331Samw 	int	rc = -1;
7475331Samw 
7485331Samw 	smb_rwx_xenter(&node->n_lock);
7495331Samw 	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
7505331Samw 	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
7515331Samw 		crhold(cr);
7525331Samw 		node->delete_on_close_cred = cr;
7535331Samw 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
7545331Samw 		rc = 0;
7555331Samw 	}
7565331Samw 	smb_rwx_xexit(&node->n_lock);
7575331Samw 	return (rc);
7585331Samw }
7595331Samw 
7605331Samw void
7615331Samw smb_node_reset_delete_on_close(smb_node_t *node)
7625331Samw {
7635331Samw 	smb_rwx_xenter(&node->n_lock);
7645331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
7655331Samw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
7665331Samw 		crfree(node->delete_on_close_cred);
7675331Samw 		node->delete_on_close_cred = NULL;
7685331Samw 	}
7695331Samw 	smb_rwx_xexit(&node->n_lock);
7705331Samw }
771*5772Sas200622 
772*5772Sas200622 /*
773*5772Sas200622  * smb_node_share_check
774*5772Sas200622  *
775*5772Sas200622  * check file sharing rules for current open request
776*5772Sas200622  * against all existing opens for a file.
777*5772Sas200622  *
778*5772Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
779*5772Sas200622  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
780*5772Sas200622  */
781*5772Sas200622 uint32_t
782*5772Sas200622 smb_node_open_check(struct smb_node *node, cred_t *cr,
783*5772Sas200622     uint32_t desired_access, uint32_t share_access)
784*5772Sas200622 {
785*5772Sas200622 	smb_ofile_t *of;
786*5772Sas200622 	uint32_t status;
787*5772Sas200622 
788*5772Sas200622 	ASSERT(node);
789*5772Sas200622 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
790*5772Sas200622 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
791*5772Sas200622 
792*5772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
793*5772Sas200622 	of = smb_llist_head(&node->n_ofile_list);
794*5772Sas200622 	while (of) {
795*5772Sas200622 		status = smb_node_share_check(node, cr, desired_access,
796*5772Sas200622 		    share_access, of);
797*5772Sas200622 		if (status == NT_STATUS_SHARING_VIOLATION) {
798*5772Sas200622 			smb_llist_exit(&node->n_ofile_list);
799*5772Sas200622 			return (status);
800*5772Sas200622 		}
801*5772Sas200622 		of = smb_llist_next(&node->n_ofile_list, of);
802*5772Sas200622 	}
803*5772Sas200622 	smb_llist_exit(&node->n_ofile_list);
804*5772Sas200622 
805*5772Sas200622 	return (NT_STATUS_SUCCESS);
806*5772Sas200622 }
807*5772Sas200622 
808*5772Sas200622 /*
809*5772Sas200622  * smb_open_share_check
810*5772Sas200622  *
811*5772Sas200622  * check file sharing rules for current open request
812*5772Sas200622  * against the given existing open.
813*5772Sas200622  *
814*5772Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
815*5772Sas200622  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
816*5772Sas200622  */
817*5772Sas200622 uint32_t
818*5772Sas200622 smb_node_share_check(
819*5772Sas200622     struct smb_node *node,
820*5772Sas200622     cred_t *cr,
821*5772Sas200622     uint32_t desired_access,
822*5772Sas200622     uint32_t share_access,
823*5772Sas200622     smb_ofile_t *of)
824*5772Sas200622 {
825*5772Sas200622 	/*
826*5772Sas200622 	 * It appears that share modes are not relevant to
827*5772Sas200622 	 * directories, but this check will remain as it is not
828*5772Sas200622 	 * clear whether it was originally put here for a reason.
829*5772Sas200622 	 */
830*5772Sas200622 	if (node->attr.sa_vattr.va_type == VDIR) {
831*5772Sas200622 		if (SMB_DENY_RW(of->f_share_access) &&
832*5772Sas200622 		    (node->n_orig_uid != crgetuid(cr))) {
833*5772Sas200622 			return (NT_STATUS_SHARING_VIOLATION);
834*5772Sas200622 		}
835*5772Sas200622 
836*5772Sas200622 		return (NT_STATUS_SUCCESS);
837*5772Sas200622 	}
838*5772Sas200622 
839*5772Sas200622 	/* if it's just meta data */
840*5772Sas200622 	if ((of->f_granted_access & FILE_DATA_ALL) == 0)
841*5772Sas200622 		return (NT_STATUS_SUCCESS);
842*5772Sas200622 
843*5772Sas200622 	/*
844*5772Sas200622 	 * Check requested share access against the
845*5772Sas200622 	 * open granted (desired) access
846*5772Sas200622 	 */
847*5772Sas200622 	if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE))
848*5772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
849*5772Sas200622 
850*5772Sas200622 	if (SMB_DENY_READ(share_access) &&
851*5772Sas200622 	    (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE)))
852*5772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
853*5772Sas200622 
854*5772Sas200622 	if (SMB_DENY_WRITE(share_access) &&
855*5772Sas200622 	    (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
856*5772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
857*5772Sas200622 
858*5772Sas200622 	/* check requested desired access against the open share access */
859*5772Sas200622 	if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE))
860*5772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
861*5772Sas200622 
862*5772Sas200622 	if (SMB_DENY_READ(of->f_share_access) &&
863*5772Sas200622 	    (desired_access & (FILE_READ_DATA | FILE_EXECUTE)))
864*5772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
865*5772Sas200622 
866*5772Sas200622 	if (SMB_DENY_WRITE(of->f_share_access) &&
867*5772Sas200622 	    (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
868*5772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
869*5772Sas200622 
870*5772Sas200622 	return (NT_STATUS_SUCCESS);
871*5772Sas200622 }
872*5772Sas200622 
873*5772Sas200622 /*
874*5772Sas200622  * smb_rename_share_check
875*5772Sas200622  *
876*5772Sas200622  * An open file can be renamed if
877*5772Sas200622  *
878*5772Sas200622  *  1. isn't opened for data writing or deleting
879*5772Sas200622  *
880*5772Sas200622  *  2. Opened with "Deny Delete" share mode
881*5772Sas200622  *         But not opened for data reading or executing
882*5772Sas200622  *         (opened for accessing meta data)
883*5772Sas200622  */
884*5772Sas200622 
885*5772Sas200622 DWORD
886*5772Sas200622 smb_node_rename_check(struct smb_node *node)
887*5772Sas200622 {
888*5772Sas200622 	struct smb_ofile *open;
889*5772Sas200622 
890*5772Sas200622 	ASSERT(node);
891*5772Sas200622 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
892*5772Sas200622 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
893*5772Sas200622 
894*5772Sas200622 	/*
895*5772Sas200622 	 * Intra-CIFS check
896*5772Sas200622 	 */
897*5772Sas200622 
898*5772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
899*5772Sas200622 	open = smb_llist_head(&node->n_ofile_list);
900*5772Sas200622 	while (open) {
901*5772Sas200622 		if (open->f_granted_access &
902*5772Sas200622 		    (FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE)) {
903*5772Sas200622 			smb_llist_exit(&node->n_ofile_list);
904*5772Sas200622 			return (NT_STATUS_SHARING_VIOLATION);
905*5772Sas200622 		}
906*5772Sas200622 
907*5772Sas200622 		if ((open->f_share_access & FILE_SHARE_DELETE) == 0) {
908*5772Sas200622 			if (open->f_granted_access &
909*5772Sas200622 			    (FILE_READ_DATA | FILE_EXECUTE)) {
910*5772Sas200622 				smb_llist_exit(&node->n_ofile_list);
911*5772Sas200622 				return (NT_STATUS_SHARING_VIOLATION);
912*5772Sas200622 			}
913*5772Sas200622 		}
914*5772Sas200622 		open = smb_llist_next(&node->n_ofile_list, open);
915*5772Sas200622 	}
916*5772Sas200622 	smb_llist_exit(&node->n_ofile_list);
917*5772Sas200622 
918*5772Sas200622 	/*
919*5772Sas200622 	 * system-wide share check
920*5772Sas200622 	 */
921*5772Sas200622 
922*5772Sas200622 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
923*5772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
924*5772Sas200622 	else
925*5772Sas200622 		return (NT_STATUS_SUCCESS);
926*5772Sas200622 }
927*5772Sas200622 
928*5772Sas200622 /*
929*5772Sas200622  * smb_node_delete_check
930*5772Sas200622  *
931*5772Sas200622  * An open file can be deleted only if opened for
932*5772Sas200622  * accessing meta data. Share modes aren't important
933*5772Sas200622  * in this case.
934*5772Sas200622  *
935*5772Sas200622  * NOTE: there is another mechanism for deleting an
936*5772Sas200622  * open file that NT clients usually use.
937*5772Sas200622  * That's setting "Delete on close" flag for an open
938*5772Sas200622  * file.  In this way the file will be deleted after
939*5772Sas200622  * last close. This flag can be set by SmbTrans2SetFileInfo
940*5772Sas200622  * with FILE_DISPOSITION_INFO information level.
941*5772Sas200622  * For setting this flag, the file should be opened by
942*5772Sas200622  * DELETE access in the FID that is passed in the Trans2
943*5772Sas200622  * request.
944*5772Sas200622  */
945*5772Sas200622 DWORD
946*5772Sas200622 smb_node_delete_check(smb_node_t *node)
947*5772Sas200622 {
948*5772Sas200622 	smb_ofile_t *file;
949*5772Sas200622 
950*5772Sas200622 	ASSERT(node);
951*5772Sas200622 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
952*5772Sas200622 	ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
953*5772Sas200622 
954*5772Sas200622 	if (node->attr.sa_vattr.va_type == VDIR)
955*5772Sas200622 		return (NT_STATUS_SUCCESS);
956*5772Sas200622 
957*5772Sas200622 	/*
958*5772Sas200622 	 * intra-CIFS check
959*5772Sas200622 	 */
960*5772Sas200622 
961*5772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
962*5772Sas200622 	file = smb_llist_head(&node->n_ofile_list);
963*5772Sas200622 	while (file) {
964*5772Sas200622 		ASSERT(file->f_magic == SMB_OFILE_MAGIC);
965*5772Sas200622 		if (file->f_granted_access &
966*5772Sas200622 		    (FILE_READ_DATA |
967*5772Sas200622 		    FILE_WRITE_DATA |
968*5772Sas200622 		    FILE_APPEND_DATA |
969*5772Sas200622 		    FILE_EXECUTE |
970*5772Sas200622 		    DELETE)) {
971*5772Sas200622 			smb_llist_exit(&node->n_ofile_list);
972*5772Sas200622 			return (NT_STATUS_SHARING_VIOLATION);
973*5772Sas200622 		}
974*5772Sas200622 		file = smb_llist_next(&node->n_ofile_list, file);
975*5772Sas200622 	}
976*5772Sas200622 	smb_llist_exit(&node->n_ofile_list);
977*5772Sas200622 
978*5772Sas200622 	/*
979*5772Sas200622 	 * system-wide share check
980*5772Sas200622 	 */
981*5772Sas200622 
982*5772Sas200622 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
983*5772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
984*5772Sas200622 	else
985*5772Sas200622 		return (NT_STATUS_SUCCESS);
986*5772Sas200622 }
987*5772Sas200622 
988*5772Sas200622 /*
989*5772Sas200622  * smb_node_start_crit()
990*5772Sas200622  *
991*5772Sas200622  * Enter critical region for share reservations.
992*5772Sas200622  * See comments above smb_fsop_shrlock().
993*5772Sas200622  */
994*5772Sas200622 
995*5772Sas200622 void
996*5772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode)
997*5772Sas200622 {
998*5772Sas200622 	rw_enter(&node->n_share_lock, mode);
999*5772Sas200622 	nbl_start_crit(node->vp, mode);
1000*5772Sas200622 }
1001*5772Sas200622 
1002*5772Sas200622 /*
1003*5772Sas200622  * smb_node_end_crit()
1004*5772Sas200622  *
1005*5772Sas200622  * Exit critical region for share reservations.
1006*5772Sas200622  */
1007*5772Sas200622 
1008*5772Sas200622 void
1009*5772Sas200622 smb_node_end_crit(smb_node_t *node)
1010*5772Sas200622 {
1011*5772Sas200622 	nbl_end_crit(node->vp);
1012*5772Sas200622 	rw_exit(&node->n_share_lock);
1013*5772Sas200622 }
1014*5772Sas200622 
1015*5772Sas200622 int
1016*5772Sas200622 smb_node_in_crit(smb_node_t *node)
1017*5772Sas200622 {
1018*5772Sas200622 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock));
1019*5772Sas200622 }
1020