xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 12508:edb7861a1533)
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
349021Samw@Sun.COM  *    +----------------------------+        T1
359021Samw@Sun.COM  *    |  SMB_NODE_STATE_AVAILABLE  |--------------------+
369021Samw@Sun.COM  *    +----------------------------+			|
379021Samw@Sun.COM  *		    |	     ^				|
389021Samw@Sun.COM  *		    |	     |				v
399021Samw@Sun.COM  *		    |	     |	  T2	+-------------------------------+
409021Samw@Sun.COM  *		    |	     |<---------| SMB_NODE_STATE_OPLOCK_GRANTED |
419021Samw@Sun.COM  *		    |	     |		+-------------------------------+
429021Samw@Sun.COM  *		    | T5     |				|
439021Samw@Sun.COM  *		    |	     |				| T3
449021Samw@Sun.COM  *		    |	     |				v
459021Samw@Sun.COM  *		    |	     |	  T4	+--------------------------------+
469021Samw@Sun.COM  *		    |	     +----------| SMB_NODE_STATE_OPLOCK_BREAKING |
479021Samw@Sun.COM  *		    |			+--------------------------------+
489021Samw@Sun.COM  *		    |
499021Samw@Sun.COM  *		    v
505331Samw  *    +-----------------------------+
519021Samw@Sun.COM  *    |  SMB_NODE_STATE_DESTROYING  |
529021Samw@Sun.COM  *    +-----------------------------+
539021Samw@Sun.COM  *		    |
549021Samw@Sun.COM  *		    |
559021Samw@Sun.COM  *		    | T6
569021Samw@Sun.COM  *		    |
579021Samw@Sun.COM  *		    +----------> Deletion/Free
585331Samw  *
595331Samw  * Transition T0
605331Samw  *
615331Samw  *    This transition occurs in smb_node_lookup(). If the node looked for is
625331Samw  *    not found in the has table a new node is created. The reference count is
635331Samw  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
645331Samw  *
655331Samw  * Transition T1
665331Samw  *
679021Samw@Sun.COM  *    This transition occurs smb_oplock_acquire() during an OPEN.
689021Samw@Sun.COM  *
699021Samw@Sun.COM  * Transition T2
709021Samw@Sun.COM  *
719021Samw@Sun.COM  *    This transition occurs in smb_oplock_release(). The events triggering
729021Samw@Sun.COM  *    it are:
739021Samw@Sun.COM  *
749021Samw@Sun.COM  *	- LockingAndX sent by the client that was granted the oplock.
759021Samw@Sun.COM  *	- Closing of the file.
769021Samw@Sun.COM  *
779021Samw@Sun.COM  * Transition T3
789021Samw@Sun.COM  *
799021Samw@Sun.COM  *    This transition occurs in smb_oplock_break(). The events triggering
809021Samw@Sun.COM  *    it are:
819021Samw@Sun.COM  *
829021Samw@Sun.COM  *	- Another client wants to open the file.
839021Samw@Sun.COM  *	- A client is trying to delete the file.
849021Samw@Sun.COM  *	- A client is trying to rename the file.
859021Samw@Sun.COM  *	- A client is trying to set/modify  the file attributes.
869021Samw@Sun.COM  *
879021Samw@Sun.COM  * Transition T4
889021Samw@Sun.COM  *
899021Samw@Sun.COM  *    This transition occurs in smb_oplock_release or smb_oplock_break(). The
909021Samw@Sun.COM  *    events triggering it are:
919021Samw@Sun.COM  *
929021Samw@Sun.COM  *	- The client that was granting the oplock releases it (close or
939021Samw@Sun.COM  *	  LockingAndx).
949021Samw@Sun.COM  *	- The time alloted to release the oplock expired.
959021Samw@Sun.COM  *
969021Samw@Sun.COM  * Transition T5
979021Samw@Sun.COM  *
985331Samw  *    This transition occurs in smb_node_release(). If the reference count
995331Samw  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
1005331Samw  *    reference count will be given out for that node.
1015331Samw  *
1029021Samw@Sun.COM  * Transition T6
1035331Samw  *
1045331Samw  *    This transition occurs in smb_node_release(). The structure is deleted.
1055331Samw  *
1065331Samw  * Comments
1075331Samw  * --------
1085331Samw  *
1095331Samw  *    The reason the smb node has 2 states is the following synchronization
1105331Samw  *    rule:
1115331Samw  *
1125331Samw  *    There's a mutex embedded in the node used to protect its fields and
1135331Samw  *    there's a lock embedded in the bucket of the hash table the node belongs
1145331Samw  *    to. To increment or to decrement the reference count the mutex must be
1155331Samw  *    entered. To insert the node into the bucket and to remove it from the
1165331Samw  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
1175331Samw  *    lock) have to be entered, the lock has always to be entered first then
1185331Samw  *    the mutex. This prevents a deadlock between smb_node_lookup() and
1195331Samw  *    smb_node_release() from occurring. However, in smb_node_release() when the
1205331Samw  *    reference count drops to zero and triggers the deletion of the node, the
1215331Samw  *    mutex has to be released before entering the lock of the bucket (to
1225331Samw  *    remove the node). This creates a window during which the node that is
1235331Samw  *    about to be freed could be given out by smb_node_lookup(). To close that
1245331Samw  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
1255331Samw  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
1265331Samw  *    state will indicate that the node should be treated as non existent (of
1275331Samw  *    course the state of the node should be tested/updated under the
1285331Samw  *    protection of the mutex).
1295331Samw  */
13010966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
1315331Samw #include <smbsrv/smb_fsops.h>
1328934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h>
1335331Samw #include <sys/pathname.h>
1345331Samw #include <sys/sdt.h>
1355772Sas200622 #include <sys/nbmlock.h>
13611963SAfshin.Ardakani@Sun.COM #include <fs/fs_reparse.h>
1375331Samw 
1388934SJose.Borrego@Sun.COM uint32_t smb_is_executable(char *);
1398934SJose.Borrego@Sun.COM static void smb_node_delete_on_close(smb_node_t *);
1408934SJose.Borrego@Sun.COM static void smb_node_create_audit_buf(smb_node_t *, int);
1418934SJose.Borrego@Sun.COM static void smb_node_destroy_audit_buf(smb_node_t *);
1428934SJose.Borrego@Sun.COM static void smb_node_audit(smb_node_t *);
14310001SJoyce.McIntosh@Sun.COM static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
1448934SJose.Borrego@Sun.COM static void smb_node_free(smb_node_t *);
1458934SJose.Borrego@Sun.COM static int smb_node_constructor(void *, void *, int);
1468934SJose.Borrego@Sun.COM static void smb_node_destructor(void *, void *);
1478934SJose.Borrego@Sun.COM static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
14810504SKeyur.Desai@Sun.COM 
14910504SKeyur.Desai@Sun.COM static void smb_node_init_cached_data(smb_node_t *);
15010504SKeyur.Desai@Sun.COM static void smb_node_clear_cached_data(smb_node_t *);
15110504SKeyur.Desai@Sun.COM 
15210504SKeyur.Desai@Sun.COM static void smb_node_init_cached_timestamps(smb_node_t *, smb_attr_t *);
15310001SJoyce.McIntosh@Sun.COM static void smb_node_clear_cached_timestamps(smb_node_t *);
15410001SJoyce.McIntosh@Sun.COM static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *);
15510001SJoyce.McIntosh@Sun.COM static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *);
1565331Samw 
15710504SKeyur.Desai@Sun.COM static void smb_node_init_cached_allocsz(smb_node_t *, smb_attr_t *);
15810504SKeyur.Desai@Sun.COM static void smb_node_clear_cached_allocsz(smb_node_t *);
15910504SKeyur.Desai@Sun.COM static void smb_node_get_cached_allocsz(smb_node_t *, smb_attr_t *);
16010504SKeyur.Desai@Sun.COM static void smb_node_set_cached_allocsz(smb_node_t *, smb_attr_t *);
16111963SAfshin.Ardakani@Sun.COM static void smb_node_init_reparse(smb_node_t *, smb_attr_t *);
16211963SAfshin.Ardakani@Sun.COM static void smb_node_init_system(smb_node_t *);
16310504SKeyur.Desai@Sun.COM 
1645331Samw #define	VALIDATE_DIR_NODE(_dir_, _node_) \
1655331Samw     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
1665331Samw     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
16710122SJordan.Brown@Sun.COM     ASSERT((_dir_)->n_dnode != (_node_));
1685331Samw 
16910504SKeyur.Desai@Sun.COM /* round sz to DEV_BSIZE block */
17010504SKeyur.Desai@Sun.COM #define	SMB_ALLOCSZ(sz)	(((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
17110504SKeyur.Desai@Sun.COM 
1728934SJose.Borrego@Sun.COM static kmem_cache_t	*smb_node_cache = NULL;
1736139Sjb150015 static boolean_t	smb_node_initialized = B_FALSE;
1746139Sjb150015 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
1756139Sjb150015 
1766139Sjb150015 /*
1776139Sjb150015  * smb_node_init
1786139Sjb150015  *
1796139Sjb150015  * Initialization of the SMB node layer.
1806139Sjb150015  *
1816139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
1826139Sjb150015  * thread makes the call.
1836139Sjb150015  */
1846139Sjb150015 int
1856139Sjb150015 smb_node_init(void)
1866139Sjb150015 {
1876139Sjb150015 	int	i;
1886139Sjb150015 
1896139Sjb150015 	if (smb_node_initialized)
1906139Sjb150015 		return (0);
1918934SJose.Borrego@Sun.COM 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
1928934SJose.Borrego@Sun.COM 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
1938934SJose.Borrego@Sun.COM 	    NULL, NULL, NULL, 0);
1946139Sjb150015 
1956139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
1966139Sjb150015 		smb_llist_constructor(&smb_node_hash_table[i],
1976139Sjb150015 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
1986139Sjb150015 	}
1996139Sjb150015 	smb_node_initialized = B_TRUE;
2006139Sjb150015 	return (0);
2016139Sjb150015 }
2026139Sjb150015 
2036139Sjb150015 /*
2046139Sjb150015  * smb_node_fini
2056139Sjb150015  *
2066139Sjb150015  * This function is not multi-thread safe. The caller must make sure only one
2076139Sjb150015  * thread makes the call.
2086139Sjb150015  */
2096139Sjb150015 void
2106139Sjb150015 smb_node_fini(void)
2116139Sjb150015 {
2126139Sjb150015 	int	i;
2136139Sjb150015 
2146139Sjb150015 	if (!smb_node_initialized)
2156139Sjb150015 		return;
2166139Sjb150015 
2176139Sjb150015 #ifdef DEBUG
2186139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
2196139Sjb150015 		smb_node_t	*node;
2206139Sjb150015 
2216139Sjb150015 		/*
2226139Sjb150015 		 * The following sequence is just intended for sanity check.
2236139Sjb150015 		 * This will have to be modified when the code goes into
2246139Sjb150015 		 * production.
2256139Sjb150015 		 *
2266139Sjb150015 		 * The SMB node hash table should be emtpy at this point. If the
2276139Sjb150015 		 * hash table is not empty a panic will be triggered.
2286139Sjb150015 		 *
2296139Sjb150015 		 * The reason why SMB nodes are still remaining in the hash
2306139Sjb150015 		 * table is problably due to a mismatch between calls to
2316139Sjb150015 		 * smb_node_lookup() and smb_node_release(). You must track that
2326139Sjb150015 		 * down.
2336139Sjb150015 		 */
2346139Sjb150015 		node = smb_llist_head(&smb_node_hash_table[i]);
2356139Sjb150015 		ASSERT(node == NULL);
2366139Sjb150015 	}
2376139Sjb150015 #endif
2386139Sjb150015 
2396139Sjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
2406139Sjb150015 		smb_llist_destructor(&smb_node_hash_table[i]);
2416139Sjb150015 	}
2428934SJose.Borrego@Sun.COM 	kmem_cache_destroy(smb_node_cache);
2438934SJose.Borrego@Sun.COM 	smb_node_cache = NULL;
2446139Sjb150015 	smb_node_initialized = B_FALSE;
2456139Sjb150015 }
2466139Sjb150015 
2475331Samw /*
2485331Samw  * smb_node_lookup()
2495331Samw  *
2505331Samw  * NOTE: This routine should only be called by the file system interface layer,
2515331Samw  * and not by SMB.
2525331Samw  *
2535331Samw  * smb_node_lookup() is called upon successful lookup, mkdir, and create
2545331Samw  * (for both non-streams and streams).  In each of these cases, a held vnode is
2558670SJose.Borrego@Sun.COM  * passed into this routine.  If a new smb_node is created it will take its
2568670SJose.Borrego@Sun.COM  * own hold on the vnode.  The caller's hold therefore still belongs to, and
2578670SJose.Borrego@Sun.COM  * should be released by, the caller.
2585331Samw  *
2595331Samw  * A reference is taken on the smb_node whether found in the hash table
2605331Samw  * or newly created.
2615331Samw  *
2625331Samw  * If an smb_node needs to be created, a reference is also taken on the
26310122SJordan.Brown@Sun.COM  * dnode (if passed in).
2645331Samw  *
2655331Samw  * See smb_node_release() for details on the release of these references.
2665331Samw  */
2675331Samw 
2685331Samw /*ARGSUSED*/
2695331Samw smb_node_t *
2705331Samw smb_node_lookup(
2715331Samw     struct smb_request	*sr,
2725331Samw     struct open_param	*op,
2735331Samw     cred_t		*cred,
2745331Samw     vnode_t		*vp,
2755331Samw     char		*od_name,
27610122SJordan.Brown@Sun.COM     smb_node_t		*dnode,
27710122SJordan.Brown@Sun.COM     smb_node_t		*unode)
2785331Samw {
2795331Samw 	smb_llist_t		*node_hdr;
2805331Samw 	smb_node_t		*node;
28110001SJoyce.McIntosh@Sun.COM 	smb_attr_t		attr;
2825331Samw 	uint32_t		hashkey = 0;
2837348SJose.Borrego@Sun.COM 	fsid_t			fsid;
2845331Samw 	int			error;
2855331Samw 	krw_t			lock_mode;
2865331Samw 	vnode_t			*unnamed_vp = NULL;
2875331Samw 
2885331Samw 	/*
2895331Samw 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
2905331Samw 	 * because the node may not yet exist.  We also do not want to call
2915331Samw 	 * it with the list lock held.
2925331Samw 	 */
2935331Samw 
29410122SJordan.Brown@Sun.COM 	if (unode)
29510122SJordan.Brown@Sun.COM 		unnamed_vp = unode->vp;
2965331Samw 
2975331Samw 	/*
2985331Samw 	 * This getattr is performed on behalf of the server
2995331Samw 	 * that's why kcred is used not the user's cred
3005331Samw 	 */
30110001SJoyce.McIntosh@Sun.COM 	attr.sa_mask = SMB_AT_ALL;
30210001SJoyce.McIntosh@Sun.COM 	error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, kcred);
3035331Samw 	if (error)
3045331Samw 		return (NULL);
3055331Samw 
3067348SJose.Borrego@Sun.COM 	if (sr && sr->tid_tree) {
3077348SJose.Borrego@Sun.COM 		/*
3087348SJose.Borrego@Sun.COM 		 * The fsid for a file is that of the tree, even
3097348SJose.Borrego@Sun.COM 		 * if the file resides in a different mountpoint
3107348SJose.Borrego@Sun.COM 		 * under the share.
3117348SJose.Borrego@Sun.COM 		 */
3127348SJose.Borrego@Sun.COM 		fsid = SMB_TREE_FSID(sr->tid_tree);
3135331Samw 	} else {
3147348SJose.Borrego@Sun.COM 		/*
3157348SJose.Borrego@Sun.COM 		 * This should be getting executed only for the
3167348SJose.Borrego@Sun.COM 		 * tree root smb_node.
3177348SJose.Borrego@Sun.COM 		 */
3187348SJose.Borrego@Sun.COM 		fsid = vp->v_vfsp->vfs_fsid;
3195331Samw 	}
3205331Samw 
32110001SJoyce.McIntosh@Sun.COM 	node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
3225331Samw 	lock_mode = RW_READER;
3235331Samw 
3245331Samw 	smb_llist_enter(node_hdr, lock_mode);
3255331Samw 	for (;;) {
3265331Samw 		node = list_head(&node_hdr->ll_list);
3275331Samw 		while (node) {
3285331Samw 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
3295331Samw 			ASSERT(node->n_hash_bucket == node_hdr);
3305331Samw 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
3318934SJose.Borrego@Sun.COM 				mutex_enter(&node->n_mutex);
3325331Samw 				DTRACE_PROBE1(smb_node_lookup_hit,
3335331Samw 				    smb_node_t *, node);
3345331Samw 				switch (node->n_state) {
3358934SJose.Borrego@Sun.COM 				case SMB_NODE_STATE_OPLOCK_GRANTED:
3368934SJose.Borrego@Sun.COM 				case SMB_NODE_STATE_OPLOCK_BREAKING:
3375331Samw 				case SMB_NODE_STATE_AVAILABLE:
3385331Samw 					/* The node was found. */
3395331Samw 					node->n_refcnt++;
34010122SJordan.Brown@Sun.COM 					if ((node->n_dnode == NULL) &&
34110122SJordan.Brown@Sun.COM 					    (dnode != NULL) &&
34211633SJoyce.McIntosh@Sun.COM 					    (node != dnode) &&
3435331Samw 					    (strcmp(od_name, "..") != 0) &&
3445331Samw 					    (strcmp(od_name, ".") != 0)) {
34510122SJordan.Brown@Sun.COM 						VALIDATE_DIR_NODE(dnode, node);
34610122SJordan.Brown@Sun.COM 						node->n_dnode = dnode;
34710122SJordan.Brown@Sun.COM 						smb_node_ref(dnode);
3485331Samw 					}
3495331Samw 
3508934SJose.Borrego@Sun.COM 					smb_node_audit(node);
3518934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3525331Samw 					smb_llist_exit(node_hdr);
3535331Samw 					return (node);
3545331Samw 
3555331Samw 				case SMB_NODE_STATE_DESTROYING:
3565331Samw 					/*
3575331Samw 					 * Although the node exists it is about
3585331Samw 					 * to be destroyed. We act as it hasn't
3595331Samw 					 * been found.
3605331Samw 					 */
3618934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3625331Samw 					break;
3635331Samw 				default:
3645331Samw 					/*
3655331Samw 					 * Although the node exists it is in an
3665331Samw 					 * unknown state. We act as it hasn't
3675331Samw 					 * been found.
3685331Samw 					 */
3695331Samw 					ASSERT(0);
3708934SJose.Borrego@Sun.COM 					mutex_exit(&node->n_mutex);
3715331Samw 					break;
3725331Samw 				}
3735331Samw 			}
3745331Samw 			node = smb_llist_next(node_hdr, node);
3755331Samw 		}
3765331Samw 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
3775331Samw 			lock_mode = RW_WRITER;
3785331Samw 			continue;
3795331Samw 		}
3805331Samw 		break;
3815331Samw 	}
38210001SJoyce.McIntosh@Sun.COM 	node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
38311963SAfshin.Ardakani@Sun.COM 	smb_node_init_reparse(node, &attr);
3845331Samw 
3855331Samw 	if (op)
3869343SAfshin.Ardakani@Sun.COM 		node->flags |= smb_is_executable(op->fqi.fq_last_comp);
3875331Samw 
38810122SJordan.Brown@Sun.COM 	if (dnode) {
38910122SJordan.Brown@Sun.COM 		smb_node_ref(dnode);
39010122SJordan.Brown@Sun.COM 		node->n_dnode = dnode;
39110122SJordan.Brown@Sun.COM 		ASSERT(dnode->n_dnode != node);
39210122SJordan.Brown@Sun.COM 		ASSERT((dnode->vp->v_xattrdir) ||
39310122SJordan.Brown@Sun.COM 		    (dnode->vp->v_type == VDIR));
3945331Samw 	}
3955331Samw 
39610122SJordan.Brown@Sun.COM 	if (unode) {
39710122SJordan.Brown@Sun.COM 		smb_node_ref(unode);
39810122SJordan.Brown@Sun.COM 		node->n_unode = unode;
3995331Samw 	}
4005331Samw 
40111963SAfshin.Ardakani@Sun.COM 	smb_node_init_system(node);
40211963SAfshin.Ardakani@Sun.COM 
4035331Samw 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
4048934SJose.Borrego@Sun.COM 	smb_node_audit(node);
4055331Samw 	smb_llist_insert_head(node_hdr, node);
4065331Samw 	smb_llist_exit(node_hdr);
4075331Samw 	return (node);
4085331Samw }
4095331Samw 
4105331Samw /*
4115331Samw  * smb_stream_node_lookup()
4125331Samw  *
4135331Samw  * Note: stream_name (the name that will be stored in the "od_name" field
4145331Samw  * of a stream's smb_node) is the same as the on-disk name for the stream
4155331Samw  * except that it does not have SMB_STREAM_PREFIX prepended.
4165331Samw  */
4175331Samw 
4185331Samw smb_node_t *
4198934SJose.Borrego@Sun.COM smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
42010001SJoyce.McIntosh@Sun.COM     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
4215331Samw {
4225331Samw 	smb_node_t	*xattrdir_node;
4235331Samw 	smb_node_t	*snode;
4245331Samw 
4255331Samw 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
42610001SJoyce.McIntosh@Sun.COM 	    fnode, NULL);
4275331Samw 
4285331Samw 	if (xattrdir_node == NULL)
4295331Samw 		return (NULL);
4305331Samw 
4315331Samw 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
43210001SJoyce.McIntosh@Sun.COM 	    fnode);
4335331Samw 
4345331Samw 	(void) smb_node_release(xattrdir_node);
4355331Samw 	return (snode);
4365331Samw }
4375331Samw 
4385331Samw 
4395331Samw /*
4405331Samw  * This function should be called whenever a reference is needed on an
4415331Samw  * smb_node pointer.  The copy of an smb_node pointer from one non-local
4425331Samw  * data structure to another requires a reference to be taken on the smb_node
4435331Samw  * (unless the usage is localized).  Each data structure deallocation routine
4445331Samw  * will call smb_node_release() on its smb_node pointers.
4455331Samw  *
4465331Samw  * In general, an smb_node pointer residing in a structure should never be
4475331Samw  * stale.  A node pointer may be NULL, however, and care should be taken
4485331Samw  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
4495331Samw  * Care also needs to be taken with respect to racing deallocations of a
4505331Samw  * structure.
4515331Samw  */
4525331Samw void
4535331Samw smb_node_ref(smb_node_t *node)
4545331Samw {
4558934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
4565331Samw 
4578934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
4588934SJose.Borrego@Sun.COM 	switch (node->n_state) {
4598934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
4608934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
4618934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
4628934SJose.Borrego@Sun.COM 		node->n_refcnt++;
4638934SJose.Borrego@Sun.COM 		ASSERT(node->n_refcnt);
4648934SJose.Borrego@Sun.COM 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
4658934SJose.Borrego@Sun.COM 		smb_node_audit(node);
4668934SJose.Borrego@Sun.COM 		break;
4678934SJose.Borrego@Sun.COM 	default:
4688934SJose.Borrego@Sun.COM 		SMB_PANIC();
4698934SJose.Borrego@Sun.COM 	}
4708934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
4715331Samw }
4725331Samw 
4735331Samw /*
4745331Samw  * smb_node_lookup() takes a hold on an smb_node, whether found in the
4755331Samw  * hash table or newly created.  This hold is expected to be released
4765331Samw  * in the following manner.
4775331Samw  *
4785331Samw  * smb_node_lookup() takes an address of an smb_node pointer.  This should
4795331Samw  * be getting passed down via a lookup (whether path name or component), mkdir,
4805331Samw  * create.  If the original smb_node pointer resides in a data structure, then
4815331Samw  * the deallocation routine for the data structure is responsible for calling
4825331Samw  * smb_node_release() on the smb_node pointer.  Alternatively,
4835331Samw  * smb_node_release() can be called as soon as the smb_node pointer is no longer
4845331Samw  * needed.  In this case, callers are responsible for setting an embedded
4855331Samw  * pointer to NULL if it is known that the last reference is being released.
4865331Samw  *
4875331Samw  * If the passed-in address of the smb_node pointer belongs to a local variable,
4885331Samw  * then the caller with the local variable should call smb_node_release()
4895331Samw  * directly.
4905331Samw  *
49110122SJordan.Brown@Sun.COM  * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
49210122SJordan.Brown@Sun.COM  * as smb_node_lookup() takes a hold on dnode.
4935331Samw  */
4945331Samw void
4955331Samw smb_node_release(smb_node_t *node)
4965331Samw {
4978934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
4985331Samw 
4998934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
5005331Samw 	ASSERT(node->n_refcnt);
5015331Samw 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
5025331Samw 	if (--node->n_refcnt == 0) {
5035331Samw 		switch (node->n_state) {
5045331Samw 
5055331Samw 		case SMB_NODE_STATE_AVAILABLE:
5065331Samw 			node->n_state = SMB_NODE_STATE_DESTROYING;
5078934SJose.Borrego@Sun.COM 			mutex_exit(&node->n_mutex);
5085331Samw 
5095331Samw 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
5105331Samw 			smb_llist_remove(node->n_hash_bucket, node);
5115331Samw 			smb_llist_exit(node->n_hash_bucket);
5125331Samw 
5135331Samw 			/*
5145331Samw 			 * Check if the file was deleted
5155331Samw 			 */
5165331Samw 			smb_node_delete_on_close(node);
5175331Samw 
51810122SJordan.Brown@Sun.COM 			if (node->n_dnode) {
51910122SJordan.Brown@Sun.COM 				ASSERT(node->n_dnode->n_magic ==
5205331Samw 				    SMB_NODE_MAGIC);
52110122SJordan.Brown@Sun.COM 				smb_node_release(node->n_dnode);
5225331Samw 			}
5235331Samw 
52410122SJordan.Brown@Sun.COM 			if (node->n_unode) {
52510122SJordan.Brown@Sun.COM 				ASSERT(node->n_unode->n_magic ==
5265331Samw 				    SMB_NODE_MAGIC);
52710122SJordan.Brown@Sun.COM 				smb_node_release(node->n_unode);
5285331Samw 			}
5295331Samw 
5308934SJose.Borrego@Sun.COM 			smb_node_free(node);
5315331Samw 			return;
5325331Samw 
5335331Samw 		default:
5348934SJose.Borrego@Sun.COM 			SMB_PANIC();
5355331Samw 		}
5365331Samw 	}
5378934SJose.Borrego@Sun.COM 	smb_node_audit(node);
5388934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
5395331Samw }
5405331Samw 
5415331Samw static void
5425331Samw smb_node_delete_on_close(smb_node_t *node)
5435331Samw {
5445331Samw 	smb_node_t	*d_snode;
5455331Samw 	int		rc = 0;
5469231SAfshin.Ardakani@Sun.COM 	uint32_t	flags = 0;
5475331Samw 
54810122SJordan.Brown@Sun.COM 	d_snode = node->n_dnode;
5495331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
5509231SAfshin.Ardakani@Sun.COM 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
5519231SAfshin.Ardakani@Sun.COM 		flags = node->n_delete_on_close_flags;
5529231SAfshin.Ardakani@Sun.COM 		ASSERT(node->od_name != NULL);
5535331Samw 
55411963SAfshin.Ardakani@Sun.COM 		if (smb_node_is_dir(node))
5555331Samw 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
5569231SAfshin.Ardakani@Sun.COM 			    d_snode, node->od_name, flags);
5575331Samw 		else
5585331Samw 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
5599231SAfshin.Ardakani@Sun.COM 			    d_snode, node->od_name, flags);
560*12508Samw@Sun.COM 		crfree(node->delete_on_close_cred);
5615331Samw 	}
5625331Samw 	if (rc != 0)
5635331Samw 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
5645331Samw 		    node->od_name, rc);
5655331Samw 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
5665331Samw }
5675331Samw 
5685331Samw /*
5695331Samw  * smb_node_rename()
5705331Samw  *
5715331Samw  */
5728934SJose.Borrego@Sun.COM void
5735331Samw smb_node_rename(
5748934SJose.Borrego@Sun.COM     smb_node_t	*from_dnode,
5758934SJose.Borrego@Sun.COM     smb_node_t	*ret_node,
5768934SJose.Borrego@Sun.COM     smb_node_t	*to_dnode,
5775331Samw     char	*to_name)
5785331Samw {
5798934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(from_dnode);
5808934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(to_dnode);
5818934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(ret_node);
5825331Samw 
5838934SJose.Borrego@Sun.COM 	smb_node_ref(to_dnode);
5848934SJose.Borrego@Sun.COM 	mutex_enter(&ret_node->n_mutex);
5858934SJose.Borrego@Sun.COM 	switch (ret_node->n_state) {
5868934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
5878934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
5888934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
58910122SJordan.Brown@Sun.COM 		ret_node->n_dnode = to_dnode;
5908934SJose.Borrego@Sun.COM 		mutex_exit(&ret_node->n_mutex);
59110122SJordan.Brown@Sun.COM 		ASSERT(to_dnode->n_dnode != ret_node);
5928934SJose.Borrego@Sun.COM 		ASSERT((to_dnode->vp->v_xattrdir) ||
5938934SJose.Borrego@Sun.COM 		    (to_dnode->vp->v_type == VDIR));
5948934SJose.Borrego@Sun.COM 		smb_node_release(from_dnode);
5958934SJose.Borrego@Sun.COM 		(void) strcpy(ret_node->od_name, to_name);
5968934SJose.Borrego@Sun.COM 		/*
5978934SJose.Borrego@Sun.COM 		 * XXX Need to update attributes?
5988934SJose.Borrego@Sun.COM 		 */
5998934SJose.Borrego@Sun.COM 		break;
6008934SJose.Borrego@Sun.COM 	default:
6018934SJose.Borrego@Sun.COM 		SMB_PANIC();
6028934SJose.Borrego@Sun.COM 	}
6035331Samw }
6045331Samw 
6055331Samw int
6066139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
6075331Samw {
60810001SJoyce.McIntosh@Sun.COM 	smb_attr_t	attr;
6096139Sjb150015 	int		error;
6106139Sjb150015 	uint32_t	hashkey;
6116139Sjb150015 	smb_llist_t	*node_hdr;
6126139Sjb150015 	smb_node_t	*node;
6135331Samw 
61410001SJoyce.McIntosh@Sun.COM 	attr.sa_mask = SMB_AT_ALL;
61510001SJoyce.McIntosh@Sun.COM 	error = smb_vop_getattr(vp, NULL, &attr, 0, kcred);
6166139Sjb150015 	if (error) {
6176139Sjb150015 		VN_RELE(vp);
6186139Sjb150015 		return (error);
6196139Sjb150015 	}
6206139Sjb150015 
62110001SJoyce.McIntosh@Sun.COM 	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &attr, &hashkey);
6225331Samw 
62310001SJoyce.McIntosh@Sun.COM 	node = smb_node_alloc(ROOTVOL, vp, node_hdr, hashkey);
6246139Sjb150015 
6256139Sjb150015 	sv->si_root_smb_node = node;
6268934SJose.Borrego@Sun.COM 	smb_node_audit(node);
6276139Sjb150015 	smb_llist_enter(node_hdr, RW_WRITER);
6286139Sjb150015 	smb_llist_insert_head(node_hdr, node);
6296139Sjb150015 	smb_llist_exit(node_hdr);
6306139Sjb150015 	*root = node;
6316139Sjb150015 	return (0);
6325331Samw }
6335331Samw 
6345331Samw /*
6359231SAfshin.Ardakani@Sun.COM  * When DeleteOnClose is set on an smb_node, the common open code will
6369231SAfshin.Ardakani@Sun.COM  * reject subsequent open requests for the file. Observation of Windows
6379231SAfshin.Ardakani@Sun.COM  * 2000 indicates that subsequent opens should be allowed (assuming
6389231SAfshin.Ardakani@Sun.COM  * there would be no sharing violation) until the file is closed using
6399231SAfshin.Ardakani@Sun.COM  * the fid on which the DeleteOnClose was requested.
6409231SAfshin.Ardakani@Sun.COM  *
6419231SAfshin.Ardakani@Sun.COM  * If there are multiple opens with delete-on-close create options,
6429231SAfshin.Ardakani@Sun.COM  * whichever the first file handle is closed will trigger the node to be
6439231SAfshin.Ardakani@Sun.COM  * marked as delete-on-close. The credentials of that ofile will be used
6449231SAfshin.Ardakani@Sun.COM  * as the delete-on-close credentials of the node.
6459231SAfshin.Ardakani@Sun.COM  */
6465331Samw int
6479231SAfshin.Ardakani@Sun.COM smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
6485331Samw {
64910717Samw@Sun.COM 	int rc = 0;
65010001SJoyce.McIntosh@Sun.COM 	smb_attr_t attr;
6515331Samw 
65210717Samw@Sun.COM 	if (node->readonly_creator)
65310001SJoyce.McIntosh@Sun.COM 		return (-1);
65410001SJoyce.McIntosh@Sun.COM 
65510001SJoyce.McIntosh@Sun.COM 	bzero(&attr, sizeof (smb_attr_t));
65610001SJoyce.McIntosh@Sun.COM 	attr.sa_mask = SMB_AT_DOSATTR;
65710001SJoyce.McIntosh@Sun.COM 	rc = smb_fsop_getattr(NULL, kcred, node, &attr);
65810001SJoyce.McIntosh@Sun.COM 	if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
65910001SJoyce.McIntosh@Sun.COM 		return (-1);
66010001SJoyce.McIntosh@Sun.COM 	}
66110001SJoyce.McIntosh@Sun.COM 
66210717Samw@Sun.COM 	mutex_enter(&node->n_mutex);
66310717Samw@Sun.COM 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
66410717Samw@Sun.COM 		rc = -1;
66510717Samw@Sun.COM 	} else {
66610717Samw@Sun.COM 		crhold(cr);
66710717Samw@Sun.COM 		node->delete_on_close_cred = cr;
66810717Samw@Sun.COM 		node->n_delete_on_close_flags = flags;
66910717Samw@Sun.COM 		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
67010717Samw@Sun.COM 		rc = 0;
67110717Samw@Sun.COM 	}
6728934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
67310717Samw@Sun.COM 	return (rc);
6745331Samw }
6755331Samw 
6765331Samw void
6775331Samw smb_node_reset_delete_on_close(smb_node_t *node)
6785331Samw {
6798934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
6805331Samw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
6815331Samw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
6825331Samw 		crfree(node->delete_on_close_cred);
6835331Samw 		node->delete_on_close_cred = NULL;
6849231SAfshin.Ardakani@Sun.COM 		node->n_delete_on_close_flags = 0;
6855331Samw 	}
6868934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
6875331Samw }
6885772Sas200622 
6895772Sas200622 /*
6906771Sjb150015  * smb_node_open_check
6915772Sas200622  *
6925772Sas200622  * check file sharing rules for current open request
6935772Sas200622  * against all existing opens for a file.
6945772Sas200622  *
6955772Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
6965772Sas200622  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
6975772Sas200622  */
6985772Sas200622 uint32_t
69911963SAfshin.Ardakani@Sun.COM smb_node_open_check(smb_node_t *node, uint32_t desired_access,
70011963SAfshin.Ardakani@Sun.COM     uint32_t share_access)
7015772Sas200622 {
7025772Sas200622 	smb_ofile_t *of;
7035772Sas200622 	uint32_t status;
7045772Sas200622 
7058934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
7065772Sas200622 
7075772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
7085772Sas200622 	of = smb_llist_head(&node->n_ofile_list);
7095772Sas200622 	while (of) {
71011963SAfshin.Ardakani@Sun.COM 		status = smb_ofile_open_check(of, desired_access, share_access);
7116771Sjb150015 
7126771Sjb150015 		switch (status) {
7136771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
7146771Sjb150015 		case NT_STATUS_SUCCESS:
7156771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
7166771Sjb150015 			break;
7176771Sjb150015 		default:
7186771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
7195772Sas200622 			smb_llist_exit(&node->n_ofile_list);
7205772Sas200622 			return (status);
7215772Sas200622 		}
7225772Sas200622 	}
7236771Sjb150015 
7245772Sas200622 	smb_llist_exit(&node->n_ofile_list);
7255772Sas200622 	return (NT_STATUS_SUCCESS);
7265772Sas200622 }
7275772Sas200622 
7285772Sas200622 uint32_t
7298934SJose.Borrego@Sun.COM smb_node_rename_check(smb_node_t *node)
7305772Sas200622 {
7318934SJose.Borrego@Sun.COM 	smb_ofile_t	*of;
7328934SJose.Borrego@Sun.COM 	uint32_t	status;
7335772Sas200622 
7348934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
7355772Sas200622 
7365772Sas200622 	/*
7375772Sas200622 	 * Intra-CIFS check
7385772Sas200622 	 */
7395772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
7406771Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
7416771Sjb150015 	while (of) {
7426771Sjb150015 		status = smb_ofile_rename_check(of);
7435772Sas200622 
7446771Sjb150015 		switch (status) {
7456771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
7466771Sjb150015 		case NT_STATUS_SUCCESS:
7476771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
7486771Sjb150015 			break;
7496771Sjb150015 		default:
7506771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
7516771Sjb150015 			smb_llist_exit(&node->n_ofile_list);
7526771Sjb150015 			return (status);
7535772Sas200622 		}
7545772Sas200622 	}
7555772Sas200622 	smb_llist_exit(&node->n_ofile_list);
7565772Sas200622 
7575772Sas200622 	/*
7585772Sas200622 	 * system-wide share check
7595772Sas200622 	 */
7605772Sas200622 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
7615772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
7625772Sas200622 	else
7635772Sas200622 		return (NT_STATUS_SUCCESS);
7645772Sas200622 }
7655772Sas200622 
7666771Sjb150015 uint32_t
7675772Sas200622 smb_node_delete_check(smb_node_t *node)
7685772Sas200622 {
7698934SJose.Borrego@Sun.COM 	smb_ofile_t	*of;
7708934SJose.Borrego@Sun.COM 	uint32_t	status;
7715772Sas200622 
7728934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
7735772Sas200622 
77411963SAfshin.Ardakani@Sun.COM 	if (smb_node_is_dir(node))
7755772Sas200622 		return (NT_STATUS_SUCCESS);
7765772Sas200622 
77711963SAfshin.Ardakani@Sun.COM 	if (smb_node_is_reparse(node))
77811963SAfshin.Ardakani@Sun.COM 		return (NT_STATUS_ACCESS_DENIED);
77911963SAfshin.Ardakani@Sun.COM 
7805772Sas200622 	/*
7815772Sas200622 	 * intra-CIFS check
7825772Sas200622 	 */
7835772Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
7846771Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
7856771Sjb150015 	while (of) {
7866771Sjb150015 		status = smb_ofile_delete_check(of);
7876771Sjb150015 
7886771Sjb150015 		switch (status) {
7896771Sjb150015 		case NT_STATUS_INVALID_HANDLE:
7906771Sjb150015 		case NT_STATUS_SUCCESS:
7916771Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
7926771Sjb150015 			break;
7936771Sjb150015 		default:
7946771Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
7955772Sas200622 			smb_llist_exit(&node->n_ofile_list);
7966771Sjb150015 			return (status);
7975772Sas200622 		}
7985772Sas200622 	}
7995772Sas200622 	smb_llist_exit(&node->n_ofile_list);
8005772Sas200622 
8015772Sas200622 	/*
8025772Sas200622 	 * system-wide share check
8035772Sas200622 	 */
8045772Sas200622 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
8055772Sas200622 		return (NT_STATUS_SHARING_VIOLATION);
8065772Sas200622 	else
8075772Sas200622 		return (NT_STATUS_SUCCESS);
8085772Sas200622 }
8095772Sas200622 
8109914Samw@Sun.COM void
8119914Samw@Sun.COM smb_node_notify_change(smb_node_t *node)
8129914Samw@Sun.COM {
8139914Samw@Sun.COM 	SMB_NODE_VALID(node);
8149914Samw@Sun.COM 
8159914Samw@Sun.COM 	if (node->flags & NODE_FLAGS_NOTIFY_CHANGE) {
8169914Samw@Sun.COM 		node->flags |= NODE_FLAGS_CHANGED;
8179914Samw@Sun.COM 		smb_process_node_notify_change_queue(node);
8189914Samw@Sun.COM 	}
81911963SAfshin.Ardakani@Sun.COM 
82011963SAfshin.Ardakani@Sun.COM 	smb_node_notify_parents(node);
8219914Samw@Sun.COM }
8229914Samw@Sun.COM 
82311963SAfshin.Ardakani@Sun.COM /*
82411963SAfshin.Ardakani@Sun.COM  * smb_node_notify_parents
82511963SAfshin.Ardakani@Sun.COM  *
82611963SAfshin.Ardakani@Sun.COM  * Iterate up the directory tree notifying any parent
82711963SAfshin.Ardakani@Sun.COM  * directories that are being watched for changes in
82811963SAfshin.Ardakani@Sun.COM  * their sub directories.
82911963SAfshin.Ardakani@Sun.COM  * Stop at the root node, which has a NULL parent node.
83011963SAfshin.Ardakani@Sun.COM  */
83111963SAfshin.Ardakani@Sun.COM void
83211963SAfshin.Ardakani@Sun.COM smb_node_notify_parents(smb_node_t *dnode)
83311337SWilliam.Krier@Sun.COM {
83411963SAfshin.Ardakani@Sun.COM 	smb_node_t *pnode = dnode;
83511963SAfshin.Ardakani@Sun.COM 
83611963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(dnode);
83711337SWilliam.Krier@Sun.COM 
83811963SAfshin.Ardakani@Sun.COM 	while ((pnode = pnode->n_dnode) != NULL) {
83911963SAfshin.Ardakani@Sun.COM 		SMB_NODE_VALID(pnode);
84011963SAfshin.Ardakani@Sun.COM 		if ((pnode->flags & NODE_FLAGS_NOTIFY_CHANGE) &&
84111963SAfshin.Ardakani@Sun.COM 		    (pnode->flags & NODE_FLAGS_WATCH_TREE)) {
84211963SAfshin.Ardakani@Sun.COM 			pnode->flags |= NODE_FLAGS_CHANGED;
84311963SAfshin.Ardakani@Sun.COM 			smb_process_node_notify_change_queue(pnode);
84411963SAfshin.Ardakani@Sun.COM 		}
84511963SAfshin.Ardakani@Sun.COM 	}
84611337SWilliam.Krier@Sun.COM }
84711337SWilliam.Krier@Sun.COM 
8485772Sas200622 /*
8495772Sas200622  * smb_node_start_crit()
8505772Sas200622  *
8515772Sas200622  * Enter critical region for share reservations.
8525772Sas200622  * See comments above smb_fsop_shrlock().
8535772Sas200622  */
8545772Sas200622 void
8555772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode)
8565772Sas200622 {
8578934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, mode);
8585772Sas200622 	nbl_start_crit(node->vp, mode);
8595772Sas200622 }
8605772Sas200622 
8615772Sas200622 /*
8625772Sas200622  * smb_node_end_crit()
8635772Sas200622  *
8645772Sas200622  * Exit critical region for share reservations.
8655772Sas200622  */
8665772Sas200622 void
8675772Sas200622 smb_node_end_crit(smb_node_t *node)
8685772Sas200622 {
8695772Sas200622 	nbl_end_crit(node->vp);
8708934SJose.Borrego@Sun.COM 	rw_exit(&node->n_lock);
8715772Sas200622 }
8725772Sas200622 
8735772Sas200622 int
8745772Sas200622 smb_node_in_crit(smb_node_t *node)
8755772Sas200622 {
8768934SJose.Borrego@Sun.COM 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
8778934SJose.Borrego@Sun.COM }
8788934SJose.Borrego@Sun.COM 
8798934SJose.Borrego@Sun.COM void
8808934SJose.Borrego@Sun.COM smb_node_rdlock(smb_node_t *node)
8818934SJose.Borrego@Sun.COM {
8828934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, RW_READER);
8838934SJose.Borrego@Sun.COM }
8848934SJose.Borrego@Sun.COM 
8858934SJose.Borrego@Sun.COM void
8868934SJose.Borrego@Sun.COM smb_node_wrlock(smb_node_t *node)
8878934SJose.Borrego@Sun.COM {
8888934SJose.Borrego@Sun.COM 	rw_enter(&node->n_lock, RW_WRITER);
8898934SJose.Borrego@Sun.COM }
8908934SJose.Borrego@Sun.COM 
8918934SJose.Borrego@Sun.COM void
8928934SJose.Borrego@Sun.COM smb_node_unlock(smb_node_t *node)
8938934SJose.Borrego@Sun.COM {
8948934SJose.Borrego@Sun.COM 	rw_exit(&node->n_lock);
8958934SJose.Borrego@Sun.COM }
8968934SJose.Borrego@Sun.COM 
8978934SJose.Borrego@Sun.COM uint32_t
8988934SJose.Borrego@Sun.COM smb_node_get_ofile_count(smb_node_t *node)
8998934SJose.Borrego@Sun.COM {
9008934SJose.Borrego@Sun.COM 	uint32_t	cntr;
9018934SJose.Borrego@Sun.COM 
9028934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9038934SJose.Borrego@Sun.COM 
9048934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_READER);
9058934SJose.Borrego@Sun.COM 	cntr = smb_llist_get_count(&node->n_ofile_list);
9068934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
9078934SJose.Borrego@Sun.COM 	return (cntr);
9088934SJose.Borrego@Sun.COM }
9098934SJose.Borrego@Sun.COM 
9108934SJose.Borrego@Sun.COM void
9118934SJose.Borrego@Sun.COM smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
9128934SJose.Borrego@Sun.COM {
9138934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9148934SJose.Borrego@Sun.COM 
9158934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
9168934SJose.Borrego@Sun.COM 	smb_llist_insert_tail(&node->n_ofile_list, of);
9178934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
9188934SJose.Borrego@Sun.COM }
9198934SJose.Borrego@Sun.COM 
9208934SJose.Borrego@Sun.COM void
9218934SJose.Borrego@Sun.COM smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
9228934SJose.Borrego@Sun.COM {
9238934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9248934SJose.Borrego@Sun.COM 
9258934SJose.Borrego@Sun.COM 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
9268934SJose.Borrego@Sun.COM 	smb_llist_remove(&node->n_ofile_list, of);
9278934SJose.Borrego@Sun.COM 	smb_llist_exit(&node->n_ofile_list);
9288934SJose.Borrego@Sun.COM }
9298934SJose.Borrego@Sun.COM 
93010001SJoyce.McIntosh@Sun.COM /*
93110001SJoyce.McIntosh@Sun.COM  * smb_node_inc_open_ofiles
93210001SJoyce.McIntosh@Sun.COM  */
9338934SJose.Borrego@Sun.COM void
9348934SJose.Borrego@Sun.COM smb_node_inc_open_ofiles(smb_node_t *node)
9358934SJose.Borrego@Sun.COM {
9368934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9378934SJose.Borrego@Sun.COM 
9388934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
9398934SJose.Borrego@Sun.COM 	node->n_open_count++;
9408934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
94110001SJoyce.McIntosh@Sun.COM 
94210504SKeyur.Desai@Sun.COM 	smb_node_init_cached_data(node);
9438934SJose.Borrego@Sun.COM }
9448934SJose.Borrego@Sun.COM 
94510001SJoyce.McIntosh@Sun.COM /*
94610001SJoyce.McIntosh@Sun.COM  * smb_node_dec_open_ofiles
94710001SJoyce.McIntosh@Sun.COM  */
9488934SJose.Borrego@Sun.COM void
9498934SJose.Borrego@Sun.COM smb_node_dec_open_ofiles(smb_node_t *node)
9508934SJose.Borrego@Sun.COM {
9518934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9528934SJose.Borrego@Sun.COM 
9538934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
9548934SJose.Borrego@Sun.COM 	node->n_open_count--;
9558934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
95610001SJoyce.McIntosh@Sun.COM 
95710504SKeyur.Desai@Sun.COM 	smb_node_clear_cached_data(node);
9588934SJose.Borrego@Sun.COM }
9598934SJose.Borrego@Sun.COM 
9608934SJose.Borrego@Sun.COM uint32_t
9618934SJose.Borrego@Sun.COM smb_node_get_open_ofiles(smb_node_t *node)
9628934SJose.Borrego@Sun.COM {
9638934SJose.Borrego@Sun.COM 	uint32_t	cnt;
9648934SJose.Borrego@Sun.COM 
9658934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
9668934SJose.Borrego@Sun.COM 
9678934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
9688934SJose.Borrego@Sun.COM 	cnt = node->n_open_count;
9698934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
9708934SJose.Borrego@Sun.COM 	return (cnt);
9715772Sas200622 }
9728934SJose.Borrego@Sun.COM 
9738934SJose.Borrego@Sun.COM /*
97411963SAfshin.Ardakani@Sun.COM  * smb_node_getmntpath
97511963SAfshin.Ardakani@Sun.COM  */
97611963SAfshin.Ardakani@Sun.COM int
97711963SAfshin.Ardakani@Sun.COM smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen)
97811963SAfshin.Ardakani@Sun.COM {
97911963SAfshin.Ardakani@Sun.COM 	vnode_t *vp, *root_vp;
98011963SAfshin.Ardakani@Sun.COM 	vfs_t *vfsp;
98111963SAfshin.Ardakani@Sun.COM 	int err;
98211963SAfshin.Ardakani@Sun.COM 
98311963SAfshin.Ardakani@Sun.COM 	ASSERT(node);
98411963SAfshin.Ardakani@Sun.COM 	ASSERT(node->vp);
98511963SAfshin.Ardakani@Sun.COM 	ASSERT(node->vp->v_vfsp);
98611963SAfshin.Ardakani@Sun.COM 
98711963SAfshin.Ardakani@Sun.COM 	vp = node->vp;
98811963SAfshin.Ardakani@Sun.COM 	vfsp = vp->v_vfsp;
98911963SAfshin.Ardakani@Sun.COM 
99011963SAfshin.Ardakani@Sun.COM 	if (VFS_ROOT(vfsp, &root_vp))
99111963SAfshin.Ardakani@Sun.COM 		return (ENOENT);
99211963SAfshin.Ardakani@Sun.COM 
99311963SAfshin.Ardakani@Sun.COM 	VN_HOLD(vp);
99411963SAfshin.Ardakani@Sun.COM 
99511963SAfshin.Ardakani@Sun.COM 	/* NULL is passed in as we want to start at "/" */
99611963SAfshin.Ardakani@Sun.COM 	err = vnodetopath(NULL, root_vp, buf, buflen, kcred);
99711963SAfshin.Ardakani@Sun.COM 
99811963SAfshin.Ardakani@Sun.COM 	VN_RELE(vp);
99911963SAfshin.Ardakani@Sun.COM 	VN_RELE(root_vp);
100011963SAfshin.Ardakani@Sun.COM 	return (err);
100111963SAfshin.Ardakani@Sun.COM }
100211963SAfshin.Ardakani@Sun.COM 
100311963SAfshin.Ardakani@Sun.COM /*
100411963SAfshin.Ardakani@Sun.COM  * smb_node_getshrpath
100511963SAfshin.Ardakani@Sun.COM  *
100611963SAfshin.Ardakani@Sun.COM  * Determine the absolute pathname of 'node' within the share (tree).
100711963SAfshin.Ardakani@Sun.COM  * For example if the node represents file "test1.txt" in directory
100811963SAfshin.Ardakani@Sun.COM  * "dir1" the pathname would be: \dir1\test1.txt
100911963SAfshin.Ardakani@Sun.COM  */
101011963SAfshin.Ardakani@Sun.COM int
101111963SAfshin.Ardakani@Sun.COM smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree,
101211963SAfshin.Ardakani@Sun.COM     char *buf, uint32_t buflen)
101311963SAfshin.Ardakani@Sun.COM {
101411963SAfshin.Ardakani@Sun.COM 	int rc;
101511963SAfshin.Ardakani@Sun.COM 
101612065SKeyur.Desai@Sun.COM 	ASSERT(node);
101712065SKeyur.Desai@Sun.COM 	ASSERT(tree);
101812065SKeyur.Desai@Sun.COM 	ASSERT(tree->t_snode);
101911963SAfshin.Ardakani@Sun.COM 
102012065SKeyur.Desai@Sun.COM 	rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen);
102112065SKeyur.Desai@Sun.COM 	(void) strsubst(buf, '/', '\\');
102212065SKeyur.Desai@Sun.COM 	return (rc);
102312065SKeyur.Desai@Sun.COM }
102411963SAfshin.Ardakani@Sun.COM 
102512065SKeyur.Desai@Sun.COM /*
102612065SKeyur.Desai@Sun.COM  * smb_node_getpath
102712065SKeyur.Desai@Sun.COM  *
102812065SKeyur.Desai@Sun.COM  * Determine the absolute pathname of 'node' from 'rootvp'.
102912065SKeyur.Desai@Sun.COM  *
103012065SKeyur.Desai@Sun.COM  * Using vnodetopath is only reliable for directory nodes (due to
103112065SKeyur.Desai@Sun.COM  * its reliance on the DNLC for non-directory nodes). Thus, if node
103212065SKeyur.Desai@Sun.COM  * represents a file, construct the pathname for the parent dnode
103312065SKeyur.Desai@Sun.COM  * and append filename.
103412065SKeyur.Desai@Sun.COM  * If node represents a named stream, construct the pathname for the
103512065SKeyur.Desai@Sun.COM  * associated unnamed stream and append the stream name.
103612065SKeyur.Desai@Sun.COM  *
103712065SKeyur.Desai@Sun.COM  * The pathname returned in buf will be '/' separated.
103812065SKeyur.Desai@Sun.COM  */
103912065SKeyur.Desai@Sun.COM int
104012065SKeyur.Desai@Sun.COM smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen)
104112065SKeyur.Desai@Sun.COM {
104212065SKeyur.Desai@Sun.COM 	int rc;
104312065SKeyur.Desai@Sun.COM 	vnode_t *vp;
104412065SKeyur.Desai@Sun.COM 	smb_node_t *unode, *dnode;
104512065SKeyur.Desai@Sun.COM 
104612065SKeyur.Desai@Sun.COM 	unode = (SMB_IS_STREAM(node)) ? node->n_unode : node;
104712065SKeyur.Desai@Sun.COM 	dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode;
104811963SAfshin.Ardakani@Sun.COM 
104912065SKeyur.Desai@Sun.COM 	/* find path to directory node */
105012065SKeyur.Desai@Sun.COM 	vp = dnode->vp;
105112065SKeyur.Desai@Sun.COM 	VN_HOLD(vp);
105212065SKeyur.Desai@Sun.COM 	if (rootvp) {
105312065SKeyur.Desai@Sun.COM 		VN_HOLD(rootvp);
105412065SKeyur.Desai@Sun.COM 		rc = vnodetopath(rootvp, vp, buf, buflen, kcred);
105512065SKeyur.Desai@Sun.COM 		VN_RELE(rootvp);
105612065SKeyur.Desai@Sun.COM 	} else {
105712065SKeyur.Desai@Sun.COM 		rc = vnodetopath(NULL, vp, buf, buflen, kcred);
105812065SKeyur.Desai@Sun.COM 	}
105912065SKeyur.Desai@Sun.COM 	VN_RELE(vp);
106011963SAfshin.Ardakani@Sun.COM 
106112065SKeyur.Desai@Sun.COM 	if (rc != 0)
106212065SKeyur.Desai@Sun.COM 		return (rc);
106312065SKeyur.Desai@Sun.COM 
106412065SKeyur.Desai@Sun.COM 	/* append filename if necessary */
106512065SKeyur.Desai@Sun.COM 	if (!smb_node_is_dir(unode)) {
106612065SKeyur.Desai@Sun.COM 		if (buf[strlen(buf) - 1] != '/')
106712065SKeyur.Desai@Sun.COM 			(void) strlcat(buf, "/", buflen);
106812065SKeyur.Desai@Sun.COM 		(void) strlcat(buf, unode->od_name, buflen);
106911963SAfshin.Ardakani@Sun.COM 	}
107011963SAfshin.Ardakani@Sun.COM 
107112065SKeyur.Desai@Sun.COM 	/* append named stream name if necessary */
107212065SKeyur.Desai@Sun.COM 	if (SMB_IS_STREAM(node))
107312065SKeyur.Desai@Sun.COM 		(void) strlcat(buf, node->od_name, buflen);
107412065SKeyur.Desai@Sun.COM 
107511963SAfshin.Ardakani@Sun.COM 	return (rc);
107611963SAfshin.Ardakani@Sun.COM }
107711963SAfshin.Ardakani@Sun.COM 
107811963SAfshin.Ardakani@Sun.COM /*
10798934SJose.Borrego@Sun.COM  * smb_node_alloc
10808934SJose.Borrego@Sun.COM  */
10818934SJose.Borrego@Sun.COM static smb_node_t *
10828934SJose.Borrego@Sun.COM smb_node_alloc(
10838934SJose.Borrego@Sun.COM     char	*od_name,
10848934SJose.Borrego@Sun.COM     vnode_t	*vp,
10858934SJose.Borrego@Sun.COM     smb_llist_t	*bucket,
10868934SJose.Borrego@Sun.COM     uint32_t	hashkey)
10878934SJose.Borrego@Sun.COM {
10888934SJose.Borrego@Sun.COM 	smb_node_t	*node;
108911963SAfshin.Ardakani@Sun.COM 	vnode_t		*root_vp;
10908934SJose.Borrego@Sun.COM 
10918934SJose.Borrego@Sun.COM 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
10928934SJose.Borrego@Sun.COM 
10938934SJose.Borrego@Sun.COM 	if (node->n_audit_buf != NULL)
10948934SJose.Borrego@Sun.COM 		node->n_audit_buf->anb_index = 0;
10958934SJose.Borrego@Sun.COM 
109610001SJoyce.McIntosh@Sun.COM 	node->flags = 0;
10978934SJose.Borrego@Sun.COM 	VN_HOLD(vp);
10988934SJose.Borrego@Sun.COM 	node->vp = vp;
10998934SJose.Borrego@Sun.COM 	node->n_refcnt = 1;
11008934SJose.Borrego@Sun.COM 	node->n_hash_bucket = bucket;
11018934SJose.Borrego@Sun.COM 	node->n_hashkey = hashkey;
11028934SJose.Borrego@Sun.COM 	node->readonly_creator = NULL;
11038934SJose.Borrego@Sun.COM 	node->waiting_event = 0;
11048934SJose.Borrego@Sun.COM 	node->n_open_count = 0;
110510122SJordan.Brown@Sun.COM 	node->n_dnode = NULL;
110610122SJordan.Brown@Sun.COM 	node->n_unode = NULL;
11078934SJose.Borrego@Sun.COM 	node->delete_on_close_cred = NULL;
11089231SAfshin.Ardakani@Sun.COM 	node->n_delete_on_close_flags = 0;
11098934SJose.Borrego@Sun.COM 
11108934SJose.Borrego@Sun.COM 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
11118934SJose.Borrego@Sun.COM 	if (strcmp(od_name, XATTR_DIR) == 0)
11128934SJose.Borrego@Sun.COM 		node->flags |= NODE_XATTR_DIR;
11138934SJose.Borrego@Sun.COM 
111411963SAfshin.Ardakani@Sun.COM 	if (VFS_ROOT(vp->v_vfsp, &root_vp) == 0) {
111511963SAfshin.Ardakani@Sun.COM 		if (vp == root_vp)
111611963SAfshin.Ardakani@Sun.COM 			node->flags |= NODE_FLAGS_VFSROOT;
111711963SAfshin.Ardakani@Sun.COM 		VN_RELE(root_vp);
111811963SAfshin.Ardakani@Sun.COM 	}
111911963SAfshin.Ardakani@Sun.COM 
11208934SJose.Borrego@Sun.COM 	node->n_state = SMB_NODE_STATE_AVAILABLE;
11218934SJose.Borrego@Sun.COM 	node->n_magic = SMB_NODE_MAGIC;
112211963SAfshin.Ardakani@Sun.COM 
11238934SJose.Borrego@Sun.COM 	return (node);
11248934SJose.Borrego@Sun.COM }
11258934SJose.Borrego@Sun.COM 
11268934SJose.Borrego@Sun.COM /*
11278934SJose.Borrego@Sun.COM  * smb_node_free
11288934SJose.Borrego@Sun.COM  */
11298934SJose.Borrego@Sun.COM static void
11308934SJose.Borrego@Sun.COM smb_node_free(smb_node_t *node)
11318934SJose.Borrego@Sun.COM {
11328934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
11338934SJose.Borrego@Sun.COM 
11348934SJose.Borrego@Sun.COM 	node->n_magic = 0;
11358934SJose.Borrego@Sun.COM 	VERIFY(!list_link_active(&node->n_lnd));
11368934SJose.Borrego@Sun.COM 	VERIFY(node->n_lock_list.ll_count == 0);
11378934SJose.Borrego@Sun.COM 	VERIFY(node->n_ofile_list.ll_count == 0);
11388934SJose.Borrego@Sun.COM 	VERIFY(node->n_oplock.ol_xthread == NULL);
11399021Samw@Sun.COM 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
11409021Samw@Sun.COM 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
11418934SJose.Borrego@Sun.COM 	VN_RELE(node->vp);
11428934SJose.Borrego@Sun.COM 	kmem_cache_free(smb_node_cache, node);
11438934SJose.Borrego@Sun.COM }
11448934SJose.Borrego@Sun.COM 
11458934SJose.Borrego@Sun.COM /*
11468934SJose.Borrego@Sun.COM  * smb_node_constructor
11478934SJose.Borrego@Sun.COM  */
11488934SJose.Borrego@Sun.COM static int
11498934SJose.Borrego@Sun.COM smb_node_constructor(void *buf, void *un, int kmflags)
11508934SJose.Borrego@Sun.COM {
11518934SJose.Borrego@Sun.COM 	_NOTE(ARGUNUSED(kmflags, un))
11528934SJose.Borrego@Sun.COM 
11538934SJose.Borrego@Sun.COM 	smb_node_t	*node = (smb_node_t *)buf;
11548934SJose.Borrego@Sun.COM 
11558934SJose.Borrego@Sun.COM 	bzero(node, sizeof (smb_node_t));
11568934SJose.Borrego@Sun.COM 
11578934SJose.Borrego@Sun.COM 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
11588934SJose.Borrego@Sun.COM 	    offsetof(smb_ofile_t, f_nnd));
11598934SJose.Borrego@Sun.COM 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
11608934SJose.Borrego@Sun.COM 	    offsetof(smb_lock_t, l_lnd));
11618934SJose.Borrego@Sun.COM 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
11628934SJose.Borrego@Sun.COM 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
11638934SJose.Borrego@Sun.COM 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
11648934SJose.Borrego@Sun.COM 	smb_node_create_audit_buf(node, kmflags);
11658934SJose.Borrego@Sun.COM 	return (0);
11668934SJose.Borrego@Sun.COM }
11678934SJose.Borrego@Sun.COM 
11688934SJose.Borrego@Sun.COM /*
11698934SJose.Borrego@Sun.COM  * smb_node_destructor
11708934SJose.Borrego@Sun.COM  */
11718934SJose.Borrego@Sun.COM static void
11728934SJose.Borrego@Sun.COM smb_node_destructor(void *buf, void *un)
11738934SJose.Borrego@Sun.COM {
11748934SJose.Borrego@Sun.COM 	_NOTE(ARGUNUSED(un))
11758934SJose.Borrego@Sun.COM 
11768934SJose.Borrego@Sun.COM 	smb_node_t	*node = (smb_node_t *)buf;
11778934SJose.Borrego@Sun.COM 
11788934SJose.Borrego@Sun.COM 	smb_node_destroy_audit_buf(node);
11798934SJose.Borrego@Sun.COM 	mutex_destroy(&node->n_mutex);
11808934SJose.Borrego@Sun.COM 	rw_destroy(&node->n_lock);
11818934SJose.Borrego@Sun.COM 	cv_destroy(&node->n_oplock.ol_cv);
11828934SJose.Borrego@Sun.COM 	smb_llist_destructor(&node->n_lock_list);
11838934SJose.Borrego@Sun.COM 	smb_llist_destructor(&node->n_ofile_list);
11848934SJose.Borrego@Sun.COM }
11858934SJose.Borrego@Sun.COM 
11868934SJose.Borrego@Sun.COM /*
11878934SJose.Borrego@Sun.COM  * smb_node_create_audit_buf
11888934SJose.Borrego@Sun.COM  */
11898934SJose.Borrego@Sun.COM static void
11908934SJose.Borrego@Sun.COM smb_node_create_audit_buf(smb_node_t *node, int kmflags)
11918934SJose.Borrego@Sun.COM {
11928934SJose.Borrego@Sun.COM 	smb_audit_buf_node_t	*abn;
11938934SJose.Borrego@Sun.COM 
11948934SJose.Borrego@Sun.COM 	if (smb_audit_flags & SMB_AUDIT_NODE) {
11958934SJose.Borrego@Sun.COM 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
11968934SJose.Borrego@Sun.COM 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
11978934SJose.Borrego@Sun.COM 		node->n_audit_buf = abn;
11988934SJose.Borrego@Sun.COM 	}
11998934SJose.Borrego@Sun.COM }
12008934SJose.Borrego@Sun.COM 
12018934SJose.Borrego@Sun.COM /*
12028934SJose.Borrego@Sun.COM  * smb_node_destroy_audit_buf
12038934SJose.Borrego@Sun.COM  */
12048934SJose.Borrego@Sun.COM static void
12058934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(smb_node_t *node)
12068934SJose.Borrego@Sun.COM {
12078934SJose.Borrego@Sun.COM 	if (node->n_audit_buf != NULL) {
12088934SJose.Borrego@Sun.COM 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
12098934SJose.Borrego@Sun.COM 		node->n_audit_buf = NULL;
12108934SJose.Borrego@Sun.COM 	}
12118934SJose.Borrego@Sun.COM }
12128934SJose.Borrego@Sun.COM 
12138934SJose.Borrego@Sun.COM /*
12148934SJose.Borrego@Sun.COM  * smb_node_audit
12158934SJose.Borrego@Sun.COM  *
12168934SJose.Borrego@Sun.COM  * This function saves the calling stack in the audit buffer of the node passed
12178934SJose.Borrego@Sun.COM  * in.
12188934SJose.Borrego@Sun.COM  */
12198934SJose.Borrego@Sun.COM static void
12208934SJose.Borrego@Sun.COM smb_node_audit(smb_node_t *node)
12218934SJose.Borrego@Sun.COM {
12228934SJose.Borrego@Sun.COM 	smb_audit_buf_node_t	*abn;
12238934SJose.Borrego@Sun.COM 	smb_audit_record_node_t	*anr;
12248934SJose.Borrego@Sun.COM 
12258934SJose.Borrego@Sun.COM 	if (node->n_audit_buf) {
12268934SJose.Borrego@Sun.COM 		abn = node->n_audit_buf;
12278934SJose.Borrego@Sun.COM 		anr = abn->anb_records;
12288934SJose.Borrego@Sun.COM 		anr += abn->anb_index;
12298934SJose.Borrego@Sun.COM 		abn->anb_index++;
12308934SJose.Borrego@Sun.COM 		abn->anb_index &= abn->anb_max_index;
12318934SJose.Borrego@Sun.COM 		anr->anr_refcnt = node->n_refcnt;
12328934SJose.Borrego@Sun.COM 		anr->anr_depth = getpcstack(anr->anr_stack,
12338934SJose.Borrego@Sun.COM 		    SMB_AUDIT_STACK_DEPTH);
12348934SJose.Borrego@Sun.COM 	}
12358934SJose.Borrego@Sun.COM }
12368934SJose.Borrego@Sun.COM 
12378934SJose.Borrego@Sun.COM static smb_llist_t *
12388934SJose.Borrego@Sun.COM smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
12398934SJose.Borrego@Sun.COM {
12408934SJose.Borrego@Sun.COM 	uint32_t	hashkey;
12418934SJose.Borrego@Sun.COM 
12428934SJose.Borrego@Sun.COM 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
12438934SJose.Borrego@Sun.COM 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
12448934SJose.Borrego@Sun.COM 	*phashkey = hashkey;
12458934SJose.Borrego@Sun.COM 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
12468934SJose.Borrego@Sun.COM }
124710001SJoyce.McIntosh@Sun.COM 
124810001SJoyce.McIntosh@Sun.COM boolean_t
124911963SAfshin.Ardakani@Sun.COM smb_node_is_file(smb_node_t *node)
125011963SAfshin.Ardakani@Sun.COM {
125111963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
125211963SAfshin.Ardakani@Sun.COM 	return (node->vp->v_type == VREG);
125311963SAfshin.Ardakani@Sun.COM }
125411963SAfshin.Ardakani@Sun.COM 
125511963SAfshin.Ardakani@Sun.COM boolean_t
125610001SJoyce.McIntosh@Sun.COM smb_node_is_dir(smb_node_t *node)
125710001SJoyce.McIntosh@Sun.COM {
125810001SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
125911963SAfshin.Ardakani@Sun.COM 	return ((node->vp->v_type == VDIR) ||
126011963SAfshin.Ardakani@Sun.COM 	    (node->flags & NODE_FLAGS_DFSLINK));
126111963SAfshin.Ardakani@Sun.COM }
126211963SAfshin.Ardakani@Sun.COM 
126311963SAfshin.Ardakani@Sun.COM boolean_t
126411963SAfshin.Ardakani@Sun.COM smb_node_is_symlink(smb_node_t *node)
126511963SAfshin.Ardakani@Sun.COM {
126611963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
126711963SAfshin.Ardakani@Sun.COM 	return ((node->vp->v_type == VLNK) &&
126811963SAfshin.Ardakani@Sun.COM 	    ((node->flags & NODE_FLAGS_REPARSE) == 0));
126910001SJoyce.McIntosh@Sun.COM }
127010001SJoyce.McIntosh@Sun.COM 
127110001SJoyce.McIntosh@Sun.COM boolean_t
127211963SAfshin.Ardakani@Sun.COM smb_node_is_dfslink(smb_node_t *node)
127311963SAfshin.Ardakani@Sun.COM {
127411963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
127511963SAfshin.Ardakani@Sun.COM 	return ((node->vp->v_type == VLNK) &&
127611963SAfshin.Ardakani@Sun.COM 	    (node->flags & NODE_FLAGS_DFSLINK));
127711963SAfshin.Ardakani@Sun.COM }
127811963SAfshin.Ardakani@Sun.COM 
127911963SAfshin.Ardakani@Sun.COM boolean_t
128011963SAfshin.Ardakani@Sun.COM smb_node_is_reparse(smb_node_t *node)
128110001SJoyce.McIntosh@Sun.COM {
128210001SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
128311963SAfshin.Ardakani@Sun.COM 	return ((node->vp->v_type == VLNK) &&
128411963SAfshin.Ardakani@Sun.COM 	    (node->flags & NODE_FLAGS_REPARSE));
128511963SAfshin.Ardakani@Sun.COM }
128611963SAfshin.Ardakani@Sun.COM 
128711963SAfshin.Ardakani@Sun.COM boolean_t
128811963SAfshin.Ardakani@Sun.COM smb_node_is_vfsroot(smb_node_t *node)
128911963SAfshin.Ardakani@Sun.COM {
129011963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
129111963SAfshin.Ardakani@Sun.COM 	return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT);
129211963SAfshin.Ardakani@Sun.COM }
129311963SAfshin.Ardakani@Sun.COM 
129411963SAfshin.Ardakani@Sun.COM boolean_t
129511963SAfshin.Ardakani@Sun.COM smb_node_is_system(smb_node_t *node)
129611963SAfshin.Ardakani@Sun.COM {
129711963SAfshin.Ardakani@Sun.COM 	SMB_NODE_VALID(node);
129811963SAfshin.Ardakani@Sun.COM 	return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM);
129910001SJoyce.McIntosh@Sun.COM }
130010001SJoyce.McIntosh@Sun.COM 
130110001SJoyce.McIntosh@Sun.COM /*
130210001SJoyce.McIntosh@Sun.COM  * smb_node_file_is_readonly
130310001SJoyce.McIntosh@Sun.COM  *
130410001SJoyce.McIntosh@Sun.COM  * Checks if the file (which node represents) is marked readonly
130510001SJoyce.McIntosh@Sun.COM  * in the filesystem. No account is taken of any pending readonly
130610001SJoyce.McIntosh@Sun.COM  * in the node, which must be handled by the callers.
130710001SJoyce.McIntosh@Sun.COM  * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY)
130810001SJoyce.McIntosh@Sun.COM  */
130910001SJoyce.McIntosh@Sun.COM boolean_t
131010001SJoyce.McIntosh@Sun.COM smb_node_file_is_readonly(smb_node_t *node)
131110001SJoyce.McIntosh@Sun.COM {
131210001SJoyce.McIntosh@Sun.COM 	smb_attr_t attr;
131310001SJoyce.McIntosh@Sun.COM 
131410001SJoyce.McIntosh@Sun.COM 	if (node == NULL)
131510001SJoyce.McIntosh@Sun.COM 		return (B_FALSE);
131610001SJoyce.McIntosh@Sun.COM 
131710001SJoyce.McIntosh@Sun.COM 	bzero(&attr, sizeof (smb_attr_t));
131810001SJoyce.McIntosh@Sun.COM 	attr.sa_mask = SMB_AT_DOSATTR;
131910001SJoyce.McIntosh@Sun.COM 	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
132010001SJoyce.McIntosh@Sun.COM 	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
132110001SJoyce.McIntosh@Sun.COM }
132210001SJoyce.McIntosh@Sun.COM 
132310001SJoyce.McIntosh@Sun.COM /*
132410001SJoyce.McIntosh@Sun.COM  * smb_node_setattr
132510001SJoyce.McIntosh@Sun.COM  *
132610001SJoyce.McIntosh@Sun.COM  * The sr may be NULL, for example when closing an ofile.
132710001SJoyce.McIntosh@Sun.COM  * The ofile may be NULL, for example when a client request
132810001SJoyce.McIntosh@Sun.COM  * specifies the file by pathname.
132910001SJoyce.McIntosh@Sun.COM  *
133010504SKeyur.Desai@Sun.COM  * Timestamps
133110001SJoyce.McIntosh@Sun.COM  * When attributes are set on an ofile, any pending timestamps
133210001SJoyce.McIntosh@Sun.COM  * from a write request on the ofile are implicitly set to "now".
133310001SJoyce.McIntosh@Sun.COM  * For compatibility with windows the following timestamps are
133410001SJoyce.McIntosh@Sun.COM  * also implicitly set to now:
133510001SJoyce.McIntosh@Sun.COM  * - if any attribute is being explicitly set, set ctime to now
133610001SJoyce.McIntosh@Sun.COM  * - if file size is being explicitly set, set atime & ctime to now
133710001SJoyce.McIntosh@Sun.COM  *
133810504SKeyur.Desai@Sun.COM  * Any timestamp that is being explicitly set, or has previously
133910001SJoyce.McIntosh@Sun.COM  * been explicitly set on the ofile, is excluded from implicit
134010001SJoyce.McIntosh@Sun.COM  * (now) setting.
134110001SJoyce.McIntosh@Sun.COM  *
134210001SJoyce.McIntosh@Sun.COM  * Updates the node's cached timestamp values.
134310001SJoyce.McIntosh@Sun.COM  * Updates the ofile's explicit times flag.
134410001SJoyce.McIntosh@Sun.COM  *
134510504SKeyur.Desai@Sun.COM  * File allocation size
134610504SKeyur.Desai@Sun.COM  * When the file allocation size is set it is first rounded up
134710504SKeyur.Desai@Sun.COM  * to block size. If the file size is smaller than the allocation
134810504SKeyur.Desai@Sun.COM  * size the file is truncated by setting the filesize to allocsz.
134910504SKeyur.Desai@Sun.COM  * If there are open ofiles, the allocsz is cached on the node.
135010504SKeyur.Desai@Sun.COM  *
135110504SKeyur.Desai@Sun.COM  * Updates the node's cached allocsz value.
135210504SKeyur.Desai@Sun.COM  *
135310001SJoyce.McIntosh@Sun.COM  * Returns: errno
135410001SJoyce.McIntosh@Sun.COM  */
135510001SJoyce.McIntosh@Sun.COM int
135610001SJoyce.McIntosh@Sun.COM smb_node_setattr(smb_request_t *sr, smb_node_t *node,
135710001SJoyce.McIntosh@Sun.COM     cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
135810001SJoyce.McIntosh@Sun.COM {
135910001SJoyce.McIntosh@Sun.COM 	int rc;
136010504SKeyur.Desai@Sun.COM 	uint32_t pending_times = 0;
136110504SKeyur.Desai@Sun.COM 	uint32_t explicit_times = 0;
136210001SJoyce.McIntosh@Sun.COM 	timestruc_t now;
136310504SKeyur.Desai@Sun.COM 	smb_attr_t tmp_attr;
136410001SJoyce.McIntosh@Sun.COM 
136510001SJoyce.McIntosh@Sun.COM 	ASSERT(attr);
136610001SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
136710001SJoyce.McIntosh@Sun.COM 
136810504SKeyur.Desai@Sun.COM 	/* set attributes specified in attr */
136910504SKeyur.Desai@Sun.COM 	if (attr->sa_mask != 0) {
137010504SKeyur.Desai@Sun.COM 		/* if allocation size is < file size, truncate the file */
137110504SKeyur.Desai@Sun.COM 		if (attr->sa_mask & SMB_AT_ALLOCSZ) {
137210504SKeyur.Desai@Sun.COM 			attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
137310001SJoyce.McIntosh@Sun.COM 
137410504SKeyur.Desai@Sun.COM 			bzero(&tmp_attr, sizeof (smb_attr_t));
137510504SKeyur.Desai@Sun.COM 			tmp_attr.sa_mask = SMB_AT_SIZE;
137610504SKeyur.Desai@Sun.COM 			(void) smb_fsop_getattr(NULL, kcred, node, &tmp_attr);
137710001SJoyce.McIntosh@Sun.COM 
137810504SKeyur.Desai@Sun.COM 			if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) {
137910504SKeyur.Desai@Sun.COM 				attr->sa_vattr.va_size = attr->sa_allocsz;
138010504SKeyur.Desai@Sun.COM 				attr->sa_mask |= SMB_AT_SIZE;
138110504SKeyur.Desai@Sun.COM 			}
138210001SJoyce.McIntosh@Sun.COM 		}
138310504SKeyur.Desai@Sun.COM 
138410504SKeyur.Desai@Sun.COM 		rc = smb_fsop_setattr(sr, cr, node, attr);
138510504SKeyur.Desai@Sun.COM 		if (rc != 0)
138610504SKeyur.Desai@Sun.COM 			return (rc);
138710504SKeyur.Desai@Sun.COM 
138810504SKeyur.Desai@Sun.COM 		smb_node_set_cached_allocsz(node, attr);
138910504SKeyur.Desai@Sun.COM 		smb_node_set_cached_timestamps(node, attr);
139010504SKeyur.Desai@Sun.COM 		if (of) {
139110504SKeyur.Desai@Sun.COM 			smb_ofile_set_explicit_times(of,
139210504SKeyur.Desai@Sun.COM 			    (attr->sa_mask & SMB_AT_TIMES));
139310001SJoyce.McIntosh@Sun.COM 		}
139410001SJoyce.McIntosh@Sun.COM 	}
139510001SJoyce.McIntosh@Sun.COM 
139610504SKeyur.Desai@Sun.COM 	/*
139710504SKeyur.Desai@Sun.COM 	 * Determine which timestamps to implicitly set to "now".
139810504SKeyur.Desai@Sun.COM 	 * Don't overwrite timestamps already explicitly set.
139910504SKeyur.Desai@Sun.COM 	 */
140010504SKeyur.Desai@Sun.COM 	bzero(&tmp_attr, sizeof (smb_attr_t));
140110504SKeyur.Desai@Sun.COM 	gethrestime(&now);
140210504SKeyur.Desai@Sun.COM 	tmp_attr.sa_vattr.va_atime = now;
140310504SKeyur.Desai@Sun.COM 	tmp_attr.sa_vattr.va_mtime = now;
140410504SKeyur.Desai@Sun.COM 	tmp_attr.sa_vattr.va_ctime = now;
140510001SJoyce.McIntosh@Sun.COM 
140610504SKeyur.Desai@Sun.COM 	/* pending write timestamps */
140710504SKeyur.Desai@Sun.COM 	if (of) {
140810504SKeyur.Desai@Sun.COM 		if (smb_ofile_write_time_pending(of)) {
140910504SKeyur.Desai@Sun.COM 			pending_times |=
141010504SKeyur.Desai@Sun.COM 			    (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
141110504SKeyur.Desai@Sun.COM 		}
141210504SKeyur.Desai@Sun.COM 		explicit_times |= (smb_ofile_explicit_times(of));
141310504SKeyur.Desai@Sun.COM 	}
141410504SKeyur.Desai@Sun.COM 	explicit_times |= (attr->sa_mask & SMB_AT_TIMES);
141510504SKeyur.Desai@Sun.COM 	pending_times &= ~explicit_times;
141610001SJoyce.McIntosh@Sun.COM 
141710504SKeyur.Desai@Sun.COM 	if (pending_times) {
141810504SKeyur.Desai@Sun.COM 		tmp_attr.sa_mask = pending_times;
141910504SKeyur.Desai@Sun.COM 		(void) smb_fsop_setattr(NULL, kcred, node, &tmp_attr);
142010504SKeyur.Desai@Sun.COM 	}
142110001SJoyce.McIntosh@Sun.COM 
142210504SKeyur.Desai@Sun.COM 	/* additional timestamps to update in cache */
142310504SKeyur.Desai@Sun.COM 	if (attr->sa_mask)
142410504SKeyur.Desai@Sun.COM 		tmp_attr.sa_mask |= SMB_AT_CTIME;
142510504SKeyur.Desai@Sun.COM 	if (attr->sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ))
142610504SKeyur.Desai@Sun.COM 		tmp_attr.sa_mask |= SMB_AT_MTIME;
142710504SKeyur.Desai@Sun.COM 	tmp_attr.sa_mask &= ~explicit_times;
142810504SKeyur.Desai@Sun.COM 
142910504SKeyur.Desai@Sun.COM 	if (tmp_attr.sa_mask)
143010504SKeyur.Desai@Sun.COM 		smb_node_set_cached_timestamps(node, &tmp_attr);
143110001SJoyce.McIntosh@Sun.COM 
143211963SAfshin.Ardakani@Sun.COM 	if (tmp_attr.sa_mask & SMB_AT_MTIME || explicit_times & SMB_AT_MTIME) {
143311963SAfshin.Ardakani@Sun.COM 		if (node->n_dnode != NULL)
143411963SAfshin.Ardakani@Sun.COM 			smb_node_notify_change(node->n_dnode);
143511963SAfshin.Ardakani@Sun.COM 	}
143611337SWilliam.Krier@Sun.COM 
143710001SJoyce.McIntosh@Sun.COM 	return (0);
143810001SJoyce.McIntosh@Sun.COM }
143910001SJoyce.McIntosh@Sun.COM 
144010001SJoyce.McIntosh@Sun.COM /*
144110001SJoyce.McIntosh@Sun.COM  * smb_node_getattr
144210001SJoyce.McIntosh@Sun.COM  *
144310001SJoyce.McIntosh@Sun.COM  * Get attributes from the file system and apply any smb-specific
144410001SJoyce.McIntosh@Sun.COM  * overrides for size, dos attributes and timestamps
144510001SJoyce.McIntosh@Sun.COM  *
144610001SJoyce.McIntosh@Sun.COM  * node->readonly_creator reflects whether a readonly set is pending
144710001SJoyce.McIntosh@Sun.COM  * from a readonly create. The readonly attribute should be visible to
144810001SJoyce.McIntosh@Sun.COM  * all clients even though the readonly creator fid is immune to the
144910001SJoyce.McIntosh@Sun.COM  * readonly bit until close.
145010001SJoyce.McIntosh@Sun.COM  *
145110001SJoyce.McIntosh@Sun.COM  * Returns: errno
145210001SJoyce.McIntosh@Sun.COM  */
145310001SJoyce.McIntosh@Sun.COM int
145410001SJoyce.McIntosh@Sun.COM smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
145510001SJoyce.McIntosh@Sun.COM {
145610001SJoyce.McIntosh@Sun.COM 	int rc;
145710001SJoyce.McIntosh@Sun.COM 
145810001SJoyce.McIntosh@Sun.COM 	SMB_NODE_VALID(node);
145910001SJoyce.McIntosh@Sun.COM 
146010001SJoyce.McIntosh@Sun.COM 	bzero(attr, sizeof (smb_attr_t));
146110001SJoyce.McIntosh@Sun.COM 	attr->sa_mask = SMB_AT_ALL;
146210001SJoyce.McIntosh@Sun.COM 	rc = smb_fsop_getattr(sr, kcred, node, attr);
146310001SJoyce.McIntosh@Sun.COM 	if (rc != 0)
146410001SJoyce.McIntosh@Sun.COM 		return (rc);
146510001SJoyce.McIntosh@Sun.COM 
146610001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
146710001SJoyce.McIntosh@Sun.COM 
146811963SAfshin.Ardakani@Sun.COM 	if (smb_node_is_dir(node)) {
146910001SJoyce.McIntosh@Sun.COM 		attr->sa_vattr.va_size = 0;
147010504SKeyur.Desai@Sun.COM 		attr->sa_allocsz = 0;
147110966SJordan.Brown@Sun.COM 		attr->sa_vattr.va_nlink = 1;
147210504SKeyur.Desai@Sun.COM 	}
147310001SJoyce.McIntosh@Sun.COM 
147410001SJoyce.McIntosh@Sun.COM 	if (node->readonly_creator)
147510001SJoyce.McIntosh@Sun.COM 		attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
147610001SJoyce.McIntosh@Sun.COM 	if (attr->sa_dosattr == 0)
147710001SJoyce.McIntosh@Sun.COM 		attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
147810001SJoyce.McIntosh@Sun.COM 
147910504SKeyur.Desai@Sun.COM 
148010001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
148110001SJoyce.McIntosh@Sun.COM 
148210504SKeyur.Desai@Sun.COM 	smb_node_get_cached_allocsz(node, attr);
148310001SJoyce.McIntosh@Sun.COM 	smb_node_get_cached_timestamps(node, attr);
148410504SKeyur.Desai@Sun.COM 
148510001SJoyce.McIntosh@Sun.COM 	return (0);
148610001SJoyce.McIntosh@Sun.COM }
148710001SJoyce.McIntosh@Sun.COM 
148810001SJoyce.McIntosh@Sun.COM /*
148910504SKeyur.Desai@Sun.COM  * smb_node_init_cached_data
149010504SKeyur.Desai@Sun.COM  */
149110504SKeyur.Desai@Sun.COM static void
149210504SKeyur.Desai@Sun.COM smb_node_init_cached_data(smb_node_t *node)
149310504SKeyur.Desai@Sun.COM {
149410504SKeyur.Desai@Sun.COM 	smb_attr_t attr;
149510504SKeyur.Desai@Sun.COM 
149610504SKeyur.Desai@Sun.COM 	bzero(&attr, sizeof (smb_attr_t));
149710504SKeyur.Desai@Sun.COM 	attr.sa_mask = SMB_AT_ALL;
149810504SKeyur.Desai@Sun.COM 	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
149910504SKeyur.Desai@Sun.COM 
150010504SKeyur.Desai@Sun.COM 	smb_node_init_cached_allocsz(node, &attr);
150110504SKeyur.Desai@Sun.COM 	smb_node_init_cached_timestamps(node, &attr);
150210504SKeyur.Desai@Sun.COM }
150310504SKeyur.Desai@Sun.COM 
150410504SKeyur.Desai@Sun.COM /*
150510504SKeyur.Desai@Sun.COM  * smb_node_clear_cached_data
150610504SKeyur.Desai@Sun.COM  */
150710504SKeyur.Desai@Sun.COM static void
150810504SKeyur.Desai@Sun.COM smb_node_clear_cached_data(smb_node_t *node)
150910504SKeyur.Desai@Sun.COM {
151010504SKeyur.Desai@Sun.COM 	smb_node_clear_cached_allocsz(node);
151110504SKeyur.Desai@Sun.COM 	smb_node_clear_cached_timestamps(node);
151210504SKeyur.Desai@Sun.COM }
151310504SKeyur.Desai@Sun.COM 
151410504SKeyur.Desai@Sun.COM /*
151510504SKeyur.Desai@Sun.COM  * File allocation size (allocsz) caching
151610504SKeyur.Desai@Sun.COM  *
151710504SKeyur.Desai@Sun.COM  * When there are open ofiles on the node, the file allocsz is cached.
151810504SKeyur.Desai@Sun.COM  * The cached value (n_allocsz) is initialized when the first ofile is
151910504SKeyur.Desai@Sun.COM  * opened and cleared when the last is closed. Allocsz calculated from
152010504SKeyur.Desai@Sun.COM  * the filesize (rounded up to block size).
152110504SKeyur.Desai@Sun.COM  * When the allocation size is queried, if the cached allocsz is less
152210504SKeyur.Desai@Sun.COM  * than the filesize, it is recalculated from the filesize.
152310504SKeyur.Desai@Sun.COM  */
152410504SKeyur.Desai@Sun.COM 
152510504SKeyur.Desai@Sun.COM /*
152610504SKeyur.Desai@Sun.COM  * smb_node_init_cached_allocsz
152710504SKeyur.Desai@Sun.COM  *
152810504SKeyur.Desai@Sun.COM  * If there are open ofiles, cache the allocsz in the node.
152910504SKeyur.Desai@Sun.COM  * Calculate the allocsz from the filesizes.
153010504SKeyur.Desai@Sun.COM  * block size).
153110504SKeyur.Desai@Sun.COM  */
153210504SKeyur.Desai@Sun.COM static void
153310504SKeyur.Desai@Sun.COM smb_node_init_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
153410504SKeyur.Desai@Sun.COM {
153510504SKeyur.Desai@Sun.COM 	mutex_enter(&node->n_mutex);
153610504SKeyur.Desai@Sun.COM 	if (node->n_open_count == 1)
153710504SKeyur.Desai@Sun.COM 		node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
153810504SKeyur.Desai@Sun.COM 	mutex_exit(&node->n_mutex);
153910504SKeyur.Desai@Sun.COM }
154010504SKeyur.Desai@Sun.COM 
154110504SKeyur.Desai@Sun.COM /*
154210504SKeyur.Desai@Sun.COM  * smb_node_clear_cached_allocsz
154310504SKeyur.Desai@Sun.COM  */
154410504SKeyur.Desai@Sun.COM static void
154510504SKeyur.Desai@Sun.COM smb_node_clear_cached_allocsz(smb_node_t *node)
154610504SKeyur.Desai@Sun.COM {
154710504SKeyur.Desai@Sun.COM 	mutex_enter(&node->n_mutex);
154810504SKeyur.Desai@Sun.COM 	if (node->n_open_count == 0)
154910504SKeyur.Desai@Sun.COM 		node->n_allocsz = 0;
155010504SKeyur.Desai@Sun.COM 	mutex_exit(&node->n_mutex);
155110504SKeyur.Desai@Sun.COM }
155210504SKeyur.Desai@Sun.COM 
155310504SKeyur.Desai@Sun.COM /*
155410504SKeyur.Desai@Sun.COM  * smb_node_get_cached_allocsz
155510504SKeyur.Desai@Sun.COM  *
155610504SKeyur.Desai@Sun.COM  * If there is no cached allocsz (no open files), calculate
155710504SKeyur.Desai@Sun.COM  * allocsz from the filesize.
155810504SKeyur.Desai@Sun.COM  * If the allocsz is cached but is smaller than the filesize
155910504SKeyur.Desai@Sun.COM  * recalculate the cached allocsz from the filesize.
156010504SKeyur.Desai@Sun.COM  *
156110504SKeyur.Desai@Sun.COM  * Return allocs in attr->sa_allocsz.
156210504SKeyur.Desai@Sun.COM  */
156310504SKeyur.Desai@Sun.COM static void
156410504SKeyur.Desai@Sun.COM smb_node_get_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
156510504SKeyur.Desai@Sun.COM {
156611963SAfshin.Ardakani@Sun.COM 	if (smb_node_is_dir(node))
156710504SKeyur.Desai@Sun.COM 		return;
156810504SKeyur.Desai@Sun.COM 
156910504SKeyur.Desai@Sun.COM 	mutex_enter(&node->n_mutex);
157010504SKeyur.Desai@Sun.COM 	if (node->n_open_count == 0) {
157110504SKeyur.Desai@Sun.COM 		attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
157210504SKeyur.Desai@Sun.COM 	} else {
157310504SKeyur.Desai@Sun.COM 		if (node->n_allocsz < attr->sa_vattr.va_size)
157410504SKeyur.Desai@Sun.COM 			node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
157510504SKeyur.Desai@Sun.COM 		attr->sa_allocsz = node->n_allocsz;
157610504SKeyur.Desai@Sun.COM 	}
157710504SKeyur.Desai@Sun.COM 	mutex_exit(&node->n_mutex);
157810504SKeyur.Desai@Sun.COM }
157910504SKeyur.Desai@Sun.COM 
158010504SKeyur.Desai@Sun.COM /*
158110504SKeyur.Desai@Sun.COM  * smb_node_set_cached_allocsz
158210504SKeyur.Desai@Sun.COM  *
158310504SKeyur.Desai@Sun.COM  * attr->sa_allocsz has already been rounded to block size by
158410504SKeyur.Desai@Sun.COM  * the caller.
158510504SKeyur.Desai@Sun.COM  */
158610504SKeyur.Desai@Sun.COM static void
158710504SKeyur.Desai@Sun.COM smb_node_set_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
158810504SKeyur.Desai@Sun.COM {
158910504SKeyur.Desai@Sun.COM 	mutex_enter(&node->n_mutex);
159010504SKeyur.Desai@Sun.COM 	if (attr->sa_mask & SMB_AT_ALLOCSZ) {
159110504SKeyur.Desai@Sun.COM 		if (node->n_open_count > 0)
159210504SKeyur.Desai@Sun.COM 			node->n_allocsz = attr->sa_allocsz;
159310504SKeyur.Desai@Sun.COM 	}
159410504SKeyur.Desai@Sun.COM 	mutex_exit(&node->n_mutex);
159510504SKeyur.Desai@Sun.COM }
159610504SKeyur.Desai@Sun.COM 
159710504SKeyur.Desai@Sun.COM 
159810504SKeyur.Desai@Sun.COM /*
159910001SJoyce.McIntosh@Sun.COM  * Timestamp caching
160010001SJoyce.McIntosh@Sun.COM  *
160110001SJoyce.McIntosh@Sun.COM  * Solaris file systems handle timestamps different from NTFS. For
160210001SJoyce.McIntosh@Sun.COM  * example when file data is written NTFS doesn't update the timestamps
160310001SJoyce.McIntosh@Sun.COM  * until the file is closed, and then only if they haven't been explicity
160410001SJoyce.McIntosh@Sun.COM  * set via a set attribute request. In order to provide a more similar
160510001SJoyce.McIntosh@Sun.COM  * view of an open file's timestamps, we cache the timestamps in the
160610001SJoyce.McIntosh@Sun.COM  * node and manipulate them in a manner more consistent with windows.
160710001SJoyce.McIntosh@Sun.COM  * (See handling of explicit times and pending timestamps from a write
160810001SJoyce.McIntosh@Sun.COM  * request in smb_node_getattr and smb_node_setattr above.)
160910001SJoyce.McIntosh@Sun.COM  * Timestamps remain cached while there are open ofiles for the node.
161010001SJoyce.McIntosh@Sun.COM  * This includes open ofiles for named streams.
161110001SJoyce.McIntosh@Sun.COM  * n_open_ofiles cannot be used as this doesn't include ofiles opened
161210001SJoyce.McIntosh@Sun.COM  * for the node's named streams. Thus n_timestamps contains a count
161310001SJoyce.McIntosh@Sun.COM  * of open ofiles (t_open_ofiles), including named streams' ofiles,
161410001SJoyce.McIntosh@Sun.COM  * to be used to control timestamp caching.
161510001SJoyce.McIntosh@Sun.COM  *
161610001SJoyce.McIntosh@Sun.COM  * If a node represents a named stream the associated unnamed streams
161710001SJoyce.McIntosh@Sun.COM  * cached timestamps are used instead.
161810001SJoyce.McIntosh@Sun.COM  */
161910001SJoyce.McIntosh@Sun.COM 
162010001SJoyce.McIntosh@Sun.COM /*
162110001SJoyce.McIntosh@Sun.COM  * smb_node_init_cached_timestamps
162210001SJoyce.McIntosh@Sun.COM  *
162310001SJoyce.McIntosh@Sun.COM  * Increment count of open ofiles which are using the cached timestamps.
162410001SJoyce.McIntosh@Sun.COM  * If this is the first open ofile, init the cached timestamps from the
162510001SJoyce.McIntosh@Sun.COM  * file system values.
162610001SJoyce.McIntosh@Sun.COM  */
162710001SJoyce.McIntosh@Sun.COM static void
162810504SKeyur.Desai@Sun.COM smb_node_init_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
162910001SJoyce.McIntosh@Sun.COM {
163010001SJoyce.McIntosh@Sun.COM 	smb_node_t *unode;
163110001SJoyce.McIntosh@Sun.COM 
163210001SJoyce.McIntosh@Sun.COM 	if ((unode = SMB_IS_STREAM(node)) != NULL)
163310001SJoyce.McIntosh@Sun.COM 		node = unode;
163410001SJoyce.McIntosh@Sun.COM 
163510001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
163610001SJoyce.McIntosh@Sun.COM 	++(node->n_timestamps.t_open_ofiles);
163710001SJoyce.McIntosh@Sun.COM 	if (node->n_timestamps.t_open_ofiles == 1) {
163810504SKeyur.Desai@Sun.COM 		node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
163910504SKeyur.Desai@Sun.COM 		node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
164010504SKeyur.Desai@Sun.COM 		node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
164110504SKeyur.Desai@Sun.COM 		node->n_timestamps.t_crtime = attr->sa_crtime;
164210001SJoyce.McIntosh@Sun.COM 		node->n_timestamps.t_cached = B_TRUE;
164310001SJoyce.McIntosh@Sun.COM 	}
164410001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
164510001SJoyce.McIntosh@Sun.COM }
164610001SJoyce.McIntosh@Sun.COM 
164710001SJoyce.McIntosh@Sun.COM /*
164810001SJoyce.McIntosh@Sun.COM  * smb_node_clear_cached_timestamps
164910001SJoyce.McIntosh@Sun.COM  *
165010001SJoyce.McIntosh@Sun.COM  * Decrement count of open ofiles using the cached timestamps.
165110001SJoyce.McIntosh@Sun.COM  * If the decremented count is zero, clear the cached timestamps.
165210001SJoyce.McIntosh@Sun.COM  */
165310001SJoyce.McIntosh@Sun.COM static void
165410001SJoyce.McIntosh@Sun.COM smb_node_clear_cached_timestamps(smb_node_t *node)
165510001SJoyce.McIntosh@Sun.COM {
165610001SJoyce.McIntosh@Sun.COM 	smb_node_t *unode;
165710001SJoyce.McIntosh@Sun.COM 
165810001SJoyce.McIntosh@Sun.COM 	if ((unode = SMB_IS_STREAM(node)) != NULL)
165910001SJoyce.McIntosh@Sun.COM 		node = unode;
166010001SJoyce.McIntosh@Sun.COM 
166110001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
166210001SJoyce.McIntosh@Sun.COM 	ASSERT(node->n_timestamps.t_open_ofiles > 0);
166310001SJoyce.McIntosh@Sun.COM 	--(node->n_timestamps.t_open_ofiles);
166410001SJoyce.McIntosh@Sun.COM 	if (node->n_timestamps.t_open_ofiles == 0)
166510001SJoyce.McIntosh@Sun.COM 		bzero(&node->n_timestamps, sizeof (smb_times_t));
166610001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
166710001SJoyce.McIntosh@Sun.COM }
166810001SJoyce.McIntosh@Sun.COM 
166910001SJoyce.McIntosh@Sun.COM /*
167010001SJoyce.McIntosh@Sun.COM  * smb_node_get_cached_timestamps
167110001SJoyce.McIntosh@Sun.COM  *
167210001SJoyce.McIntosh@Sun.COM  * Overwrite timestamps in attr with those cached in node.
167310001SJoyce.McIntosh@Sun.COM  */
167410001SJoyce.McIntosh@Sun.COM static void
167510001SJoyce.McIntosh@Sun.COM smb_node_get_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
167610001SJoyce.McIntosh@Sun.COM {
167710001SJoyce.McIntosh@Sun.COM 	smb_node_t *unode;
167810001SJoyce.McIntosh@Sun.COM 
167910001SJoyce.McIntosh@Sun.COM 	if ((unode = SMB_IS_STREAM(node)) != NULL)
168010001SJoyce.McIntosh@Sun.COM 		node = unode;
168110001SJoyce.McIntosh@Sun.COM 
168210001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
168310001SJoyce.McIntosh@Sun.COM 	if (node->n_timestamps.t_cached) {
168410001SJoyce.McIntosh@Sun.COM 		attr->sa_vattr.va_mtime = node->n_timestamps.t_mtime;
168510001SJoyce.McIntosh@Sun.COM 		attr->sa_vattr.va_atime = node->n_timestamps.t_atime;
168610001SJoyce.McIntosh@Sun.COM 		attr->sa_vattr.va_ctime = node->n_timestamps.t_ctime;
168710001SJoyce.McIntosh@Sun.COM 		attr->sa_crtime = node->n_timestamps.t_crtime;
168810001SJoyce.McIntosh@Sun.COM 	}
168910001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
169010001SJoyce.McIntosh@Sun.COM }
169110001SJoyce.McIntosh@Sun.COM 
169210001SJoyce.McIntosh@Sun.COM /*
169310001SJoyce.McIntosh@Sun.COM  * smb_node_set_cached_timestamps
169410001SJoyce.McIntosh@Sun.COM  *
169510001SJoyce.McIntosh@Sun.COM  * Update the node's cached timestamps with values from attr.
169610001SJoyce.McIntosh@Sun.COM  */
169710001SJoyce.McIntosh@Sun.COM static void
169810001SJoyce.McIntosh@Sun.COM smb_node_set_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
169910001SJoyce.McIntosh@Sun.COM {
170010001SJoyce.McIntosh@Sun.COM 	smb_node_t *unode;
170110001SJoyce.McIntosh@Sun.COM 
170210001SJoyce.McIntosh@Sun.COM 	if ((unode = SMB_IS_STREAM(node)) != NULL)
170310001SJoyce.McIntosh@Sun.COM 		node = unode;
170410001SJoyce.McIntosh@Sun.COM 
170510001SJoyce.McIntosh@Sun.COM 	mutex_enter(&node->n_mutex);
170610001SJoyce.McIntosh@Sun.COM 	if (node->n_timestamps.t_cached) {
170710001SJoyce.McIntosh@Sun.COM 		if (attr->sa_mask & SMB_AT_MTIME)
170810001SJoyce.McIntosh@Sun.COM 			node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
170910001SJoyce.McIntosh@Sun.COM 		if (attr->sa_mask & SMB_AT_ATIME)
171010001SJoyce.McIntosh@Sun.COM 			node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
171110001SJoyce.McIntosh@Sun.COM 		if (attr->sa_mask & SMB_AT_CTIME)
171210001SJoyce.McIntosh@Sun.COM 			node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
171310001SJoyce.McIntosh@Sun.COM 		if (attr->sa_mask & SMB_AT_CRTIME)
171410001SJoyce.McIntosh@Sun.COM 			node->n_timestamps.t_crtime = attr->sa_crtime;
171510001SJoyce.McIntosh@Sun.COM 	}
171610001SJoyce.McIntosh@Sun.COM 	mutex_exit(&node->n_mutex);
171710001SJoyce.McIntosh@Sun.COM }
171811963SAfshin.Ardakani@Sun.COM 
171911963SAfshin.Ardakani@Sun.COM /*
172011963SAfshin.Ardakani@Sun.COM  * Check to see if the node represents a reparse point.
172111963SAfshin.Ardakani@Sun.COM  * If yes, whether the reparse point contains a DFS link.
172211963SAfshin.Ardakani@Sun.COM  */
172311963SAfshin.Ardakani@Sun.COM static void
172411963SAfshin.Ardakani@Sun.COM smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr)
172511963SAfshin.Ardakani@Sun.COM {
172611963SAfshin.Ardakani@Sun.COM 	nvlist_t *nvl;
172711963SAfshin.Ardakani@Sun.COM 	nvpair_t *rec;
172811963SAfshin.Ardakani@Sun.COM 	char *rec_type;
172911963SAfshin.Ardakani@Sun.COM 
173011963SAfshin.Ardakani@Sun.COM 	if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
173111963SAfshin.Ardakani@Sun.COM 		return;
173211963SAfshin.Ardakani@Sun.COM 
173311963SAfshin.Ardakani@Sun.COM 	if ((nvl = reparse_init()) == NULL)
173411963SAfshin.Ardakani@Sun.COM 		return;
173511963SAfshin.Ardakani@Sun.COM 
173611963SAfshin.Ardakani@Sun.COM 	if (reparse_vnode_parse(node->vp, nvl) != 0) {
173711963SAfshin.Ardakani@Sun.COM 		reparse_free(nvl);
173811963SAfshin.Ardakani@Sun.COM 		return;
173911963SAfshin.Ardakani@Sun.COM 	}
174011963SAfshin.Ardakani@Sun.COM 
174111963SAfshin.Ardakani@Sun.COM 	node->flags |= NODE_FLAGS_REPARSE;
174211963SAfshin.Ardakani@Sun.COM 
174311963SAfshin.Ardakani@Sun.COM 	rec = nvlist_next_nvpair(nvl, NULL);
174411963SAfshin.Ardakani@Sun.COM 	while (rec != NULL) {
174511963SAfshin.Ardakani@Sun.COM 		rec_type = nvpair_name(rec);
174611963SAfshin.Ardakani@Sun.COM 		if ((rec_type != NULL) &&
174711963SAfshin.Ardakani@Sun.COM 		    (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) {
174811963SAfshin.Ardakani@Sun.COM 			node->flags |= NODE_FLAGS_DFSLINK;
174911963SAfshin.Ardakani@Sun.COM 			break;
175011963SAfshin.Ardakani@Sun.COM 		}
175111963SAfshin.Ardakani@Sun.COM 		rec = nvlist_next_nvpair(nvl, rec);
175211963SAfshin.Ardakani@Sun.COM 	}
175311963SAfshin.Ardakani@Sun.COM 
175411963SAfshin.Ardakani@Sun.COM 	reparse_free(nvl);
175511963SAfshin.Ardakani@Sun.COM }
175611963SAfshin.Ardakani@Sun.COM 
175711963SAfshin.Ardakani@Sun.COM /*
175811963SAfshin.Ardakani@Sun.COM  * smb_node_init_system
175911963SAfshin.Ardakani@Sun.COM  *
176011963SAfshin.Ardakani@Sun.COM  * If the node represents a special system file set NODE_FLAG_SYSTEM.
176111963SAfshin.Ardakani@Sun.COM  * System files:
176211963SAfshin.Ardakani@Sun.COM  * - any node whose parent dnode has NODE_FLAG_SYSTEM set
176311963SAfshin.Ardakani@Sun.COM  * - any node whose associated unnamed stream node (unode) has
176411963SAfshin.Ardakani@Sun.COM  *   NODE_FLAG_SYSTEM set
176511963SAfshin.Ardakani@Sun.COM  * - .$EXTEND at root of share (quota management)
176611963SAfshin.Ardakani@Sun.COM  */
176711963SAfshin.Ardakani@Sun.COM static void
176811963SAfshin.Ardakani@Sun.COM smb_node_init_system(smb_node_t *node)
176911963SAfshin.Ardakani@Sun.COM {
177011963SAfshin.Ardakani@Sun.COM 	smb_node_t *dnode = node->n_dnode;
177111963SAfshin.Ardakani@Sun.COM 	smb_node_t *unode = node->n_unode;
177211963SAfshin.Ardakani@Sun.COM 
177311963SAfshin.Ardakani@Sun.COM 	if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) {
177411963SAfshin.Ardakani@Sun.COM 		node->flags |= NODE_FLAGS_SYSTEM;
177511963SAfshin.Ardakani@Sun.COM 		return;
177611963SAfshin.Ardakani@Sun.COM 	}
177711963SAfshin.Ardakani@Sun.COM 
177811963SAfshin.Ardakani@Sun.COM 	if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) {
177911963SAfshin.Ardakani@Sun.COM 		node->flags |= NODE_FLAGS_SYSTEM;
178011963SAfshin.Ardakani@Sun.COM 		return;
178111963SAfshin.Ardakani@Sun.COM 	}
178211963SAfshin.Ardakani@Sun.COM 
178311963SAfshin.Ardakani@Sun.COM 	if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) &&
178411963SAfshin.Ardakani@Sun.COM 	    (strcasecmp(node->od_name, ".$EXTEND") == 0))) {
178511963SAfshin.Ardakani@Sun.COM 		node->flags |= NODE_FLAGS_SYSTEM;
178611963SAfshin.Ardakani@Sun.COM 	}
178711963SAfshin.Ardakani@Sun.COM }
1788