xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 12890:16985853e3aa)
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 /*
2212065SKeyur.Desai@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw  */
245331Samw /*
255331Samw  * SMB Node State Machine
265331Samw  * ----------------------
275331Samw  *
289021Samw@Sun.COM  *
299021Samw@Sun.COM  *		    +----------- Creation/Allocation
305331Samw  *		    |
319021Samw@Sun.COM  *		    | T0
325331Samw  *		    |
335331Samw  *		    v
34*12890SJoyce.McIntosh@Sun.COM  *    +----------------------------+
35*12890SJoyce.McIntosh@Sun.COM  *    |  SMB_NODE_STATE_AVAILABLE  |
36*12890SJoyce.McIntosh@Sun.COM  *    +----------------------------+
37*12890SJoyce.McIntosh@Sun.COM  *		    |
38*12890SJoyce.McIntosh@Sun.COM  *		    | T1
399021Samw@Sun.COM  *		    |
409021Samw@Sun.COM  *		    v
415331Samw  *    +-----------------------------+
429021Samw@Sun.COM  *    |  SMB_NODE_STATE_DESTROYING  |
439021Samw@Sun.COM  *    +-----------------------------+
449021Samw@Sun.COM  *		    |
459021Samw@Sun.COM  *		    |
46*12890SJoyce.McIntosh@Sun.COM  *		    | T2
479021Samw@Sun.COM  *		    |
489021Samw@Sun.COM  *		    +----------> Deletion/Free
495331Samw  *
505331Samw  * Transition T0
515331Samw  *
525331Samw  *    This transition occurs in smb_node_lookup(). If the node looked for is
535331Samw  *    not found in the has table a new node is created. The reference count is
545331Samw  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
555331Samw  *
565331Samw  * Transition T1
575331Samw  *
585331Samw  *    This transition occurs in smb_node_release(). If the reference count
595331Samw  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
605331Samw  *    reference count will be given out for that node.
615331Samw  *
62*12890SJoyce.McIntosh@Sun.COM  * Transition T2
635331Samw  *
645331Samw  *    This transition occurs in smb_node_release(). The structure is deleted.
655331Samw  *
665331Samw  * Comments
675331Samw  * --------
685331Samw  *
695331Samw  *    The reason the smb node has 2 states is the following synchronization
705331Samw  *    rule:
715331Samw  *
725331Samw  *    There's a mutex embedded in the node used to protect its fields and
735331Samw  *    there's a lock embedded in the bucket of the hash table the node belongs
745331Samw  *    to. To increment or to decrement the reference count the mutex must be
755331Samw  *    entered. To insert the node into the bucket and to remove it from the
765331Samw  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
775331Samw  *    lock) have to be entered, the lock has always to be entered first then
785331Samw  *    the mutex. This prevents a deadlock between smb_node_lookup() and
795331Samw  *    smb_node_release() from occurring. However, in smb_node_release() when the
805331Samw  *    reference count drops to zero and triggers the deletion of the node, the
815331Samw  *    mutex has to be released before entering the lock of the bucket (to
825331Samw  *    remove the node). This creates a window during which the node that is
835331Samw  *    about to be freed could be given out by smb_node_lookup(). To close that
845331Samw  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
855331Samw  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
865331Samw  *    state will indicate that the node should be treated as non existent (of
875331Samw  *    course the state of the node should be tested/updated under the
885331Samw  *    protection of the mutex).
895331Samw  */
9010966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
915331Samw #include <smbsrv/smb_fsops.h>
928934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h>
935331Samw #include <sys/pathname.h>
945331Samw #include <sys/sdt.h>
955772Sas200622 #include <sys/nbmlock.h>
9611963SAfshin.Ardakani@Sun.COM #include <fs/fs_reparse.h>
975331Samw 
988934SJose.Borrego@Sun.COM uint32_t smb_is_executable(char *);
998934SJose.Borrego@Sun.COM static void smb_node_delete_on_close(smb_node_t *);
1008934SJose.Borrego@Sun.COM static void smb_node_create_audit_buf(smb_node_t *, int);
1018934SJose.Borrego@Sun.COM static void smb_node_destroy_audit_buf(smb_node_t *);
1028934SJose.Borrego@Sun.COM static void smb_node_audit(smb_node_t *);
10310001SJoyce.McIntosh@Sun.COM static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
1048934SJose.Borrego@Sun.COM static void smb_node_free(smb_node_t *);
1058934SJose.Borrego@Sun.COM static int smb_node_constructor(void *, void *, int);
1068934SJose.Borrego@Sun.COM static void smb_node_destructor(void *, void *);
1078934SJose.Borrego@Sun.COM static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
10810504SKeyur.Desai@Sun.COM 
10910504SKeyur.Desai@Sun.COM static void smb_node_init_cached_data(smb_node_t *);
11010504SKeyur.Desai@Sun.COM static void smb_node_clear_cached_data(smb_node_t *);
11110504SKeyur.Desai@Sun.COM 
11210504SKeyur.Desai@Sun.COM static void smb_node_init_cached_timestamps(smb_node_t *, smb_attr_t *);
11310001SJoyce.McIntosh@Sun.COM static void smb_node_clear_cached_timestamps(smb_node_t *);
11410001SJoyce.McIntosh@Sun.COM static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *);
11510001SJoyce.McIntosh@Sun.COM static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *);
1165331Samw 
11710504SKeyur.Desai@Sun.COM static void smb_node_init_cached_allocsz(smb_node_t *, smb_attr_t *);
11810504SKeyur.Desai@Sun.COM static void smb_node_clear_cached_allocsz(smb_node_t *);
11910504SKeyur.Desai@Sun.COM static void smb_node_get_cached_allocsz(smb_node_t *, smb_attr_t *);
12010504SKeyur.Desai@Sun.COM static void smb_node_set_cached_allocsz(smb_node_t *, smb_attr_t *);
12111963SAfshin.Ardakani@Sun.COM static void smb_node_init_reparse(smb_node_t *, smb_attr_t *);
12211963SAfshin.Ardakani@Sun.COM static void smb_node_init_system(smb_node_t *);
12310504SKeyur.Desai@Sun.COM 
1245331Samw #define	VALIDATE_DIR_NODE(_dir_, _node_) \
1255331Samw     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
1265331Samw     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
12710122SJordan.Brown@Sun.COM     ASSERT((_dir_)->n_dnode != (_node_));
1285331Samw 
12910504SKeyur.Desai@Sun.COM /* round sz to DEV_BSIZE block */
13010504SKeyur.Desai@Sun.COM #define	SMB_ALLOCSZ(sz)	(((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
13110504SKeyur.Desai@Sun.COM 
1328934SJose.Borrego@Sun.COM static kmem_cache_t	*smb_node_cache = NULL;
1336139Sjb150015 static boolean_t	smb_node_initialized = B_FALSE;
1346139Sjb150015 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
1356139Sjb150015 
1366139Sjb150015 /*
1376139Sjb150015  * smb_node_init
1386139Sjb150015  *
1396139Sjb150015  * Initialization of the SMB node layer.
1406139Sjb150015  *
1416139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1426139Sjb150015  * thread makes the call.
1436139Sjb150015  */
1446139Sjb150015 int
smb_node_init(void)1456139Sjb150015 smb_node_init(void)
1466139Sjb150015 {
1476139Sjb150015 	int	i;
1486139Sjb150015 
1496139Sjb150015 	if (smb_node_initialized)
1506139Sjb150015 		return (0);
1518934SJose.Borrego@Sun.COM 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
1528934SJose.Borrego@Sun.COM 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
1538934SJose.Borrego@Sun.COM 	    NULL, NULL, NULL, 0);
1546139Sjb150015 
1556139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
1566139Sjb150015 		smb_llist_constructor(&smb_node_hash_table[i],
1576139Sjb150015 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
1586139Sjb150015 	}
1596139Sjb150015 	smb_node_initialized = B_TRUE;
1606139Sjb150015 	return (0);
1616139Sjb150015 }
1626139Sjb150015 
1636139Sjb150015 /*
1646139Sjb150015  * smb_node_fini
1656139Sjb150015  *
1666139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1676139Sjb150015  * thread makes the call.
1686139Sjb150015  */
1696139Sjb150015 void
smb_node_fini(void)1706139Sjb150015 smb_node_fini(void)
1716139Sjb150015 {
1726139Sjb150015 	int	i;
1736139Sjb150015 
1746139Sjb150015 	if (!smb_node_initialized)
1756139Sjb150015 		return;
1766139Sjb150015 
1776139Sjb150015 #ifdef DEBUG
1786139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
1796139Sjb150015 		smb_node_t	*node;
1806139Sjb150015 
1816139Sjb150015 		/*
1826139Sjb150015 		 * The following sequence is just intended for sanity check.
1836139Sjb150015 		 * This will have to be modified when the code goes into
1846139Sjb150015 		 * production.
1856139Sjb150015 		 *
1866139Sjb150015 		 * The SMB node hash table should be emtpy at this point. If the
1876139Sjb150015 		 * hash table is not empty a panic will be triggered.
1886139Sjb150015 		 *
1896139Sjb150015 		 * The reason why SMB nodes are still remaining in the hash
1906139Sjb150015 		 * table is problably due to a mismatch between calls to
1916139Sjb150015 		 * smb_node_lookup() and smb_node_release(). You must track that
1926139Sjb150015 		 * down.
1936139Sjb150015 		 */
1946139Sjb150015 		node = smb_llist_head(&smb_node_hash_table[i]);
1956139Sjb150015 		ASSERT(node == NULL);
1966139Sjb150015 	}
1976139Sjb150015 #endif
1986139Sjb150015 
1996139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
2006139Sjb150015 		smb_llist_destructor(&smb_node_hash_table[i]);
2016139Sjb150015 	}
2028934SJose.Borrego@Sun.COM 	kmem_cache_destroy(smb_node_cache);
2038934SJose.Borrego@Sun.COM 	smb_node_cache = NULL;
2046139Sjb150015 	smb_node_initialized = B_FALSE;
2056139Sjb150015 }
2066139Sjb150015 
2075331Samw /*
2085331Samw  * smb_node_lookup()
2095331Samw  *
2105331Samw  * NOTE: This routine should only be called by the file system interface layer,
2115331Samw  * and not by SMB.
2125331Samw  *
2135331Samw  * smb_node_lookup() is called upon successful lookup, mkdir, and create
2145331Samw  * (for both non-streams and streams).  In each of these cases, a held vnode is
2158670SJose.Borrego@Sun.COM  * passed into this routine.  If a new smb_node is created it will take its
2168670SJose.Borrego@Sun.COM  * own hold on the vnode.  The caller's hold therefore still belongs to, and
2178670SJose.Borrego@Sun.COM  * should be released by, the caller.
2185331Samw  *
2195331Samw  * A reference is taken on the smb_node whether found in the hash table
2205331Samw  * or newly created.
2215331Samw  *
2225331Samw  * If an smb_node needs to be created, a reference is also taken on the
22310122SJordan.Brown@Sun.COM  * dnode (if passed in).
2245331Samw  *
2255331Samw  * See smb_node_release() for details on the release of these references.
2265331Samw  */
2275331Samw 
2285331Samw /*ARGSUSED*/
2295331Samw smb_node_t *
smb_node_lookup(struct smb_request * sr,struct open_param * op,cred_t * cred,vnode_t * vp,char * od_name,smb_node_t * dnode,smb_node_t * unode)2305331Samw smb_node_lookup(
2315331Samw     struct smb_request	*sr,
2325331Samw     struct open_param	*op,
2335331Samw     cred_t		*cred,
2345331Samw     vnode_t		*vp,
2355331Samw     char		*od_name,
23610122SJordan.Brown@Sun.COM     smb_node_t		*dnode,
23710122SJordan.Brown@Sun.COM     smb_node_t		*unode)
2385331Samw {
2395331Samw 	smb_llist_t		*node_hdr;
2405331Samw 	smb_node_t		*node;
24110001SJoyce.McIntosh@Sun.COM 	smb_attr_t		attr;
2425331Samw 	uint32_t		hashkey = 0;
2437348SJose.Borrego@Sun.COM 	fsid_t			fsid;
2445331Samw 	int			error;
2455331Samw 	krw_t			lock_mode;
2465331Samw 	vnode_t			*unnamed_vp = NULL;
2475331Samw 
2485331Samw 	/*
2495331Samw 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
2505331Samw 	 * because the node may not yet exist.  We also do not want to call
2515331Samw 	 * it with the list lock held.
2525331Samw 	 */
2535331Samw 
25410122SJordan.Brown@Sun.COM 	if (unode)
25510122SJordan.Brown@Sun.COM 		unnamed_vp = unode->vp;
2565331Samw 
2575331Samw 	/*
2585331Samw 	 * This getattr is performed on behalf of the server
2595331Samw 	 * that's why kcred is used not the user's cred
2605331Samw 	 */
26110001SJoyce.McIntosh@Sun.COM 	attr.sa_mask = SMB_AT_ALL;
26210001SJoyce.McIntosh@Sun.COM 	error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, kcred);
2635331Samw 	if (error)
2645331Samw 		return (NULL);
2655331Samw 
2667348SJose.Borrego@Sun.COM 	if (sr && sr->tid_tree) {
2677348SJose.Borrego@Sun.COM 		/*
2687348SJose.Borrego@Sun.COM 		 * The fsid for a file is that of the tree, even
2697348SJose.Borrego@Sun.COM 		 * if the file resides in a different mountpoint
2707348SJose.Borrego@Sun.COM 		 * under the share.
2717348SJose.Borrego@Sun.COM 		 */
2727348SJose.Borrego@Sun.COM 		fsid = SMB_TREE_FSID(sr->tid_tree);
2735331Samw 	} else {
2747348SJose.Borrego@Sun.COM 		/*
2757348SJose.Borrego@Sun.COM 		 * This should be getting executed only for the
2767348SJose.Borrego@Sun.COM 		 * tree root smb_node.
2777348SJose.Borrego@Sun.COM 		 */
2787348SJose.Borrego@Sun.COM 		fsid = vp->v_vfsp->vfs_fsid;
2795331Samw 	}
2805331Samw 
28110001SJoyce.McIntosh@Sun.COM 	node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
2825331Samw 	lock_mode = RW_READER;
2835331Samw 
2845331Samw 	smb_llist_enter(node_hdr, lock_mode);
2855331Samw 	for (;;) {
2865331Samw 		node = list_head(&node_hdr->ll_list);
2875331Samw 		while (node) {
2885331Samw 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
2895331Samw 			ASSERT(node->n_hash_bucket == node_hdr);
2905331Samw 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
2918934SJose.Borrego@Sun.COM 				mutex_enter(&node->n_mutex);
2925331Samw 				DTRACE_PROBE1(smb_node_lookup_hit,
2935331Samw 				    smb_node_t *, node);
2945331Samw 				switch (node->n_state) {
2955331Samw 				case SMB_NODE_STATE_AVAILABLE:
2965331Samw 					/* The node was found. */
2975331Samw 					node->n_refcnt++;
29810122SJordan.Brown@Sun.COM 					if ((node->n_dnode == NULL) &&
29910122SJordan.Brown@Sun.COM 					    (dnode != NULL) &&
30011633SJoyce.McIntosh@Sun.COM 					    (node != dnode) &&
3015331Samw 					    (strcmp(od_name, "..") != 0) &&
3025331Samw 					    (strcmp(od_name, ".") != 0)) {
30310122SJordan.Brown@Sun.COM 						VALIDATE_DIR_NODE(dnode, node);
30410122SJordan.Brown@Sun.COM 						node->n_dnode = dnode;
30510122SJordan.Brown@Sun.COM 						smb_node_ref(dnode);
3065331Samw 					}
3075331Samw 
3088934SJose.Borrego@Sun.COM 					smb_node_audit(node);
3098934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3105331Samw 					smb_llist_exit(node_hdr);
3115331Samw 					return (node);
3125331Samw 
3135331Samw 				case SMB_NODE_STATE_DESTROYING:
3145331Samw 					/*
3155331Samw 					 * Although the node exists it is about
3165331Samw 					 * to be destroyed. We act as it hasn't
3175331Samw 					 * been found.
3185331Samw 					 */
3198934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3205331Samw 					break;
3215331Samw 				default:
3225331Samw 					/*
3235331Samw 					 * Although the node exists it is in an
3245331Samw 					 * unknown state. We act as it hasn't
3255331Samw 					 * been found.
3265331Samw 					 */
3275331Samw 					ASSERT(0);
3288934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3295331Samw 					break;
3305331Samw 				}
3315331Samw 			}
3325331Samw 			node = smb_llist_next(node_hdr, node);
3335331Samw 		}
3345331Samw 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
3355331Samw 			lock_mode = RW_WRITER;
3365331Samw 			continue;
3375331Samw 		}
3385331Samw 		break;
3395331Samw 	}
34010001SJoyce.McIntosh@Sun.COM 	node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
34111963SAfshin.Ardakani@Sun.COM 	smb_node_init_reparse(node, &attr);
3425331Samw 
3435331Samw 	if (op)
3449343SAfshin.Ardakani@Sun.COM 		node->flags |= smb_is_executable(op->fqi.fq_last_comp);
3455331Samw 
34610122SJordan.Brown@Sun.COM 	if (dnode) {
34710122SJordan.Brown@Sun.COM 		smb_node_ref(dnode);
34810122SJordan.Brown@Sun.COM 		node->n_dnode = dnode;
34910122SJordan.Brown@Sun.COM 		ASSERT(dnode->n_dnode != node);
35010122SJordan.Brown@Sun.COM 		ASSERT((dnode->vp->v_xattrdir) ||
35110122SJordan.Brown@Sun.COM 		    (dnode->vp->v_type == VDIR));
3525331Samw 	}
3535331Samw 
35410122SJordan.Brown@Sun.COM 	if (unode) {
35510122SJordan.Brown@Sun.COM 		smb_node_ref(unode);
35610122SJordan.Brown@Sun.COM 		node->n_unode = unode;
3575331Samw 	}
3585331Samw 
35911963SAfshin.Ardakani@Sun.COM 	smb_node_init_system(node);
36011963SAfshin.Ardakani@Sun.COM 
3615331Samw 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
3628934SJose.Borrego@Sun.COM 	smb_node_audit(node);
3635331Samw 	smb_llist_insert_head(node_hdr, node);
3645331Samw 	smb_llist_exit(node_hdr);
3655331Samw 	return (node);
3665331Samw }
3675331Samw 
3685331Samw /*
3695331Samw  * smb_stream_node_lookup()
3705331Samw  *
3715331Samw  * Note: stream_name (the name that will be stored in the "od_name" field
3725331Samw  * of a stream's smb_node) is the same as the on-disk name for the stream
3735331Samw  * except that it does not have SMB_STREAM_PREFIX prepended.
3745331Samw  */
3755331Samw 
3765331Samw smb_node_t *
smb_stream_node_lookup(smb_request_t * sr,cred_t * cr,smb_node_t * fnode,vnode_t * xattrdirvp,vnode_t * vp,char * stream_name)3778934SJose.Borrego@Sun.COM smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
37810001SJoyce.McIntosh@Sun.COM     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
3795331Samw {
3805331Samw 	smb_node_t	*xattrdir_node;
3815331Samw 	smb_node_t	*snode;
3825331Samw 
3835331Samw 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
38410001SJoyce.McIntosh@Sun.COM 	    fnode, NULL);
3855331Samw 
3865331Samw 	if (xattrdir_node == NULL)
3875331Samw 		return (NULL);
3885331Samw 
3895331Samw 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
39010001SJoyce.McIntosh@Sun.COM 	    fnode);
3915331Samw 
3925331Samw 	(void) smb_node_release(xattrdir_node);
3935331Samw 	return (snode);
3945331Samw }
3955331Samw 
3965331Samw 
3975331Samw /*
3985331Samw  * This function should be called whenever a reference is needed on an
3995331Samw  * smb_node pointer.  The copy of an smb_node pointer from one non-local
4005331Samw  * data structure to another requires a reference to be taken on the smb_node
4015331Samw  * (unless the usage is localized).  Each data structure deallocation routine
4025331Samw  * will call smb_node_release() on its smb_node pointers.
4035331Samw  *
4045331Samw  * In general, an smb_node pointer residing in a structure should never be
4055331Samw  * stale.  A node pointer may be NULL, however, and care should be taken
4065331Samw  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
4075331Samw  * Care also needs to be taken with respect to racing deallocations of a
4085331Samw  * structure.
4095331Samw  */
4105331Samw void
smb_node_ref(smb_node_t * node)4115331Samw smb_node_ref(smb_node_t *node)
4125331Samw {
4138934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
4145331Samw 
4158934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
4168934SJose.Borrego@Sun.COM 	switch (node->n_state) {
4178934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
4188934SJose.Borrego@Sun.COM 		node->n_refcnt++;
4198934SJose.Borrego@Sun.COM 		ASSERT(node->n_refcnt);
4208934SJose.Borrego@Sun.COM 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
4218934SJose.Borrego@Sun.COM 		smb_node_audit(node);
4228934SJose.Borrego@Sun.COM 		break;
4238934SJose.Borrego@Sun.COM 	default:
4248934SJose.Borrego@Sun.COM 		SMB_PANIC();
4258934SJose.Borrego@Sun.COM 	}
4268934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
4275331Samw }
4285331Samw 
4295331Samw /*
4305331Samw  * smb_node_lookup() takes a hold on an smb_node, whether found in the
4315331Samw  * hash table or newly created.  This hold is expected to be released
4325331Samw  * in the following manner.
4335331Samw  *
4345331Samw  * smb_node_lookup() takes an address of an smb_node pointer.  This should
4355331Samw  * be getting passed down via a lookup (whether path name or component), mkdir,
4365331Samw  * create.  If the original smb_node pointer resides in a data structure, then
4375331Samw  * the deallocation routine for the data structure is responsible for calling
4385331Samw  * smb_node_release() on the smb_node pointer.  Alternatively,
4395331Samw  * smb_node_release() can be called as soon as the smb_node pointer is no longer
4405331Samw  * needed.  In this case, callers are responsible for setting an embedded
4415331Samw  * pointer to NULL if it is known that the last reference is being released.
4425331Samw  *
4435331Samw  * If the passed-in address of the smb_node pointer belongs to a local variable,
4445331Samw  * then the caller with the local variable should call smb_node_release()
4455331Samw  * directly.
4465331Samw  *
44710122SJordan.Brown@Sun.COM  * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
44810122SJordan.Brown@Sun.COM  * as smb_node_lookup() takes a hold on dnode.
4495331Samw  */
4505331Samw void
smb_node_release(smb_node_t * node)4515331Samw smb_node_release(smb_node_t *node)
4525331Samw {
4538934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
4545331Samw 
4558934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
4565331Samw 	ASSERT(node->n_refcnt);
4575331Samw 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
4585331Samw 	if (--node->n_refcnt == 0) {
4595331Samw 		switch (node->n_state) {
4605331Samw 
4615331Samw 		case SMB_NODE_STATE_AVAILABLE:
4625331Samw 			node->n_state = SMB_NODE_STATE_DESTROYING;
4638934SJose.Borrego@Sun.COM 			mutex_exit(&node->n_mutex);
4645331Samw 
4655331Samw 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
4665331Samw 			smb_llist_remove(node->n_hash_bucket, node);
4675331Samw 			smb_llist_exit(node->n_hash_bucket);
4685331Samw 
4695331Samw 			/*
4705331Samw 			 * Check if the file was deleted
4715331Samw 			 */
4725331Samw 			smb_node_delete_on_close(node);
4735331Samw 
47410122SJordan.Brown@Sun.COM 			if (node->n_dnode) {
47510122SJordan.Brown@Sun.COM 				ASSERT(node->n_dnode->n_magic ==
4765331Samw 				    SMB_NODE_MAGIC);
47710122SJordan.Brown@Sun.COM 				smb_node_release(node->n_dnode);
4785331Samw 			}
4795331Samw 
48010122SJordan.Brown@Sun.COM 			if (node->n_unode) {
48110122SJordan.Brown@Sun.COM 				ASSERT(node->n_unode->n_magic ==
4825331Samw 				    SMB_NODE_MAGIC);
48310122SJordan.Brown@Sun.COM 				smb_node_release(node->n_unode);
4845331Samw 			}
4855331Samw 
4868934SJose.Borrego@Sun.COM 			smb_node_free(node);
4875331Samw 			return;
4885331Samw 
4895331Samw 		default:
4908934SJose.Borrego@Sun.COM 			SMB_PANIC();
4915331Samw 		}
4925331Samw 	}
4938934SJose.Borrego@Sun.COM 	smb_node_audit(node);
4948934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
4955331Samw }
4965331Samw 
4975331Samw static void
smb_node_delete_on_close(smb_node_t * node)4985331Samw smb_node_delete_on_close(smb_node_t *node)
4995331Samw {
5005331Samw 	smb_node_t	*d_snode;
5015331Samw 	int		rc = 0;
5029231SAfshin.Ardakani@Sun.COM 	uint32_t	flags = 0;
5035331Samw 
50410122SJordan.Brown@Sun.COM 	d_snode = node->n_dnode;
5055331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
5069231SAfshin.Ardakani@Sun.COM 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
5079231SAfshin.Ardakani@Sun.COM 		flags = node->n_delete_on_close_flags;
5089231SAfshin.Ardakani@Sun.COM 		ASSERT(node->od_name != NULL);
5095331Samw 
51011963SAfshin.Ardakani@Sun.COM 		if (smb_node_is_dir(node))
5115331Samw 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
5129231SAfshin.Ardakani@Sun.COM 			    d_snode, node->od_name, flags);
5135331Samw 		else
5145331Samw 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
5159231SAfshin.Ardakani@Sun.COM 			    d_snode, node->od_name, flags);
51612508Samw@Sun.COM 		crfree(node->delete_on_close_cred);
5175331Samw 	}
5185331Samw 	if (rc != 0)
5195331Samw 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
5205331Samw 		    node->od_name, rc);
5215331Samw 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
5225331Samw }
5235331Samw 
5245331Samw /*
5255331Samw  * smb_node_rename()
5265331Samw  *
5275331Samw  */
5288934SJose.Borrego@Sun.COM void
smb_node_rename(smb_node_t * from_dnode,smb_node_t * ret_node,smb_node_t * to_dnode,char * to_name)5295331Samw smb_node_rename(
5308934SJose.Borrego@Sun.COM     smb_node_t	*from_dnode,
5318934SJose.Borrego@Sun.COM     smb_node_t	*ret_node,
5328934SJose.Borrego@Sun.COM     smb_node_t	*to_dnode,
5335331Samw     char	*to_name)
5345331Samw {
5358934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(from_dnode);
5368934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(to_dnode);
5378934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(ret_node);
5385331Samw 
5398934SJose.Borrego@Sun.COM 	smb_node_ref(to_dnode);
5408934SJose.Borrego@Sun.COM 	mutex_enter(&ret_node->n_mutex);
5418934SJose.Borrego@Sun.COM 	switch (ret_node->n_state) {
5428934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
54310122SJordan.Brown@Sun.COM 		ret_node->n_dnode = to_dnode;
5448934SJose.Borrego@Sun.COM 		mutex_exit(&ret_node->n_mutex);
54510122SJordan.Brown@Sun.COM 		ASSERT(to_dnode->n_dnode != ret_node);
5468934SJose.Borrego@Sun.COM 		ASSERT((to_dnode->vp->v_xattrdir) ||
5478934SJose.Borrego@Sun.COM 		    (to_dnode->vp->v_type == VDIR));
5488934SJose.Borrego@Sun.COM 		smb_node_release(from_dnode);
5498934SJose.Borrego@Sun.COM 		(void) strcpy(ret_node->od_name, to_name);
5508934SJose.Borrego@Sun.COM 		/*
5518934SJose.Borrego@Sun.COM 		 * XXX Need to update attributes?
5528934SJose.Borrego@Sun.COM 		 */
5538934SJose.Borrego@Sun.COM 		break;
5548934SJose.Borrego@Sun.COM 	default:
5558934SJose.Borrego@Sun.COM 		SMB_PANIC();
5568934SJose.Borrego@Sun.COM 	}
5575331Samw }
5585331Samw 
5595331Samw int
smb_node_root_init(vnode_t * vp,smb_server_t * sv,smb_node_t ** root)5606139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
5615331Samw {
56210001SJoyce.McIntosh@Sun.COM 	smb_attr_t	attr;
5636139Sjb150015 	int		error;
5646139Sjb150015 	uint32_t	hashkey;
5656139Sjb150015 	smb_llist_t	*node_hdr;
5666139Sjb150015 	smb_node_t	*node;
5675331Samw 
56810001SJoyce.McIntosh@Sun.COM 	attr.sa_mask = SMB_AT_ALL;
56910001SJoyce.McIntosh@Sun.COM 	error = smb_vop_getattr(vp, NULL, &attr, 0, kcred);
5706139Sjb150015 	if (error) {
5716139Sjb150015 		VN_RELE(vp);
5726139Sjb150015 		return (error);
5736139Sjb150015 	}
5746139Sjb150015 
57510001SJoyce.McIntosh@Sun.COM 	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &attr, &hashkey);
5765331Samw 
57710001SJoyce.McIntosh@Sun.COM 	node = smb_node_alloc(ROOTVOL, vp, node_hdr, hashkey);
5786139Sjb150015 
5796139Sjb150015 	sv->si_root_smb_node = node;
5808934SJose.Borrego@Sun.COM 	smb_node_audit(node);
5816139Sjb150015 	smb_llist_enter(node_hdr, RW_WRITER);
5826139Sjb150015 	smb_llist_insert_head(node_hdr, node);
5836139Sjb150015 	smb_llist_exit(node_hdr);
5846139Sjb150015 	*root = node;
5856139Sjb150015 	return (0);
5865331Samw }
5875331Samw 
5885331Samw /*
5899231SAfshin.Ardakani@Sun.COM  * When DeleteOnClose is set on an smb_node, the common open code will
5909231SAfshin.Ardakani@Sun.COM  * reject subsequent open requests for the file. Observation of Windows
5919231SAfshin.Ardakani@Sun.COM  * 2000 indicates that subsequent opens should be allowed (assuming
5929231SAfshin.Ardakani@Sun.COM  * there would be no sharing violation) until the file is closed using
5939231SAfshin.Ardakani@Sun.COM  * the fid on which the DeleteOnClose was requested.
5949231SAfshin.Ardakani@Sun.COM  *
5959231SAfshin.Ardakani@Sun.COM  * If there are multiple opens with delete-on-close create options,
5969231SAfshin.Ardakani@Sun.COM  * whichever the first file handle is closed will trigger the node to be
5979231SAfshin.Ardakani@Sun.COM  * marked as delete-on-close. The credentials of that ofile will be used
5989231SAfshin.Ardakani@Sun.COM  * as the delete-on-close credentials of the node.
5999231SAfshin.Ardakani@Sun.COM  */
6005331Samw int
smb_node_set_delete_on_close(smb_node_t * node,cred_t * cr,uint32_t flags)6019231SAfshin.Ardakani@Sun.COM smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
6025331Samw {
60310717Samw@Sun.COM 	int rc = 0;
60410001SJoyce.McIntosh@Sun.COM 	smb_attr_t attr;
6055331Samw 
60610717Samw@Sun.COM 	if (node->readonly_creator)
60710001SJoyce.McIntosh@Sun.COM 		return (-1);
60810001SJoyce.McIntosh@Sun.COM 
60910001SJoyce.McIntosh@Sun.COM 	bzero(&attr, sizeof (smb_attr_t));
61010001SJoyce.McIntosh@Sun.COM 	attr.sa_mask = SMB_AT_DOSATTR;
61110001SJoyce.McIntosh@Sun.COM 	rc = smb_fsop_getattr(NULL, kcred, node, &attr);
61210001SJoyce.McIntosh@Sun.COM 	if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
61310001SJoyce.McIntosh@Sun.COM 		return (-1);
61410001SJoyce.McIntosh@Sun.COM 	}
61510001SJoyce.McIntosh@Sun.COM 
61610717Samw@Sun.COM 	mutex_enter(&node->n_mutex);
61710717Samw@Sun.COM 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
61810717Samw@Sun.COM 		rc = -1;
61910717Samw@Sun.COM 	} else {
62010717Samw@Sun.COM 		crhold(cr);
62110717Samw@Sun.COM 		node->delete_on_close_cred = cr;
62210717Samw@Sun.COM 		node->n_delete_on_close_flags = flags;
62310717Samw@Sun.COM 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
62410717Samw@Sun.COM 		rc = 0;
62510717Samw@Sun.COM 	}
6268934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
62710717Samw@Sun.COM 	return (rc);
6285331Samw }
6295331Samw 
6305331Samw void
smb_node_reset_delete_on_close(smb_node_t * node)6315331Samw smb_node_reset_delete_on_close(smb_node_t *node)
6325331Samw {
6338934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
6345331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
6355331Samw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
6365331Samw 		crfree(node->delete_on_close_cred);
6375331Samw 		node->delete_on_close_cred = NULL;
6389231SAfshin.Ardakani@Sun.COM 		node->n_delete_on_close_flags = 0;
6395331Samw 	}
6408934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
6415331Samw }
6425772Sas200622 
6435772Sas200622 /*
6446771Sjb150015  * smb_node_open_check
6455772Sas200622  *
6465772Sas200622  * check file sharing rules for current open request
6475772Sas200622  * against all existing opens for a file.
6485772Sas200622  *
6495772Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
6505772Sas200622  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
6515772Sas200622  */
6525772Sas200622 uint32_t
smb_node_open_check(smb_node_t * node,uint32_t desired_access,uint32_t share_access)65311963SAfshin.Ardakani@Sun.COM smb_node_open_check(smb_node_t *node, uint32_t desired_access,
65411963SAfshin.Ardakani@Sun.COM     uint32_t share_access)
6555772Sas200622 {
6565772Sas200622 	smb_ofile_t *of;
6575772Sas200622 	uint32_t status;
6585772Sas200622 
6598934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
6605772Sas200622 
6615772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
6625772Sas200622 	of = smb_llist_head(&node->n_ofile_list);
6635772Sas200622 	while (of) {
66411963SAfshin.Ardakani@Sun.COM 		status = smb_ofile_open_check(of, desired_access, share_access);
6656771Sjb150015 
6666771Sjb150015 		switch (status) {
6676771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
6686771Sjb150015 		case NT_STATUS_SUCCESS:
6696771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
6706771Sjb150015 			break;
6716771Sjb150015 		default:
6726771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
6735772Sas200622 			smb_llist_exit(&node->n_ofile_list);
6745772Sas200622 			return (status);
6755772Sas200622 		}
6765772Sas200622 	}
6776771Sjb150015 
6785772Sas200622 	smb_llist_exit(&node->n_ofile_list);
6795772Sas200622 	return (NT_STATUS_SUCCESS);
6805772Sas200622 }
6815772Sas200622 
6825772Sas200622 uint32_t
smb_node_rename_check(smb_node_t * node)6838934SJose.Borrego@Sun.COM smb_node_rename_check(smb_node_t *node)
6845772Sas200622 {
6858934SJose.Borrego@Sun.COM 	smb_ofile_t	*of;
6868934SJose.Borrego@Sun.COM 	uint32_t	status;
6875772Sas200622 
6888934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
6895772Sas200622 
6905772Sas200622 	/*
6915772Sas200622 	 * Intra-CIFS check
6925772Sas200622 	 */
6935772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
6946771Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
6956771Sjb150015 	while (of) {
6966771Sjb150015 		status = smb_ofile_rename_check(of);
6975772Sas200622 
6986771Sjb150015 		switch (status) {
6996771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
7006771Sjb150015 		case NT_STATUS_SUCCESS:
7016771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
7026771Sjb150015 			break;
7036771Sjb150015 		default:
7046771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
7056771Sjb150015 			smb_llist_exit(&node->n_ofile_list);
7066771Sjb150015 			return (status);
7075772Sas200622 		}
7085772Sas200622 	}
7095772Sas200622 	smb_llist_exit(&node->n_ofile_list);
7105772Sas200622 
7115772Sas200622 	/*
7125772Sas200622 	 * system-wide share check
7135772Sas200622 	 */
7145772Sas200622 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
7155772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
7165772Sas200622 	else
7175772Sas200622 		return (NT_STATUS_SUCCESS);
7185772Sas200622 }
7195772Sas200622 
7206771Sjb150015 uint32_t
smb_node_delete_check(smb_node_t * node)7215772Sas200622 smb_node_delete_check(smb_node_t *node)
7225772Sas200622 {
7238934SJose.Borrego@Sun.COM 	smb_ofile_t	*of;
7248934SJose.Borrego@Sun.COM 	uint32_t	status;
7255772Sas200622 
7268934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
7275772Sas200622 
72811963SAfshin.Ardakani@Sun.COM 	if (smb_node_is_dir(node))
7295772Sas200622 		return (NT_STATUS_SUCCESS);
7305772Sas200622 
73111963SAfshin.Ardakani@Sun.COM 	if (smb_node_is_reparse(node))
73211963SAfshin.Ardakani@Sun.COM 		return (NT_STATUS_ACCESS_DENIED);
73311963SAfshin.Ardakani@Sun.COM 
7345772Sas200622 	/*
7355772Sas200622 	 * intra-CIFS check
7365772Sas200622 	 */
7375772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
7386771Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
7396771Sjb150015 	while (of) {
7406771Sjb150015 		status = smb_ofile_delete_check(of);
7416771Sjb150015 
7426771Sjb150015 		switch (status) {
7436771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
7446771Sjb150015 		case NT_STATUS_SUCCESS:
7456771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
7466771Sjb150015 			break;
7476771Sjb150015 		default:
7486771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
7495772Sas200622 			smb_llist_exit(&node->n_ofile_list);
7506771Sjb150015 			return (status);
7515772Sas200622 		}
7525772Sas200622 	}
7535772Sas200622 	smb_llist_exit(&node->n_ofile_list);
7545772Sas200622 
7555772Sas200622 	/*
7565772Sas200622 	 * system-wide share check
7575772Sas200622 	 */
7585772Sas200622 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
7595772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
7605772Sas200622 	else
7615772Sas200622 		return (NT_STATUS_SUCCESS);
7625772Sas200622 }
7635772Sas200622 
764*12890SJoyce.McIntosh@Sun.COM /*
765*12890SJoyce.McIntosh@Sun.COM  * smb_node_share_check
766*12890SJoyce.McIntosh@Sun.COM  *
767*12890SJoyce.McIntosh@Sun.COM  * Returns: TRUE    - ofiles have non-zero share access
768*12890SJoyce.McIntosh@Sun.COM  *          B_FALSE - ofile with share access NONE.
769*12890SJoyce.McIntosh@Sun.COM  */
770*12890SJoyce.McIntosh@Sun.COM boolean_t
smb_node_share_check(smb_node_t * node)771*12890SJoyce.McIntosh@Sun.COM smb_node_share_check(smb_node_t *node)
772*12890SJoyce.McIntosh@Sun.COM {
773*12890SJoyce.McIntosh@Sun.COM 	smb_ofile_t	*of;
774*12890SJoyce.McIntosh@Sun.COM 	boolean_t	status = B_TRUE;
775*12890SJoyce.McIntosh@Sun.COM 
776*12890SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
777*12890SJoyce.McIntosh@Sun.COM 
778*12890SJoyce.McIntosh@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_READER);
779*12890SJoyce.McIntosh@Sun.COM 	of = smb_llist_head(&node->n_ofile_list);
780*12890SJoyce.McIntosh@Sun.COM 	if (of)
781*12890SJoyce.McIntosh@Sun.COM 		status = smb_ofile_share_check(of);
782*12890SJoyce.McIntosh@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
783*12890SJoyce.McIntosh@Sun.COM 
784*12890SJoyce.McIntosh@Sun.COM 	return (status);
785*12890SJoyce.McIntosh@Sun.COM }
786*12890SJoyce.McIntosh@Sun.COM 
7879914Samw@Sun.COM void
smb_node_notify_change(smb_node_t * node)7889914Samw@Sun.COM smb_node_notify_change(smb_node_t *node)
7899914Samw@Sun.COM {
7909914Samw@Sun.COM 	SMB_NODE_VALID(node);
7919914Samw@Sun.COM 
7929914Samw@Sun.COM 	if (node->flags & NODE_FLAGS_NOTIFY_CHANGE) {
7939914Samw@Sun.COM 		node->flags |= NODE_FLAGS_CHANGED;
7949914Samw@Sun.COM 		smb_process_node_notify_change_queue(node);
7959914Samw@Sun.COM 	}
79611963SAfshin.Ardakani@Sun.COM 
79711963SAfshin.Ardakani@Sun.COM 	smb_node_notify_parents(node);
7989914Samw@Sun.COM }
7999914Samw@Sun.COM 
80011963SAfshin.Ardakani@Sun.COM /*
80111963SAfshin.Ardakani@Sun.COM  * smb_node_notify_parents
80211963SAfshin.Ardakani@Sun.COM  *
80311963SAfshin.Ardakani@Sun.COM  * Iterate up the directory tree notifying any parent
80411963SAfshin.Ardakani@Sun.COM  * directories that are being watched for changes in
80511963SAfshin.Ardakani@Sun.COM  * their sub directories.
80611963SAfshin.Ardakani@Sun.COM  * Stop at the root node, which has a NULL parent node.
80711963SAfshin.Ardakani@Sun.COM  */
80811963SAfshin.Ardakani@Sun.COM void
smb_node_notify_parents(smb_node_t * dnode)80911963SAfshin.Ardakani@Sun.COM smb_node_notify_parents(smb_node_t *dnode)
81011337SWilliam.Krier@Sun.COM {
81111963SAfshin.Ardakani@Sun.COM 	smb_node_t *pnode = dnode;
81211963SAfshin.Ardakani@Sun.COM 
81311963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(dnode);
81411337SWilliam.Krier@Sun.COM 
81511963SAfshin.Ardakani@Sun.COM 	while ((pnode = pnode->n_dnode) != NULL) {
81611963SAfshin.Ardakani@Sun.COM 		SMB_NODE_VALID(pnode);
81711963SAfshin.Ardakani@Sun.COM 		if ((pnode->flags & NODE_FLAGS_NOTIFY_CHANGE) &&
81811963SAfshin.Ardakani@Sun.COM 		    (pnode->flags & NODE_FLAGS_WATCH_TREE)) {
81911963SAfshin.Ardakani@Sun.COM 			pnode->flags |= NODE_FLAGS_CHANGED;
82011963SAfshin.Ardakani@Sun.COM 			smb_process_node_notify_change_queue(pnode);
82111963SAfshin.Ardakani@Sun.COM 		}
82211963SAfshin.Ardakani@Sun.COM 	}
82311337SWilliam.Krier@Sun.COM }
82411337SWilliam.Krier@Sun.COM 
8255772Sas200622 /*
8265772Sas200622  * smb_node_start_crit()
8275772Sas200622  *
8285772Sas200622  * Enter critical region for share reservations.
8295772Sas200622  * See comments above smb_fsop_shrlock().
8305772Sas200622  */
8315772Sas200622 void
smb_node_start_crit(smb_node_t * node,krw_t mode)8325772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode)
8335772Sas200622 {
8348934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, mode);
8355772Sas200622 	nbl_start_crit(node->vp, mode);
8365772Sas200622 }
8375772Sas200622 
8385772Sas200622 /*
8395772Sas200622  * smb_node_end_crit()
8405772Sas200622  *
8415772Sas200622  * Exit critical region for share reservations.
8425772Sas200622  */
8435772Sas200622 void
smb_node_end_crit(smb_node_t * node)8445772Sas200622 smb_node_end_crit(smb_node_t *node)
8455772Sas200622 {
8465772Sas200622 	nbl_end_crit(node->vp);
8478934SJose.Borrego@Sun.COM 	rw_exit(&node->n_lock);
8485772Sas200622 }
8495772Sas200622 
8505772Sas200622 int
smb_node_in_crit(smb_node_t * node)8515772Sas200622 smb_node_in_crit(smb_node_t *node)
8525772Sas200622 {
8538934SJose.Borrego@Sun.COM 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
8548934SJose.Borrego@Sun.COM }
8558934SJose.Borrego@Sun.COM 
8568934SJose.Borrego@Sun.COM void
smb_node_rdlock(smb_node_t * node)8578934SJose.Borrego@Sun.COM smb_node_rdlock(smb_node_t *node)
8588934SJose.Borrego@Sun.COM {
8598934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, RW_READER);
8608934SJose.Borrego@Sun.COM }
8618934SJose.Borrego@Sun.COM 
8628934SJose.Borrego@Sun.COM void
smb_node_wrlock(smb_node_t * node)8638934SJose.Borrego@Sun.COM smb_node_wrlock(smb_node_t *node)
8648934SJose.Borrego@Sun.COM {
8658934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, RW_WRITER);
8668934SJose.Borrego@Sun.COM }
8678934SJose.Borrego@Sun.COM 
8688934SJose.Borrego@Sun.COM void
smb_node_unlock(smb_node_t * node)8698934SJose.Borrego@Sun.COM smb_node_unlock(smb_node_t *node)
8708934SJose.Borrego@Sun.COM {
8718934SJose.Borrego@Sun.COM 	rw_exit(&node->n_lock);
8728934SJose.Borrego@Sun.COM }
8738934SJose.Borrego@Sun.COM 
8748934SJose.Borrego@Sun.COM void
smb_node_add_ofile(smb_node_t * node,smb_ofile_t * of)8758934SJose.Borrego@Sun.COM smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
8768934SJose.Borrego@Sun.COM {
8778934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
8788934SJose.Borrego@Sun.COM 
8798934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
8808934SJose.Borrego@Sun.COM 	smb_llist_insert_tail(&node->n_ofile_list, of);
8818934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
8828934SJose.Borrego@Sun.COM }
8838934SJose.Borrego@Sun.COM 
8848934SJose.Borrego@Sun.COM void
smb_node_rem_ofile(smb_node_t * node,smb_ofile_t * of)8858934SJose.Borrego@Sun.COM smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
8868934SJose.Borrego@Sun.COM {
8878934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
8888934SJose.Borrego@Sun.COM 
8898934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
8908934SJose.Borrego@Sun.COM 	smb_llist_remove(&node->n_ofile_list, of);
8918934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
8928934SJose.Borrego@Sun.COM }
8938934SJose.Borrego@Sun.COM 
89410001SJoyce.McIntosh@Sun.COM /*
89510001SJoyce.McIntosh@Sun.COM  * smb_node_inc_open_ofiles
89610001SJoyce.McIntosh@Sun.COM  */
8978934SJose.Borrego@Sun.COM void
smb_node_inc_open_ofiles(smb_node_t * node)8988934SJose.Borrego@Sun.COM smb_node_inc_open_ofiles(smb_node_t *node)
8998934SJose.Borrego@Sun.COM {
9008934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9018934SJose.Borrego@Sun.COM 
9028934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
9038934SJose.Borrego@Sun.COM 	node->n_open_count++;
9048934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
90510001SJoyce.McIntosh@Sun.COM 
90610504SKeyur.Desai@Sun.COM 	smb_node_init_cached_data(node);
9078934SJose.Borrego@Sun.COM }
9088934SJose.Borrego@Sun.COM 
90910001SJoyce.McIntosh@Sun.COM /*
91010001SJoyce.McIntosh@Sun.COM  * smb_node_dec_open_ofiles
91110001SJoyce.McIntosh@Sun.COM  */
9128934SJose.Borrego@Sun.COM void
smb_node_dec_open_ofiles(smb_node_t * node)9138934SJose.Borrego@Sun.COM smb_node_dec_open_ofiles(smb_node_t *node)
9148934SJose.Borrego@Sun.COM {
9158934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9168934SJose.Borrego@Sun.COM 
9178934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
9188934SJose.Borrego@Sun.COM 	node->n_open_count--;
9198934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
92010001SJoyce.McIntosh@Sun.COM 
92110504SKeyur.Desai@Sun.COM 	smb_node_clear_cached_data(node);
9228934SJose.Borrego@Sun.COM }
9238934SJose.Borrego@Sun.COM 
924*12890SJoyce.McIntosh@Sun.COM /*
925*12890SJoyce.McIntosh@Sun.COM  * smb_node_inc_opening_count
926*12890SJoyce.McIntosh@Sun.COM  */
927*12890SJoyce.McIntosh@Sun.COM void
smb_node_inc_opening_count(smb_node_t * node)928*12890SJoyce.McIntosh@Sun.COM smb_node_inc_opening_count(smb_node_t *node)
9298934SJose.Borrego@Sun.COM {
9308934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9318934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
932*12890SJoyce.McIntosh@Sun.COM 	node->n_opening_count++;
9338934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
934*12890SJoyce.McIntosh@Sun.COM }
935*12890SJoyce.McIntosh@Sun.COM 
936*12890SJoyce.McIntosh@Sun.COM /*
937*12890SJoyce.McIntosh@Sun.COM  * smb_node_dec_opening_count
938*12890SJoyce.McIntosh@Sun.COM  */
939*12890SJoyce.McIntosh@Sun.COM void
smb_node_dec_opening_count(smb_node_t * node)940*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(smb_node_t *node)
941*12890SJoyce.McIntosh@Sun.COM {
942*12890SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
943*12890SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
944*12890SJoyce.McIntosh@Sun.COM 	ASSERT(node->n_opening_count > 0);
945*12890SJoyce.McIntosh@Sun.COM 	node->n_opening_count--;
946*12890SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
9475772Sas200622 }
9488934SJose.Borrego@Sun.COM 
9498934SJose.Borrego@Sun.COM /*
95011963SAfshin.Ardakani@Sun.COM  * smb_node_getmntpath
95111963SAfshin.Ardakani@Sun.COM  */
95211963SAfshin.Ardakani@Sun.COM int
smb_node_getmntpath(smb_node_t * node,char * buf,uint32_t buflen)95311963SAfshin.Ardakani@Sun.COM smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen)
95411963SAfshin.Ardakani@Sun.COM {
95511963SAfshin.Ardakani@Sun.COM 	vnode_t *vp, *root_vp;
95611963SAfshin.Ardakani@Sun.COM 	vfs_t *vfsp;
95711963SAfshin.Ardakani@Sun.COM 	int err;
95811963SAfshin.Ardakani@Sun.COM 
95911963SAfshin.Ardakani@Sun.COM 	ASSERT(node);
96011963SAfshin.Ardakani@Sun.COM 	ASSERT(node->vp);
96111963SAfshin.Ardakani@Sun.COM 	ASSERT(node->vp->v_vfsp);
96211963SAfshin.Ardakani@Sun.COM 
96311963SAfshin.Ardakani@Sun.COM 	vp = node->vp;
96411963SAfshin.Ardakani@Sun.COM 	vfsp = vp->v_vfsp;
96511963SAfshin.Ardakani@Sun.COM 
96611963SAfshin.Ardakani@Sun.COM 	if (VFS_ROOT(vfsp, &root_vp))
96711963SAfshin.Ardakani@Sun.COM 		return (ENOENT);
96811963SAfshin.Ardakani@Sun.COM 
96911963SAfshin.Ardakani@Sun.COM 	VN_HOLD(vp);
97011963SAfshin.Ardakani@Sun.COM 
97111963SAfshin.Ardakani@Sun.COM 	/* NULL is passed in as we want to start at "/" */
97211963SAfshin.Ardakani@Sun.COM 	err = vnodetopath(NULL, root_vp, buf, buflen, kcred);
97311963SAfshin.Ardakani@Sun.COM 
97411963SAfshin.Ardakani@Sun.COM 	VN_RELE(vp);
97511963SAfshin.Ardakani@Sun.COM 	VN_RELE(root_vp);
97611963SAfshin.Ardakani@Sun.COM 	return (err);
97711963SAfshin.Ardakani@Sun.COM }
97811963SAfshin.Ardakani@Sun.COM 
97911963SAfshin.Ardakani@Sun.COM /*
98011963SAfshin.Ardakani@Sun.COM  * smb_node_getshrpath
98111963SAfshin.Ardakani@Sun.COM  *
98211963SAfshin.Ardakani@Sun.COM  * Determine the absolute pathname of 'node' within the share (tree).
98311963SAfshin.Ardakani@Sun.COM  * For example if the node represents file "test1.txt" in directory
98411963SAfshin.Ardakani@Sun.COM  * "dir1" the pathname would be: \dir1\test1.txt
98511963SAfshin.Ardakani@Sun.COM  */
98611963SAfshin.Ardakani@Sun.COM int
smb_node_getshrpath(smb_node_t * node,smb_tree_t * tree,char * buf,uint32_t buflen)98711963SAfshin.Ardakani@Sun.COM smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree,
98811963SAfshin.Ardakani@Sun.COM     char *buf, uint32_t buflen)
98911963SAfshin.Ardakani@Sun.COM {
99011963SAfshin.Ardakani@Sun.COM 	int rc;
99111963SAfshin.Ardakani@Sun.COM 
99212065SKeyur.Desai@Sun.COM 	ASSERT(node);
99312065SKeyur.Desai@Sun.COM 	ASSERT(tree);
99412065SKeyur.Desai@Sun.COM 	ASSERT(tree->t_snode);
99511963SAfshin.Ardakani@Sun.COM 
99612065SKeyur.Desai@Sun.COM 	rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen);
99712065SKeyur.Desai@Sun.COM 	(void) strsubst(buf, '/', '\\');
99812065SKeyur.Desai@Sun.COM 	return (rc);
99912065SKeyur.Desai@Sun.COM }
100011963SAfshin.Ardakani@Sun.COM 
100112065SKeyur.Desai@Sun.COM /*
100212065SKeyur.Desai@Sun.COM  * smb_node_getpath
100312065SKeyur.Desai@Sun.COM  *
100412065SKeyur.Desai@Sun.COM  * Determine the absolute pathname of 'node' from 'rootvp'.
100512065SKeyur.Desai@Sun.COM  *
100612065SKeyur.Desai@Sun.COM  * Using vnodetopath is only reliable for directory nodes (due to
100712065SKeyur.Desai@Sun.COM  * its reliance on the DNLC for non-directory nodes). Thus, if node
100812065SKeyur.Desai@Sun.COM  * represents a file, construct the pathname for the parent dnode
100912065SKeyur.Desai@Sun.COM  * and append filename.
101012065SKeyur.Desai@Sun.COM  * If node represents a named stream, construct the pathname for the
101112065SKeyur.Desai@Sun.COM  * associated unnamed stream and append the stream name.
101212065SKeyur.Desai@Sun.COM  *
101312065SKeyur.Desai@Sun.COM  * The pathname returned in buf will be '/' separated.
101412065SKeyur.Desai@Sun.COM  */
101512065SKeyur.Desai@Sun.COM int
smb_node_getpath(smb_node_t * node,vnode_t * rootvp,char * buf,uint32_t buflen)101612065SKeyur.Desai@Sun.COM smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen)
101712065SKeyur.Desai@Sun.COM {
101812065SKeyur.Desai@Sun.COM 	int rc;
101912065SKeyur.Desai@Sun.COM 	vnode_t *vp;
102012065SKeyur.Desai@Sun.COM 	smb_node_t *unode, *dnode;
102112065SKeyur.Desai@Sun.COM 
102212065SKeyur.Desai@Sun.COM 	unode = (SMB_IS_STREAM(node)) ? node->n_unode : node;
102312065SKeyur.Desai@Sun.COM 	dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode;
102411963SAfshin.Ardakani@Sun.COM 
102512065SKeyur.Desai@Sun.COM 	/* find path to directory node */
102612065SKeyur.Desai@Sun.COM 	vp = dnode->vp;
102712065SKeyur.Desai@Sun.COM 	VN_HOLD(vp);
102812065SKeyur.Desai@Sun.COM 	if (rootvp) {
102912065SKeyur.Desai@Sun.COM 		VN_HOLD(rootvp);
103012065SKeyur.Desai@Sun.COM 		rc = vnodetopath(rootvp, vp, buf, buflen, kcred);
103112065SKeyur.Desai@Sun.COM 		VN_RELE(rootvp);
103212065SKeyur.Desai@Sun.COM 	} else {
103312065SKeyur.Desai@Sun.COM 		rc = vnodetopath(NULL, vp, buf, buflen, kcred);
103412065SKeyur.Desai@Sun.COM 	}
103512065SKeyur.Desai@Sun.COM 	VN_RELE(vp);
103611963SAfshin.Ardakani@Sun.COM 
103712065SKeyur.Desai@Sun.COM 	if (rc != 0)
103812065SKeyur.Desai@Sun.COM 		return (rc);
103912065SKeyur.Desai@Sun.COM 
104012065SKeyur.Desai@Sun.COM 	/* append filename if necessary */
104112065SKeyur.Desai@Sun.COM 	if (!smb_node_is_dir(unode)) {
104212065SKeyur.Desai@Sun.COM 		if (buf[strlen(buf) - 1] != '/')
104312065SKeyur.Desai@Sun.COM 			(void) strlcat(buf, "/", buflen);
104412065SKeyur.Desai@Sun.COM 		(void) strlcat(buf, unode->od_name, buflen);
104511963SAfshin.Ardakani@Sun.COM 	}
104611963SAfshin.Ardakani@Sun.COM 
104712065SKeyur.Desai@Sun.COM 	/* append named stream name if necessary */
104812065SKeyur.Desai@Sun.COM 	if (SMB_IS_STREAM(node))
104912065SKeyur.Desai@Sun.COM 		(void) strlcat(buf, node->od_name, buflen);
105012065SKeyur.Desai@Sun.COM 
105111963SAfshin.Ardakani@Sun.COM 	return (rc);
105211963SAfshin.Ardakani@Sun.COM }
105311963SAfshin.Ardakani@Sun.COM 
105411963SAfshin.Ardakani@Sun.COM /*
10558934SJose.Borrego@Sun.COM  * smb_node_alloc
10568934SJose.Borrego@Sun.COM  */
10578934SJose.Borrego@Sun.COM static smb_node_t *
smb_node_alloc(char * od_name,vnode_t * vp,smb_llist_t * bucket,uint32_t hashkey)10588934SJose.Borrego@Sun.COM smb_node_alloc(
10598934SJose.Borrego@Sun.COM     char	*od_name,
10608934SJose.Borrego@Sun.COM     vnode_t	*vp,
10618934SJose.Borrego@Sun.COM     smb_llist_t	*bucket,
10628934SJose.Borrego@Sun.COM     uint32_t	hashkey)
10638934SJose.Borrego@Sun.COM {
10648934SJose.Borrego@Sun.COM 	smb_node_t	*node;
106511963SAfshin.Ardakani@Sun.COM 	vnode_t		*root_vp;
10668934SJose.Borrego@Sun.COM 
10678934SJose.Borrego@Sun.COM 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
10688934SJose.Borrego@Sun.COM 
10698934SJose.Borrego@Sun.COM 	if (node->n_audit_buf != NULL)
10708934SJose.Borrego@Sun.COM 		node->n_audit_buf->anb_index = 0;
10718934SJose.Borrego@Sun.COM 
107210001SJoyce.McIntosh@Sun.COM 	node->flags = 0;
10738934SJose.Borrego@Sun.COM 	VN_HOLD(vp);
10748934SJose.Borrego@Sun.COM 	node->vp = vp;
10758934SJose.Borrego@Sun.COM 	node->n_refcnt = 1;
10768934SJose.Borrego@Sun.COM 	node->n_hash_bucket = bucket;
10778934SJose.Borrego@Sun.COM 	node->n_hashkey = hashkey;
10788934SJose.Borrego@Sun.COM 	node->readonly_creator = NULL;
10798934SJose.Borrego@Sun.COM 	node->waiting_event = 0;
10808934SJose.Borrego@Sun.COM 	node->n_open_count = 0;
108110122SJordan.Brown@Sun.COM 	node->n_dnode = NULL;
108210122SJordan.Brown@Sun.COM 	node->n_unode = NULL;
10838934SJose.Borrego@Sun.COM 	node->delete_on_close_cred = NULL;
10849231SAfshin.Ardakani@Sun.COM 	node->n_delete_on_close_flags = 0;
1085*12890SJoyce.McIntosh@Sun.COM 	node->n_oplock.ol_fem = B_FALSE;
1086*12890SJoyce.McIntosh@Sun.COM 	node->n_oplock.ol_xthread = NULL;
1087*12890SJoyce.McIntosh@Sun.COM 	node->n_oplock.ol_count = 0;
1088*12890SJoyce.McIntosh@Sun.COM 	node->n_oplock.ol_break = SMB_OPLOCK_NO_BREAK;
10898934SJose.Borrego@Sun.COM 
10908934SJose.Borrego@Sun.COM 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
10918934SJose.Borrego@Sun.COM 	if (strcmp(od_name, XATTR_DIR) == 0)
10928934SJose.Borrego@Sun.COM 		node->flags |= NODE_XATTR_DIR;
10938934SJose.Borrego@Sun.COM 
109411963SAfshin.Ardakani@Sun.COM 	if (VFS_ROOT(vp->v_vfsp, &root_vp) == 0) {
109511963SAfshin.Ardakani@Sun.COM 		if (vp == root_vp)
109611963SAfshin.Ardakani@Sun.COM 			node->flags |= NODE_FLAGS_VFSROOT;
109711963SAfshin.Ardakani@Sun.COM 		VN_RELE(root_vp);
109811963SAfshin.Ardakani@Sun.COM 	}
109911963SAfshin.Ardakani@Sun.COM 
11008934SJose.Borrego@Sun.COM 	node->n_state = SMB_NODE_STATE_AVAILABLE;
11018934SJose.Borrego@Sun.COM 	node->n_magic = SMB_NODE_MAGIC;
110211963SAfshin.Ardakani@Sun.COM 
11038934SJose.Borrego@Sun.COM 	return (node);
11048934SJose.Borrego@Sun.COM }
11058934SJose.Borrego@Sun.COM 
11068934SJose.Borrego@Sun.COM /*
11078934SJose.Borrego@Sun.COM  * smb_node_free
11088934SJose.Borrego@Sun.COM  */
11098934SJose.Borrego@Sun.COM static void
smb_node_free(smb_node_t * node)11108934SJose.Borrego@Sun.COM smb_node_free(smb_node_t *node)
11118934SJose.Borrego@Sun.COM {
11128934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
11138934SJose.Borrego@Sun.COM 
11148934SJose.Borrego@Sun.COM 	node->n_magic = 0;
11158934SJose.Borrego@Sun.COM 	VERIFY(!list_link_active(&node->n_lnd));
11168934SJose.Borrego@Sun.COM 	VERIFY(node->n_lock_list.ll_count == 0);
11178934SJose.Borrego@Sun.COM 	VERIFY(node->n_ofile_list.ll_count == 0);
1118*12890SJoyce.McIntosh@Sun.COM 	VERIFY(node->n_oplock.ol_count == 0);
11198934SJose.Borrego@Sun.COM 	VERIFY(node->n_oplock.ol_xthread == NULL);
1120*12890SJoyce.McIntosh@Sun.COM 	VERIFY(node->n_oplock.ol_fem == B_FALSE);
11219021Samw@Sun.COM 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
11229021Samw@Sun.COM 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
11238934SJose.Borrego@Sun.COM 	VN_RELE(node->vp);
11248934SJose.Borrego@Sun.COM 	kmem_cache_free(smb_node_cache, node);
11258934SJose.Borrego@Sun.COM }
11268934SJose.Borrego@Sun.COM 
11278934SJose.Borrego@Sun.COM /*
11288934SJose.Borrego@Sun.COM  * smb_node_constructor
11298934SJose.Borrego@Sun.COM  */
11308934SJose.Borrego@Sun.COM static int
smb_node_constructor(void * buf,void * un,int kmflags)11318934SJose.Borrego@Sun.COM smb_node_constructor(void *buf, void *un, int kmflags)
11328934SJose.Borrego@Sun.COM {
11338934SJose.Borrego@Sun.COM 	_NOTE(ARGUNUSED(kmflags, un))
11348934SJose.Borrego@Sun.COM 
11358934SJose.Borrego@Sun.COM 	smb_node_t	*node = (smb_node_t *)buf;
11368934SJose.Borrego@Sun.COM 
11378934SJose.Borrego@Sun.COM 	bzero(node, sizeof (smb_node_t));
11388934SJose.Borrego@Sun.COM 
11398934SJose.Borrego@Sun.COM 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
11408934SJose.Borrego@Sun.COM 	    offsetof(smb_ofile_t, f_nnd));
11418934SJose.Borrego@Sun.COM 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
11428934SJose.Borrego@Sun.COM 	    offsetof(smb_lock_t, l_lnd));
11438934SJose.Borrego@Sun.COM 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
1144*12890SJoyce.McIntosh@Sun.COM 	mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL);
1145*12890SJoyce.McIntosh@Sun.COM 	list_create(&node->n_oplock.ol_grants, sizeof (smb_oplock_grant_t),
1146*12890SJoyce.McIntosh@Sun.COM 	    offsetof(smb_oplock_grant_t, og_lnd));
11478934SJose.Borrego@Sun.COM 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
11488934SJose.Borrego@Sun.COM 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
11498934SJose.Borrego@Sun.COM 	smb_node_create_audit_buf(node, kmflags);
11508934SJose.Borrego@Sun.COM 	return (0);
11518934SJose.Borrego@Sun.COM }
11528934SJose.Borrego@Sun.COM 
11538934SJose.Borrego@Sun.COM /*
11548934SJose.Borrego@Sun.COM  * smb_node_destructor
11558934SJose.Borrego@Sun.COM  */
11568934SJose.Borrego@Sun.COM static void
smb_node_destructor(void * buf,void * un)11578934SJose.Borrego@Sun.COM smb_node_destructor(void *buf, void *un)
11588934SJose.Borrego@Sun.COM {
11598934SJose.Borrego@Sun.COM 	_NOTE(ARGUNUSED(un))
11608934SJose.Borrego@Sun.COM 
11618934SJose.Borrego@Sun.COM 	smb_node_t	*node = (smb_node_t *)buf;
11628934SJose.Borrego@Sun.COM 
11638934SJose.Borrego@Sun.COM 	smb_node_destroy_audit_buf(node);
11648934SJose.Borrego@Sun.COM 	mutex_destroy(&node->n_mutex);
11658934SJose.Borrego@Sun.COM 	rw_destroy(&node->n_lock);
11668934SJose.Borrego@Sun.COM 	cv_destroy(&node->n_oplock.ol_cv);
1167*12890SJoyce.McIntosh@Sun.COM 	mutex_destroy(&node->n_oplock.ol_mutex);
11688934SJose.Borrego@Sun.COM 	smb_llist_destructor(&node->n_lock_list);
11698934SJose.Borrego@Sun.COM 	smb_llist_destructor(&node->n_ofile_list);
1170*12890SJoyce.McIntosh@Sun.COM 	list_destroy(&node->n_oplock.ol_grants);
11718934SJose.Borrego@Sun.COM }
11728934SJose.Borrego@Sun.COM 
11738934SJose.Borrego@Sun.COM /*
11748934SJose.Borrego@Sun.COM  * smb_node_create_audit_buf
11758934SJose.Borrego@Sun.COM  */
11768934SJose.Borrego@Sun.COM static void
smb_node_create_audit_buf(smb_node_t * node,int kmflags)11778934SJose.Borrego@Sun.COM smb_node_create_audit_buf(smb_node_t *node, int kmflags)
11788934SJose.Borrego@Sun.COM {
11798934SJose.Borrego@Sun.COM 	smb_audit_buf_node_t	*abn;
11808934SJose.Borrego@Sun.COM 
11818934SJose.Borrego@Sun.COM 	if (smb_audit_flags & SMB_AUDIT_NODE) {
11828934SJose.Borrego@Sun.COM 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
11838934SJose.Borrego@Sun.COM 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
11848934SJose.Borrego@Sun.COM 		node->n_audit_buf = abn;
11858934SJose.Borrego@Sun.COM 	}
11868934SJose.Borrego@Sun.COM }
11878934SJose.Borrego@Sun.COM 
11888934SJose.Borrego@Sun.COM /*
11898934SJose.Borrego@Sun.COM  * smb_node_destroy_audit_buf
11908934SJose.Borrego@Sun.COM  */
11918934SJose.Borrego@Sun.COM static void
smb_node_destroy_audit_buf(smb_node_t * node)11928934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(smb_node_t *node)
11938934SJose.Borrego@Sun.COM {
11948934SJose.Borrego@Sun.COM 	if (node->n_audit_buf != NULL) {
11958934SJose.Borrego@Sun.COM 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
11968934SJose.Borrego@Sun.COM 		node->n_audit_buf = NULL;
11978934SJose.Borrego@Sun.COM 	}
11988934SJose.Borrego@Sun.COM }
11998934SJose.Borrego@Sun.COM 
12008934SJose.Borrego@Sun.COM /*
12018934SJose.Borrego@Sun.COM  * smb_node_audit
12028934SJose.Borrego@Sun.COM  *
12038934SJose.Borrego@Sun.COM  * This function saves the calling stack in the audit buffer of the node passed
12048934SJose.Borrego@Sun.COM  * in.
12058934SJose.Borrego@Sun.COM  */
12068934SJose.Borrego@Sun.COM static void
smb_node_audit(smb_node_t * node)12078934SJose.Borrego@Sun.COM smb_node_audit(smb_node_t *node)
12088934SJose.Borrego@Sun.COM {
12098934SJose.Borrego@Sun.COM 	smb_audit_buf_node_t	*abn;
12108934SJose.Borrego@Sun.COM 	smb_audit_record_node_t	*anr;
12118934SJose.Borrego@Sun.COM 
12128934SJose.Borrego@Sun.COM 	if (node->n_audit_buf) {
12138934SJose.Borrego@Sun.COM 		abn = node->n_audit_buf;
12148934SJose.Borrego@Sun.COM 		anr = abn->anb_records;
12158934SJose.Borrego@Sun.COM 		anr += abn->anb_index;
12168934SJose.Borrego@Sun.COM 		abn->anb_index++;
12178934SJose.Borrego@Sun.COM 		abn->anb_index &= abn->anb_max_index;
12188934SJose.Borrego@Sun.COM 		anr->anr_refcnt = node->n_refcnt;
12198934SJose.Borrego@Sun.COM 		anr->anr_depth = getpcstack(anr->anr_stack,
12208934SJose.Borrego@Sun.COM 		    SMB_AUDIT_STACK_DEPTH);
12218934SJose.Borrego@Sun.COM 	}
12228934SJose.Borrego@Sun.COM }
12238934SJose.Borrego@Sun.COM 
12248934SJose.Borrego@Sun.COM static smb_llist_t *
smb_node_get_hash(fsid_t * fsid,smb_attr_t * attr,uint32_t * phashkey)12258934SJose.Borrego@Sun.COM smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
12268934SJose.Borrego@Sun.COM {
12278934SJose.Borrego@Sun.COM 	uint32_t	hashkey;
12288934SJose.Borrego@Sun.COM 
12298934SJose.Borrego@Sun.COM 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
12308934SJose.Borrego@Sun.COM 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
12318934SJose.Borrego@Sun.COM 	*phashkey = hashkey;
12328934SJose.Borrego@Sun.COM 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
12338934SJose.Borrego@Sun.COM }
123410001SJoyce.McIntosh@Sun.COM 
123510001SJoyce.McIntosh@Sun.COM boolean_t
smb_node_is_file(smb_node_t * node)123611963SAfshin.Ardakani@Sun.COM smb_node_is_file(smb_node_t *node)
123711963SAfshin.Ardakani@Sun.COM {
123811963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
123911963SAfshin.Ardakani@Sun.COM 	return (node->vp->v_type == VREG);
124011963SAfshin.Ardakani@Sun.COM }
124111963SAfshin.Ardakani@Sun.COM 
124211963SAfshin.Ardakani@Sun.COM boolean_t
smb_node_is_dir(smb_node_t * node)124310001SJoyce.McIntosh@Sun.COM smb_node_is_dir(smb_node_t *node)
124410001SJoyce.McIntosh@Sun.COM {
124510001SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
124611963SAfshin.Ardakani@Sun.COM 	return ((node->vp->v_type == VDIR) ||
124711963SAfshin.Ardakani@Sun.COM 	    (node->flags & NODE_FLAGS_DFSLINK));
124811963SAfshin.Ardakani@Sun.COM }
124911963SAfshin.Ardakani@Sun.COM 
125011963SAfshin.Ardakani@Sun.COM boolean_t
smb_node_is_symlink(smb_node_t * node)125111963SAfshin.Ardakani@Sun.COM smb_node_is_symlink(smb_node_t *node)
125211963SAfshin.Ardakani@Sun.COM {
125311963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
125411963SAfshin.Ardakani@Sun.COM 	return ((node->vp->v_type == VLNK) &&
125511963SAfshin.Ardakani@Sun.COM 	    ((node->flags & NODE_FLAGS_REPARSE) == 0));
125610001SJoyce.McIntosh@Sun.COM }
125710001SJoyce.McIntosh@Sun.COM 
125810001SJoyce.McIntosh@Sun.COM boolean_t
smb_node_is_dfslink(smb_node_t * node)125911963SAfshin.Ardakani@Sun.COM smb_node_is_dfslink(smb_node_t *node)
126011963SAfshin.Ardakani@Sun.COM {
126111963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
126211963SAfshin.Ardakani@Sun.COM 	return ((node->vp->v_type == VLNK) &&
126311963SAfshin.Ardakani@Sun.COM 	    (node->flags & NODE_FLAGS_DFSLINK));
126411963SAfshin.Ardakani@Sun.COM }
126511963SAfshin.Ardakani@Sun.COM 
126611963SAfshin.Ardakani@Sun.COM boolean_t
smb_node_is_reparse(smb_node_t * node)126711963SAfshin.Ardakani@Sun.COM smb_node_is_reparse(smb_node_t *node)
126810001SJoyce.McIntosh@Sun.COM {
126910001SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
127011963SAfshin.Ardakani@Sun.COM 	return ((node->vp->v_type == VLNK) &&
127111963SAfshin.Ardakani@Sun.COM 	    (node->flags & NODE_FLAGS_REPARSE));
127211963SAfshin.Ardakani@Sun.COM }
127311963SAfshin.Ardakani@Sun.COM 
127411963SAfshin.Ardakani@Sun.COM boolean_t
smb_node_is_vfsroot(smb_node_t * node)127511963SAfshin.Ardakani@Sun.COM smb_node_is_vfsroot(smb_node_t *node)
127611963SAfshin.Ardakani@Sun.COM {
127711963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
127811963SAfshin.Ardakani@Sun.COM 	return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT);
127911963SAfshin.Ardakani@Sun.COM }
128011963SAfshin.Ardakani@Sun.COM 
128111963SAfshin.Ardakani@Sun.COM boolean_t
smb_node_is_system(smb_node_t * node)128211963SAfshin.Ardakani@Sun.COM smb_node_is_system(smb_node_t *node)
128311963SAfshin.Ardakani@Sun.COM {
128411963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
128511963SAfshin.Ardakani@Sun.COM 	return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM);
128610001SJoyce.McIntosh@Sun.COM }
128710001SJoyce.McIntosh@Sun.COM 
128810001SJoyce.McIntosh@Sun.COM /*
128910001SJoyce.McIntosh@Sun.COM  * smb_node_file_is_readonly
129010001SJoyce.McIntosh@Sun.COM  *
129110001SJoyce.McIntosh@Sun.COM  * Checks if the file (which node represents) is marked readonly
129210001SJoyce.McIntosh@Sun.COM  * in the filesystem. No account is taken of any pending readonly
129310001SJoyce.McIntosh@Sun.COM  * in the node, which must be handled by the callers.
129410001SJoyce.McIntosh@Sun.COM  * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY)
129510001SJoyce.McIntosh@Sun.COM  */
129610001SJoyce.McIntosh@Sun.COM boolean_t
smb_node_file_is_readonly(smb_node_t * node)129710001SJoyce.McIntosh@Sun.COM smb_node_file_is_readonly(smb_node_t *node)
129810001SJoyce.McIntosh@Sun.COM {
129910001SJoyce.McIntosh@Sun.COM 	smb_attr_t attr;
130010001SJoyce.McIntosh@Sun.COM 
130110001SJoyce.McIntosh@Sun.COM 	if (node == NULL)
130210001SJoyce.McIntosh@Sun.COM 		return (B_FALSE);
130310001SJoyce.McIntosh@Sun.COM 
130410001SJoyce.McIntosh@Sun.COM 	bzero(&attr, sizeof (smb_attr_t));
130510001SJoyce.McIntosh@Sun.COM 	attr.sa_mask = SMB_AT_DOSATTR;
130610001SJoyce.McIntosh@Sun.COM 	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
130710001SJoyce.McIntosh@Sun.COM 	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
130810001SJoyce.McIntosh@Sun.COM }
130910001SJoyce.McIntosh@Sun.COM 
131010001SJoyce.McIntosh@Sun.COM /*
131110001SJoyce.McIntosh@Sun.COM  * smb_node_setattr
131210001SJoyce.McIntosh@Sun.COM  *
131310001SJoyce.McIntosh@Sun.COM  * The sr may be NULL, for example when closing an ofile.
131410001SJoyce.McIntosh@Sun.COM  * The ofile may be NULL, for example when a client request
131510001SJoyce.McIntosh@Sun.COM  * specifies the file by pathname.
131610001SJoyce.McIntosh@Sun.COM  *
131710504SKeyur.Desai@Sun.COM  * Timestamps
131810001SJoyce.McIntosh@Sun.COM  * When attributes are set on an ofile, any pending timestamps
131910001SJoyce.McIntosh@Sun.COM  * from a write request on the ofile are implicitly set to "now".
132010001SJoyce.McIntosh@Sun.COM  * For compatibility with windows the following timestamps are
132110001SJoyce.McIntosh@Sun.COM  * also implicitly set to now:
132210001SJoyce.McIntosh@Sun.COM  * - if any attribute is being explicitly set, set ctime to now
132310001SJoyce.McIntosh@Sun.COM  * - if file size is being explicitly set, set atime & ctime to now
132410001SJoyce.McIntosh@Sun.COM  *
132510504SKeyur.Desai@Sun.COM  * Any timestamp that is being explicitly set, or has previously
132610001SJoyce.McIntosh@Sun.COM  * been explicitly set on the ofile, is excluded from implicit
132710001SJoyce.McIntosh@Sun.COM  * (now) setting.
132810001SJoyce.McIntosh@Sun.COM  *
132910001SJoyce.McIntosh@Sun.COM  * Updates the node's cached timestamp values.
133010001SJoyce.McIntosh@Sun.COM  * Updates the ofile's explicit times flag.
133110001SJoyce.McIntosh@Sun.COM  *
133210504SKeyur.Desai@Sun.COM  * File allocation size
133310504SKeyur.Desai@Sun.COM  * When the file allocation size is set it is first rounded up
133410504SKeyur.Desai@Sun.COM  * to block size. If the file size is smaller than the allocation
133510504SKeyur.Desai@Sun.COM  * size the file is truncated by setting the filesize to allocsz.
133610504SKeyur.Desai@Sun.COM  * If there are open ofiles, the allocsz is cached on the node.
133710504SKeyur.Desai@Sun.COM  *
133810504SKeyur.Desai@Sun.COM  * Updates the node's cached allocsz value.
133910504SKeyur.Desai@Sun.COM  *
134010001SJoyce.McIntosh@Sun.COM  * Returns: errno
134110001SJoyce.McIntosh@Sun.COM  */
134210001SJoyce.McIntosh@Sun.COM int
smb_node_setattr(smb_request_t * sr,smb_node_t * node,cred_t * cr,smb_ofile_t * of,smb_attr_t * attr)134310001SJoyce.McIntosh@Sun.COM smb_node_setattr(smb_request_t *sr, smb_node_t *node,
134410001SJoyce.McIntosh@Sun.COM     cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
134510001SJoyce.McIntosh@Sun.COM {
134610001SJoyce.McIntosh@Sun.COM 	int rc;
134710504SKeyur.Desai@Sun.COM 	uint32_t pending_times = 0;
134810504SKeyur.Desai@Sun.COM 	uint32_t explicit_times = 0;
134910001SJoyce.McIntosh@Sun.COM 	timestruc_t now;
135010504SKeyur.Desai@Sun.COM 	smb_attr_t tmp_attr;
135110001SJoyce.McIntosh@Sun.COM 
135210001SJoyce.McIntosh@Sun.COM 	ASSERT(attr);
135310001SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
135410001SJoyce.McIntosh@Sun.COM 
135510504SKeyur.Desai@Sun.COM 	/* set attributes specified in attr */
135610504SKeyur.Desai@Sun.COM 	if (attr->sa_mask != 0) {
135710504SKeyur.Desai@Sun.COM 		/* if allocation size is < file size, truncate the file */
135810504SKeyur.Desai@Sun.COM 		if (attr->sa_mask & SMB_AT_ALLOCSZ) {
135910504SKeyur.Desai@Sun.COM 			attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
136010001SJoyce.McIntosh@Sun.COM 
136110504SKeyur.Desai@Sun.COM 			bzero(&tmp_attr, sizeof (smb_attr_t));
136210504SKeyur.Desai@Sun.COM 			tmp_attr.sa_mask = SMB_AT_SIZE;
136310504SKeyur.Desai@Sun.COM 			(void) smb_fsop_getattr(NULL, kcred, node, &tmp_attr);
136410001SJoyce.McIntosh@Sun.COM 
136510504SKeyur.Desai@Sun.COM 			if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) {
136610504SKeyur.Desai@Sun.COM 				attr->sa_vattr.va_size = attr->sa_allocsz;
136710504SKeyur.Desai@Sun.COM 				attr->sa_mask |= SMB_AT_SIZE;
136810504SKeyur.Desai@Sun.COM 			}
136910001SJoyce.McIntosh@Sun.COM 		}
137010504SKeyur.Desai@Sun.COM 
137110504SKeyur.Desai@Sun.COM 		rc = smb_fsop_setattr(sr, cr, node, attr);
137210504SKeyur.Desai@Sun.COM 		if (rc != 0)
137310504SKeyur.Desai@Sun.COM 			return (rc);
137410504SKeyur.Desai@Sun.COM 
137510504SKeyur.Desai@Sun.COM 		smb_node_set_cached_allocsz(node, attr);
137610504SKeyur.Desai@Sun.COM 		smb_node_set_cached_timestamps(node, attr);
137710504SKeyur.Desai@Sun.COM 		if (of) {
137810504SKeyur.Desai@Sun.COM 			smb_ofile_set_explicit_times(of,
137910504SKeyur.Desai@Sun.COM 			    (attr->sa_mask & SMB_AT_TIMES));
138010001SJoyce.McIntosh@Sun.COM 		}
138110001SJoyce.McIntosh@Sun.COM 	}
138210001SJoyce.McIntosh@Sun.COM 
138310504SKeyur.Desai@Sun.COM 	/*
138410504SKeyur.Desai@Sun.COM 	 * Determine which timestamps to implicitly set to "now".
138510504SKeyur.Desai@Sun.COM 	 * Don't overwrite timestamps already explicitly set.
138610504SKeyur.Desai@Sun.COM 	 */
138710504SKeyur.Desai@Sun.COM 	bzero(&tmp_attr, sizeof (smb_attr_t));
138810504SKeyur.Desai@Sun.COM 	gethrestime(&now);
138910504SKeyur.Desai@Sun.COM 	tmp_attr.sa_vattr.va_atime = now;
139010504SKeyur.Desai@Sun.COM 	tmp_attr.sa_vattr.va_mtime = now;
139110504SKeyur.Desai@Sun.COM 	tmp_attr.sa_vattr.va_ctime = now;
139210001SJoyce.McIntosh@Sun.COM 
139310504SKeyur.Desai@Sun.COM 	/* pending write timestamps */
139410504SKeyur.Desai@Sun.COM 	if (of) {
139510504SKeyur.Desai@Sun.COM 		if (smb_ofile_write_time_pending(of)) {
139610504SKeyur.Desai@Sun.COM 			pending_times |=
139710504SKeyur.Desai@Sun.COM 			    (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
139810504SKeyur.Desai@Sun.COM 		}
139910504SKeyur.Desai@Sun.COM 		explicit_times |= (smb_ofile_explicit_times(of));
140010504SKeyur.Desai@Sun.COM 	}
140110504SKeyur.Desai@Sun.COM 	explicit_times |= (attr->sa_mask & SMB_AT_TIMES);
140210504SKeyur.Desai@Sun.COM 	pending_times &= ~explicit_times;
140310001SJoyce.McIntosh@Sun.COM 
140410504SKeyur.Desai@Sun.COM 	if (pending_times) {
140510504SKeyur.Desai@Sun.COM 		tmp_attr.sa_mask = pending_times;
140610504SKeyur.Desai@Sun.COM 		(void) smb_fsop_setattr(NULL, kcred, node, &tmp_attr);
140710504SKeyur.Desai@Sun.COM 	}
140810001SJoyce.McIntosh@Sun.COM 
140910504SKeyur.Desai@Sun.COM 	/* additional timestamps to update in cache */
141010504SKeyur.Desai@Sun.COM 	if (attr->sa_mask)
141110504SKeyur.Desai@Sun.COM 		tmp_attr.sa_mask |= SMB_AT_CTIME;
141210504SKeyur.Desai@Sun.COM 	if (attr->sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ))
141310504SKeyur.Desai@Sun.COM 		tmp_attr.sa_mask |= SMB_AT_MTIME;
141410504SKeyur.Desai@Sun.COM 	tmp_attr.sa_mask &= ~explicit_times;
141510504SKeyur.Desai@Sun.COM 
141610504SKeyur.Desai@Sun.COM 	if (tmp_attr.sa_mask)
141710504SKeyur.Desai@Sun.COM 		smb_node_set_cached_timestamps(node, &tmp_attr);
141810001SJoyce.McIntosh@Sun.COM 
141911963SAfshin.Ardakani@Sun.COM 	if (tmp_attr.sa_mask & SMB_AT_MTIME || explicit_times & SMB_AT_MTIME) {
142011963SAfshin.Ardakani@Sun.COM 		if (node->n_dnode != NULL)
142111963SAfshin.Ardakani@Sun.COM 			smb_node_notify_change(node->n_dnode);
142211963SAfshin.Ardakani@Sun.COM 	}
142311337SWilliam.Krier@Sun.COM 
142410001SJoyce.McIntosh@Sun.COM 	return (0);
142510001SJoyce.McIntosh@Sun.COM }
142610001SJoyce.McIntosh@Sun.COM 
142710001SJoyce.McIntosh@Sun.COM /*
142810001SJoyce.McIntosh@Sun.COM  * smb_node_getattr
142910001SJoyce.McIntosh@Sun.COM  *
143010001SJoyce.McIntosh@Sun.COM  * Get attributes from the file system and apply any smb-specific
143110001SJoyce.McIntosh@Sun.COM  * overrides for size, dos attributes and timestamps
143210001SJoyce.McIntosh@Sun.COM  *
143310001SJoyce.McIntosh@Sun.COM  * node->readonly_creator reflects whether a readonly set is pending
143410001SJoyce.McIntosh@Sun.COM  * from a readonly create. The readonly attribute should be visible to
143510001SJoyce.McIntosh@Sun.COM  * all clients even though the readonly creator fid is immune to the
143610001SJoyce.McIntosh@Sun.COM  * readonly bit until close.
143710001SJoyce.McIntosh@Sun.COM  *
143810001SJoyce.McIntosh@Sun.COM  * Returns: errno
143910001SJoyce.McIntosh@Sun.COM  */
144010001SJoyce.McIntosh@Sun.COM int
smb_node_getattr(smb_request_t * sr,smb_node_t * node,smb_attr_t * attr)144110001SJoyce.McIntosh@Sun.COM smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
144210001SJoyce.McIntosh@Sun.COM {
144310001SJoyce.McIntosh@Sun.COM 	int rc;
144410001SJoyce.McIntosh@Sun.COM 
144510001SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
144610001SJoyce.McIntosh@Sun.COM 
144710001SJoyce.McIntosh@Sun.COM 	bzero(attr, sizeof (smb_attr_t));
144810001SJoyce.McIntosh@Sun.COM 	attr->sa_mask = SMB_AT_ALL;
144910001SJoyce.McIntosh@Sun.COM 	rc = smb_fsop_getattr(sr, kcred, node, attr);
145010001SJoyce.McIntosh@Sun.COM 	if (rc != 0)
145110001SJoyce.McIntosh@Sun.COM 		return (rc);
145210001SJoyce.McIntosh@Sun.COM 
145310001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
145410001SJoyce.McIntosh@Sun.COM 
145511963SAfshin.Ardakani@Sun.COM 	if (smb_node_is_dir(node)) {
145610001SJoyce.McIntosh@Sun.COM 		attr->sa_vattr.va_size = 0;
145710504SKeyur.Desai@Sun.COM 		attr->sa_allocsz = 0;
145810966SJordan.Brown@Sun.COM 		attr->sa_vattr.va_nlink = 1;
145910504SKeyur.Desai@Sun.COM 	}
146010001SJoyce.McIntosh@Sun.COM 
146110001SJoyce.McIntosh@Sun.COM 	if (node->readonly_creator)
146210001SJoyce.McIntosh@Sun.COM 		attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
146310001SJoyce.McIntosh@Sun.COM 	if (attr->sa_dosattr == 0)
146410001SJoyce.McIntosh@Sun.COM 		attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
146510001SJoyce.McIntosh@Sun.COM 
146610504SKeyur.Desai@Sun.COM 
146710001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
146810001SJoyce.McIntosh@Sun.COM 
146910504SKeyur.Desai@Sun.COM 	smb_node_get_cached_allocsz(node, attr);
147010001SJoyce.McIntosh@Sun.COM 	smb_node_get_cached_timestamps(node, attr);
147110504SKeyur.Desai@Sun.COM 
147210001SJoyce.McIntosh@Sun.COM 	return (0);
147310001SJoyce.McIntosh@Sun.COM }
147410001SJoyce.McIntosh@Sun.COM 
147510001SJoyce.McIntosh@Sun.COM /*
147610504SKeyur.Desai@Sun.COM  * smb_node_init_cached_data
147710504SKeyur.Desai@Sun.COM  */
147810504SKeyur.Desai@Sun.COM static void
smb_node_init_cached_data(smb_node_t * node)147910504SKeyur.Desai@Sun.COM smb_node_init_cached_data(smb_node_t *node)
148010504SKeyur.Desai@Sun.COM {
148110504SKeyur.Desai@Sun.COM 	smb_attr_t attr;
148210504SKeyur.Desai@Sun.COM 
148310504SKeyur.Desai@Sun.COM 	bzero(&attr, sizeof (smb_attr_t));
148410504SKeyur.Desai@Sun.COM 	attr.sa_mask = SMB_AT_ALL;
148510504SKeyur.Desai@Sun.COM 	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
148610504SKeyur.Desai@Sun.COM 
148710504SKeyur.Desai@Sun.COM 	smb_node_init_cached_allocsz(node, &attr);
148810504SKeyur.Desai@Sun.COM 	smb_node_init_cached_timestamps(node, &attr);
148910504SKeyur.Desai@Sun.COM }
149010504SKeyur.Desai@Sun.COM 
149110504SKeyur.Desai@Sun.COM /*
149210504SKeyur.Desai@Sun.COM  * smb_node_clear_cached_data
149310504SKeyur.Desai@Sun.COM  */
149410504SKeyur.Desai@Sun.COM static void
smb_node_clear_cached_data(smb_node_t * node)149510504SKeyur.Desai@Sun.COM smb_node_clear_cached_data(smb_node_t *node)
149610504SKeyur.Desai@Sun.COM {
149710504SKeyur.Desai@Sun.COM 	smb_node_clear_cached_allocsz(node);
149810504SKeyur.Desai@Sun.COM 	smb_node_clear_cached_timestamps(node);
149910504SKeyur.Desai@Sun.COM }
150010504SKeyur.Desai@Sun.COM 
150110504SKeyur.Desai@Sun.COM /*
150210504SKeyur.Desai@Sun.COM  * File allocation size (allocsz) caching
150310504SKeyur.Desai@Sun.COM  *
150410504SKeyur.Desai@Sun.COM  * When there are open ofiles on the node, the file allocsz is cached.
150510504SKeyur.Desai@Sun.COM  * The cached value (n_allocsz) is initialized when the first ofile is
150610504SKeyur.Desai@Sun.COM  * opened and cleared when the last is closed. Allocsz calculated from
150710504SKeyur.Desai@Sun.COM  * the filesize (rounded up to block size).
150810504SKeyur.Desai@Sun.COM  * When the allocation size is queried, if the cached allocsz is less
150910504SKeyur.Desai@Sun.COM  * than the filesize, it is recalculated from the filesize.
151010504SKeyur.Desai@Sun.COM  */
151110504SKeyur.Desai@Sun.COM 
151210504SKeyur.Desai@Sun.COM /*
151310504SKeyur.Desai@Sun.COM  * smb_node_init_cached_allocsz
151410504SKeyur.Desai@Sun.COM  *
151510504SKeyur.Desai@Sun.COM  * If there are open ofiles, cache the allocsz in the node.
151610504SKeyur.Desai@Sun.COM  * Calculate the allocsz from the filesizes.
151710504SKeyur.Desai@Sun.COM  * block size).
151810504SKeyur.Desai@Sun.COM  */
151910504SKeyur.Desai@Sun.COM static void
smb_node_init_cached_allocsz(smb_node_t * node,smb_attr_t * attr)152010504SKeyur.Desai@Sun.COM smb_node_init_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
152110504SKeyur.Desai@Sun.COM {
152210504SKeyur.Desai@Sun.COM 	mutex_enter(&node->n_mutex);
152310504SKeyur.Desai@Sun.COM 	if (node->n_open_count == 1)
152410504SKeyur.Desai@Sun.COM 		node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
152510504SKeyur.Desai@Sun.COM 	mutex_exit(&node->n_mutex);
152610504SKeyur.Desai@Sun.COM }
152710504SKeyur.Desai@Sun.COM 
152810504SKeyur.Desai@Sun.COM /*
152910504SKeyur.Desai@Sun.COM  * smb_node_clear_cached_allocsz
153010504SKeyur.Desai@Sun.COM  */
153110504SKeyur.Desai@Sun.COM static void
smb_node_clear_cached_allocsz(smb_node_t * node)153210504SKeyur.Desai@Sun.COM smb_node_clear_cached_allocsz(smb_node_t *node)
153310504SKeyur.Desai@Sun.COM {
153410504SKeyur.Desai@Sun.COM 	mutex_enter(&node->n_mutex);
153510504SKeyur.Desai@Sun.COM 	if (node->n_open_count == 0)
153610504SKeyur.Desai@Sun.COM 		node->n_allocsz = 0;
153710504SKeyur.Desai@Sun.COM 	mutex_exit(&node->n_mutex);
153810504SKeyur.Desai@Sun.COM }
153910504SKeyur.Desai@Sun.COM 
154010504SKeyur.Desai@Sun.COM /*
154110504SKeyur.Desai@Sun.COM  * smb_node_get_cached_allocsz
154210504SKeyur.Desai@Sun.COM  *
154310504SKeyur.Desai@Sun.COM  * If there is no cached allocsz (no open files), calculate
154410504SKeyur.Desai@Sun.COM  * allocsz from the filesize.
154510504SKeyur.Desai@Sun.COM  * If the allocsz is cached but is smaller than the filesize
154610504SKeyur.Desai@Sun.COM  * recalculate the cached allocsz from the filesize.
154710504SKeyur.Desai@Sun.COM  *
154810504SKeyur.Desai@Sun.COM  * Return allocs in attr->sa_allocsz.
154910504SKeyur.Desai@Sun.COM  */
155010504SKeyur.Desai@Sun.COM static void
smb_node_get_cached_allocsz(smb_node_t * node,smb_attr_t * attr)155110504SKeyur.Desai@Sun.COM smb_node_get_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
155210504SKeyur.Desai@Sun.COM {
155311963SAfshin.Ardakani@Sun.COM 	if (smb_node_is_dir(node))
155410504SKeyur.Desai@Sun.COM 		return;
155510504SKeyur.Desai@Sun.COM 
155610504SKeyur.Desai@Sun.COM 	mutex_enter(&node->n_mutex);
155710504SKeyur.Desai@Sun.COM 	if (node->n_open_count == 0) {
155810504SKeyur.Desai@Sun.COM 		attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
155910504SKeyur.Desai@Sun.COM 	} else {
156010504SKeyur.Desai@Sun.COM 		if (node->n_allocsz < attr->sa_vattr.va_size)
156110504SKeyur.Desai@Sun.COM 			node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
156210504SKeyur.Desai@Sun.COM 		attr->sa_allocsz = node->n_allocsz;
156310504SKeyur.Desai@Sun.COM 	}
156410504SKeyur.Desai@Sun.COM 	mutex_exit(&node->n_mutex);
156510504SKeyur.Desai@Sun.COM }
156610504SKeyur.Desai@Sun.COM 
156710504SKeyur.Desai@Sun.COM /*
156810504SKeyur.Desai@Sun.COM  * smb_node_set_cached_allocsz
156910504SKeyur.Desai@Sun.COM  *
157010504SKeyur.Desai@Sun.COM  * attr->sa_allocsz has already been rounded to block size by
157110504SKeyur.Desai@Sun.COM  * the caller.
157210504SKeyur.Desai@Sun.COM  */
157310504SKeyur.Desai@Sun.COM static void
smb_node_set_cached_allocsz(smb_node_t * node,smb_attr_t * attr)157410504SKeyur.Desai@Sun.COM smb_node_set_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
157510504SKeyur.Desai@Sun.COM {
157610504SKeyur.Desai@Sun.COM 	mutex_enter(&node->n_mutex);
157710504SKeyur.Desai@Sun.COM 	if (attr->sa_mask & SMB_AT_ALLOCSZ) {
157810504SKeyur.Desai@Sun.COM 		if (node->n_open_count > 0)
157910504SKeyur.Desai@Sun.COM 			node->n_allocsz = attr->sa_allocsz;
158010504SKeyur.Desai@Sun.COM 	}
158110504SKeyur.Desai@Sun.COM 	mutex_exit(&node->n_mutex);
158210504SKeyur.Desai@Sun.COM }
158310504SKeyur.Desai@Sun.COM 
158410504SKeyur.Desai@Sun.COM 
158510504SKeyur.Desai@Sun.COM /*
158610001SJoyce.McIntosh@Sun.COM  * Timestamp caching
158710001SJoyce.McIntosh@Sun.COM  *
158810001SJoyce.McIntosh@Sun.COM  * Solaris file systems handle timestamps different from NTFS. For
158910001SJoyce.McIntosh@Sun.COM  * example when file data is written NTFS doesn't update the timestamps
159010001SJoyce.McIntosh@Sun.COM  * until the file is closed, and then only if they haven't been explicity
159110001SJoyce.McIntosh@Sun.COM  * set via a set attribute request. In order to provide a more similar
159210001SJoyce.McIntosh@Sun.COM  * view of an open file's timestamps, we cache the timestamps in the
159310001SJoyce.McIntosh@Sun.COM  * node and manipulate them in a manner more consistent with windows.
159410001SJoyce.McIntosh@Sun.COM  * (See handling of explicit times and pending timestamps from a write
159510001SJoyce.McIntosh@Sun.COM  * request in smb_node_getattr and smb_node_setattr above.)
159610001SJoyce.McIntosh@Sun.COM  * Timestamps remain cached while there are open ofiles for the node.
159710001SJoyce.McIntosh@Sun.COM  * This includes open ofiles for named streams.
1598*12890SJoyce.McIntosh@Sun.COM  * n_ofile_list cannot be used as this doesn't include ofiles opened
159910001SJoyce.McIntosh@Sun.COM  * for the node's named streams. Thus n_timestamps contains a count
160010001SJoyce.McIntosh@Sun.COM  * of open ofiles (t_open_ofiles), including named streams' ofiles,
160110001SJoyce.McIntosh@Sun.COM  * to be used to control timestamp caching.
160210001SJoyce.McIntosh@Sun.COM  *
160310001SJoyce.McIntosh@Sun.COM  * If a node represents a named stream the associated unnamed streams
160410001SJoyce.McIntosh@Sun.COM  * cached timestamps are used instead.
160510001SJoyce.McIntosh@Sun.COM  */
160610001SJoyce.McIntosh@Sun.COM 
160710001SJoyce.McIntosh@Sun.COM /*
160810001SJoyce.McIntosh@Sun.COM  * smb_node_init_cached_timestamps
160910001SJoyce.McIntosh@Sun.COM  *
161010001SJoyce.McIntosh@Sun.COM  * Increment count of open ofiles which are using the cached timestamps.
161110001SJoyce.McIntosh@Sun.COM  * If this is the first open ofile, init the cached timestamps from the
161210001SJoyce.McIntosh@Sun.COM  * file system values.
161310001SJoyce.McIntosh@Sun.COM  */
161410001SJoyce.McIntosh@Sun.COM static void
smb_node_init_cached_timestamps(smb_node_t * node,smb_attr_t * attr)161510504SKeyur.Desai@Sun.COM smb_node_init_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
161610001SJoyce.McIntosh@Sun.COM {
161710001SJoyce.McIntosh@Sun.COM 	smb_node_t *unode;
161810001SJoyce.McIntosh@Sun.COM 
161910001SJoyce.McIntosh@Sun.COM 	if ((unode = SMB_IS_STREAM(node)) != NULL)
162010001SJoyce.McIntosh@Sun.COM 		node = unode;
162110001SJoyce.McIntosh@Sun.COM 
162210001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
162310001SJoyce.McIntosh@Sun.COM 	++(node->n_timestamps.t_open_ofiles);
162410001SJoyce.McIntosh@Sun.COM 	if (node->n_timestamps.t_open_ofiles == 1) {
162510504SKeyur.Desai@Sun.COM 		node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
162610504SKeyur.Desai@Sun.COM 		node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
162710504SKeyur.Desai@Sun.COM 		node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
162810504SKeyur.Desai@Sun.COM 		node->n_timestamps.t_crtime = attr->sa_crtime;
162910001SJoyce.McIntosh@Sun.COM 		node->n_timestamps.t_cached = B_TRUE;
163010001SJoyce.McIntosh@Sun.COM 	}
163110001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
163210001SJoyce.McIntosh@Sun.COM }
163310001SJoyce.McIntosh@Sun.COM 
163410001SJoyce.McIntosh@Sun.COM /*
163510001SJoyce.McIntosh@Sun.COM  * smb_node_clear_cached_timestamps
163610001SJoyce.McIntosh@Sun.COM  *
163710001SJoyce.McIntosh@Sun.COM  * Decrement count of open ofiles using the cached timestamps.
163810001SJoyce.McIntosh@Sun.COM  * If the decremented count is zero, clear the cached timestamps.
163910001SJoyce.McIntosh@Sun.COM  */
164010001SJoyce.McIntosh@Sun.COM static void
smb_node_clear_cached_timestamps(smb_node_t * node)164110001SJoyce.McIntosh@Sun.COM smb_node_clear_cached_timestamps(smb_node_t *node)
164210001SJoyce.McIntosh@Sun.COM {
164310001SJoyce.McIntosh@Sun.COM 	smb_node_t *unode;
164410001SJoyce.McIntosh@Sun.COM 
164510001SJoyce.McIntosh@Sun.COM 	if ((unode = SMB_IS_STREAM(node)) != NULL)
164610001SJoyce.McIntosh@Sun.COM 		node = unode;
164710001SJoyce.McIntosh@Sun.COM 
164810001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
164910001SJoyce.McIntosh@Sun.COM 	ASSERT(node->n_timestamps.t_open_ofiles > 0);
165010001SJoyce.McIntosh@Sun.COM 	--(node->n_timestamps.t_open_ofiles);
165110001SJoyce.McIntosh@Sun.COM 	if (node->n_timestamps.t_open_ofiles == 0)
165210001SJoyce.McIntosh@Sun.COM 		bzero(&node->n_timestamps, sizeof (smb_times_t));
165310001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
165410001SJoyce.McIntosh@Sun.COM }
165510001SJoyce.McIntosh@Sun.COM 
165610001SJoyce.McIntosh@Sun.COM /*
165710001SJoyce.McIntosh@Sun.COM  * smb_node_get_cached_timestamps
165810001SJoyce.McIntosh@Sun.COM  *
165910001SJoyce.McIntosh@Sun.COM  * Overwrite timestamps in attr with those cached in node.
166010001SJoyce.McIntosh@Sun.COM  */
166110001SJoyce.McIntosh@Sun.COM static void
smb_node_get_cached_timestamps(smb_node_t * node,smb_attr_t * attr)166210001SJoyce.McIntosh@Sun.COM smb_node_get_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
166310001SJoyce.McIntosh@Sun.COM {
166410001SJoyce.McIntosh@Sun.COM 	smb_node_t *unode;
166510001SJoyce.McIntosh@Sun.COM 
166610001SJoyce.McIntosh@Sun.COM 	if ((unode = SMB_IS_STREAM(node)) != NULL)
166710001SJoyce.McIntosh@Sun.COM 		node = unode;
166810001SJoyce.McIntosh@Sun.COM 
166910001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
167010001SJoyce.McIntosh@Sun.COM 	if (node->n_timestamps.t_cached) {
167110001SJoyce.McIntosh@Sun.COM 		attr->sa_vattr.va_mtime = node->n_timestamps.t_mtime;
167210001SJoyce.McIntosh@Sun.COM 		attr->sa_vattr.va_atime = node->n_timestamps.t_atime;
167310001SJoyce.McIntosh@Sun.COM 		attr->sa_vattr.va_ctime = node->n_timestamps.t_ctime;
167410001SJoyce.McIntosh@Sun.COM 		attr->sa_crtime = node->n_timestamps.t_crtime;
167510001SJoyce.McIntosh@Sun.COM 	}
167610001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
167710001SJoyce.McIntosh@Sun.COM }
167810001SJoyce.McIntosh@Sun.COM 
167910001SJoyce.McIntosh@Sun.COM /*
168010001SJoyce.McIntosh@Sun.COM  * smb_node_set_cached_timestamps
168110001SJoyce.McIntosh@Sun.COM  *
168210001SJoyce.McIntosh@Sun.COM  * Update the node's cached timestamps with values from attr.
168310001SJoyce.McIntosh@Sun.COM  */
168410001SJoyce.McIntosh@Sun.COM static void
smb_node_set_cached_timestamps(smb_node_t * node,smb_attr_t * attr)168510001SJoyce.McIntosh@Sun.COM smb_node_set_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
168610001SJoyce.McIntosh@Sun.COM {
168710001SJoyce.McIntosh@Sun.COM 	smb_node_t *unode;
168810001SJoyce.McIntosh@Sun.COM 
168910001SJoyce.McIntosh@Sun.COM 	if ((unode = SMB_IS_STREAM(node)) != NULL)
169010001SJoyce.McIntosh@Sun.COM 		node = unode;
169110001SJoyce.McIntosh@Sun.COM 
169210001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
169310001SJoyce.McIntosh@Sun.COM 	if (node->n_timestamps.t_cached) {
169410001SJoyce.McIntosh@Sun.COM 		if (attr->sa_mask & SMB_AT_MTIME)
169510001SJoyce.McIntosh@Sun.COM 			node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
169610001SJoyce.McIntosh@Sun.COM 		if (attr->sa_mask & SMB_AT_ATIME)
169710001SJoyce.McIntosh@Sun.COM 			node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
169810001SJoyce.McIntosh@Sun.COM 		if (attr->sa_mask & SMB_AT_CTIME)
169910001SJoyce.McIntosh@Sun.COM 			node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
170010001SJoyce.McIntosh@Sun.COM 		if (attr->sa_mask & SMB_AT_CRTIME)
170110001SJoyce.McIntosh@Sun.COM 			node->n_timestamps.t_crtime = attr->sa_crtime;
170210001SJoyce.McIntosh@Sun.COM 	}
170310001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
170410001SJoyce.McIntosh@Sun.COM }
170511963SAfshin.Ardakani@Sun.COM 
170611963SAfshin.Ardakani@Sun.COM /*
170711963SAfshin.Ardakani@Sun.COM  * Check to see if the node represents a reparse point.
170811963SAfshin.Ardakani@Sun.COM  * If yes, whether the reparse point contains a DFS link.
170911963SAfshin.Ardakani@Sun.COM  */
171011963SAfshin.Ardakani@Sun.COM static void
smb_node_init_reparse(smb_node_t * node,smb_attr_t * attr)171111963SAfshin.Ardakani@Sun.COM smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr)
171211963SAfshin.Ardakani@Sun.COM {
171311963SAfshin.Ardakani@Sun.COM 	nvlist_t *nvl;
171411963SAfshin.Ardakani@Sun.COM 	nvpair_t *rec;
171511963SAfshin.Ardakani@Sun.COM 	char *rec_type;
171611963SAfshin.Ardakani@Sun.COM 
171711963SAfshin.Ardakani@Sun.COM 	if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
171811963SAfshin.Ardakani@Sun.COM 		return;
171911963SAfshin.Ardakani@Sun.COM 
172011963SAfshin.Ardakani@Sun.COM 	if ((nvl = reparse_init()) == NULL)
172111963SAfshin.Ardakani@Sun.COM 		return;
172211963SAfshin.Ardakani@Sun.COM 
172311963SAfshin.Ardakani@Sun.COM 	if (reparse_vnode_parse(node->vp, nvl) != 0) {
172411963SAfshin.Ardakani@Sun.COM 		reparse_free(nvl);
172511963SAfshin.Ardakani@Sun.COM 		return;
172611963SAfshin.Ardakani@Sun.COM 	}
172711963SAfshin.Ardakani@Sun.COM 
172811963SAfshin.Ardakani@Sun.COM 	node->flags |= NODE_FLAGS_REPARSE;
172911963SAfshin.Ardakani@Sun.COM 
173011963SAfshin.Ardakani@Sun.COM 	rec = nvlist_next_nvpair(nvl, NULL);
173111963SAfshin.Ardakani@Sun.COM 	while (rec != NULL) {
173211963SAfshin.Ardakani@Sun.COM 		rec_type = nvpair_name(rec);
173311963SAfshin.Ardakani@Sun.COM 		if ((rec_type != NULL) &&
173411963SAfshin.Ardakani@Sun.COM 		    (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) {
173511963SAfshin.Ardakani@Sun.COM 			node->flags |= NODE_FLAGS_DFSLINK;
173611963SAfshin.Ardakani@Sun.COM 			break;
173711963SAfshin.Ardakani@Sun.COM 		}
173811963SAfshin.Ardakani@Sun.COM 		rec = nvlist_next_nvpair(nvl, rec);
173911963SAfshin.Ardakani@Sun.COM 	}
174011963SAfshin.Ardakani@Sun.COM 
174111963SAfshin.Ardakani@Sun.COM 	reparse_free(nvl);
174211963SAfshin.Ardakani@Sun.COM }
174311963SAfshin.Ardakani@Sun.COM 
174411963SAfshin.Ardakani@Sun.COM /*
174511963SAfshin.Ardakani@Sun.COM  * smb_node_init_system
174611963SAfshin.Ardakani@Sun.COM  *
174711963SAfshin.Ardakani@Sun.COM  * If the node represents a special system file set NODE_FLAG_SYSTEM.
174811963SAfshin.Ardakani@Sun.COM  * System files:
174911963SAfshin.Ardakani@Sun.COM  * - any node whose parent dnode has NODE_FLAG_SYSTEM set
175011963SAfshin.Ardakani@Sun.COM  * - any node whose associated unnamed stream node (unode) has
175111963SAfshin.Ardakani@Sun.COM  *   NODE_FLAG_SYSTEM set
175211963SAfshin.Ardakani@Sun.COM  * - .$EXTEND at root of share (quota management)
175311963SAfshin.Ardakani@Sun.COM  */
175411963SAfshin.Ardakani@Sun.COM static void
smb_node_init_system(smb_node_t * node)175511963SAfshin.Ardakani@Sun.COM smb_node_init_system(smb_node_t *node)
175611963SAfshin.Ardakani@Sun.COM {
175711963SAfshin.Ardakani@Sun.COM 	smb_node_t *dnode = node->n_dnode;
175811963SAfshin.Ardakani@Sun.COM 	smb_node_t *unode = node->n_unode;
175911963SAfshin.Ardakani@Sun.COM 
176011963SAfshin.Ardakani@Sun.COM 	if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) {
176111963SAfshin.Ardakani@Sun.COM 		node->flags |= NODE_FLAGS_SYSTEM;
176211963SAfshin.Ardakani@Sun.COM 		return;
176311963SAfshin.Ardakani@Sun.COM 	}
176411963SAfshin.Ardakani@Sun.COM 
176511963SAfshin.Ardakani@Sun.COM 	if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) {
176611963SAfshin.Ardakani@Sun.COM 		node->flags |= NODE_FLAGS_SYSTEM;
176711963SAfshin.Ardakani@Sun.COM 		return;
176811963SAfshin.Ardakani@Sun.COM 	}
176911963SAfshin.Ardakani@Sun.COM 
177011963SAfshin.Ardakani@Sun.COM 	if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) &&
177111963SAfshin.Ardakani@Sun.COM 	    (strcasecmp(node->od_name, ".$EXTEND") == 0))) {
177211963SAfshin.Ardakani@Sun.COM 		node->flags |= NODE_FLAGS_SYSTEM;
177311963SAfshin.Ardakani@Sun.COM 	}
177411963SAfshin.Ardakani@Sun.COM }
1775