xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_node.c (revision b62fa64bd1b93f15d05f01b9f01842071f059a30)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22c5866007SKeyur Desai  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23a8e9db1cSGordon Ross  * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
24*b62fa64bSToomas Soome  * Copyright 2022-2023 RackTop Systems, Inc.
25da6c28aaSamw  */
26da6c28aaSamw /*
27da6c28aaSamw  * SMB Node State Machine
28da6c28aaSamw  * ----------------------
29da6c28aaSamw  *
30fc724630SAlan Wright  *
31fc724630SAlan Wright  *		    +----------- Creation/Allocation
32da6c28aaSamw  *		    |
33fc724630SAlan Wright  *		    | T0
34da6c28aaSamw  *		    |
35da6c28aaSamw  *		    v
36cb174861Sjoyce mcintosh  *    +----------------------------+
37cb174861Sjoyce mcintosh  *    |  SMB_NODE_STATE_AVAILABLE  |
38cb174861Sjoyce mcintosh  *    +----------------------------+
39cb174861Sjoyce mcintosh  *		    |
40cb174861Sjoyce mcintosh  *		    | T1
41fc724630SAlan Wright  *		    |
42fc724630SAlan Wright  *		    v
43da6c28aaSamw  *    +-----------------------------+
44fc724630SAlan Wright  *    |  SMB_NODE_STATE_DESTROYING  |
45fc724630SAlan Wright  *    +-----------------------------+
46fc724630SAlan Wright  *		    |
47fc724630SAlan Wright  *		    |
48cb174861Sjoyce mcintosh  *		    | T2
49fc724630SAlan Wright  *		    |
50fc724630SAlan Wright  *		    +----------> Deletion/Free
51da6c28aaSamw  *
52da6c28aaSamw  * Transition T0
53da6c28aaSamw  *
54da6c28aaSamw  *    This transition occurs in smb_node_lookup(). If the node looked for is
55da6c28aaSamw  *    not found in the has table a new node is created. The reference count is
56da6c28aaSamw  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
57da6c28aaSamw  *
58da6c28aaSamw  * Transition T1
59da6c28aaSamw  *
60da6c28aaSamw  *    This transition occurs in smb_node_release(). If the reference count
61da6c28aaSamw  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
62da6c28aaSamw  *    reference count will be given out for that node.
63da6c28aaSamw  *
64cb174861Sjoyce mcintosh  * Transition T2
65da6c28aaSamw  *
66da6c28aaSamw  *    This transition occurs in smb_node_release(). The structure is deleted.
67da6c28aaSamw  *
68da6c28aaSamw  * Comments
69da6c28aaSamw  * --------
70da6c28aaSamw  *
71da6c28aaSamw  *    The reason the smb node has 2 states is the following synchronization
72da6c28aaSamw  *    rule:
73da6c28aaSamw  *
74da6c28aaSamw  *    There's a mutex embedded in the node used to protect its fields and
75da6c28aaSamw  *    there's a lock embedded in the bucket of the hash table the node belongs
76da6c28aaSamw  *    to. To increment or to decrement the reference count the mutex must be
77da6c28aaSamw  *    entered. To insert the node into the bucket and to remove it from the
78da6c28aaSamw  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
79da6c28aaSamw  *    lock) have to be entered, the lock has always to be entered first then
80da6c28aaSamw  *    the mutex. This prevents a deadlock between smb_node_lookup() and
81da6c28aaSamw  *    smb_node_release() from occurring. However, in smb_node_release() when the
82da6c28aaSamw  *    reference count drops to zero and triggers the deletion of the node, the
83da6c28aaSamw  *    mutex has to be released before entering the lock of the bucket (to
84da6c28aaSamw  *    remove the node). This creates a window during which the node that is
85da6c28aaSamw  *    about to be freed could be given out by smb_node_lookup(). To close that
86da6c28aaSamw  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
87da6c28aaSamw  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
88da6c28aaSamw  *    state will indicate that the node should be treated as non existent (of
89da6c28aaSamw  *    course the state of the node should be tested/updated under the
90da6c28aaSamw  *    protection of the mutex).
91da6c28aaSamw  */
928d94f651SGordon Ross #include <smbsrv/smb2_kproto.h>
93da6c28aaSamw #include <smbsrv/smb_fsops.h>
942c2961f8Sjose borrego #include <smbsrv/smb_kstat.h>
955496c117SAlek Pinchuk #include <sys/ddi.h>
965496c117SAlek Pinchuk #include <sys/extdirent.h>
97da6c28aaSamw #include <sys/pathname.h>
98da6c28aaSamw #include <sys/sdt.h>
99dc20a302Sas200622 #include <sys/nbmlock.h>
1009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <fs/fs_reparse.h>
101da6c28aaSamw 
102*b62fa64bSToomas Soome /* Todo: move this to sys/time.h */
103*b62fa64bSToomas Soome #ifndef	timespeccmp
104*b62fa64bSToomas Soome #define	timespeccmp(tvp, uvp, cmp)				\
105*b62fa64bSToomas Soome 	(((tvp)->tv_sec == (uvp)->tv_sec) ?			\
106*b62fa64bSToomas Soome 	((tvp)->tv_nsec cmp (uvp)->tv_nsec) :			\
107*b62fa64bSToomas Soome 	((tvp)->tv_sec cmp (uvp)->tv_sec))
108*b62fa64bSToomas Soome #endif
109*b62fa64bSToomas Soome 
1102c2961f8Sjose borrego uint32_t smb_is_executable(char *);
1112c2961f8Sjose borrego static void smb_node_create_audit_buf(smb_node_t *, int);
1122c2961f8Sjose borrego static void smb_node_destroy_audit_buf(smb_node_t *);
1132c2961f8Sjose borrego static void smb_node_audit(smb_node_t *);
114037cac00Sjoyce mcintosh static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
1152c2961f8Sjose borrego static void smb_node_free(smb_node_t *);
1162c2961f8Sjose borrego static int smb_node_constructor(void *, void *, int);
1172c2961f8Sjose borrego static void smb_node_destructor(void *, void *);
1182c2961f8Sjose borrego static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
119e3f2c991SKeyur Desai 
1209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_node_init_reparse(smb_node_t *, smb_attr_t *);
1219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_node_init_system(smb_node_t *);
122e3f2c991SKeyur Desai 
123da6c28aaSamw #define	VALIDATE_DIR_NODE(_dir_, _node_) \
124da6c28aaSamw     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
125da6c28aaSamw     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
1261fcced4cSJordan Brown     ASSERT((_dir_)->n_dnode != (_node_));
127da6c28aaSamw 
128e3f2c991SKeyur Desai /* round sz to DEV_BSIZE block */
129e3f2c991SKeyur Desai #define	SMB_ALLOCSZ(sz)	(((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
130e3f2c991SKeyur Desai 
1312c2961f8Sjose borrego static kmem_cache_t	*smb_node_cache = NULL;
132faa1795aSjb150015 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
1338622ec45SGordon Ross static smb_node_t	*smb_root_node;
134faa1795aSjb150015 
135faa1795aSjb150015 /*
136faa1795aSjb150015  * smb_node_init
137faa1795aSjb150015  *
138faa1795aSjb150015  * Initialization of the SMB node layer.
139faa1795aSjb150015  *
140faa1795aSjb150015  * This function is not multi-thread safe. The caller must make sure only one
141faa1795aSjb150015  * thread makes the call.
142faa1795aSjb150015  */
1438622ec45SGordon Ross void
smb_node_init(void)144faa1795aSjb150015 smb_node_init(void)
145faa1795aSjb150015 {
1468622ec45SGordon Ross 	smb_attr_t	attr;
1478622ec45SGordon Ross 	smb_llist_t	*node_hdr;
1488622ec45SGordon Ross 	smb_node_t	*node;
1498622ec45SGordon Ross 	uint32_t	hashkey;
150faa1795aSjb150015 	int		i;
151faa1795aSjb150015 
1528622ec45SGordon Ross 	if (smb_node_cache != NULL)
1538622ec45SGordon Ross 		return;
1548622ec45SGordon Ross 
1552c2961f8Sjose borrego 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
1562c2961f8Sjose borrego 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
1572c2961f8Sjose borrego 	    NULL, NULL, NULL, 0);
158faa1795aSjb150015 
159faa1795aSjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
160faa1795aSjb150015 		smb_llist_constructor(&smb_node_hash_table[i],
161faa1795aSjb150015 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
162faa1795aSjb150015 	}
1638622ec45SGordon Ross 
1648622ec45SGordon Ross 	/*
1658622ec45SGordon Ross 	 * The node cache is shared by all zones, so the smb_root_node
1668622ec45SGordon Ross 	 * must represent the real (global zone) rootdir.
1678622ec45SGordon Ross 	 * Note intentional use of kcred here.
1688622ec45SGordon Ross 	 */
1698622ec45SGordon Ross 	attr.sa_mask = SMB_AT_ALL;
1708622ec45SGordon Ross 	VERIFY0(smb_vop_getattr(rootdir, NULL, &attr, 0, kcred));
1718622ec45SGordon Ross 	node_hdr = smb_node_get_hash(&rootdir->v_vfsp->vfs_fsid, &attr,
1728622ec45SGordon Ross 	    &hashkey);
1738622ec45SGordon Ross 	node = smb_node_alloc("/", rootdir, node_hdr, hashkey);
1748622ec45SGordon Ross 	smb_llist_enter(node_hdr, RW_WRITER);
1758622ec45SGordon Ross 	smb_llist_insert_head(node_hdr, node);
1768622ec45SGordon Ross 	smb_llist_exit(node_hdr);
1778622ec45SGordon Ross 	smb_root_node = node;	/* smb_node_release in smb_node_fini */
178faa1795aSjb150015 }
179faa1795aSjb150015 
180faa1795aSjb150015 /*
181faa1795aSjb150015  * smb_node_fini
182faa1795aSjb150015  *
183faa1795aSjb150015  * This function is not multi-thread safe. The caller must make sure only one
184faa1795aSjb150015  * thread makes the call.
185faa1795aSjb150015  */
186faa1795aSjb150015 void
smb_node_fini(void)187faa1795aSjb150015 smb_node_fini(void)
188faa1795aSjb150015 {
189faa1795aSjb150015 	int	i;
190faa1795aSjb150015 
1918622ec45SGordon Ross 	if (smb_root_node != NULL) {
1928622ec45SGordon Ross 		smb_node_release(smb_root_node);
1938622ec45SGordon Ross 		smb_root_node = NULL;
1948622ec45SGordon Ross 	}
1958622ec45SGordon Ross 
1968622ec45SGordon Ross 	if (smb_node_cache == NULL)
197faa1795aSjb150015 		return;
198faa1795aSjb150015 
199faa1795aSjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
200811599a4SMatt Barden 		smb_llist_t	*bucket;
201faa1795aSjb150015 		smb_node_t	*node;
202faa1795aSjb150015 
203faa1795aSjb150015 		/*
2047f5d80fdSGordon Ross 		 * The SMB node hash table should be empty at this point.
2057f5d80fdSGordon Ross 		 * If the hash table is not empty, clean it up.
206faa1795aSjb150015 		 *
2077f5d80fdSGordon Ross 		 * The reason why SMB nodes might remain in this table is
2087f5d80fdSGordon Ross 		 * generally forgotten references somewhere, perhaps on
2097f5d80fdSGordon Ross 		 * open files, etc.  Those are defects.
210faa1795aSjb150015 		 */
211811599a4SMatt Barden 		bucket = &smb_node_hash_table[i];
212811599a4SMatt Barden 		node = smb_llist_head(bucket);
213811599a4SMatt Barden 		while (node != NULL) {
2147f5d80fdSGordon Ross #ifdef DEBUG
215811599a4SMatt Barden 			cmn_err(CE_NOTE, "leaked node: 0x%p %s",
216811599a4SMatt Barden 			    (void *)node, node->od_name);
2177f5d80fdSGordon Ross 			cmn_err(CE_NOTE, "...bucket: 0x%p", bucket);
2187f5d80fdSGordon Ross 			debug_enter("leaked_node");
219faa1795aSjb150015 #endif
2207f5d80fdSGordon Ross 			smb_llist_remove(bucket, node);
2217f5d80fdSGordon Ross 			node = smb_llist_head(bucket);
2227f5d80fdSGordon Ross 		}
2237f5d80fdSGordon Ross 	}
224faa1795aSjb150015 
225faa1795aSjb150015 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
226faa1795aSjb150015 		smb_llist_destructor(&smb_node_hash_table[i]);
227faa1795aSjb150015 	}
2282c2961f8Sjose borrego 	kmem_cache_destroy(smb_node_cache);
2292c2961f8Sjose borrego 	smb_node_cache = NULL;
230faa1795aSjb150015 }
231faa1795aSjb150015 
232da6c28aaSamw /*
233da6c28aaSamw  * smb_node_lookup()
234da6c28aaSamw  *
235da6c28aaSamw  * NOTE: This routine should only be called by the file system interface layer,
236da6c28aaSamw  * and not by SMB.
237da6c28aaSamw  *
238da6c28aaSamw  * smb_node_lookup() is called upon successful lookup, mkdir, and create
239da6c28aaSamw  * (for both non-streams and streams).  In each of these cases, a held vnode is
2407f667e74Sjose borrego  * passed into this routine.  If a new smb_node is created it will take its
2417f667e74Sjose borrego  * own hold on the vnode.  The caller's hold therefore still belongs to, and
2427f667e74Sjose borrego  * should be released by, the caller.
243da6c28aaSamw  *
244da6c28aaSamw  * A reference is taken on the smb_node whether found in the hash table
245da6c28aaSamw  * or newly created.
246da6c28aaSamw  *
247da6c28aaSamw  * If an smb_node needs to be created, a reference is also taken on the
2481fcced4cSJordan Brown  * dnode (if passed in).
249da6c28aaSamw  *
250da6c28aaSamw  * See smb_node_release() for details on the release of these references.
251da6c28aaSamw  */
252da6c28aaSamw 
253da6c28aaSamw /*ARGSUSED*/
254da6c28aaSamw 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)255da6c28aaSamw smb_node_lookup(
256da6c28aaSamw     struct smb_request	*sr,
257da6c28aaSamw     struct open_param	*op,
258da6c28aaSamw     cred_t		*cred,
259da6c28aaSamw     vnode_t		*vp,
260da6c28aaSamw     char		*od_name,
2611fcced4cSJordan Brown     smb_node_t		*dnode,
2621fcced4cSJordan Brown     smb_node_t		*unode)
263da6c28aaSamw {
264da6c28aaSamw 	smb_llist_t		*node_hdr;
265da6c28aaSamw 	smb_node_t		*node;
266037cac00Sjoyce mcintosh 	smb_attr_t		attr;
267da6c28aaSamw 	uint32_t		hashkey = 0;
268c8ec8eeaSjose borrego 	fsid_t			fsid;
269da6c28aaSamw 	int			error;
270da6c28aaSamw 	krw_t			lock_mode;
271da6c28aaSamw 	vnode_t			*unnamed_vp = NULL;
272da6c28aaSamw 
273da6c28aaSamw 	/*
274da6c28aaSamw 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
275da6c28aaSamw 	 * because the node may not yet exist.  We also do not want to call
276da6c28aaSamw 	 * it with the list lock held.
277da6c28aaSamw 	 */
278da6c28aaSamw 
2791fcced4cSJordan Brown 	if (unode)
2801fcced4cSJordan Brown 		unnamed_vp = unode->vp;
281da6c28aaSamw 
282da6c28aaSamw 	/*
283da6c28aaSamw 	 * This getattr is performed on behalf of the server
284da6c28aaSamw 	 * that's why kcred is used not the user's cred
285da6c28aaSamw 	 */
286037cac00Sjoyce mcintosh 	attr.sa_mask = SMB_AT_ALL;
2878622ec45SGordon Ross 	error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, zone_kcred());
288da6c28aaSamw 	if (error)
289da6c28aaSamw 		return (NULL);
290da6c28aaSamw 
291c8ec8eeaSjose borrego 	if (sr && sr->tid_tree) {
292da6c28aaSamw 		/*
293c8ec8eeaSjose borrego 		 * The fsid for a file is that of the tree, even
294da6c28aaSamw 		 * if the file resides in a different mountpoint
295da6c28aaSamw 		 * under the share.
296da6c28aaSamw 		 */
297c8ec8eeaSjose borrego 		fsid = SMB_TREE_FSID(sr->tid_tree);
298da6c28aaSamw 	} else {
299da6c28aaSamw 		/*
300da6c28aaSamw 		 * This should be getting executed only for the
301c8ec8eeaSjose borrego 		 * tree root smb_node.
302da6c28aaSamw 		 */
303c8ec8eeaSjose borrego 		fsid = vp->v_vfsp->vfs_fsid;
304da6c28aaSamw 	}
305da6c28aaSamw 
306037cac00Sjoyce mcintosh 	node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
307da6c28aaSamw 	lock_mode = RW_READER;
308da6c28aaSamw 
309da6c28aaSamw 	smb_llist_enter(node_hdr, lock_mode);
310da6c28aaSamw 	for (;;) {
311da6c28aaSamw 		node = list_head(&node_hdr->ll_list);
312da6c28aaSamw 		while (node) {
313da6c28aaSamw 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
314da6c28aaSamw 			ASSERT(node->n_hash_bucket == node_hdr);
315da6c28aaSamw 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
3162c2961f8Sjose borrego 				mutex_enter(&node->n_mutex);
317da6c28aaSamw 				DTRACE_PROBE1(smb_node_lookup_hit,
318da6c28aaSamw 				    smb_node_t *, node);
319da6c28aaSamw 				switch (node->n_state) {
320da6c28aaSamw 				case SMB_NODE_STATE_AVAILABLE:
321da6c28aaSamw 					/* The node was found. */
322da6c28aaSamw 					node->n_refcnt++;
3231fcced4cSJordan Brown 					if ((node->n_dnode == NULL) &&
3241fcced4cSJordan Brown 					    (dnode != NULL) &&
32596a62adaSjoyce mcintosh 					    (node != dnode) &&
326da6c28aaSamw 					    (strcmp(od_name, "..") != 0) &&
327da6c28aaSamw 					    (strcmp(od_name, ".") != 0)) {
3281fcced4cSJordan Brown 						VALIDATE_DIR_NODE(dnode, node);
3291fcced4cSJordan Brown 						node->n_dnode = dnode;
3301fcced4cSJordan Brown 						smb_node_ref(dnode);
331da6c28aaSamw 					}
332da6c28aaSamw 
3332c2961f8Sjose borrego 					smb_node_audit(node);
3342c2961f8Sjose borrego 					mutex_exit(&node->n_mutex);
335da6c28aaSamw 					smb_llist_exit(node_hdr);
336da6c28aaSamw 					return (node);
337da6c28aaSamw 
338da6c28aaSamw 				case SMB_NODE_STATE_DESTROYING:
339da6c28aaSamw 					/*
340da6c28aaSamw 					 * Although the node exists it is about
341da6c28aaSamw 					 * to be destroyed. We act as it hasn't
342da6c28aaSamw 					 * been found.
343da6c28aaSamw 					 */
3442c2961f8Sjose borrego 					mutex_exit(&node->n_mutex);
345da6c28aaSamw 					break;
346da6c28aaSamw 				default:
347da6c28aaSamw 					/*
348da6c28aaSamw 					 * Although the node exists it is in an
349da6c28aaSamw 					 * unknown state. We act as it hasn't
350da6c28aaSamw 					 * been found.
351da6c28aaSamw 					 */
352da6c28aaSamw 					ASSERT(0);
3532c2961f8Sjose borrego 					mutex_exit(&node->n_mutex);
354da6c28aaSamw 					break;
355da6c28aaSamw 				}
356da6c28aaSamw 			}
357da6c28aaSamw 			node = smb_llist_next(node_hdr, node);
358da6c28aaSamw 		}
359da6c28aaSamw 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
360da6c28aaSamw 			lock_mode = RW_WRITER;
361da6c28aaSamw 			continue;
362da6c28aaSamw 		}
363da6c28aaSamw 		break;
364da6c28aaSamw 	}
365037cac00Sjoyce mcintosh 	node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
3669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_init_reparse(node, &attr);
367da6c28aaSamw 
368da6c28aaSamw 	if (op)
369eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		node->flags |= smb_is_executable(op->fqi.fq_last_comp);
370da6c28aaSamw 
3711fcced4cSJordan Brown 	if (dnode) {
3721fcced4cSJordan Brown 		smb_node_ref(dnode);
3731fcced4cSJordan Brown 		node->n_dnode = dnode;
3741fcced4cSJordan Brown 		ASSERT(dnode->n_dnode != node);
3751fcced4cSJordan Brown 		ASSERT((dnode->vp->v_xattrdir) ||
3761fcced4cSJordan Brown 		    (dnode->vp->v_type == VDIR));
377da6c28aaSamw 	}
378da6c28aaSamw 
3791fcced4cSJordan Brown 	if (unode) {
3801fcced4cSJordan Brown 		smb_node_ref(unode);
3811fcced4cSJordan Brown 		node->n_unode = unode;
382da6c28aaSamw 	}
383da6c28aaSamw 
3849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_init_system(node);
3859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
386da6c28aaSamw 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
3872c2961f8Sjose borrego 	smb_node_audit(node);
388da6c28aaSamw 	smb_llist_insert_head(node_hdr, node);
389da6c28aaSamw 	smb_llist_exit(node_hdr);
390da6c28aaSamw 	return (node);
391da6c28aaSamw }
392da6c28aaSamw 
393da6c28aaSamw /*
394da6c28aaSamw  * smb_stream_node_lookup()
395da6c28aaSamw  *
396da6c28aaSamw  * Note: stream_name (the name that will be stored in the "od_name" field
397da6c28aaSamw  * of a stream's smb_node) is the same as the on-disk name for the stream
398da6c28aaSamw  * except that it does not have SMB_STREAM_PREFIX prepended.
399da6c28aaSamw  */
400da6c28aaSamw 
401da6c28aaSamw 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)4022c2961f8Sjose borrego smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
403037cac00Sjoyce mcintosh     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
404da6c28aaSamw {
405da6c28aaSamw 	smb_node_t	*xattrdir_node;
406da6c28aaSamw 	smb_node_t	*snode;
407da6c28aaSamw 
408da6c28aaSamw 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
409037cac00Sjoyce mcintosh 	    fnode, NULL);
410da6c28aaSamw 
411da6c28aaSamw 	if (xattrdir_node == NULL)
412da6c28aaSamw 		return (NULL);
413da6c28aaSamw 
414da6c28aaSamw 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
415037cac00Sjoyce mcintosh 	    fnode);
416da6c28aaSamw 
417da6c28aaSamw 	(void) smb_node_release(xattrdir_node);
418da6c28aaSamw 	return (snode);
419da6c28aaSamw }
420da6c28aaSamw 
421da6c28aaSamw 
422da6c28aaSamw /*
423da6c28aaSamw  * This function should be called whenever a reference is needed on an
424da6c28aaSamw  * smb_node pointer.  The copy of an smb_node pointer from one non-local
425da6c28aaSamw  * data structure to another requires a reference to be taken on the smb_node
426da6c28aaSamw  * (unless the usage is localized).  Each data structure deallocation routine
427da6c28aaSamw  * will call smb_node_release() on its smb_node pointers.
428da6c28aaSamw  *
429da6c28aaSamw  * In general, an smb_node pointer residing in a structure should never be
430da6c28aaSamw  * stale.  A node pointer may be NULL, however, and care should be taken
431da6c28aaSamw  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
432da6c28aaSamw  * Care also needs to be taken with respect to racing deallocations of a
433da6c28aaSamw  * structure.
434da6c28aaSamw  */
435da6c28aaSamw void
smb_node_ref(smb_node_t * node)436da6c28aaSamw smb_node_ref(smb_node_t *node)
437da6c28aaSamw {
4382c2961f8Sjose borrego 	SMB_NODE_VALID(node);
439da6c28aaSamw 
4402c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
4412c2961f8Sjose borrego 	switch (node->n_state) {
4422c2961f8Sjose borrego 	case SMB_NODE_STATE_AVAILABLE:
443da6c28aaSamw 		node->n_refcnt++;
444da6c28aaSamw 		ASSERT(node->n_refcnt);
445da6c28aaSamw 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
4462c2961f8Sjose borrego 		smb_node_audit(node);
4472c2961f8Sjose borrego 		break;
4482c2961f8Sjose borrego 	default:
4492c2961f8Sjose borrego 		SMB_PANIC();
4502c2961f8Sjose borrego 	}
4512c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
452da6c28aaSamw }
453da6c28aaSamw 
454da6c28aaSamw /*
455da6c28aaSamw  * smb_node_lookup() takes a hold on an smb_node, whether found in the
456da6c28aaSamw  * hash table or newly created.  This hold is expected to be released
457da6c28aaSamw  * in the following manner.
458da6c28aaSamw  *
459da6c28aaSamw  * smb_node_lookup() takes an address of an smb_node pointer.  This should
460da6c28aaSamw  * be getting passed down via a lookup (whether path name or component), mkdir,
461da6c28aaSamw  * create.  If the original smb_node pointer resides in a data structure, then
462da6c28aaSamw  * the deallocation routine for the data structure is responsible for calling
463da6c28aaSamw  * smb_node_release() on the smb_node pointer.  Alternatively,
464da6c28aaSamw  * smb_node_release() can be called as soon as the smb_node pointer is no longer
465da6c28aaSamw  * needed.  In this case, callers are responsible for setting an embedded
466da6c28aaSamw  * pointer to NULL if it is known that the last reference is being released.
467da6c28aaSamw  *
468da6c28aaSamw  * If the passed-in address of the smb_node pointer belongs to a local variable,
469da6c28aaSamw  * then the caller with the local variable should call smb_node_release()
470da6c28aaSamw  * directly.
471da6c28aaSamw  *
4721fcced4cSJordan Brown  * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
4731fcced4cSJordan Brown  * as smb_node_lookup() takes a hold on dnode.
474da6c28aaSamw  */
475da6c28aaSamw void
smb_node_release(smb_node_t * node)476da6c28aaSamw smb_node_release(smb_node_t *node)
477da6c28aaSamw {
4782c2961f8Sjose borrego 	SMB_NODE_VALID(node);
479da6c28aaSamw 
4802c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
481da6c28aaSamw 	ASSERT(node->n_refcnt);
482da6c28aaSamw 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
483da6c28aaSamw 	if (--node->n_refcnt == 0) {
484da6c28aaSamw 		switch (node->n_state) {
485da6c28aaSamw 
486da6c28aaSamw 		case SMB_NODE_STATE_AVAILABLE:
487da6c28aaSamw 			node->n_state = SMB_NODE_STATE_DESTROYING;
4884b69ad09SGordon Ross 
4894b69ad09SGordon Ross 			/*
4904b69ad09SGordon Ross 			 * While we still hold n_mutex,
4914b69ad09SGordon Ross 			 * make sure FEM hooks are gone.
4924b69ad09SGordon Ross 			 */
4934b69ad09SGordon Ross 			if (node->n_fcn_count > 0) {
4944b69ad09SGordon Ross 				DTRACE_PROBE1(fem__fcn__dangles,
4954b69ad09SGordon Ross 				    smb_node_t *, node);
4964b69ad09SGordon Ross 				node->n_fcn_count = 0;
4974b69ad09SGordon Ross 				(void) smb_fem_fcn_uninstall(node);
4984b69ad09SGordon Ross 			}
4994b69ad09SGordon Ross 
5002c2961f8Sjose borrego 			mutex_exit(&node->n_mutex);
501da6c28aaSamw 
502e8754e84SGordon Ross 			/*
503e8754e84SGordon Ross 			 * Out of caution, make sure FEM hooks
504e8754e84SGordon Ross 			 * used by oplocks are also gone.
505e8754e84SGordon Ross 			 */
506e8754e84SGordon Ross 			mutex_enter(&node->n_oplock.ol_mutex);
507e8754e84SGordon Ross 			ASSERT(node->n_oplock.ol_fem == B_FALSE);
508e8754e84SGordon Ross 			if (node->n_oplock.ol_fem == B_TRUE) {
509e8754e84SGordon Ross 				smb_fem_oplock_uninstall(node);
510e8754e84SGordon Ross 				node->n_oplock.ol_fem = B_FALSE;
511e8754e84SGordon Ross 			}
512e8754e84SGordon Ross 			mutex_exit(&node->n_oplock.ol_mutex);
513e8754e84SGordon Ross 
514da6c28aaSamw 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
515da6c28aaSamw 			smb_llist_remove(node->n_hash_bucket, node);
516da6c28aaSamw 			smb_llist_exit(node->n_hash_bucket);
517da6c28aaSamw 
518da6c28aaSamw 			/*
519da6c28aaSamw 			 * Check if the file was deleted
520da6c28aaSamw 			 */
52149d83597SMatt Barden 			if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
522da6c28aaSamw 				smb_node_delete_on_close(node);
52349d83597SMatt Barden 			}
524da6c28aaSamw 
5251fcced4cSJordan Brown 			if (node->n_dnode) {
5261fcced4cSJordan Brown 				ASSERT(node->n_dnode->n_magic ==
527da6c28aaSamw 				    SMB_NODE_MAGIC);
5281fcced4cSJordan Brown 				smb_node_release(node->n_dnode);
529da6c28aaSamw 			}
530da6c28aaSamw 
5311fcced4cSJordan Brown 			if (node->n_unode) {
5321fcced4cSJordan Brown 				ASSERT(node->n_unode->n_magic ==
533da6c28aaSamw 				    SMB_NODE_MAGIC);
5341fcced4cSJordan Brown 				smb_node_release(node->n_unode);
535da6c28aaSamw 			}
536da6c28aaSamw 
5372c2961f8Sjose borrego 			smb_node_free(node);
538da6c28aaSamw 			return;
539da6c28aaSamw 
540da6c28aaSamw 		default:
5412c2961f8Sjose borrego 			SMB_PANIC();
542da6c28aaSamw 		}
543da6c28aaSamw 	}
5442c2961f8Sjose borrego 	smb_node_audit(node);
5452c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
546da6c28aaSamw }
547da6c28aaSamw 
54849d83597SMatt Barden void
smb_node_delete_on_close(smb_node_t * node)549da6c28aaSamw smb_node_delete_on_close(smb_node_t *node)
550da6c28aaSamw {
551da6c28aaSamw 	smb_node_t	*d_snode;
552da6c28aaSamw 	int		rc = 0;
5538b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	flags = 0;
554da6c28aaSamw 
5551fcced4cSJordan Brown 	d_snode = node->n_dnode;
55649d83597SMatt Barden 
55749d83597SMatt Barden 	ASSERT((node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0);
55849d83597SMatt Barden 
559da6c28aaSamw 	node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
56049d83597SMatt Barden 	node->flags |= NODE_FLAGS_DELETE_COMMITTED;
5618b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	flags = node->n_delete_on_close_flags;
562da6c28aaSamw 	ASSERT(node->od_name != NULL);
5638b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_node_is_dir(node))
565da6c28aaSamw 		rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
5668b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    d_snode, node->od_name, flags);
567da6c28aaSamw 	else
568da6c28aaSamw 		rc = smb_fsop_remove(0, node->delete_on_close_cred,
5698b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    d_snode, node->od_name, flags);
570148c5f43SAlan Wright 	crfree(node->delete_on_close_cred);
57149d83597SMatt Barden 	node->delete_on_close_cred = NULL;
57249d83597SMatt Barden 
573da6c28aaSamw 	if (rc != 0)
574da6c28aaSamw 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
575da6c28aaSamw 		    node->od_name, rc);
576da6c28aaSamw 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
577da6c28aaSamw }
578da6c28aaSamw 
579da6c28aaSamw /*
580da6c28aaSamw  * smb_node_rename()
581da6c28aaSamw  *
582da6c28aaSamw  */
5832c2961f8Sjose borrego void
smb_node_rename(smb_node_t * from_dnode,smb_node_t * ret_node,smb_node_t * to_dnode,char * to_name)584da6c28aaSamw smb_node_rename(
5852c2961f8Sjose borrego     smb_node_t	*from_dnode,
5862c2961f8Sjose borrego     smb_node_t	*ret_node,
5872c2961f8Sjose borrego     smb_node_t	*to_dnode,
588da6c28aaSamw     char	*to_name)
589da6c28aaSamw {
5902c2961f8Sjose borrego 	SMB_NODE_VALID(from_dnode);
5912c2961f8Sjose borrego 	SMB_NODE_VALID(to_dnode);
5922c2961f8Sjose borrego 	SMB_NODE_VALID(ret_node);
593da6c28aaSamw 
5942c2961f8Sjose borrego 	smb_node_ref(to_dnode);
5952c2961f8Sjose borrego 	mutex_enter(&ret_node->n_mutex);
5962c2961f8Sjose borrego 	switch (ret_node->n_state) {
5972c2961f8Sjose borrego 	case SMB_NODE_STATE_AVAILABLE:
5981fcced4cSJordan Brown 		ret_node->n_dnode = to_dnode;
5992c2961f8Sjose borrego 		mutex_exit(&ret_node->n_mutex);
6001fcced4cSJordan Brown 		ASSERT(to_dnode->n_dnode != ret_node);
6012c2961f8Sjose borrego 		ASSERT((to_dnode->vp->v_xattrdir) ||
6022c2961f8Sjose borrego 		    (to_dnode->vp->v_type == VDIR));
6032c2961f8Sjose borrego 		smb_node_release(from_dnode);
6042c2961f8Sjose borrego 		(void) strcpy(ret_node->od_name, to_name);
605da6c28aaSamw 		/*
606da6c28aaSamw 		 * XXX Need to update attributes?
607da6c28aaSamw 		 */
6082c2961f8Sjose borrego 		break;
6092c2961f8Sjose borrego 	default:
6102c2961f8Sjose borrego 		SMB_PANIC();
6112c2961f8Sjose borrego 	}
612da6c28aaSamw }
613da6c28aaSamw 
6148622ec45SGordon Ross /*
6158622ec45SGordon Ross  * Find/create an SMB node for the root of this zone and store it
6168622ec45SGordon Ross  * in *svrootp.  Also create nodes leading to this directory.
6178622ec45SGordon Ross  */
618da6c28aaSamw int
smb_node_root_init(smb_server_t * sv,smb_node_t ** svrootp)6198622ec45SGordon Ross smb_node_root_init(smb_server_t *sv, smb_node_t **svrootp)
620da6c28aaSamw {
6218622ec45SGordon Ross 	zone_t		*zone = curzone;
622faa1795aSjb150015 	int		error;
623da6c28aaSamw 
6248622ec45SGordon Ross 	ASSERT(zone->zone_id == sv->sv_zid);
6258622ec45SGordon Ross 	if (smb_root_node == NULL)
6268622ec45SGordon Ross 		return (ENOENT);
6278622ec45SGordon Ross 
6288622ec45SGordon Ross 	/*
6298622ec45SGordon Ross 	 * We're getting smb nodes below the zone root here,
6308622ec45SGordon Ross 	 * so need to use kcred, not zone_kcred().
6318622ec45SGordon Ross 	 */
6328622ec45SGordon Ross 	error = smb_pathname(NULL, zone->zone_rootpath, 0,
6331bc6aeeeSMatt Barden 	    smb_root_node, smb_root_node, NULL, svrootp, kcred, NULL);
6348622ec45SGordon Ross 
635faa1795aSjb150015 	return (error);
636faa1795aSjb150015 }
637a90cf9f2SGordon Ross 
6385496c117SAlek Pinchuk /*
6395496c117SAlek Pinchuk  * Helper function for smb_node_set_delete_on_close(). Assumes node is a dir.
6405496c117SAlek Pinchuk  * Return 0 if this is an empty dir. Otherwise return a NT_STATUS code.
641b5b772b0SGordon Ross  * Unfortunately, to find out if a directory is empty, we have to read it
642b5b772b0SGordon Ross  * and check for anything other than "." or ".." in the readdir buf.
6435496c117SAlek Pinchuk  */
6445496c117SAlek Pinchuk static uint32_t
smb_rmdir_possible(smb_node_t * n)645d2488fe8SGordon Ross smb_rmdir_possible(smb_node_t *n)
6465496c117SAlek Pinchuk {
6475496c117SAlek Pinchuk 	ASSERT(n->vp->v_type == VDIR);
648d2488fe8SGordon Ross 	char *buf;
649d2488fe8SGordon Ross 	char *bufptr;
650d2488fe8SGordon Ross 	struct dirent64	*dp;
651d2488fe8SGordon Ross 	uint32_t status = NT_STATUS_SUCCESS;
652d2488fe8SGordon Ross 	int bsize = SMB_ODIR_BUFSIZE;
653d2488fe8SGordon Ross 	int eof = 0;
6545496c117SAlek Pinchuk 
655d2488fe8SGordon Ross 	buf = kmem_alloc(SMB_ODIR_BUFSIZE, KM_SLEEP);
6565496c117SAlek Pinchuk 
657d2488fe8SGordon Ross 	/* Flags zero: no edirent, no ABE wanted here */
658d2488fe8SGordon Ross 	if (smb_vop_readdir(n->vp, 0, buf, &bsize, &eof, 0, zone_kcred())) {
659d2488fe8SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
660d2488fe8SGordon Ross 		goto out;
661d2488fe8SGordon Ross 	}
662d2488fe8SGordon Ross 
6635496c117SAlek Pinchuk 	bufptr = buf;
664d2488fe8SGordon Ross 	while (bsize > 0) {
665d2488fe8SGordon Ross 		/* LINTED pointer alignment */
666d2488fe8SGordon Ross 		dp = (struct dirent64 *)bufptr;
667d2488fe8SGordon Ross 
668d2488fe8SGordon Ross 		bufptr += dp->d_reclen;
669d2488fe8SGordon Ross 		bsize  -= dp->d_reclen;
670d2488fe8SGordon Ross 		if (bsize < 0) {
671d2488fe8SGordon Ross 			/* partial record */
672d2488fe8SGordon Ross 			status = NT_STATUS_DIRECTORY_NOT_EMPTY;
673d2488fe8SGordon Ross 			break;
6745496c117SAlek Pinchuk 		}
675d2488fe8SGordon Ross 
676d2488fe8SGordon Ross 		if (strcmp(dp->d_name, ".") != 0 &&
677d2488fe8SGordon Ross 		    strcmp(dp->d_name, "..") != 0) {
678d2488fe8SGordon Ross 			status = NT_STATUS_DIRECTORY_NOT_EMPTY;
679d2488fe8SGordon Ross 			break;
6805496c117SAlek Pinchuk 		}
681d2488fe8SGordon Ross 	}
682d2488fe8SGordon Ross 
683d2488fe8SGordon Ross out:
684d2488fe8SGordon Ross 	kmem_free(buf, SMB_ODIR_BUFSIZE);
685d2488fe8SGordon Ross 	return (status);
6865496c117SAlek Pinchuk }
687da6c28aaSamw 
688da6c28aaSamw /*
6898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * When DeleteOnClose is set on an smb_node, the common open code will
6908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * reject subsequent open requests for the file. Observation of Windows
6918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * 2000 indicates that subsequent opens should be allowed (assuming
6928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * there would be no sharing violation) until the file is closed using
6938b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * the fid on which the DeleteOnClose was requested.
6948b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *
6958b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * If there are multiple opens with delete-on-close create options,
6968b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * whichever the first file handle is closed will trigger the node to be
6978b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * marked as delete-on-close. The credentials of that ofile will be used
6988b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * as the delete-on-close credentials of the node.
699b5b772b0SGordon Ross  *
700b5b772b0SGordon Ross  * Note that "read-only" tests have already happened before this call.
7018b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  */
7025496c117SAlek Pinchuk uint32_t
smb_node_set_delete_on_close(smb_node_t * node,cred_t * cr,uint32_t flags)7038b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
704da6c28aaSamw {
7055496c117SAlek Pinchuk 	uint32_t status;
7065496c117SAlek Pinchuk 
7075496c117SAlek Pinchuk 	/*
7085496c117SAlek Pinchuk 	 * If the directory is not empty we should fail setting del-on-close
7095496c117SAlek Pinchuk 	 * with STATUS_DIRECTORY_NOT_EMPTY. see MS's
7105496c117SAlek Pinchuk 	 * "File System Behavior Overview" doc section 4.3.2
7115496c117SAlek Pinchuk 	 */
7125496c117SAlek Pinchuk 	if (smb_node_is_dir(node)) {
713d2488fe8SGordon Ross 		status = smb_rmdir_possible(node);
7145496c117SAlek Pinchuk 		if (status != 0) {
7155496c117SAlek Pinchuk 			return (status);
7165496c117SAlek Pinchuk 		}
717037cac00Sjoyce mcintosh 	}
718037cac00Sjoyce mcintosh 
71906721c88SMatt Barden 	/* Dataset roots can't be deleted, so don't set DOC */
72006721c88SMatt Barden 	if ((node->flags & NODE_FLAGS_VFSROOT) != 0) {
72106721c88SMatt Barden 		return (NT_STATUS_CANNOT_DELETE);
72206721c88SMatt Barden 	}
72306721c88SMatt Barden 
724a0aa776eSAlan Wright 	mutex_enter(&node->n_mutex);
725a0aa776eSAlan Wright 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
726b5b772b0SGordon Ross 		/* It was already marked.  We're done. */
7275496c117SAlek Pinchuk 		mutex_exit(&node->n_mutex);
728b5b772b0SGordon Ross 		return (NT_STATUS_SUCCESS);
7295496c117SAlek Pinchuk 	}
7305496c117SAlek Pinchuk 
731da6c28aaSamw 	crhold(cr);
732da6c28aaSamw 	node->delete_on_close_cred = cr;
7338b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	node->n_delete_on_close_flags = flags;
734da6c28aaSamw 	node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
7352c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
7365496c117SAlek Pinchuk 
737a90cf9f2SGordon Ross 	/*
738a90cf9f2SGordon Ross 	 * Tell any change notify calls to close their handles
739a90cf9f2SGordon Ross 	 * and get out of the way.  FILE_ACTION_DELETE_PENDING
740a90cf9f2SGordon Ross 	 * is a special, internal-only action for this purpose.
741a90cf9f2SGordon Ross 	 */
742bfe5e737SGordon Ross 	smb_node_notify_change(node, FILE_ACTION_DELETE_PENDING, NULL);
743a90cf9f2SGordon Ross 
7445496c117SAlek Pinchuk 	return (NT_STATUS_SUCCESS);
745da6c28aaSamw }
746da6c28aaSamw 
747da6c28aaSamw void
smb_node_reset_delete_on_close(smb_node_t * node)748da6c28aaSamw smb_node_reset_delete_on_close(smb_node_t *node)
749da6c28aaSamw {
7502c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
751da6c28aaSamw 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
752da6c28aaSamw 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
753da6c28aaSamw 		crfree(node->delete_on_close_cred);
754da6c28aaSamw 		node->delete_on_close_cred = NULL;
7558b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		node->n_delete_on_close_flags = 0;
756da6c28aaSamw 	}
7572c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
758da6c28aaSamw }
759dc20a302Sas200622 
760dc20a302Sas200622 /*
7613ad684d6Sjb150015  * smb_node_open_check
762dc20a302Sas200622  *
763dc20a302Sas200622  * check file sharing rules for current open request
764dc20a302Sas200622  * against all existing opens for a file.
765dc20a302Sas200622  *
766dc20a302Sas200622  * Returns NT_STATUS_SHARING_VIOLATION if there is any
767dc20a302Sas200622  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
768dc20a302Sas200622  */
769dc20a302Sas200622 uint32_t
smb_node_open_check(smb_node_t * node,uint32_t desired_access,uint32_t share_access)7709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_open_check(smb_node_t *node, uint32_t desired_access,
7712c2961f8Sjose borrego     uint32_t share_access)
772dc20a302Sas200622 {
773dc20a302Sas200622 	smb_ofile_t *of;
774dc20a302Sas200622 	uint32_t status;
775dc20a302Sas200622 
7762c2961f8Sjose borrego 	SMB_NODE_VALID(node);
777dc20a302Sas200622 
778dc20a302Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
779dc20a302Sas200622 	of = smb_llist_head(&node->n_ofile_list);
780dc20a302Sas200622 	while (of) {
7819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		status = smb_ofile_open_check(of, desired_access, share_access);
7823ad684d6Sjb150015 
7833ad684d6Sjb150015 		switch (status) {
7843ad684d6Sjb150015 		case NT_STATUS_INVALID_HANDLE:
7853ad684d6Sjb150015 		case NT_STATUS_SUCCESS:
7863ad684d6Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
7873ad684d6Sjb150015 			break;
7883ad684d6Sjb150015 		default:
7893ad684d6Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
79094047d49SGordon Ross 			DTRACE_PROBE3(conflict3,
791a5a9a6bbSGordon Ross 			    smb_ofile_t *, of,
79294047d49SGordon Ross 			    uint32_t, desired_access,
79394047d49SGordon Ross 			    uint32_t, share_access);
794dc20a302Sas200622 			smb_llist_exit(&node->n_ofile_list);
795dc20a302Sas200622 			return (status);
796dc20a302Sas200622 		}
797dc20a302Sas200622 	}
7983ad684d6Sjb150015 
799dc20a302Sas200622 	smb_llist_exit(&node->n_ofile_list);
800dc20a302Sas200622 	return (NT_STATUS_SUCCESS);
801dc20a302Sas200622 }
802dc20a302Sas200622 
803dc20a302Sas200622 uint32_t
smb_node_rename_check(smb_node_t * node)8042c2961f8Sjose borrego smb_node_rename_check(smb_node_t *node)
805dc20a302Sas200622 {
8062c2961f8Sjose borrego 	smb_ofile_t	*of;
8073ad684d6Sjb150015 	uint32_t	status;
808dc20a302Sas200622 
8092c2961f8Sjose borrego 	SMB_NODE_VALID(node);
810dc20a302Sas200622 
811dc20a302Sas200622 	/*
812dc20a302Sas200622 	 * Intra-CIFS check
813dc20a302Sas200622 	 */
814dc20a302Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
8153ad684d6Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
8163ad684d6Sjb150015 	while (of) {
8173ad684d6Sjb150015 		status = smb_ofile_rename_check(of);
818dc20a302Sas200622 
8193ad684d6Sjb150015 		switch (status) {
8203ad684d6Sjb150015 		case NT_STATUS_INVALID_HANDLE:
8213ad684d6Sjb150015 		case NT_STATUS_SUCCESS:
8223ad684d6Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
8233ad684d6Sjb150015 			break;
8243ad684d6Sjb150015 		default:
8253ad684d6Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
826a5a9a6bbSGordon Ross 			DTRACE_PROBE1(conflict1, smb_ofile_t *, of);
827dc20a302Sas200622 			smb_llist_exit(&node->n_ofile_list);
8283ad684d6Sjb150015 			return (status);
829dc20a302Sas200622 		}
830dc20a302Sas200622 	}
831dc20a302Sas200622 	smb_llist_exit(&node->n_ofile_list);
832dc20a302Sas200622 	return (NT_STATUS_SUCCESS);
833dc20a302Sas200622 }
834dc20a302Sas200622 
8353ad684d6Sjb150015 uint32_t
smb_node_delete_check(smb_node_t * node)836dc20a302Sas200622 smb_node_delete_check(smb_node_t *node)
837dc20a302Sas200622 {
8383ad684d6Sjb150015 	smb_ofile_t	*of;
8393ad684d6Sjb150015 	uint32_t	status;
840dc20a302Sas200622 
8412c2961f8Sjose borrego 	SMB_NODE_VALID(node);
842dc20a302Sas200622 
8439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_node_is_dir(node))
844dc20a302Sas200622 		return (NT_STATUS_SUCCESS);
845dc20a302Sas200622 
8469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_node_is_reparse(node))
8479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (NT_STATUS_ACCESS_DENIED);
8489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
849dc20a302Sas200622 	/*
850dc20a302Sas200622 	 * intra-CIFS check
851dc20a302Sas200622 	 */
852dc20a302Sas200622 	smb_llist_enter(&node->n_ofile_list, RW_READER);
8533ad684d6Sjb150015 	of = smb_llist_head(&node->n_ofile_list);
8543ad684d6Sjb150015 	while (of) {
8553ad684d6Sjb150015 		status = smb_ofile_delete_check(of);
8563ad684d6Sjb150015 
8573ad684d6Sjb150015 		switch (status) {
8583ad684d6Sjb150015 		case NT_STATUS_INVALID_HANDLE:
8593ad684d6Sjb150015 		case NT_STATUS_SUCCESS:
8603ad684d6Sjb150015 			of = smb_llist_next(&node->n_ofile_list, of);
8613ad684d6Sjb150015 			break;
8623ad684d6Sjb150015 		default:
8633ad684d6Sjb150015 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
864a5a9a6bbSGordon Ross 			DTRACE_PROBE1(conflict1, smb_ofile_t *, of);
865dc20a302Sas200622 			smb_llist_exit(&node->n_ofile_list);
8663ad684d6Sjb150015 			return (status);
867dc20a302Sas200622 		}
868dc20a302Sas200622 	}
869dc20a302Sas200622 	smb_llist_exit(&node->n_ofile_list);
870dc20a302Sas200622 	return (NT_STATUS_SUCCESS);
871dc20a302Sas200622 }
872dc20a302Sas200622 
873cb174861Sjoyce mcintosh /*
874cb174861Sjoyce mcintosh  * smb_node_share_check
875cb174861Sjoyce mcintosh  *
876cb174861Sjoyce mcintosh  * Returns: TRUE    - ofiles have non-zero share access
877cb174861Sjoyce mcintosh  *          B_FALSE - ofile with share access NONE.
878cb174861Sjoyce mcintosh  */
879cb174861Sjoyce mcintosh boolean_t
smb_node_share_check(smb_node_t * node)880cb174861Sjoyce mcintosh smb_node_share_check(smb_node_t *node)
881cb174861Sjoyce mcintosh {
882cb174861Sjoyce mcintosh 	smb_ofile_t	*of;
883cb174861Sjoyce mcintosh 	boolean_t	status = B_TRUE;
884cb174861Sjoyce mcintosh 
885cb174861Sjoyce mcintosh 	SMB_NODE_VALID(node);
886cb174861Sjoyce mcintosh 
887cb174861Sjoyce mcintosh 	smb_llist_enter(&node->n_ofile_list, RW_READER);
888cb174861Sjoyce mcintosh 	of = smb_llist_head(&node->n_ofile_list);
889cb174861Sjoyce mcintosh 	if (of)
890cb174861Sjoyce mcintosh 		status = smb_ofile_share_check(of);
891cb174861Sjoyce mcintosh 	smb_llist_exit(&node->n_ofile_list);
892cb174861Sjoyce mcintosh 
893cb174861Sjoyce mcintosh 	return (status);
894cb174861Sjoyce mcintosh }
895cb174861Sjoyce mcintosh 
896ccc71be5SGordon Ross /*
897ccc71be5SGordon Ross  * SMB Change Notification
898ccc71be5SGordon Ross  */
899ccc71be5SGordon Ross 
900b1352070SAlan Wright void
smb_node_fcn_subscribe(smb_node_t * node)901bfe5e737SGordon Ross smb_node_fcn_subscribe(smb_node_t *node)
902ccc71be5SGordon Ross {
903ccc71be5SGordon Ross 
904bfe5e737SGordon Ross 	mutex_enter(&node->n_mutex);
905bfe5e737SGordon Ross 	if (node->n_fcn_count == 0)
9068622ec45SGordon Ross 		(void) smb_fem_fcn_install(node);
907bfe5e737SGordon Ross 	node->n_fcn_count++;
908bfe5e737SGordon Ross 	mutex_exit(&node->n_mutex);
909ccc71be5SGordon Ross }
910ccc71be5SGordon Ross 
911ccc71be5SGordon Ross void
smb_node_fcn_unsubscribe(smb_node_t * node)912bfe5e737SGordon Ross smb_node_fcn_unsubscribe(smb_node_t *node)
913ccc71be5SGordon Ross {
914ccc71be5SGordon Ross 
915bfe5e737SGordon Ross 	mutex_enter(&node->n_mutex);
916bfe5e737SGordon Ross 	node->n_fcn_count--;
9174b69ad09SGordon Ross 	if (node->n_fcn_count == 0) {
9184b69ad09SGordon Ross 		VERIFY0(smb_fem_fcn_uninstall(node));
9194b69ad09SGordon Ross 	}
920bfe5e737SGordon Ross 	mutex_exit(&node->n_mutex);
921ccc71be5SGordon Ross }
922ccc71be5SGordon Ross 
923ccc71be5SGordon Ross void
smb_node_notify_change(smb_node_t * node,uint_t action,const char * name)924ccc71be5SGordon Ross smb_node_notify_change(smb_node_t *node, uint_t action, const char *name)
925b1352070SAlan Wright {
926bfe5e737SGordon Ross 	smb_ofile_t	*of;
927bfe5e737SGordon Ross 
928b1352070SAlan Wright 	SMB_NODE_VALID(node);
929b1352070SAlan Wright 
930bfe5e737SGordon Ross 	smb_llist_enter(&node->n_ofile_list, RW_READER);
931bfe5e737SGordon Ross 	of = smb_llist_head(&node->n_ofile_list);
932bfe5e737SGordon Ross 	while (of) {
933bfe5e737SGordon Ross 		/*
934bfe5e737SGordon Ross 		 * We'd rather deliver events only to ofiles that have
935bfe5e737SGordon Ross 		 * subscribed.  There's no explicit synchronization with
936bfe5e737SGordon Ross 		 * where this flag is set, but other actions cause this
937bfe5e737SGordon Ross 		 * value to reach visibility soon enough for events to
938bfe5e737SGordon Ross 		 * start arriving by the time we need them to start.
939bfe5e737SGordon Ross 		 * Once nc_subscribed is set, it stays set for the
940bfe5e737SGordon Ross 		 * life of the ofile.
941bfe5e737SGordon Ross 		 */
942bfe5e737SGordon Ross 		if (of->f_notify.nc_subscribed)
943bfe5e737SGordon Ross 			smb_notify_ofile(of, action, name);
944bfe5e737SGordon Ross 		of = smb_llist_next(&node->n_ofile_list, of);
945bfe5e737SGordon Ross 	}
946bfe5e737SGordon Ross 	smb_llist_exit(&node->n_ofile_list);
947ccc71be5SGordon Ross 
948ccc71be5SGordon Ross 	/*
949bfe5e737SGordon Ross 	 * After changes that add or remove a name,
950bfe5e737SGordon Ross 	 * we know the directory attributes changed,
951bfe5e737SGordon Ross 	 * and we can tell the immediate parent.
952ccc71be5SGordon Ross 	 */
953bfe5e737SGordon Ross 	switch (action) {
954bfe5e737SGordon Ross 	case FILE_ACTION_ADDED:
955bfe5e737SGordon Ross 	case FILE_ACTION_REMOVED:
956bfe5e737SGordon Ross 	case FILE_ACTION_RENAMED_NEW_NAME:
957bfe5e737SGordon Ross 		/*
958bfe5e737SGordon Ross 		 * Note: FILE_ACTION_RENAMED_OLD_NAME is intentionally
959bfe5e737SGordon Ross 		 * omitted, because it's always followed by another
960bfe5e737SGordon Ross 		 * event with FILE_ACTION_RENAMED_NEW_NAME posted to
961bfe5e737SGordon Ross 		 * the same directory, and we only need/want one.
962bfe5e737SGordon Ross 		 */
963bfe5e737SGordon Ross 		if (node->n_dnode != NULL) {
964bfe5e737SGordon Ross 			smb_node_notify_change(node->n_dnode,
965bfe5e737SGordon Ross 			    FILE_ACTION_MODIFIED, node->od_name);
966bfe5e737SGordon Ross 		}
967bfe5e737SGordon Ross 		break;
968b1352070SAlan Wright 	}
969b1352070SAlan Wright 
9709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	/*
971bfe5e737SGordon Ross 	 * If we wanted to support recursive notify events
972bfe5e737SGordon Ross 	 * (where a notify call on some directory receives
973bfe5e737SGordon Ross 	 * events from all objects below that directory),
974bfe5e737SGordon Ross 	 * we might deliver _SUBDIR_CHANGED to all our
975bfe5e737SGordon Ross 	 * parents, grandparents etc, here.  However, we
976bfe5e737SGordon Ross 	 * don't currently subscribe to changes on all the
977bfe5e737SGordon Ross 	 * child (and grandchild) objects that would be
978bfe5e737SGordon Ross 	 * needed to make that work. It's prohibitively
979bfe5e737SGordon Ross 	 * expensive to do that, and support for recursive
980bfe5e737SGordon Ross 	 * notify is optional anyway, so don't bother.
9819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 */
982fe1c642dSBill Krier }
983fe1c642dSBill Krier 
984dc20a302Sas200622 /*
985f8e30ca2SGordon Ross  * Change notify modified differs for stream vs regular file.
986f8e30ca2SGordon Ross  * Changes to a stream give a notification on the "unnamed" node,
987f8e30ca2SGordon Ross  * which is the parent object of the stream.
988f8e30ca2SGordon Ross  */
989f8e30ca2SGordon Ross void
smb_node_notify_modified(smb_node_t * node)990f8e30ca2SGordon Ross smb_node_notify_modified(smb_node_t *node)
991f8e30ca2SGordon Ross {
992f8e30ca2SGordon Ross 	smb_node_t *u_node;
993f8e30ca2SGordon Ross 
994f8e30ca2SGordon Ross 	u_node = SMB_IS_STREAM(node);
995f8e30ca2SGordon Ross 	if (u_node != NULL) {
996f8e30ca2SGordon Ross 		/* This is a named stream */
997f8e30ca2SGordon Ross 		if (u_node->n_dnode != NULL) {
998f8e30ca2SGordon Ross 			smb_node_notify_change(u_node->n_dnode,
999f8e30ca2SGordon Ross 			    FILE_ACTION_MODIFIED_STREAM, u_node->od_name);
1000f8e30ca2SGordon Ross 		}
1001f8e30ca2SGordon Ross 	} else {
1002f8e30ca2SGordon Ross 		/* regular file or directory */
1003f8e30ca2SGordon Ross 		if (node->n_dnode != NULL) {
1004f8e30ca2SGordon Ross 			smb_node_notify_change(node->n_dnode,
1005f8e30ca2SGordon Ross 			    FILE_ACTION_MODIFIED, node->od_name);
1006f8e30ca2SGordon Ross 		}
1007f8e30ca2SGordon Ross 	}
1008f8e30ca2SGordon Ross }
1009f8e30ca2SGordon Ross 
1010f8e30ca2SGordon Ross /*
1011dc20a302Sas200622  * smb_node_start_crit()
1012dc20a302Sas200622  *
1013dc20a302Sas200622  * Enter critical region for share reservations.
1014dc20a302Sas200622  * See comments above smb_fsop_shrlock().
1015dc20a302Sas200622  */
1016dc20a302Sas200622 void
smb_node_start_crit(smb_node_t * node,krw_t mode)1017dc20a302Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode)
1018dc20a302Sas200622 {
10192c2961f8Sjose borrego 	rw_enter(&node->n_lock, mode);
1020dc20a302Sas200622 	nbl_start_crit(node->vp, mode);
1021dc20a302Sas200622 }
1022dc20a302Sas200622 
1023dc20a302Sas200622 /*
1024dc20a302Sas200622  * smb_node_end_crit()
1025dc20a302Sas200622  *
1026dc20a302Sas200622  * Exit critical region for share reservations.
1027dc20a302Sas200622  */
1028dc20a302Sas200622 void
smb_node_end_crit(smb_node_t * node)1029dc20a302Sas200622 smb_node_end_crit(smb_node_t *node)
1030dc20a302Sas200622 {
1031dc20a302Sas200622 	nbl_end_crit(node->vp);
10322c2961f8Sjose borrego 	rw_exit(&node->n_lock);
1033dc20a302Sas200622 }
1034dc20a302Sas200622 
1035dc20a302Sas200622 int
smb_node_in_crit(smb_node_t * node)1036dc20a302Sas200622 smb_node_in_crit(smb_node_t *node)
1037dc20a302Sas200622 {
10382c2961f8Sjose borrego 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
10392c2961f8Sjose borrego }
10402c2961f8Sjose borrego 
10412c2961f8Sjose borrego void
smb_node_rdlock(smb_node_t * node)10422c2961f8Sjose borrego smb_node_rdlock(smb_node_t *node)
10432c2961f8Sjose borrego {
10442c2961f8Sjose borrego 	rw_enter(&node->n_lock, RW_READER);
10452c2961f8Sjose borrego }
10462c2961f8Sjose borrego 
10472c2961f8Sjose borrego void
smb_node_wrlock(smb_node_t * node)10482c2961f8Sjose borrego smb_node_wrlock(smb_node_t *node)
10492c2961f8Sjose borrego {
10502c2961f8Sjose borrego 	rw_enter(&node->n_lock, RW_WRITER);
10512c2961f8Sjose borrego }
10522c2961f8Sjose borrego 
10532c2961f8Sjose borrego void
smb_node_unlock(smb_node_t * node)10542c2961f8Sjose borrego smb_node_unlock(smb_node_t *node)
10552c2961f8Sjose borrego {
10562c2961f8Sjose borrego 	rw_exit(&node->n_lock);
10572c2961f8Sjose borrego }
10582c2961f8Sjose borrego 
10592c2961f8Sjose borrego void
smb_node_add_ofile(smb_node_t * node,smb_ofile_t * of)10602c2961f8Sjose borrego smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
10612c2961f8Sjose borrego {
10622c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10632c2961f8Sjose borrego 
10642c2961f8Sjose borrego 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
10652c2961f8Sjose borrego 	smb_llist_insert_tail(&node->n_ofile_list, of);
10662c2961f8Sjose borrego 	smb_llist_exit(&node->n_ofile_list);
10672c2961f8Sjose borrego }
10682c2961f8Sjose borrego 
10692c2961f8Sjose borrego void
smb_node_rem_ofile(smb_node_t * node,smb_ofile_t * of)10702c2961f8Sjose borrego smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
10712c2961f8Sjose borrego {
10722c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10732c2961f8Sjose borrego 
10742c2961f8Sjose borrego 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
10752c2961f8Sjose borrego 	smb_llist_remove(&node->n_ofile_list, of);
10762c2961f8Sjose borrego 	smb_llist_exit(&node->n_ofile_list);
10772c2961f8Sjose borrego }
10782c2961f8Sjose borrego 
1079037cac00Sjoyce mcintosh /*
1080037cac00Sjoyce mcintosh  * smb_node_inc_open_ofiles
1081037cac00Sjoyce mcintosh  */
10822c2961f8Sjose borrego void
smb_node_inc_open_ofiles(smb_node_t * node)10832c2961f8Sjose borrego smb_node_inc_open_ofiles(smb_node_t *node)
10842c2961f8Sjose borrego {
10852c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10865fd03bc0SGordon Ross 	atomic_inc_32(&node->n_open_count);
10872c2961f8Sjose borrego }
10882c2961f8Sjose borrego 
1089037cac00Sjoyce mcintosh /*
1090037cac00Sjoyce mcintosh  * smb_node_dec_open_ofiles
10915fd03bc0SGordon Ross  * returns new value
1092037cac00Sjoyce mcintosh  */
10935fd03bc0SGordon Ross uint32_t
smb_node_dec_open_ofiles(smb_node_t * node)10942c2961f8Sjose borrego smb_node_dec_open_ofiles(smb_node_t *node)
10952c2961f8Sjose borrego {
10962c2961f8Sjose borrego 	SMB_NODE_VALID(node);
10975fd03bc0SGordon Ross 	return (atomic_dec_32_nv(&node->n_open_count));
10982c2961f8Sjose borrego }
10992c2961f8Sjose borrego 
1100cb174861Sjoyce mcintosh /*
1101cb174861Sjoyce mcintosh  * smb_node_inc_opening_count
1102cb174861Sjoyce mcintosh  */
1103cb174861Sjoyce mcintosh void
smb_node_inc_opening_count(smb_node_t * node)1104cb174861Sjoyce mcintosh smb_node_inc_opening_count(smb_node_t *node)
11052c2961f8Sjose borrego {
11062c2961f8Sjose borrego 	SMB_NODE_VALID(node);
11075fd03bc0SGordon Ross 	atomic_inc_32(&node->n_opening_count);
1108cb174861Sjoyce mcintosh }
1109cb174861Sjoyce mcintosh 
1110cb174861Sjoyce mcintosh /*
1111cb174861Sjoyce mcintosh  * smb_node_dec_opening_count
1112cb174861Sjoyce mcintosh  */
1113cb174861Sjoyce mcintosh void
smb_node_dec_opening_count(smb_node_t * node)1114cb174861Sjoyce mcintosh smb_node_dec_opening_count(smb_node_t *node)
1115cb174861Sjoyce mcintosh {
1116cb174861Sjoyce mcintosh 	SMB_NODE_VALID(node);
11175fd03bc0SGordon Ross 	atomic_dec_32(&node->n_opening_count);
11182c2961f8Sjose borrego }
11192c2961f8Sjose borrego 
11202c2961f8Sjose borrego /*
11219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * smb_node_getmntpath
11229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
11239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int
smb_node_getmntpath(smb_node_t * node,char * buf,uint32_t buflen)11249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen)
11259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
11269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	vnode_t *vp, *root_vp;
11279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	vfs_t *vfsp;
11289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	int err;
11299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(node);
11319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(node->vp);
11329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(node->vp->v_vfsp);
11339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	vp = node->vp;
11359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	vfsp = vp->v_vfsp;
11369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (VFS_ROOT(vfsp, &root_vp))
11389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (ENOENT);
11399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	VN_HOLD(vp);
11419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	/* NULL is passed in as we want to start at "/" */
11438622ec45SGordon Ross 	err = vnodetopath(NULL, root_vp, buf, buflen, zone_kcred());
11449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	VN_RELE(vp);
11469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	VN_RELE(root_vp);
11479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (err);
11489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
11499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
11519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * smb_node_getshrpath
11529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *
11539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Determine the absolute pathname of 'node' within the share (tree).
11549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * For example if the node represents file "test1.txt" in directory
11559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * "dir1" the pathname would be: \dir1\test1.txt
11569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
11579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int
smb_node_getshrpath(smb_node_t * node,smb_tree_t * tree,char * buf,uint32_t buflen)11589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree,
11599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States     char *buf, uint32_t buflen)
11609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
11619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	int rc;
11629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1163c5866007SKeyur Desai 	ASSERT(node);
1164c5866007SKeyur Desai 	ASSERT(tree);
1165c5866007SKeyur Desai 	ASSERT(tree->t_snode);
11669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1167c5866007SKeyur Desai 	rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen);
11689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) strsubst(buf, '/', '\\');
1169c5866007SKeyur Desai 	return (rc);
1170c5866007SKeyur Desai }
11719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1172c5866007SKeyur Desai /*
1173c5866007SKeyur Desai  * smb_node_getpath
1174c5866007SKeyur Desai  *
1175c5866007SKeyur Desai  * Determine the absolute pathname of 'node' from 'rootvp'.
1176c5866007SKeyur Desai  *
1177c5866007SKeyur Desai  * Using vnodetopath is only reliable for directory nodes (due to
1178c5866007SKeyur Desai  * its reliance on the DNLC for non-directory nodes). Thus, if node
1179c5866007SKeyur Desai  * represents a file, construct the pathname for the parent dnode
1180c5866007SKeyur Desai  * and append filename.
1181c5866007SKeyur Desai  * If node represents a named stream, construct the pathname for the
1182c5866007SKeyur Desai  * associated unnamed stream and append the stream name.
1183c5866007SKeyur Desai  *
1184c5866007SKeyur Desai  * The pathname returned in buf will be '/' separated.
1185c5866007SKeyur Desai  */
1186c5866007SKeyur Desai int
smb_node_getpath(smb_node_t * node,vnode_t * rootvp,char * buf,uint32_t buflen)1187c5866007SKeyur Desai smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen)
1188c5866007SKeyur Desai {
1189c5866007SKeyur Desai 	int rc;
1190c5866007SKeyur Desai 	vnode_t *vp;
1191c5866007SKeyur Desai 	smb_node_t *unode, *dnode;
11928622ec45SGordon Ross 	cred_t *kcr = zone_kcred();
1193c5866007SKeyur Desai 
1194c5866007SKeyur Desai 	unode = (SMB_IS_STREAM(node)) ? node->n_unode : node;
1195c5866007SKeyur Desai 	dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode;
1196c5866007SKeyur Desai 
1197c5866007SKeyur Desai 	/* find path to directory node */
1198c5866007SKeyur Desai 	vp = dnode->vp;
1199c5866007SKeyur Desai 	VN_HOLD(vp);
1200c5866007SKeyur Desai 	if (rootvp) {
1201c5866007SKeyur Desai 		VN_HOLD(rootvp);
12028622ec45SGordon Ross 		rc = vnodetopath(rootvp, vp, buf, buflen, kcr);
1203c5866007SKeyur Desai 		VN_RELE(rootvp);
1204c5866007SKeyur Desai 	} else {
12058622ec45SGordon Ross 		rc = vnodetopath(NULL, vp, buf, buflen, kcr);
1206c5866007SKeyur Desai 	}
1207c5866007SKeyur Desai 	VN_RELE(vp);
1208c5866007SKeyur Desai 
1209c5866007SKeyur Desai 	if (rc != 0)
1210c5866007SKeyur Desai 		return (rc);
1211c5866007SKeyur Desai 
1212c5866007SKeyur Desai 	/* append filename if necessary */
1213c5866007SKeyur Desai 	if (!smb_node_is_dir(unode)) {
1214c5866007SKeyur Desai 		if (buf[strlen(buf) - 1] != '/')
1215c5866007SKeyur Desai 			(void) strlcat(buf, "/", buflen);
1216c5866007SKeyur Desai 		(void) strlcat(buf, unode->od_name, buflen);
1217c5866007SKeyur Desai 	}
1218c5866007SKeyur Desai 
1219c5866007SKeyur Desai 	/* append named stream name if necessary */
12209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (SMB_IS_STREAM(node))
12219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) strlcat(buf, node->od_name, buflen);
12229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (rc);
12249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
12259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
12272c2961f8Sjose borrego  * smb_node_alloc
12282c2961f8Sjose borrego  */
12292c2961f8Sjose borrego static smb_node_t *
smb_node_alloc(char * od_name,vnode_t * vp,smb_llist_t * bucket,uint32_t hashkey)12302c2961f8Sjose borrego smb_node_alloc(
12312c2961f8Sjose borrego     char	*od_name,
12322c2961f8Sjose borrego     vnode_t	*vp,
12332c2961f8Sjose borrego     smb_llist_t	*bucket,
12342c2961f8Sjose borrego     uint32_t	hashkey)
12352c2961f8Sjose borrego {
12362c2961f8Sjose borrego 	smb_node_t	*node;
12372c2961f8Sjose borrego 
12382c2961f8Sjose borrego 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
12392c2961f8Sjose borrego 
12402c2961f8Sjose borrego 	if (node->n_audit_buf != NULL)
12412c2961f8Sjose borrego 		node->n_audit_buf->anb_index = 0;
12422c2961f8Sjose borrego 
1243037cac00Sjoyce mcintosh 	node->flags = 0;
12442c2961f8Sjose borrego 	VN_HOLD(vp);
12452c2961f8Sjose borrego 	node->vp = vp;
12462c2961f8Sjose borrego 	node->n_refcnt = 1;
12472c2961f8Sjose borrego 	node->n_hash_bucket = bucket;
12482c2961f8Sjose borrego 	node->n_hashkey = hashkey;
12492c2961f8Sjose borrego 	node->n_open_count = 0;
12505fd03bc0SGordon Ross 	node->n_allocsz = 0;
12511fcced4cSJordan Brown 	node->n_dnode = NULL;
12521fcced4cSJordan Brown 	node->n_unode = NULL;
12532c2961f8Sjose borrego 	node->delete_on_close_cred = NULL;
12548b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	node->n_delete_on_close_flags = 0;
1255cb174861Sjoyce mcintosh 	node->n_oplock.ol_fem = B_FALSE;
12562c2961f8Sjose borrego 
12572c2961f8Sjose borrego 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
12582c2961f8Sjose borrego 	if (strcmp(od_name, XATTR_DIR) == 0)
12592c2961f8Sjose borrego 		node->flags |= NODE_XATTR_DIR;
12602c2961f8Sjose borrego 
126156a8f96bSGordon Ross 	if ((vp->v_flag & VROOT) != 0)
12629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		node->flags |= NODE_FLAGS_VFSROOT;
12639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12642c2961f8Sjose borrego 	node->n_state = SMB_NODE_STATE_AVAILABLE;
12652c2961f8Sjose borrego 	node->n_magic = SMB_NODE_MAGIC;
12669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12672c2961f8Sjose borrego 	return (node);
12682c2961f8Sjose borrego }
12692c2961f8Sjose borrego 
12702c2961f8Sjose borrego /*
12712c2961f8Sjose borrego  * smb_node_free
12722c2961f8Sjose borrego  */
12732c2961f8Sjose borrego static void
smb_node_free(smb_node_t * node)12742c2961f8Sjose borrego smb_node_free(smb_node_t *node)
12752c2961f8Sjose borrego {
12762c2961f8Sjose borrego 	SMB_NODE_VALID(node);
12772c2961f8Sjose borrego 
12782c2961f8Sjose borrego 	node->n_magic = 0;
12792c2961f8Sjose borrego 	VERIFY(!list_link_active(&node->n_lnd));
12802c2961f8Sjose borrego 	VERIFY(node->n_lock_list.ll_count == 0);
12810897f7fbSGordon Ross 	VERIFY(node->n_wlock_list.ll_count == 0);
12822c2961f8Sjose borrego 	VERIFY(node->n_ofile_list.ll_count == 0);
1283cb174861Sjoyce mcintosh 	VERIFY(node->n_oplock.ol_fem == B_FALSE);
1284b819cea2SGordon Ross 	VERIFY(MUTEX_NOT_HELD(&node->n_mutex));
1285fc724630SAlan Wright 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
12862c2961f8Sjose borrego 	VN_RELE(node->vp);
12872c2961f8Sjose borrego 	kmem_cache_free(smb_node_cache, node);
12882c2961f8Sjose borrego }
12892c2961f8Sjose borrego 
12902c2961f8Sjose borrego /*
12912c2961f8Sjose borrego  * smb_node_constructor
12922c2961f8Sjose borrego  */
12932c2961f8Sjose borrego static int
smb_node_constructor(void * buf,void * un,int kmflags)12942c2961f8Sjose borrego smb_node_constructor(void *buf, void *un, int kmflags)
12952c2961f8Sjose borrego {
12962c2961f8Sjose borrego 	_NOTE(ARGUNUSED(kmflags, un))
12972c2961f8Sjose borrego 
12982c2961f8Sjose borrego 	smb_node_t	*node = (smb_node_t *)buf;
12992c2961f8Sjose borrego 
13002c2961f8Sjose borrego 	bzero(node, sizeof (smb_node_t));
13012c2961f8Sjose borrego 
13022c2961f8Sjose borrego 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1303811599a4SMatt Barden 	    offsetof(smb_ofile_t, f_node_lnd));
13042c2961f8Sjose borrego 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
13052c2961f8Sjose borrego 	    offsetof(smb_lock_t, l_lnd));
13060897f7fbSGordon Ross 	smb_llist_constructor(&node->n_wlock_list, sizeof (smb_lock_t),
13070897f7fbSGordon Ross 	    offsetof(smb_lock_t, l_lnd));
1308cb174861Sjoyce mcintosh 	mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL);
130994047d49SGordon Ross 	cv_init(&node->n_oplock.WaitingOpenCV, NULL, CV_DEFAULT, NULL);
13102c2961f8Sjose borrego 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
13112c2961f8Sjose borrego 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
13122c2961f8Sjose borrego 	smb_node_create_audit_buf(node, kmflags);
13132c2961f8Sjose borrego 	return (0);
13142c2961f8Sjose borrego }
13152c2961f8Sjose borrego 
13162c2961f8Sjose borrego /*
13172c2961f8Sjose borrego  * smb_node_destructor
13182c2961f8Sjose borrego  */
13192c2961f8Sjose borrego static void
smb_node_destructor(void * buf,void * un)13202c2961f8Sjose borrego smb_node_destructor(void *buf, void *un)
13212c2961f8Sjose borrego {
13222c2961f8Sjose borrego 	_NOTE(ARGUNUSED(un))
13232c2961f8Sjose borrego 
13242c2961f8Sjose borrego 	smb_node_t	*node = (smb_node_t *)buf;
13252c2961f8Sjose borrego 
13262c2961f8Sjose borrego 	smb_node_destroy_audit_buf(node);
13272c2961f8Sjose borrego 	mutex_destroy(&node->n_mutex);
13282c2961f8Sjose borrego 	rw_destroy(&node->n_lock);
132994047d49SGordon Ross 	cv_destroy(&node->n_oplock.WaitingOpenCV);
1330cb174861Sjoyce mcintosh 	mutex_destroy(&node->n_oplock.ol_mutex);
13312c2961f8Sjose borrego 	smb_llist_destructor(&node->n_lock_list);
13320897f7fbSGordon Ross 	smb_llist_destructor(&node->n_wlock_list);
13332c2961f8Sjose borrego 	smb_llist_destructor(&node->n_ofile_list);
13342c2961f8Sjose borrego }
13352c2961f8Sjose borrego 
13362c2961f8Sjose borrego /*
13372c2961f8Sjose borrego  * smb_node_create_audit_buf
13382c2961f8Sjose borrego  */
13392c2961f8Sjose borrego static void
smb_node_create_audit_buf(smb_node_t * node,int kmflags)13402c2961f8Sjose borrego smb_node_create_audit_buf(smb_node_t *node, int kmflags)
13412c2961f8Sjose borrego {
13422c2961f8Sjose borrego 	smb_audit_buf_node_t	*abn;
13432c2961f8Sjose borrego 
13442c2961f8Sjose borrego 	if (smb_audit_flags & SMB_AUDIT_NODE) {
13452c2961f8Sjose borrego 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
13462c2961f8Sjose borrego 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
13472c2961f8Sjose borrego 		node->n_audit_buf = abn;
13482c2961f8Sjose borrego 	}
13492c2961f8Sjose borrego }
13502c2961f8Sjose borrego 
13512c2961f8Sjose borrego /*
13522c2961f8Sjose borrego  * smb_node_destroy_audit_buf
13532c2961f8Sjose borrego  */
13542c2961f8Sjose borrego static void
smb_node_destroy_audit_buf(smb_node_t * node)13552c2961f8Sjose borrego smb_node_destroy_audit_buf(smb_node_t *node)
13562c2961f8Sjose borrego {
13572c2961f8Sjose borrego 	if (node->n_audit_buf != NULL) {
13582c2961f8Sjose borrego 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
13592c2961f8Sjose borrego 		node->n_audit_buf = NULL;
13602c2961f8Sjose borrego 	}
13612c2961f8Sjose borrego }
13622c2961f8Sjose borrego 
13632c2961f8Sjose borrego /*
13642c2961f8Sjose borrego  * smb_node_audit
13652c2961f8Sjose borrego  *
13662c2961f8Sjose borrego  * This function saves the calling stack in the audit buffer of the node passed
13672c2961f8Sjose borrego  * in.
13682c2961f8Sjose borrego  */
13692c2961f8Sjose borrego static void
smb_node_audit(smb_node_t * node)13702c2961f8Sjose borrego smb_node_audit(smb_node_t *node)
13712c2961f8Sjose borrego {
1372b819cea2SGordon Ross #ifdef	_KERNEL
13732c2961f8Sjose borrego 	smb_audit_buf_node_t	*abn;
13742c2961f8Sjose borrego 	smb_audit_record_node_t	*anr;
13752c2961f8Sjose borrego 
13762c2961f8Sjose borrego 	if (node->n_audit_buf) {
13772c2961f8Sjose borrego 		abn = node->n_audit_buf;
13782c2961f8Sjose borrego 		anr = abn->anb_records;
13792c2961f8Sjose borrego 		anr += abn->anb_index;
13802c2961f8Sjose borrego 		abn->anb_index++;
13812c2961f8Sjose borrego 		abn->anb_index &= abn->anb_max_index;
13822c2961f8Sjose borrego 		anr->anr_refcnt = node->n_refcnt;
13832c2961f8Sjose borrego 		anr->anr_depth = getpcstack(anr->anr_stack,
13842c2961f8Sjose borrego 		    SMB_AUDIT_STACK_DEPTH);
13852c2961f8Sjose borrego 	}
1386b819cea2SGordon Ross #else	/* _KERNEL */
1387b819cea2SGordon Ross 	_NOTE(ARGUNUSED(node))
1388b819cea2SGordon Ross #endif	/* _KERNEL */
13892c2961f8Sjose borrego }
13902c2961f8Sjose borrego 
13912c2961f8Sjose borrego static smb_llist_t *
smb_node_get_hash(fsid_t * fsid,smb_attr_t * attr,uint32_t * phashkey)13922c2961f8Sjose borrego smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
13932c2961f8Sjose borrego {
13942c2961f8Sjose borrego 	uint32_t	hashkey;
13952c2961f8Sjose borrego 
13962c2961f8Sjose borrego 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
13972c2961f8Sjose borrego 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
13982c2961f8Sjose borrego 	*phashkey = hashkey;
13992c2961f8Sjose borrego 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1400dc20a302Sas200622 }
1401037cac00Sjoyce mcintosh 
1402037cac00Sjoyce mcintosh boolean_t
smb_node_is_file(smb_node_t * node)14039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_file(smb_node_t *node)
1404037cac00Sjoyce mcintosh {
1405037cac00Sjoyce mcintosh 	SMB_NODE_VALID(node);
14069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (node->vp->v_type == VREG);
1407037cac00Sjoyce mcintosh }
1408037cac00Sjoyce mcintosh 
1409037cac00Sjoyce mcintosh boolean_t
smb_node_is_dir(smb_node_t * node)14109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_dir(smb_node_t *node)
1411037cac00Sjoyce mcintosh {
1412037cac00Sjoyce mcintosh 	SMB_NODE_VALID(node);
14139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return ((node->vp->v_type == VDIR) ||
14149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    (node->flags & NODE_FLAGS_DFSLINK));
14159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
14169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
14179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t
smb_node_is_symlink(smb_node_t * node)14189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_symlink(smb_node_t *node)
14199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
14209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_NODE_VALID(node);
14219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return ((node->vp->v_type == VLNK) &&
14229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    ((node->flags & NODE_FLAGS_REPARSE) == 0));
14239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
14249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
14259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t
smb_node_is_dfslink(smb_node_t * node)14269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_dfslink(smb_node_t *node)
14279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
14289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_NODE_VALID(node);
14299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return ((node->vp->v_type == VLNK) &&
14309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    (node->flags & NODE_FLAGS_DFSLINK));
14319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
14329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
14339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t
smb_node_is_reparse(smb_node_t * node)14349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_reparse(smb_node_t *node)
14359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
14369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_NODE_VALID(node);
14379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return ((node->vp->v_type == VLNK) &&
14389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    (node->flags & NODE_FLAGS_REPARSE));
14399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
14409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
14419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t
smb_node_is_vfsroot(smb_node_t * node)14429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_vfsroot(smb_node_t *node)
14439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
14449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_NODE_VALID(node);
14459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT);
14469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
14479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
14489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t
smb_node_is_system(smb_node_t * node)14499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_system(smb_node_t *node)
14509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
14519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_NODE_VALID(node);
14529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM);
1453037cac00Sjoyce mcintosh }
1454037cac00Sjoyce mcintosh 
1455037cac00Sjoyce mcintosh /*
1456037cac00Sjoyce mcintosh  * smb_node_file_is_readonly
1457037cac00Sjoyce mcintosh  *
1458037cac00Sjoyce mcintosh  * Checks if the file (which node represents) is marked readonly
14595cb2894aSGordon Ross  * in the filesystem.  Note that there may be handles open with
14605cb2894aSGordon Ross  * modify rights, and those continue to allow access even after
14615cb2894aSGordon Ross  * the DOS read-only flag has been set in the file system.
1462037cac00Sjoyce mcintosh  */
1463037cac00Sjoyce mcintosh boolean_t
smb_node_file_is_readonly(smb_node_t * node)1464037cac00Sjoyce mcintosh smb_node_file_is_readonly(smb_node_t *node)
1465037cac00Sjoyce mcintosh {
1466037cac00Sjoyce mcintosh 	smb_attr_t attr;
1467037cac00Sjoyce mcintosh 
1468037cac00Sjoyce mcintosh 	if (node == NULL)
14695fd03bc0SGordon Ross 		return (B_FALSE);	/* pipes */
14705fd03bc0SGordon Ross 
1471037cac00Sjoyce mcintosh 	bzero(&attr, sizeof (smb_attr_t));
1472037cac00Sjoyce mcintosh 	attr.sa_mask = SMB_AT_DOSATTR;
14738622ec45SGordon Ross 	(void) smb_fsop_getattr(NULL, zone_kcred(), node, &attr);
1474037cac00Sjoyce mcintosh 	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
1475037cac00Sjoyce mcintosh }
1476037cac00Sjoyce mcintosh 
1477037cac00Sjoyce mcintosh /*
1478037cac00Sjoyce mcintosh  * smb_node_setattr
1479037cac00Sjoyce mcintosh  *
1480037cac00Sjoyce mcintosh  * The sr may be NULL, for example when closing an ofile.
1481037cac00Sjoyce mcintosh  * The ofile may be NULL, for example when a client request
1482037cac00Sjoyce mcintosh  * specifies the file by pathname.
1483037cac00Sjoyce mcintosh  *
14845fd03bc0SGordon Ross  * Returns: errno
14855fd03bc0SGordon Ross  *
1486e3f2c991SKeyur Desai  * Timestamps
1487037cac00Sjoyce mcintosh  *
14885fd03bc0SGordon Ross  * Windows and Unix have different models for timestamp updates.
14895fd03bc0SGordon Ross  * [MS-FSA 2.1.5.14 Server Requests Setting of File Information]
1490037cac00Sjoyce mcintosh  *
14915fd03bc0SGordon Ross  * An open "handle" in Windows can control whether and when
14925fd03bc0SGordon Ross  * any timestamp updates happen for that handle.  For example,
14935fd03bc0SGordon Ross  * timestamps set via some handle are no longer updated by I/O
14945fd03bc0SGordon Ross  * operations on that handle.  In Unix we don't really have any
14955fd03bc0SGordon Ross  * way to avoid the timestamp updates that the file system does.
14965fd03bc0SGordon Ross  * Therefore, we need to make some compromises, and simulate the
14975fd03bc0SGordon Ross  * more important parts of the Windows file system semantics.
1498037cac00Sjoyce mcintosh  *
14995fd03bc0SGordon Ross  * For example, when an SMB client sets file times, set those
15005fd03bc0SGordon Ross  * times in the file system (so the change will be visible to
15015fd03bc0SGordon Ross  * other clients, at least until they change again) but we also
15025fd03bc0SGordon Ross  * make those times "sticky" in our open handle, and reapply
15035fd03bc0SGordon Ross  * those times when the handle is closed.  That reapply on close
15045fd03bc0SGordon Ross  * simulates the Windows behavior where the timestamp updates
15055fd03bc0SGordon Ross  * would be discontinued after they were set.  These "sticky"
15065fd03bc0SGordon Ross  * attributes are returned in any query on the handle where
15075fd03bc0SGordon Ross  * they are stored.
15085fd03bc0SGordon Ross  *
1509*b62fa64bSToomas Soome  * The client can also turn on or off these "sticky" times using
1510*b62fa64bSToomas Soome  * the special NT time values -1 or -2, as described in:
1511*b62fa64bSToomas Soome  *	[MS-FSCC] Section 2.4.7, the paragraphs describing:
1512*b62fa64bSToomas Soome  *	CreationTime, LastAccessTime, LastWriteTime, ChangeTime
1513*b62fa64bSToomas Soome  * and the Windows behavior notes in those descriptions.
1514*b62fa64bSToomas Soome  * To summarize all the "special" NT time values:
1515*b62fa64bSToomas Soome  *	 0: no change (caller handles this case)
1516*b62fa64bSToomas Soome  *	-1: pause time updates (current value becomes "sticky")
1517*b62fa64bSToomas Soome  *	-2: resume time updates (discontiue "sticky" behavior)
1518*b62fa64bSToomas Soome  *
15195fd03bc0SGordon Ross  * Other than the above, the file system layer takes care of the
15205fd03bc0SGordon Ross  * normal time stamp updates, such as updating the mtime after a
15215fd03bc0SGordon Ross  * write, and ctime after an attribute change.
15225fd03bc0SGordon Ross  *
15235fd03bc0SGordon Ross  * File allocation size is also simulated, and not persistent.
1524e3f2c991SKeyur Desai  * When the file allocation size is set it is first rounded up
1525e3f2c991SKeyur Desai  * to block size. If the file size is smaller than the allocation
1526e3f2c991SKeyur Desai  * size the file is truncated by setting the filesize to allocsz.
1527037cac00Sjoyce mcintosh  */
1528037cac00Sjoyce mcintosh int
smb_node_setattr(smb_request_t * sr,smb_node_t * node,cred_t * cr,smb_ofile_t * of,smb_attr_t * attr)1529037cac00Sjoyce mcintosh smb_node_setattr(smb_request_t *sr, smb_node_t *node,
1530037cac00Sjoyce mcintosh     cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
1531037cac00Sjoyce mcintosh {
1532*b62fa64bSToomas Soome 	smb_attr_t cur_attr;
1533*b62fa64bSToomas Soome 	uint_t times_set = 0;
1534*b62fa64bSToomas Soome 	uint_t times_clr = 0;
1535037cac00Sjoyce mcintosh 	int rc;
1536037cac00Sjoyce mcintosh 
1537037cac00Sjoyce mcintosh 	SMB_NODE_VALID(node);
1538037cac00Sjoyce mcintosh 
1539e3f2c991SKeyur Desai 	/* set attributes specified in attr */
15405fd03bc0SGordon Ross 	if (attr->sa_mask == 0)
15415fd03bc0SGordon Ross 		return (0);  /* nothing to do (caller bug?) */
1542037cac00Sjoyce mcintosh 
15435fd03bc0SGordon Ross 	/*
15445fd03bc0SGordon Ross 	 * Allocation size and EOF position interact.
15455fd03bc0SGordon Ross 	 * We don't persistently store the allocation size
15465fd03bc0SGordon Ross 	 * but make it look like we do while there are opens.
15475fd03bc0SGordon Ross 	 * Note: We update the caller's attr in the cases
15485fd03bc0SGordon Ross 	 * where they're setting only one of allocsz|size.
15495fd03bc0SGordon Ross 	 */
15505fd03bc0SGordon Ross 	switch (attr->sa_mask & (SMB_AT_ALLOCSZ | SMB_AT_SIZE)) {
15515fd03bc0SGordon Ross 
15525fd03bc0SGordon Ross 	case SMB_AT_ALLOCSZ:
15535fd03bc0SGordon Ross 		/*
15545fd03bc0SGordon Ross 		 * Setting the allocation size but not EOF position.
1555*b62fa64bSToomas Soome 		 * Get the current EOF in cur_attr and (if necessary)
15565fd03bc0SGordon Ross 		 * truncate to the (rounded up) allocation size.
15578622ec45SGordon Ross 		 * Using kcred here because if we don't have access,
15588622ec45SGordon Ross 		 * we want to fail at setattr below and not here.
15595fd03bc0SGordon Ross 		 */
1560*b62fa64bSToomas Soome 		bzero(&cur_attr, sizeof (smb_attr_t));
1561*b62fa64bSToomas Soome 		cur_attr.sa_mask = SMB_AT_SIZE;
1562*b62fa64bSToomas Soome 		rc = smb_fsop_getattr(NULL, zone_kcred(), node, &cur_attr);
15635fd03bc0SGordon Ross 		if (rc != 0)
15645fd03bc0SGordon Ross 			return (rc);
15655fd03bc0SGordon Ross 		attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
1566*b62fa64bSToomas Soome 		if (cur_attr.sa_vattr.va_size > attr->sa_allocsz) {
15675fd03bc0SGordon Ross 			/* truncate the file to allocsz */
1568e3f2c991SKeyur Desai 			attr->sa_vattr.va_size = attr->sa_allocsz;
1569e3f2c991SKeyur Desai 			attr->sa_mask |= SMB_AT_SIZE;
1570037cac00Sjoyce mcintosh 		}
15715fd03bc0SGordon Ross 		break;
1572037cac00Sjoyce mcintosh 
15735fd03bc0SGordon Ross 	case SMB_AT_SIZE:
15745fd03bc0SGordon Ross 		/*
15755fd03bc0SGordon Ross 		 * Setting the EOF position but not allocation size.
15765fd03bc0SGordon Ross 		 * If the new EOF position would be greater than
15775fd03bc0SGordon Ross 		 * the allocation size, increase the latter.
15785fd03bc0SGordon Ross 		 */
15795fd03bc0SGordon Ross 		if (node->n_allocsz < attr->sa_vattr.va_size) {
15805fd03bc0SGordon Ross 			attr->sa_mask |= SMB_AT_ALLOCSZ;
15815fd03bc0SGordon Ross 			attr->sa_allocsz =
15825fd03bc0SGordon Ross 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1583e3f2c991SKeyur Desai 		}
15845fd03bc0SGordon Ross 		break;
15855fd03bc0SGordon Ross 
15865fd03bc0SGordon Ross 	case SMB_AT_ALLOCSZ | SMB_AT_SIZE:
15875fd03bc0SGordon Ross 		/*
15885fd03bc0SGordon Ross 		 * Setting both.  Increase alloc size if needed.
15895fd03bc0SGordon Ross 		 */
15905fd03bc0SGordon Ross 		if (attr->sa_allocsz < attr->sa_vattr.va_size)
15915fd03bc0SGordon Ross 			attr->sa_allocsz =
15925fd03bc0SGordon Ross 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
15935fd03bc0SGordon Ross 		break;
15945fd03bc0SGordon Ross 
15955fd03bc0SGordon Ross 	default:
15965fd03bc0SGordon Ross 		break;
1597e3f2c991SKeyur Desai 	}
1598037cac00Sjoyce mcintosh 
1599e3f2c991SKeyur Desai 	/*
1600*b62fa64bSToomas Soome 	 * When setting times, -1 and -2 are "special" (see above).
1601*b62fa64bSToomas Soome 	 * Keep track of -2 values and just clear mask.
1602*b62fa64bSToomas Soome 	 * Replace -1 values with current time.
1603*b62fa64bSToomas Soome 	 *
1604*b62fa64bSToomas Soome 	 * Note that NT times -1, -2 have been converted to
1605*b62fa64bSToomas Soome 	 * smb_nttime_m1, smb_nttime_m2, respectively.
16065fd03bc0SGordon Ross 	 */
1607*b62fa64bSToomas Soome 	times_set = attr->sa_mask & SMB_AT_TIMES;
1608*b62fa64bSToomas Soome 	if (times_set != 0) {
1609*b62fa64bSToomas Soome 		bzero(&cur_attr, sizeof (smb_attr_t));
1610*b62fa64bSToomas Soome 		cur_attr.sa_mask = SMB_AT_TIMES;
1611*b62fa64bSToomas Soome 		rc = smb_fsop_getattr(NULL, zone_kcred(), node, &cur_attr);
1612*b62fa64bSToomas Soome 		if (rc != 0)
1613*b62fa64bSToomas Soome 			return (rc);
1614*b62fa64bSToomas Soome 
1615*b62fa64bSToomas Soome 		/* Easiest to get these right with a macro. */
1616*b62fa64bSToomas Soome #define	FIX_TIME(FIELD, MASK)				\
1617*b62fa64bSToomas Soome 		if (timespeccmp(&attr->FIELD, &smb_nttime_m2, ==)) { \
1618*b62fa64bSToomas Soome 			times_clr |= MASK;		\
1619*b62fa64bSToomas Soome 			times_set &= ~MASK;		\
1620*b62fa64bSToomas Soome 		}					\
1621*b62fa64bSToomas Soome 		if (timespeccmp(&attr->FIELD, &smb_nttime_m1, ==)) \
1622*b62fa64bSToomas Soome 			attr->FIELD = cur_attr.FIELD	/* no ; */
1623*b62fa64bSToomas Soome 
1624*b62fa64bSToomas Soome 		if (times_set & SMB_AT_ATIME) {
1625*b62fa64bSToomas Soome 			FIX_TIME(sa_vattr.va_atime, SMB_AT_ATIME);
1626*b62fa64bSToomas Soome 		}
1627*b62fa64bSToomas Soome 		if (times_set & SMB_AT_MTIME) {
1628*b62fa64bSToomas Soome 			FIX_TIME(sa_vattr.va_mtime, SMB_AT_MTIME);
1629*b62fa64bSToomas Soome 		}
1630*b62fa64bSToomas Soome 		if (times_set & SMB_AT_CTIME) {
1631*b62fa64bSToomas Soome 			FIX_TIME(sa_vattr.va_ctime, SMB_AT_CTIME);
1632*b62fa64bSToomas Soome 		}
1633*b62fa64bSToomas Soome 		if (times_set & SMB_AT_CRTIME) {
1634*b62fa64bSToomas Soome 			FIX_TIME(sa_crtime, SMB_AT_CRTIME);
1635*b62fa64bSToomas Soome 		}
1636*b62fa64bSToomas Soome #undef	FIX_TIME
1637*b62fa64bSToomas Soome 
1638*b62fa64bSToomas Soome 		/* Clear mask for -2 fields. */
1639*b62fa64bSToomas Soome 		attr->sa_mask &= ~times_clr;
1640*b62fa64bSToomas Soome 	}
1641*b62fa64bSToomas Soome 
1642*b62fa64bSToomas Soome 	/*
1643*b62fa64bSToomas Soome 	 * When operating on an open file, some settable attributes
1644*b62fa64bSToomas Soome 	 * become "sticky" in the open file object until close, or until
1645*b62fa64bSToomas Soome 	 * a set-time with value -2 (see above re. timestamps)
1646*b62fa64bSToomas Soome 	 *
1647*b62fa64bSToomas Soome 	 * Save the pending attributes.  We've handled -2 and -1 above,
1648*b62fa64bSToomas Soome 	 * and cleared the -2 cases from the times_set mask.
1649*b62fa64bSToomas Soome 	 */
1650*b62fa64bSToomas Soome 	if (of != NULL && (times_set != 0 || times_clr != 0)) {
16515fd03bc0SGordon Ross 		smb_attr_t *pa;
1652e3f2c991SKeyur Desai 
16535fd03bc0SGordon Ross 		SMB_OFILE_VALID(of);
16545fd03bc0SGordon Ross 		mutex_enter(&of->f_mutex);
16555fd03bc0SGordon Ross 		pa = &of->f_pending_attr;
16565fd03bc0SGordon Ross 
1657*b62fa64bSToomas Soome 		pa->sa_mask |= times_set;
1658*b62fa64bSToomas Soome 		pa->sa_mask &= ~times_clr;
16595fd03bc0SGordon Ross 
1660*b62fa64bSToomas Soome 		if (times_set & SMB_AT_ATIME)
1661*b62fa64bSToomas Soome 			pa->sa_vattr.va_atime = attr->sa_vattr.va_atime;
1662*b62fa64bSToomas Soome 		if (times_set & SMB_AT_MTIME)
1663*b62fa64bSToomas Soome 			pa->sa_vattr.va_mtime = attr->sa_vattr.va_mtime;
1664*b62fa64bSToomas Soome 		if (times_set & SMB_AT_CTIME)
1665*b62fa64bSToomas Soome 			pa->sa_vattr.va_ctime = attr->sa_vattr.va_ctime;
1666*b62fa64bSToomas Soome 		if (times_set & SMB_AT_CRTIME)
1667*b62fa64bSToomas Soome 			pa->sa_crtime = attr->sa_crtime;
16685fd03bc0SGordon Ross 
16695fd03bc0SGordon Ross 		mutex_exit(&of->f_mutex);
16708d94f651SGordon Ross 
16715fd03bc0SGordon Ross 		/*
16725fd03bc0SGordon Ross 		 * The f_pending_attr times are reapplied in
16735fd03bc0SGordon Ross 		 * smb_ofile_close().
16745fd03bc0SGordon Ross 		 */
16758d94f651SGordon Ross 
16768d94f651SGordon Ross 		/*
16778d94f651SGordon Ross 		 * If this change is coming directly from a client
16788d94f651SGordon Ross 		 * (sr != NULL) and it's a persistent handle, save
16798d94f651SGordon Ross 		 * the "sticky times" in the handle.
16808d94f651SGordon Ross 		 */
16818d94f651SGordon Ross 		if (sr != NULL && of->dh_persist) {
16828d94f651SGordon Ross 			smb2_dh_update_times(sr, of, attr);
16838d94f651SGordon Ross 		}
1684e3f2c991SKeyur Desai 	}
1685e3f2c991SKeyur Desai 
16865cb2894aSGordon Ross 	if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0) {
16875fd03bc0SGordon Ross 		mutex_enter(&node->n_mutex);
16885fd03bc0SGordon Ross 		/*
16895fd03bc0SGordon Ross 		 * Simulate n_allocsz persistence only while
16905fd03bc0SGordon Ross 		 * there are opens.  See smb_node_getattr
16915fd03bc0SGordon Ross 		 */
16925cb2894aSGordon Ross 		if (node->n_open_count != 0)
16935fd03bc0SGordon Ross 			node->n_allocsz = attr->sa_allocsz;
16945fd03bc0SGordon Ross 		mutex_exit(&node->n_mutex);
16955fd03bc0SGordon Ross 	}
1696e3f2c991SKeyur Desai 
16975cb2894aSGordon Ross 	rc = smb_fsop_setattr(sr, cr, node, attr);
1698f8e30ca2SGordon Ross 
1699f8e30ca2SGordon Ross 	/*
1700f8e30ca2SGordon Ross 	 * Only generate change notify events for client requests.
1701f8e30ca2SGordon Ross 	 * Internal operations use sr=NULL
1702f8e30ca2SGordon Ross 	 */
1703f8e30ca2SGordon Ross 	if (rc == 0 && sr != NULL)
1704f8e30ca2SGordon Ross 		smb_node_notify_modified(node);
1705f8e30ca2SGordon Ross 
17065fd03bc0SGordon Ross 	return (rc);
1707037cac00Sjoyce mcintosh }
1708037cac00Sjoyce mcintosh 
1709037cac00Sjoyce mcintosh /*
1710037cac00Sjoyce mcintosh  * smb_node_getattr
1711037cac00Sjoyce mcintosh  *
1712037cac00Sjoyce mcintosh  * Get attributes from the file system and apply any smb-specific
1713037cac00Sjoyce mcintosh  * overrides for size, dos attributes and timestamps
1714037cac00Sjoyce mcintosh  *
1715037cac00Sjoyce mcintosh  * Returns: errno
1716037cac00Sjoyce mcintosh  */
1717037cac00Sjoyce mcintosh int
smb_node_getattr(smb_request_t * sr,smb_node_t * node,cred_t * cr,smb_ofile_t * of,smb_attr_t * attr)17185fd03bc0SGordon Ross smb_node_getattr(smb_request_t *sr, smb_node_t *node, cred_t *cr,
17195fd03bc0SGordon Ross     smb_ofile_t *of, smb_attr_t *attr)
1720037cac00Sjoyce mcintosh {
1721037cac00Sjoyce mcintosh 	int rc;
17225fd03bc0SGordon Ross 	uint_t want_mask, pend_mask;
17235fd03bc0SGordon Ross 	boolean_t isdir;
1724037cac00Sjoyce mcintosh 
1725037cac00Sjoyce mcintosh 	SMB_NODE_VALID(node);
1726037cac00Sjoyce mcintosh 
17275fd03bc0SGordon Ross 	rc = smb_fsop_getattr(sr, cr, node, attr);
1728037cac00Sjoyce mcintosh 	if (rc != 0)
1729037cac00Sjoyce mcintosh 		return (rc);
1730037cac00Sjoyce mcintosh 
17315fd03bc0SGordon Ross 	isdir = smb_node_is_dir(node);
17325fd03bc0SGordon Ross 
1733037cac00Sjoyce mcintosh 	mutex_enter(&node->n_mutex);
1734037cac00Sjoyce mcintosh 
17355fd03bc0SGordon Ross 	/*
1736cdf79589SGordon Ross 	 * Fix-up sa_allocsz, for which we simulate persistence
1737cdf79589SGordon Ross 	 * while there are open files. (See smb_node_setattr)
1738cdf79589SGordon Ross 	 *
1739cdf79589SGordon Ross 	 * The value in node->n_allocsz is the value last set via
1740cdf79589SGordon Ross 	 * smb_node_setattr.  It's possible that writes may have
1741cdf79589SGordon Ross 	 * increased the file size beyond n_allocsz, in which case
1742cdf79589SGordon Ross 	 * the sa_vattr.va_size, sa_allocsz from smb_fsop_getattr
1743cdf79589SGordon Ross 	 * will be greater than n_allocsz, so this returns the
1744cdf79589SGordon Ross 	 * greater of n_allocsz and sa_allocsz.
17455fd03bc0SGordon Ross 	 */
1746cdf79589SGordon Ross 	if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0 &&
1747cdf79589SGordon Ross 	    node->n_open_count > 0 && !isdir &&
1748cdf79589SGordon Ross 	    attr->sa_allocsz < node->n_allocsz) {
17495fd03bc0SGordon Ross 		attr->sa_allocsz = node->n_allocsz;
17505fd03bc0SGordon Ross 	}
1751e3f2c991SKeyur Desai 
1752037cac00Sjoyce mcintosh 	mutex_exit(&node->n_mutex);
1753037cac00Sjoyce mcintosh 
17545fd03bc0SGordon Ross 	/*
17555fd03bc0SGordon Ross 	 * getattr with an ofile gets any "pending" times that
17565fd03bc0SGordon Ross 	 * might have been previously set via this ofile.
17575fd03bc0SGordon Ross 	 * This is what makes these times "sticky".
17585fd03bc0SGordon Ross 	 */
17595fd03bc0SGordon Ross 	want_mask = attr->sa_mask & SMB_AT_TIMES;
17605fd03bc0SGordon Ross 	if (of != NULL && want_mask != 0) {
17615fd03bc0SGordon Ross 		smb_attr_t *pa;
17625fd03bc0SGordon Ross 
17635fd03bc0SGordon Ross 		SMB_OFILE_VALID(of);
17645fd03bc0SGordon Ross 		mutex_enter(&of->f_mutex);
17655fd03bc0SGordon Ross 		pa = &of->f_pending_attr;
17665fd03bc0SGordon Ross 
17675fd03bc0SGordon Ross 		pend_mask = pa->sa_mask;
17685fd03bc0SGordon Ross 
17695fd03bc0SGordon Ross 		if (want_mask & pend_mask & SMB_AT_ATIME)
17705fd03bc0SGordon Ross 			attr->sa_vattr.va_atime =
17715fd03bc0SGordon Ross 			    pa->sa_vattr.va_atime;
17725fd03bc0SGordon Ross 		if (want_mask & pend_mask & SMB_AT_MTIME)
17735fd03bc0SGordon Ross 			attr->sa_vattr.va_mtime =
17745fd03bc0SGordon Ross 			    pa->sa_vattr.va_mtime;
17755fd03bc0SGordon Ross 		if (want_mask & pend_mask & SMB_AT_CTIME)
17765fd03bc0SGordon Ross 			attr->sa_vattr.va_ctime =
17775fd03bc0SGordon Ross 			    pa->sa_vattr.va_ctime;
17785fd03bc0SGordon Ross 		if (want_mask & pend_mask & SMB_AT_CRTIME)
17795fd03bc0SGordon Ross 			attr->sa_crtime =
17805fd03bc0SGordon Ross 			    pa->sa_crtime;
17815fd03bc0SGordon Ross 
17825fd03bc0SGordon Ross 		mutex_exit(&of->f_mutex);
17835fd03bc0SGordon Ross 	}
17845fd03bc0SGordon Ross 
1785e3f2c991SKeyur Desai 
1786037cac00Sjoyce mcintosh 	return (0);
1787037cac00Sjoyce mcintosh }
1788037cac00Sjoyce mcintosh 
17899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1790b819cea2SGordon Ross #ifndef	_KERNEL
1791b819cea2SGordon Ross extern int reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl);
1792b819cea2SGordon Ross #endif	/* _KERNEL */
1793b819cea2SGordon Ross 
17949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
17959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Check to see if the node represents a reparse point.
17969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * If yes, whether the reparse point contains a DFS link.
17979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
17989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void
smb_node_init_reparse(smb_node_t * node,smb_attr_t * attr)17999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr)
18009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
18019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	nvlist_t *nvl;
18029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	nvpair_t *rec;
18039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	char *rec_type;
18049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
18069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
18079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((nvl = reparse_init()) == NULL)
18099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
18109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (reparse_vnode_parse(node->vp, nvl) != 0) {
18129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		reparse_free(nvl);
18139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
18149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
18159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	node->flags |= NODE_FLAGS_REPARSE;
18179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	rec = nvlist_next_nvpair(nvl, NULL);
18199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	while (rec != NULL) {
18209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		rec_type = nvpair_name(rec);
18219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if ((rec_type != NULL) &&
18229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		    (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) {
18239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			node->flags |= NODE_FLAGS_DFSLINK;
18249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			break;
18259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		}
18269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		rec = nvlist_next_nvpair(nvl, rec);
18279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
18289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	reparse_free(nvl);
18309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
18319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
18339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * smb_node_init_system
18349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *
18359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * If the node represents a special system file set NODE_FLAG_SYSTEM.
18369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * System files:
18379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * - any node whose parent dnode has NODE_FLAG_SYSTEM set
18389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * - any node whose associated unnamed stream node (unode) has
18399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *   NODE_FLAG_SYSTEM set
18409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * - .$EXTEND at root of share (quota management)
18419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
18429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void
smb_node_init_system(smb_node_t * node)18439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_init_system(smb_node_t *node)
18449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
18459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_t *dnode = node->n_dnode;
18469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_node_t *unode = node->n_unode;
18479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) {
18499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		node->flags |= NODE_FLAGS_SYSTEM;
18509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
18519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
18529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) {
18549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		node->flags |= NODE_FLAGS_SYSTEM;
18559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
18569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
18579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
18589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) &&
18599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    (strcasecmp(node->od_name, ".$EXTEND") == 0))) {
18609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		node->flags |= NODE_FLAGS_SYSTEM;
18619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
18629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
1863