xref: /titanic_44/usr/src/uts/common/fs/smbsrv/smb_node.c (revision e7619b69689d6a40a07425ef14002f2ab4d724d9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
24  */
25 /*
26  * SMB Node State Machine
27  * ----------------------
28  *
29  *
30  *		    +----------- Creation/Allocation
31  *		    |
32  *		    | T0
33  *		    |
34  *		    v
35  *    +----------------------------+
36  *    |  SMB_NODE_STATE_AVAILABLE  |
37  *    +----------------------------+
38  *		    |
39  *		    | T1
40  *		    |
41  *		    v
42  *    +-----------------------------+
43  *    |  SMB_NODE_STATE_DESTROYING  |
44  *    +-----------------------------+
45  *		    |
46  *		    |
47  *		    | T2
48  *		    |
49  *		    +----------> Deletion/Free
50  *
51  * Transition T0
52  *
53  *    This transition occurs in smb_node_lookup(). If the node looked for is
54  *    not found in the has table a new node is created. The reference count is
55  *    initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
56  *
57  * Transition T1
58  *
59  *    This transition occurs in smb_node_release(). If the reference count
60  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
61  *    reference count will be given out for that node.
62  *
63  * Transition T2
64  *
65  *    This transition occurs in smb_node_release(). The structure is deleted.
66  *
67  * Comments
68  * --------
69  *
70  *    The reason the smb node has 2 states is the following synchronization
71  *    rule:
72  *
73  *    There's a mutex embedded in the node used to protect its fields and
74  *    there's a lock embedded in the bucket of the hash table the node belongs
75  *    to. To increment or to decrement the reference count the mutex must be
76  *    entered. To insert the node into the bucket and to remove it from the
77  *    bucket the lock must be entered in RW_WRITER mode. When both (mutex and
78  *    lock) have to be entered, the lock has always to be entered first then
79  *    the mutex. This prevents a deadlock between smb_node_lookup() and
80  *    smb_node_release() from occurring. However, in smb_node_release() when the
81  *    reference count drops to zero and triggers the deletion of the node, the
82  *    mutex has to be released before entering the lock of the bucket (to
83  *    remove the node). This creates a window during which the node that is
84  *    about to be freed could be given out by smb_node_lookup(). To close that
85  *    window the node is moved to the state SMB_NODE_STATE_DESTROYING before
86  *    releasing the mutex. That way, even if smb_node_lookup() finds it, the
87  *    state will indicate that the node should be treated as non existent (of
88  *    course the state of the node should be tested/updated under the
89  *    protection of the mutex).
90  */
91 #include <smbsrv/smb_kproto.h>
92 #include <smbsrv/smb_fsops.h>
93 #include <smbsrv/smb_kstat.h>
94 #include <sys/ddi.h>
95 #include <sys/extdirent.h>
96 #include <sys/pathname.h>
97 #include <sys/sdt.h>
98 #include <sys/nbmlock.h>
99 #include <fs/fs_reparse.h>
100 
101 uint32_t smb_is_executable(char *);
102 static void smb_node_delete_on_close(smb_node_t *);
103 static void smb_node_create_audit_buf(smb_node_t *, int);
104 static void smb_node_destroy_audit_buf(smb_node_t *);
105 static void smb_node_audit(smb_node_t *);
106 static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
107 static void smb_node_free(smb_node_t *);
108 static int smb_node_constructor(void *, void *, int);
109 static void smb_node_destructor(void *, void *);
110 static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
111 
112 static void smb_node_init_reparse(smb_node_t *, smb_attr_t *);
113 static void smb_node_init_system(smb_node_t *);
114 
115 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
116     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
117     ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
118     ASSERT((_dir_)->n_dnode != (_node_));
119 
120 /* round sz to DEV_BSIZE block */
121 #define	SMB_ALLOCSZ(sz)	(((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
122 
123 static kmem_cache_t	*smb_node_cache = NULL;
124 static smb_llist_t	smb_node_hash_table[SMBND_HASH_MASK+1];
125 static smb_node_t	*smb_root_node;
126 
127 /*
128  * smb_node_init
129  *
130  * Initialization of the SMB node layer.
131  *
132  * This function is not multi-thread safe. The caller must make sure only one
133  * thread makes the call.
134  */
135 void
136 smb_node_init(void)
137 {
138 	smb_attr_t	attr;
139 	smb_llist_t	*node_hdr;
140 	smb_node_t	*node;
141 	uint32_t	hashkey;
142 	int		i;
143 
144 	if (smb_node_cache != NULL)
145 		return;
146 
147 	smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
148 	    sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
149 	    NULL, NULL, NULL, 0);
150 
151 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
152 		smb_llist_constructor(&smb_node_hash_table[i],
153 		    sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
154 	}
155 
156 	/*
157 	 * The node cache is shared by all zones, so the smb_root_node
158 	 * must represent the real (global zone) rootdir.
159 	 * Note intentional use of kcred here.
160 	 */
161 	attr.sa_mask = SMB_AT_ALL;
162 	VERIFY0(smb_vop_getattr(rootdir, NULL, &attr, 0, kcred));
163 	node_hdr = smb_node_get_hash(&rootdir->v_vfsp->vfs_fsid, &attr,
164 	    &hashkey);
165 	node = smb_node_alloc("/", rootdir, node_hdr, hashkey);
166 	smb_llist_enter(node_hdr, RW_WRITER);
167 	smb_llist_insert_head(node_hdr, node);
168 	smb_llist_exit(node_hdr);
169 	smb_root_node = node;	/* smb_node_release in smb_node_fini */
170 }
171 
172 /*
173  * smb_node_fini
174  *
175  * This function is not multi-thread safe. The caller must make sure only one
176  * thread makes the call.
177  */
178 void
179 smb_node_fini(void)
180 {
181 	int	i;
182 
183 	if (smb_root_node != NULL) {
184 		smb_node_release(smb_root_node);
185 		smb_root_node = NULL;
186 	}
187 
188 	if (smb_node_cache == NULL)
189 		return;
190 
191 #ifdef DEBUG
192 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
193 		smb_node_t	*node;
194 
195 		/*
196 		 * The following sequence is just intended for sanity check.
197 		 * This will have to be modified when the code goes into
198 		 * production.
199 		 *
200 		 * The SMB node hash table should be emtpy at this point. If the
201 		 * hash table is not empty a panic will be triggered.
202 		 *
203 		 * The reason why SMB nodes are still remaining in the hash
204 		 * table is problably due to a mismatch between calls to
205 		 * smb_node_lookup() and smb_node_release(). You must track that
206 		 * down.
207 		 */
208 		node = smb_llist_head(&smb_node_hash_table[i]);
209 		ASSERT(node == NULL);
210 	}
211 #endif
212 
213 	for (i = 0; i <= SMBND_HASH_MASK; i++) {
214 		smb_llist_destructor(&smb_node_hash_table[i]);
215 	}
216 	kmem_cache_destroy(smb_node_cache);
217 	smb_node_cache = NULL;
218 }
219 
220 /*
221  * smb_node_lookup()
222  *
223  * NOTE: This routine should only be called by the file system interface layer,
224  * and not by SMB.
225  *
226  * smb_node_lookup() is called upon successful lookup, mkdir, and create
227  * (for both non-streams and streams).  In each of these cases, a held vnode is
228  * passed into this routine.  If a new smb_node is created it will take its
229  * own hold on the vnode.  The caller's hold therefore still belongs to, and
230  * should be released by, the caller.
231  *
232  * A reference is taken on the smb_node whether found in the hash table
233  * or newly created.
234  *
235  * If an smb_node needs to be created, a reference is also taken on the
236  * dnode (if passed in).
237  *
238  * See smb_node_release() for details on the release of these references.
239  */
240 
241 /*ARGSUSED*/
242 smb_node_t *
243 smb_node_lookup(
244     struct smb_request	*sr,
245     struct open_param	*op,
246     cred_t		*cred,
247     vnode_t		*vp,
248     char		*od_name,
249     smb_node_t		*dnode,
250     smb_node_t		*unode)
251 {
252 	smb_llist_t		*node_hdr;
253 	smb_node_t		*node;
254 	smb_attr_t		attr;
255 	uint32_t		hashkey = 0;
256 	fsid_t			fsid;
257 	int			error;
258 	krw_t			lock_mode;
259 	vnode_t			*unnamed_vp = NULL;
260 
261 	/*
262 	 * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
263 	 * because the node may not yet exist.  We also do not want to call
264 	 * it with the list lock held.
265 	 */
266 
267 	if (unode)
268 		unnamed_vp = unode->vp;
269 
270 	/*
271 	 * This getattr is performed on behalf of the server
272 	 * that's why kcred is used not the user's cred
273 	 */
274 	attr.sa_mask = SMB_AT_ALL;
275 	error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, zone_kcred());
276 	if (error)
277 		return (NULL);
278 
279 	if (sr && sr->tid_tree) {
280 		/*
281 		 * The fsid for a file is that of the tree, even
282 		 * if the file resides in a different mountpoint
283 		 * under the share.
284 		 */
285 		fsid = SMB_TREE_FSID(sr->tid_tree);
286 	} else {
287 		/*
288 		 * This should be getting executed only for the
289 		 * tree root smb_node.
290 		 */
291 		fsid = vp->v_vfsp->vfs_fsid;
292 	}
293 
294 	node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
295 	lock_mode = RW_READER;
296 
297 	smb_llist_enter(node_hdr, lock_mode);
298 	for (;;) {
299 		node = list_head(&node_hdr->ll_list);
300 		while (node) {
301 			ASSERT(node->n_magic == SMB_NODE_MAGIC);
302 			ASSERT(node->n_hash_bucket == node_hdr);
303 			if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
304 				mutex_enter(&node->n_mutex);
305 				DTRACE_PROBE1(smb_node_lookup_hit,
306 				    smb_node_t *, node);
307 				switch (node->n_state) {
308 				case SMB_NODE_STATE_AVAILABLE:
309 					/* The node was found. */
310 					node->n_refcnt++;
311 					if ((node->n_dnode == NULL) &&
312 					    (dnode != NULL) &&
313 					    (node != dnode) &&
314 					    (strcmp(od_name, "..") != 0) &&
315 					    (strcmp(od_name, ".") != 0)) {
316 						VALIDATE_DIR_NODE(dnode, node);
317 						node->n_dnode = dnode;
318 						smb_node_ref(dnode);
319 					}
320 
321 					smb_node_audit(node);
322 					mutex_exit(&node->n_mutex);
323 					smb_llist_exit(node_hdr);
324 					return (node);
325 
326 				case SMB_NODE_STATE_DESTROYING:
327 					/*
328 					 * Although the node exists it is about
329 					 * to be destroyed. We act as it hasn't
330 					 * been found.
331 					 */
332 					mutex_exit(&node->n_mutex);
333 					break;
334 				default:
335 					/*
336 					 * Although the node exists it is in an
337 					 * unknown state. We act as it hasn't
338 					 * been found.
339 					 */
340 					ASSERT(0);
341 					mutex_exit(&node->n_mutex);
342 					break;
343 				}
344 			}
345 			node = smb_llist_next(node_hdr, node);
346 		}
347 		if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
348 			lock_mode = RW_WRITER;
349 			continue;
350 		}
351 		break;
352 	}
353 	node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
354 	smb_node_init_reparse(node, &attr);
355 
356 	if (op)
357 		node->flags |= smb_is_executable(op->fqi.fq_last_comp);
358 
359 	if (dnode) {
360 		smb_node_ref(dnode);
361 		node->n_dnode = dnode;
362 		ASSERT(dnode->n_dnode != node);
363 		ASSERT((dnode->vp->v_xattrdir) ||
364 		    (dnode->vp->v_type == VDIR));
365 	}
366 
367 	if (unode) {
368 		smb_node_ref(unode);
369 		node->n_unode = unode;
370 	}
371 
372 	smb_node_init_system(node);
373 
374 	DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
375 	smb_node_audit(node);
376 	smb_llist_insert_head(node_hdr, node);
377 	smb_llist_exit(node_hdr);
378 	return (node);
379 }
380 
381 /*
382  * smb_stream_node_lookup()
383  *
384  * Note: stream_name (the name that will be stored in the "od_name" field
385  * of a stream's smb_node) is the same as the on-disk name for the stream
386  * except that it does not have SMB_STREAM_PREFIX prepended.
387  */
388 
389 smb_node_t *
390 smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
391     vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
392 {
393 	smb_node_t	*xattrdir_node;
394 	smb_node_t	*snode;
395 
396 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
397 	    fnode, NULL);
398 
399 	if (xattrdir_node == NULL)
400 		return (NULL);
401 
402 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
403 	    fnode);
404 
405 	(void) smb_node_release(xattrdir_node);
406 	return (snode);
407 }
408 
409 
410 /*
411  * This function should be called whenever a reference is needed on an
412  * smb_node pointer.  The copy of an smb_node pointer from one non-local
413  * data structure to another requires a reference to be taken on the smb_node
414  * (unless the usage is localized).  Each data structure deallocation routine
415  * will call smb_node_release() on its smb_node pointers.
416  *
417  * In general, an smb_node pointer residing in a structure should never be
418  * stale.  A node pointer may be NULL, however, and care should be taken
419  * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
420  * Care also needs to be taken with respect to racing deallocations of a
421  * structure.
422  */
423 void
424 smb_node_ref(smb_node_t *node)
425 {
426 	SMB_NODE_VALID(node);
427 
428 	mutex_enter(&node->n_mutex);
429 	switch (node->n_state) {
430 	case SMB_NODE_STATE_AVAILABLE:
431 		node->n_refcnt++;
432 		ASSERT(node->n_refcnt);
433 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
434 		smb_node_audit(node);
435 		break;
436 	default:
437 		SMB_PANIC();
438 	}
439 	mutex_exit(&node->n_mutex);
440 }
441 
442 /*
443  * smb_node_lookup() takes a hold on an smb_node, whether found in the
444  * hash table or newly created.  This hold is expected to be released
445  * in the following manner.
446  *
447  * smb_node_lookup() takes an address of an smb_node pointer.  This should
448  * be getting passed down via a lookup (whether path name or component), mkdir,
449  * create.  If the original smb_node pointer resides in a data structure, then
450  * the deallocation routine for the data structure is responsible for calling
451  * smb_node_release() on the smb_node pointer.  Alternatively,
452  * smb_node_release() can be called as soon as the smb_node pointer is no longer
453  * needed.  In this case, callers are responsible for setting an embedded
454  * pointer to NULL if it is known that the last reference is being released.
455  *
456  * If the passed-in address of the smb_node pointer belongs to a local variable,
457  * then the caller with the local variable should call smb_node_release()
458  * directly.
459  *
460  * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
461  * as smb_node_lookup() takes a hold on dnode.
462  */
463 void
464 smb_node_release(smb_node_t *node)
465 {
466 	SMB_NODE_VALID(node);
467 
468 	mutex_enter(&node->n_mutex);
469 	ASSERT(node->n_refcnt);
470 	DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
471 	if (--node->n_refcnt == 0) {
472 		switch (node->n_state) {
473 
474 		case SMB_NODE_STATE_AVAILABLE:
475 			node->n_state = SMB_NODE_STATE_DESTROYING;
476 			mutex_exit(&node->n_mutex);
477 
478 			smb_llist_enter(node->n_hash_bucket, RW_WRITER);
479 			smb_llist_remove(node->n_hash_bucket, node);
480 			smb_llist_exit(node->n_hash_bucket);
481 
482 			/*
483 			 * Check if the file was deleted
484 			 */
485 			smb_node_delete_on_close(node);
486 
487 			if (node->n_dnode) {
488 				ASSERT(node->n_dnode->n_magic ==
489 				    SMB_NODE_MAGIC);
490 				smb_node_release(node->n_dnode);
491 			}
492 
493 			if (node->n_unode) {
494 				ASSERT(node->n_unode->n_magic ==
495 				    SMB_NODE_MAGIC);
496 				smb_node_release(node->n_unode);
497 			}
498 
499 			smb_node_free(node);
500 			return;
501 
502 		default:
503 			SMB_PANIC();
504 		}
505 	}
506 	smb_node_audit(node);
507 	mutex_exit(&node->n_mutex);
508 }
509 
510 static void
511 smb_node_delete_on_close(smb_node_t *node)
512 {
513 	smb_node_t	*d_snode;
514 	int		rc = 0;
515 	uint32_t	flags = 0;
516 
517 	d_snode = node->n_dnode;
518 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
519 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
520 		flags = node->n_delete_on_close_flags;
521 		ASSERT(node->od_name != NULL);
522 
523 		if (smb_node_is_dir(node))
524 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
525 			    d_snode, node->od_name, flags);
526 		else
527 			rc = smb_fsop_remove(0, node->delete_on_close_cred,
528 			    d_snode, node->od_name, flags);
529 		crfree(node->delete_on_close_cred);
530 	}
531 	if (rc != 0)
532 		cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
533 		    node->od_name, rc);
534 	DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
535 }
536 
537 /*
538  * smb_node_rename()
539  *
540  */
541 void
542 smb_node_rename(
543     smb_node_t	*from_dnode,
544     smb_node_t	*ret_node,
545     smb_node_t	*to_dnode,
546     char	*to_name)
547 {
548 	SMB_NODE_VALID(from_dnode);
549 	SMB_NODE_VALID(to_dnode);
550 	SMB_NODE_VALID(ret_node);
551 
552 	smb_node_ref(to_dnode);
553 	mutex_enter(&ret_node->n_mutex);
554 	switch (ret_node->n_state) {
555 	case SMB_NODE_STATE_AVAILABLE:
556 		ret_node->n_dnode = to_dnode;
557 		mutex_exit(&ret_node->n_mutex);
558 		ASSERT(to_dnode->n_dnode != ret_node);
559 		ASSERT((to_dnode->vp->v_xattrdir) ||
560 		    (to_dnode->vp->v_type == VDIR));
561 		smb_node_release(from_dnode);
562 		(void) strcpy(ret_node->od_name, to_name);
563 		/*
564 		 * XXX Need to update attributes?
565 		 */
566 		break;
567 	default:
568 		SMB_PANIC();
569 	}
570 }
571 
572 /*
573  * Find/create an SMB node for the root of this zone and store it
574  * in *svrootp.  Also create nodes leading to this directory.
575  */
576 int
577 smb_node_root_init(smb_server_t *sv, smb_node_t **svrootp)
578 {
579 	zone_t		*zone = curzone;
580 	int		error;
581 
582 	ASSERT(zone->zone_id == sv->sv_zid);
583 	if (smb_root_node == NULL)
584 		return (ENOENT);
585 
586 	/*
587 	 * We're getting smb nodes below the zone root here,
588 	 * so need to use kcred, not zone_kcred().
589 	 */
590 	error = smb_pathname(NULL, zone->zone_rootpath, 0,
591 	    smb_root_node, smb_root_node, NULL, svrootp, kcred);
592 
593 	return (error);
594 }
595 /*
596  * Helper function for smb_node_set_delete_on_close(). Assumes node is a dir.
597  * Return 0 if this is an empty dir. Otherwise return a NT_STATUS code.
598  * We distinguish between readdir failure and non-empty dir by returning
599  * different values.
600  */
601 static uint32_t
602 smb_rmdir_possible(smb_node_t *n, uint32_t flags)
603 {
604 	ASSERT(n->vp->v_type == VDIR);
605 	char buf[512]; /* Only large enough to see if the dir is empty. */
606 	int eof, bsize = sizeof (buf), reclen = 0;
607 	char *name;
608 	boolean_t edp = vfs_has_feature(n->vp->v_vfsp, VFSFT_DIRENTFLAGS);
609 
610 	union {
611 		char		*u_bufptr;
612 		struct edirent	*u_edp;
613 		struct dirent64	*u_dp;
614 	} u;
615 #define	bufptr	u.u_bufptr
616 #define	extdp	u.u_edp
617 #define	dp	u.u_dp
618 
619 	if (smb_vop_readdir(n->vp, 0, buf, &bsize, &eof, flags, zone_kcred()))
620 		return (NT_STATUS_CANNOT_DELETE);
621 	if (bsize == 0)
622 		return (NT_STATUS_CANNOT_DELETE);
623 	bufptr = buf;
624 	while ((bufptr += reclen) < buf + bsize) {
625 		if (edp) {
626 			reclen = extdp->ed_reclen;
627 			name = extdp->ed_name;
628 		} else {
629 			reclen = dp->d_reclen;
630 			name = dp->d_name;
631 		}
632 		if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
633 			return (NT_STATUS_DIRECTORY_NOT_EMPTY);
634 	}
635 	return (0);
636 }
637 
638 /*
639  * When DeleteOnClose is set on an smb_node, the common open code will
640  * reject subsequent open requests for the file. Observation of Windows
641  * 2000 indicates that subsequent opens should be allowed (assuming
642  * there would be no sharing violation) until the file is closed using
643  * the fid on which the DeleteOnClose was requested.
644  *
645  * If there are multiple opens with delete-on-close create options,
646  * whichever the first file handle is closed will trigger the node to be
647  * marked as delete-on-close. The credentials of that ofile will be used
648  * as the delete-on-close credentials of the node.
649  */
650 uint32_t
651 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
652 {
653 	int rc = 0;
654 	uint32_t status;
655 	smb_attr_t attr;
656 
657 	if (node->n_pending_dosattr & FILE_ATTRIBUTE_READONLY)
658 		return (NT_STATUS_CANNOT_DELETE);
659 
660 	bzero(&attr, sizeof (smb_attr_t));
661 	attr.sa_mask = SMB_AT_DOSATTR;
662 	rc = smb_fsop_getattr(NULL, zone_kcred(), node, &attr);
663 	if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
664 		return (NT_STATUS_CANNOT_DELETE);
665 	}
666 
667 	/*
668 	 * If the directory is not empty we should fail setting del-on-close
669 	 * with STATUS_DIRECTORY_NOT_EMPTY. see MS's
670 	 * "File System Behavior Overview" doc section 4.3.2
671 	 */
672 	if (smb_node_is_dir(node)) {
673 		status = smb_rmdir_possible(node, flags);
674 		if (status != 0) {
675 			return (status);
676 		}
677 	}
678 
679 	mutex_enter(&node->n_mutex);
680 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
681 		mutex_exit(&node->n_mutex);
682 		return (NT_STATUS_CANNOT_DELETE);
683 	}
684 
685 	crhold(cr);
686 	node->delete_on_close_cred = cr;
687 	node->n_delete_on_close_flags = flags;
688 	node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
689 	mutex_exit(&node->n_mutex);
690 
691 	return (NT_STATUS_SUCCESS);
692 }
693 
694 void
695 smb_node_reset_delete_on_close(smb_node_t *node)
696 {
697 	mutex_enter(&node->n_mutex);
698 	if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
699 		node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
700 		crfree(node->delete_on_close_cred);
701 		node->delete_on_close_cred = NULL;
702 		node->n_delete_on_close_flags = 0;
703 	}
704 	mutex_exit(&node->n_mutex);
705 }
706 
707 /*
708  * smb_node_open_check
709  *
710  * check file sharing rules for current open request
711  * against all existing opens for a file.
712  *
713  * Returns NT_STATUS_SHARING_VIOLATION if there is any
714  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
715  */
716 uint32_t
717 smb_node_open_check(smb_node_t *node, uint32_t desired_access,
718     uint32_t share_access)
719 {
720 	smb_ofile_t *of;
721 	uint32_t status;
722 
723 	SMB_NODE_VALID(node);
724 
725 	smb_llist_enter(&node->n_ofile_list, RW_READER);
726 	of = smb_llist_head(&node->n_ofile_list);
727 	while (of) {
728 		status = smb_ofile_open_check(of, desired_access, share_access);
729 
730 		switch (status) {
731 		case NT_STATUS_INVALID_HANDLE:
732 		case NT_STATUS_SUCCESS:
733 			of = smb_llist_next(&node->n_ofile_list, of);
734 			break;
735 		default:
736 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
737 			smb_llist_exit(&node->n_ofile_list);
738 			return (status);
739 		}
740 	}
741 
742 	smb_llist_exit(&node->n_ofile_list);
743 	return (NT_STATUS_SUCCESS);
744 }
745 
746 uint32_t
747 smb_node_rename_check(smb_node_t *node)
748 {
749 	smb_ofile_t	*of;
750 	uint32_t	status;
751 
752 	SMB_NODE_VALID(node);
753 
754 	/*
755 	 * Intra-CIFS check
756 	 */
757 	smb_llist_enter(&node->n_ofile_list, RW_READER);
758 	of = smb_llist_head(&node->n_ofile_list);
759 	while (of) {
760 		status = smb_ofile_rename_check(of);
761 
762 		switch (status) {
763 		case NT_STATUS_INVALID_HANDLE:
764 		case NT_STATUS_SUCCESS:
765 			of = smb_llist_next(&node->n_ofile_list, of);
766 			break;
767 		default:
768 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
769 			smb_llist_exit(&node->n_ofile_list);
770 			return (status);
771 		}
772 	}
773 	smb_llist_exit(&node->n_ofile_list);
774 	return (NT_STATUS_SUCCESS);
775 }
776 
777 uint32_t
778 smb_node_delete_check(smb_node_t *node)
779 {
780 	smb_ofile_t	*of;
781 	uint32_t	status;
782 
783 	SMB_NODE_VALID(node);
784 
785 	if (smb_node_is_dir(node))
786 		return (NT_STATUS_SUCCESS);
787 
788 	if (smb_node_is_reparse(node))
789 		return (NT_STATUS_ACCESS_DENIED);
790 
791 	/*
792 	 * intra-CIFS check
793 	 */
794 	smb_llist_enter(&node->n_ofile_list, RW_READER);
795 	of = smb_llist_head(&node->n_ofile_list);
796 	while (of) {
797 		status = smb_ofile_delete_check(of);
798 
799 		switch (status) {
800 		case NT_STATUS_INVALID_HANDLE:
801 		case NT_STATUS_SUCCESS:
802 			of = smb_llist_next(&node->n_ofile_list, of);
803 			break;
804 		default:
805 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
806 			smb_llist_exit(&node->n_ofile_list);
807 			return (status);
808 		}
809 	}
810 	smb_llist_exit(&node->n_ofile_list);
811 	return (NT_STATUS_SUCCESS);
812 }
813 
814 /*
815  * smb_node_share_check
816  *
817  * Returns: TRUE    - ofiles have non-zero share access
818  *          B_FALSE - ofile with share access NONE.
819  */
820 boolean_t
821 smb_node_share_check(smb_node_t *node)
822 {
823 	smb_ofile_t	*of;
824 	boolean_t	status = B_TRUE;
825 
826 	SMB_NODE_VALID(node);
827 
828 	smb_llist_enter(&node->n_ofile_list, RW_READER);
829 	of = smb_llist_head(&node->n_ofile_list);
830 	if (of)
831 		status = smb_ofile_share_check(of);
832 	smb_llist_exit(&node->n_ofile_list);
833 
834 	return (status);
835 }
836 
837 /*
838  * SMB Change Notification
839  */
840 
841 void
842 smb_node_fcn_subscribe(smb_node_t *node, smb_request_t *sr)
843 {
844 	smb_node_fcn_t		*fcn = &node->n_fcn;
845 
846 	mutex_enter(&fcn->fcn_mutex);
847 	if (fcn->fcn_count == 0)
848 		(void) smb_fem_fcn_install(node);
849 	fcn->fcn_count++;
850 	list_insert_tail(&fcn->fcn_watchers, sr);
851 	mutex_exit(&fcn->fcn_mutex);
852 }
853 
854 void
855 smb_node_fcn_unsubscribe(smb_node_t *node, smb_request_t *sr)
856 {
857 	smb_node_fcn_t		*fcn = &node->n_fcn;
858 
859 	mutex_enter(&fcn->fcn_mutex);
860 	list_remove(&fcn->fcn_watchers, sr);
861 	fcn->fcn_count--;
862 	if (fcn->fcn_count == 0)
863 		smb_fem_fcn_uninstall(node);
864 	mutex_exit(&fcn->fcn_mutex);
865 }
866 
867 void
868 smb_node_notify_change(smb_node_t *node, uint_t action, const char *name)
869 {
870 	SMB_NODE_VALID(node);
871 
872 	smb_notify_event(node, action, name);
873 
874 	/*
875 	 * These two events come as a pair:
876 	 *   FILE_ACTION_RENAMED_OLD_NAME
877 	 *   FILE_ACTION_RENAMED_NEW_NAME
878 	 * Only do the parent notify for "new".
879 	 */
880 	if (action == FILE_ACTION_RENAMED_OLD_NAME)
881 		return;
882 
883 	smb_node_notify_parents(node);
884 }
885 
886 /*
887  * smb_node_notify_parents
888  *
889  * Iterate up the directory tree notifying any parent
890  * directories that are being watched for changes in
891  * their sub directories.
892  * Stop at the root node, which has a NULL parent node.
893  */
894 void
895 smb_node_notify_parents(smb_node_t *dnode)
896 {
897 	smb_node_t *pnode;	/* parent */
898 
899 	SMB_NODE_VALID(dnode);
900 	pnode = dnode->n_dnode;
901 
902 	while (pnode != NULL) {
903 		SMB_NODE_VALID(pnode);
904 		smb_notify_event(pnode, 0, dnode->od_name);
905 		/* cd .. */
906 		dnode = pnode;
907 		pnode = dnode->n_dnode;
908 	}
909 }
910 
911 /*
912  * smb_node_start_crit()
913  *
914  * Enter critical region for share reservations.
915  * See comments above smb_fsop_shrlock().
916  */
917 void
918 smb_node_start_crit(smb_node_t *node, krw_t mode)
919 {
920 	rw_enter(&node->n_lock, mode);
921 	nbl_start_crit(node->vp, mode);
922 }
923 
924 /*
925  * smb_node_end_crit()
926  *
927  * Exit critical region for share reservations.
928  */
929 void
930 smb_node_end_crit(smb_node_t *node)
931 {
932 	nbl_end_crit(node->vp);
933 	rw_exit(&node->n_lock);
934 }
935 
936 int
937 smb_node_in_crit(smb_node_t *node)
938 {
939 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
940 }
941 
942 void
943 smb_node_rdlock(smb_node_t *node)
944 {
945 	rw_enter(&node->n_lock, RW_READER);
946 }
947 
948 void
949 smb_node_wrlock(smb_node_t *node)
950 {
951 	rw_enter(&node->n_lock, RW_WRITER);
952 }
953 
954 void
955 smb_node_unlock(smb_node_t *node)
956 {
957 	rw_exit(&node->n_lock);
958 }
959 
960 void
961 smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
962 {
963 	SMB_NODE_VALID(node);
964 
965 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
966 	smb_llist_insert_tail(&node->n_ofile_list, of);
967 	smb_llist_exit(&node->n_ofile_list);
968 }
969 
970 void
971 smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
972 {
973 	SMB_NODE_VALID(node);
974 
975 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
976 	smb_llist_remove(&node->n_ofile_list, of);
977 	smb_llist_exit(&node->n_ofile_list);
978 }
979 
980 /*
981  * smb_node_inc_open_ofiles
982  */
983 void
984 smb_node_inc_open_ofiles(smb_node_t *node)
985 {
986 	SMB_NODE_VALID(node);
987 	atomic_inc_32(&node->n_open_count);
988 }
989 
990 /*
991  * smb_node_dec_open_ofiles
992  * returns new value
993  */
994 uint32_t
995 smb_node_dec_open_ofiles(smb_node_t *node)
996 {
997 	SMB_NODE_VALID(node);
998 	return (atomic_dec_32_nv(&node->n_open_count));
999 }
1000 
1001 /*
1002  * smb_node_inc_opening_count
1003  */
1004 void
1005 smb_node_inc_opening_count(smb_node_t *node)
1006 {
1007 	SMB_NODE_VALID(node);
1008 	atomic_inc_32(&node->n_opening_count);
1009 }
1010 
1011 /*
1012  * smb_node_dec_opening_count
1013  */
1014 void
1015 smb_node_dec_opening_count(smb_node_t *node)
1016 {
1017 	SMB_NODE_VALID(node);
1018 	atomic_dec_32(&node->n_opening_count);
1019 }
1020 
1021 /*
1022  * smb_node_getmntpath
1023  */
1024 int
1025 smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen)
1026 {
1027 	vnode_t *vp, *root_vp;
1028 	vfs_t *vfsp;
1029 	int err;
1030 
1031 	ASSERT(node);
1032 	ASSERT(node->vp);
1033 	ASSERT(node->vp->v_vfsp);
1034 
1035 	vp = node->vp;
1036 	vfsp = vp->v_vfsp;
1037 
1038 	if (VFS_ROOT(vfsp, &root_vp))
1039 		return (ENOENT);
1040 
1041 	VN_HOLD(vp);
1042 
1043 	/* NULL is passed in as we want to start at "/" */
1044 	err = vnodetopath(NULL, root_vp, buf, buflen, zone_kcred());
1045 
1046 	VN_RELE(vp);
1047 	VN_RELE(root_vp);
1048 	return (err);
1049 }
1050 
1051 /*
1052  * smb_node_getshrpath
1053  *
1054  * Determine the absolute pathname of 'node' within the share (tree).
1055  * For example if the node represents file "test1.txt" in directory
1056  * "dir1" the pathname would be: \dir1\test1.txt
1057  */
1058 int
1059 smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree,
1060     char *buf, uint32_t buflen)
1061 {
1062 	int rc;
1063 
1064 	ASSERT(node);
1065 	ASSERT(tree);
1066 	ASSERT(tree->t_snode);
1067 
1068 	rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen);
1069 	(void) strsubst(buf, '/', '\\');
1070 	return (rc);
1071 }
1072 
1073 /*
1074  * smb_node_getpath
1075  *
1076  * Determine the absolute pathname of 'node' from 'rootvp'.
1077  *
1078  * Using vnodetopath is only reliable for directory nodes (due to
1079  * its reliance on the DNLC for non-directory nodes). Thus, if node
1080  * represents a file, construct the pathname for the parent dnode
1081  * and append filename.
1082  * If node represents a named stream, construct the pathname for the
1083  * associated unnamed stream and append the stream name.
1084  *
1085  * The pathname returned in buf will be '/' separated.
1086  */
1087 int
1088 smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen)
1089 {
1090 	int rc;
1091 	vnode_t *vp;
1092 	smb_node_t *unode, *dnode;
1093 	cred_t *kcr = zone_kcred();
1094 
1095 	unode = (SMB_IS_STREAM(node)) ? node->n_unode : node;
1096 	dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode;
1097 
1098 	/* find path to directory node */
1099 	vp = dnode->vp;
1100 	VN_HOLD(vp);
1101 	if (rootvp) {
1102 		VN_HOLD(rootvp);
1103 		rc = vnodetopath(rootvp, vp, buf, buflen, kcr);
1104 		VN_RELE(rootvp);
1105 	} else {
1106 		rc = vnodetopath(NULL, vp, buf, buflen, kcr);
1107 	}
1108 	VN_RELE(vp);
1109 
1110 	if (rc != 0)
1111 		return (rc);
1112 
1113 	/* append filename if necessary */
1114 	if (!smb_node_is_dir(unode)) {
1115 		if (buf[strlen(buf) - 1] != '/')
1116 			(void) strlcat(buf, "/", buflen);
1117 		(void) strlcat(buf, unode->od_name, buflen);
1118 	}
1119 
1120 	/* append named stream name if necessary */
1121 	if (SMB_IS_STREAM(node))
1122 		(void) strlcat(buf, node->od_name, buflen);
1123 
1124 	return (rc);
1125 }
1126 
1127 /*
1128  * smb_node_alloc
1129  */
1130 static smb_node_t *
1131 smb_node_alloc(
1132     char	*od_name,
1133     vnode_t	*vp,
1134     smb_llist_t	*bucket,
1135     uint32_t	hashkey)
1136 {
1137 	smb_node_t	*node;
1138 	vnode_t		*root_vp;
1139 
1140 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
1141 
1142 	if (node->n_audit_buf != NULL)
1143 		node->n_audit_buf->anb_index = 0;
1144 
1145 	node->flags = 0;
1146 	VN_HOLD(vp);
1147 	node->vp = vp;
1148 	node->n_refcnt = 1;
1149 	node->n_hash_bucket = bucket;
1150 	node->n_hashkey = hashkey;
1151 	node->n_pending_dosattr = 0;
1152 	node->n_open_count = 0;
1153 	node->n_allocsz = 0;
1154 	node->n_dnode = NULL;
1155 	node->n_unode = NULL;
1156 	node->delete_on_close_cred = NULL;
1157 	node->n_delete_on_close_flags = 0;
1158 	node->n_oplock.ol_fem = B_FALSE;
1159 	node->n_oplock.ol_xthread = NULL;
1160 	node->n_oplock.ol_count = 0;
1161 	node->n_oplock.ol_break = SMB_OPLOCK_NO_BREAK;
1162 
1163 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
1164 	if (strcmp(od_name, XATTR_DIR) == 0)
1165 		node->flags |= NODE_XATTR_DIR;
1166 
1167 	if (VFS_ROOT(vp->v_vfsp, &root_vp) == 0) {
1168 		if (vp == root_vp)
1169 			node->flags |= NODE_FLAGS_VFSROOT;
1170 		VN_RELE(root_vp);
1171 	}
1172 
1173 	node->n_state = SMB_NODE_STATE_AVAILABLE;
1174 	node->n_magic = SMB_NODE_MAGIC;
1175 
1176 	return (node);
1177 }
1178 
1179 /*
1180  * smb_node_free
1181  */
1182 static void
1183 smb_node_free(smb_node_t *node)
1184 {
1185 	SMB_NODE_VALID(node);
1186 
1187 	node->n_magic = 0;
1188 	VERIFY(!list_link_active(&node->n_lnd));
1189 	VERIFY(node->n_lock_list.ll_count == 0);
1190 	VERIFY(node->n_ofile_list.ll_count == 0);
1191 	VERIFY(node->n_oplock.ol_count == 0);
1192 	VERIFY(node->n_oplock.ol_xthread == NULL);
1193 	VERIFY(node->n_oplock.ol_fem == B_FALSE);
1194 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
1195 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
1196 	VN_RELE(node->vp);
1197 	kmem_cache_free(smb_node_cache, node);
1198 }
1199 
1200 /*
1201  * smb_node_constructor
1202  */
1203 static int
1204 smb_node_constructor(void *buf, void *un, int kmflags)
1205 {
1206 	_NOTE(ARGUNUSED(kmflags, un))
1207 
1208 	smb_node_t	*node = (smb_node_t *)buf;
1209 
1210 	bzero(node, sizeof (smb_node_t));
1211 
1212 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1213 	    offsetof(smb_ofile_t, f_nnd));
1214 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
1215 	    offsetof(smb_lock_t, l_lnd));
1216 	mutex_init(&node->n_fcn.fcn_mutex, NULL, MUTEX_DEFAULT, NULL);
1217 	list_create(&node->n_fcn.fcn_watchers, sizeof (smb_request_t),
1218 	    offsetof(smb_request_t, sr_ncr.nc_lnd));
1219 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
1220 	mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL);
1221 	list_create(&node->n_oplock.ol_grants, sizeof (smb_oplock_grant_t),
1222 	    offsetof(smb_oplock_grant_t, og_lnd));
1223 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
1224 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
1225 	smb_node_create_audit_buf(node, kmflags);
1226 	return (0);
1227 }
1228 
1229 /*
1230  * smb_node_destructor
1231  */
1232 static void
1233 smb_node_destructor(void *buf, void *un)
1234 {
1235 	_NOTE(ARGUNUSED(un))
1236 
1237 	smb_node_t	*node = (smb_node_t *)buf;
1238 
1239 	smb_node_destroy_audit_buf(node);
1240 	mutex_destroy(&node->n_mutex);
1241 	rw_destroy(&node->n_lock);
1242 	cv_destroy(&node->n_oplock.ol_cv);
1243 	mutex_destroy(&node->n_oplock.ol_mutex);
1244 	list_destroy(&node->n_fcn.fcn_watchers);
1245 	mutex_destroy(&node->n_fcn.fcn_mutex);
1246 	smb_llist_destructor(&node->n_lock_list);
1247 	smb_llist_destructor(&node->n_ofile_list);
1248 	list_destroy(&node->n_oplock.ol_grants);
1249 }
1250 
1251 /*
1252  * smb_node_create_audit_buf
1253  */
1254 static void
1255 smb_node_create_audit_buf(smb_node_t *node, int kmflags)
1256 {
1257 	smb_audit_buf_node_t	*abn;
1258 
1259 	if (smb_audit_flags & SMB_AUDIT_NODE) {
1260 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
1261 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
1262 		node->n_audit_buf = abn;
1263 	}
1264 }
1265 
1266 /*
1267  * smb_node_destroy_audit_buf
1268  */
1269 static void
1270 smb_node_destroy_audit_buf(smb_node_t *node)
1271 {
1272 	if (node->n_audit_buf != NULL) {
1273 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
1274 		node->n_audit_buf = NULL;
1275 	}
1276 }
1277 
1278 /*
1279  * smb_node_audit
1280  *
1281  * This function saves the calling stack in the audit buffer of the node passed
1282  * in.
1283  */
1284 static void
1285 smb_node_audit(smb_node_t *node)
1286 {
1287 	smb_audit_buf_node_t	*abn;
1288 	smb_audit_record_node_t	*anr;
1289 
1290 	if (node->n_audit_buf) {
1291 		abn = node->n_audit_buf;
1292 		anr = abn->anb_records;
1293 		anr += abn->anb_index;
1294 		abn->anb_index++;
1295 		abn->anb_index &= abn->anb_max_index;
1296 		anr->anr_refcnt = node->n_refcnt;
1297 		anr->anr_depth = getpcstack(anr->anr_stack,
1298 		    SMB_AUDIT_STACK_DEPTH);
1299 	}
1300 }
1301 
1302 static smb_llist_t *
1303 smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
1304 {
1305 	uint32_t	hashkey;
1306 
1307 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
1308 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1309 	*phashkey = hashkey;
1310 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1311 }
1312 
1313 boolean_t
1314 smb_node_is_file(smb_node_t *node)
1315 {
1316 	SMB_NODE_VALID(node);
1317 	return (node->vp->v_type == VREG);
1318 }
1319 
1320 boolean_t
1321 smb_node_is_dir(smb_node_t *node)
1322 {
1323 	SMB_NODE_VALID(node);
1324 	return ((node->vp->v_type == VDIR) ||
1325 	    (node->flags & NODE_FLAGS_DFSLINK));
1326 }
1327 
1328 boolean_t
1329 smb_node_is_symlink(smb_node_t *node)
1330 {
1331 	SMB_NODE_VALID(node);
1332 	return ((node->vp->v_type == VLNK) &&
1333 	    ((node->flags & NODE_FLAGS_REPARSE) == 0));
1334 }
1335 
1336 boolean_t
1337 smb_node_is_dfslink(smb_node_t *node)
1338 {
1339 	SMB_NODE_VALID(node);
1340 	return ((node->vp->v_type == VLNK) &&
1341 	    (node->flags & NODE_FLAGS_DFSLINK));
1342 }
1343 
1344 boolean_t
1345 smb_node_is_reparse(smb_node_t *node)
1346 {
1347 	SMB_NODE_VALID(node);
1348 	return ((node->vp->v_type == VLNK) &&
1349 	    (node->flags & NODE_FLAGS_REPARSE));
1350 }
1351 
1352 boolean_t
1353 smb_node_is_vfsroot(smb_node_t *node)
1354 {
1355 	SMB_NODE_VALID(node);
1356 	return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT);
1357 }
1358 
1359 boolean_t
1360 smb_node_is_system(smb_node_t *node)
1361 {
1362 	SMB_NODE_VALID(node);
1363 	return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM);
1364 }
1365 
1366 /*
1367  * smb_node_file_is_readonly
1368  *
1369  * Checks if the file (which node represents) is marked readonly
1370  * in the filesystem. No account is taken of any pending readonly
1371  * in the node, which must be handled by the callers.
1372  * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY)
1373  */
1374 boolean_t
1375 smb_node_file_is_readonly(smb_node_t *node)
1376 {
1377 	smb_attr_t attr;
1378 
1379 	if (node == NULL)
1380 		return (B_FALSE);	/* pipes */
1381 
1382 	if (node->n_pending_dosattr & FILE_ATTRIBUTE_READONLY)
1383 		return (B_TRUE);
1384 
1385 	bzero(&attr, sizeof (smb_attr_t));
1386 	attr.sa_mask = SMB_AT_DOSATTR;
1387 	(void) smb_fsop_getattr(NULL, zone_kcred(), node, &attr);
1388 	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
1389 }
1390 
1391 /*
1392  * smb_node_setattr
1393  *
1394  * The sr may be NULL, for example when closing an ofile.
1395  * The ofile may be NULL, for example when a client request
1396  * specifies the file by pathname.
1397  *
1398  * Returns: errno
1399  *
1400  * Timestamps
1401  *
1402  * Windows and Unix have different models for timestamp updates.
1403  * [MS-FSA 2.1.5.14 Server Requests Setting of File Information]
1404  *
1405  * An open "handle" in Windows can control whether and when
1406  * any timestamp updates happen for that handle.  For example,
1407  * timestamps set via some handle are no longer updated by I/O
1408  * operations on that handle.  In Unix we don't really have any
1409  * way to avoid the timestamp updates that the file system does.
1410  * Therefore, we need to make some compromises, and simulate the
1411  * more important parts of the Windows file system semantics.
1412  *
1413  * For example, when an SMB client sets file times, set those
1414  * times in the file system (so the change will be visible to
1415  * other clients, at least until they change again) but we also
1416  * make those times "sticky" in our open handle, and reapply
1417  * those times when the handle is closed.  That reapply on close
1418  * simulates the Windows behavior where the timestamp updates
1419  * would be discontinued after they were set.  These "sticky"
1420  * attributes are returned in any query on the handle where
1421  * they are stored.
1422  *
1423  * Other than the above, the file system layer takes care of the
1424  * normal time stamp updates, such as updating the mtime after a
1425  * write, and ctime after an attribute change.
1426  *
1427  * Dos Attributes are stored persistently, but with a twist:
1428  * In Windows, when you set the "read-only" bit on some file,
1429  * existing writable handles to that file continue to have
1430  * write access.  (because access check happens at open)
1431  * If we were to set the read-only bit directly, we would
1432  * cause errors in subsequent writes on any of our open
1433  * (and writable) file handles.  So here too, we have to
1434  * simulate the Windows behavior.  We keep the read-only
1435  * bit "pending" in the smb_node (so it will be visible in
1436  * any new opens of the file) and apply it on close.
1437  *
1438  * File allocation size is also simulated, and not persistent.
1439  * When the file allocation size is set it is first rounded up
1440  * to block size. If the file size is smaller than the allocation
1441  * size the file is truncated by setting the filesize to allocsz.
1442  */
1443 int
1444 smb_node_setattr(smb_request_t *sr, smb_node_t *node,
1445     cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
1446 {
1447 	int rc;
1448 	uint_t times_mask;
1449 	smb_attr_t tmp_attr;
1450 
1451 	SMB_NODE_VALID(node);
1452 
1453 	/* set attributes specified in attr */
1454 	if (attr->sa_mask == 0)
1455 		return (0);  /* nothing to do (caller bug?) */
1456 
1457 	/*
1458 	 * Allocation size and EOF position interact.
1459 	 * We don't persistently store the allocation size
1460 	 * but make it look like we do while there are opens.
1461 	 * Note: We update the caller's attr in the cases
1462 	 * where they're setting only one of allocsz|size.
1463 	 */
1464 	switch (attr->sa_mask & (SMB_AT_ALLOCSZ | SMB_AT_SIZE)) {
1465 
1466 	case SMB_AT_ALLOCSZ:
1467 		/*
1468 		 * Setting the allocation size but not EOF position.
1469 		 * Get the current EOF in tmp_attr and (if necessary)
1470 		 * truncate to the (rounded up) allocation size.
1471 		 * Using kcred here because if we don't have access,
1472 		 * we want to fail at setattr below and not here.
1473 		 */
1474 		bzero(&tmp_attr, sizeof (smb_attr_t));
1475 		tmp_attr.sa_mask = SMB_AT_SIZE;
1476 		rc = smb_fsop_getattr(NULL, zone_kcred(), node, &tmp_attr);
1477 		if (rc != 0)
1478 			return (rc);
1479 		attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
1480 		if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) {
1481 			/* truncate the file to allocsz */
1482 			attr->sa_vattr.va_size = attr->sa_allocsz;
1483 			attr->sa_mask |= SMB_AT_SIZE;
1484 		}
1485 		break;
1486 
1487 	case SMB_AT_SIZE:
1488 		/*
1489 		 * Setting the EOF position but not allocation size.
1490 		 * If the new EOF position would be greater than
1491 		 * the allocation size, increase the latter.
1492 		 */
1493 		if (node->n_allocsz < attr->sa_vattr.va_size) {
1494 			attr->sa_mask |= SMB_AT_ALLOCSZ;
1495 			attr->sa_allocsz =
1496 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1497 		}
1498 		break;
1499 
1500 	case SMB_AT_ALLOCSZ | SMB_AT_SIZE:
1501 		/*
1502 		 * Setting both.  Increase alloc size if needed.
1503 		 */
1504 		if (attr->sa_allocsz < attr->sa_vattr.va_size)
1505 			attr->sa_allocsz =
1506 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1507 		break;
1508 
1509 	default:
1510 		break;
1511 	}
1512 
1513 	/*
1514 	 * If we have an open file, and we set the size,
1515 	 * then set the "written" flag so that at close,
1516 	 * we can force an mtime update.
1517 	 */
1518 	if (of != NULL && (attr->sa_mask & SMB_AT_SIZE) != 0)
1519 		of->f_written = B_TRUE;
1520 
1521 	/*
1522 	 * When operating on an open file, some settable attributes
1523 	 * become "sticky" in the open file object until close.
1524 	 * (see above re. timestamps)
1525 	 */
1526 	times_mask = attr->sa_mask & SMB_AT_TIMES;
1527 	if (of != NULL && times_mask != 0) {
1528 		smb_attr_t *pa;
1529 
1530 		SMB_OFILE_VALID(of);
1531 		mutex_enter(&of->f_mutex);
1532 		pa = &of->f_pending_attr;
1533 
1534 		pa->sa_mask |= times_mask;
1535 
1536 		if (times_mask & SMB_AT_ATIME)
1537 			pa->sa_vattr.va_atime =
1538 			    attr->sa_vattr.va_atime;
1539 		if (times_mask & SMB_AT_MTIME)
1540 			pa->sa_vattr.va_mtime =
1541 			    attr->sa_vattr.va_mtime;
1542 		if (times_mask & SMB_AT_CTIME)
1543 			pa->sa_vattr.va_ctime =
1544 			    attr->sa_vattr.va_ctime;
1545 		if (times_mask & SMB_AT_CRTIME)
1546 			pa->sa_crtime =
1547 			    attr->sa_crtime;
1548 
1549 		mutex_exit(&of->f_mutex);
1550 		/*
1551 		 * The f_pending_attr times are reapplied in
1552 		 * smb_ofile_close().
1553 		 */
1554 	}
1555 
1556 	/*
1557 	 * After this point, tmp_attr is what we will actually
1558 	 * store in the file system _now_, which may differ
1559 	 * from the callers attr and f_pending_attr w.r.t.
1560 	 * the DOS readonly flag etc.
1561 	 */
1562 	bcopy(attr, &tmp_attr, sizeof (tmp_attr));
1563 	if (attr->sa_mask & (SMB_AT_DOSATTR | SMB_AT_ALLOCSZ)) {
1564 		mutex_enter(&node->n_mutex);
1565 		if ((attr->sa_mask & SMB_AT_DOSATTR) != 0) {
1566 			tmp_attr.sa_dosattr &= smb_vop_dosattr_settable;
1567 			if (((tmp_attr.sa_dosattr &
1568 			    FILE_ATTRIBUTE_READONLY) != 0) &&
1569 			    (node->n_open_count != 0)) {
1570 				/* Delay setting readonly */
1571 				node->n_pending_dosattr =
1572 				    tmp_attr.sa_dosattr;
1573 				tmp_attr.sa_dosattr &=
1574 				    ~FILE_ATTRIBUTE_READONLY;
1575 			} else {
1576 				node->n_pending_dosattr = 0;
1577 			}
1578 		}
1579 		/*
1580 		 * Simulate n_allocsz persistence only while
1581 		 * there are opens.  See smb_node_getattr
1582 		 */
1583 		if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0 &&
1584 		    node->n_open_count != 0)
1585 			node->n_allocsz = attr->sa_allocsz;
1586 		mutex_exit(&node->n_mutex);
1587 	}
1588 
1589 	rc = smb_fsop_setattr(sr, cr, node, &tmp_attr);
1590 	if (rc != 0)
1591 		return (rc);
1592 
1593 	if (node->n_dnode != NULL) {
1594 		smb_node_notify_change(node->n_dnode,
1595 		    FILE_ACTION_MODIFIED, node->od_name);
1596 	}
1597 
1598 	return (0);
1599 }
1600 
1601 /*
1602  * smb_node_getattr
1603  *
1604  * Get attributes from the file system and apply any smb-specific
1605  * overrides for size, dos attributes and timestamps
1606  *
1607  * When node->n_pending_readonly is set on a node, pretend that
1608  * we've already set this node readonly at the filesystem level.
1609  * We can't actually do that until all writable handles are closed
1610  * or those writable handles would suddenly loose their access.
1611  *
1612  * Returns: errno
1613  */
1614 int
1615 smb_node_getattr(smb_request_t *sr, smb_node_t *node, cred_t *cr,
1616     smb_ofile_t *of, smb_attr_t *attr)
1617 {
1618 	int rc;
1619 	uint_t want_mask, pend_mask;
1620 	boolean_t isdir;
1621 
1622 	SMB_NODE_VALID(node);
1623 
1624 	/* Deal with some interdependencies */
1625 	if (attr->sa_mask & SMB_AT_ALLOCSZ)
1626 		attr->sa_mask |= SMB_AT_SIZE;
1627 	if (attr->sa_mask & SMB_AT_DOSATTR)
1628 		attr->sa_mask |= SMB_AT_TYPE;
1629 
1630 	rc = smb_fsop_getattr(sr, cr, node, attr);
1631 	if (rc != 0)
1632 		return (rc);
1633 
1634 	isdir = smb_node_is_dir(node);
1635 
1636 	mutex_enter(&node->n_mutex);
1637 
1638 	/*
1639 	 * When there are open handles, and one of them has
1640 	 * set the DOS readonly flag (in n_pending_dosattr),
1641 	 * it will not have been stored in the file system.
1642 	 * In this case use n_pending_dosattr. Note that
1643 	 * n_pending_dosattr has only the settable bits,
1644 	 * (setattr masks it with smb_vop_dosattr_settable)
1645 	 * so we need to keep any non-settable bits we got
1646 	 * from the file-system above.
1647 	 */
1648 	if (attr->sa_mask & SMB_AT_DOSATTR) {
1649 		if (node->n_pending_dosattr) {
1650 			attr->sa_dosattr &= ~smb_vop_dosattr_settable;
1651 			attr->sa_dosattr |= node->n_pending_dosattr;
1652 		}
1653 		if (attr->sa_dosattr == 0) {
1654 			attr->sa_dosattr = (isdir) ?
1655 			    FILE_ATTRIBUTE_DIRECTORY:
1656 			    FILE_ATTRIBUTE_NORMAL;
1657 		}
1658 	}
1659 
1660 	/*
1661 	 * Also fix-up sa_allocsz, which is not persistent.
1662 	 * When there are no open files, allocsz is faked.
1663 	 * While there are open files, we pretend we have a
1664 	 * persistent allocation size in n_allocsz, and
1665 	 * keep that up-to-date here, increasing it when
1666 	 * we see the file size grow past it.
1667 	 */
1668 	if (attr->sa_mask & SMB_AT_ALLOCSZ) {
1669 		if (isdir) {
1670 			attr->sa_allocsz = 0;
1671 		} else if (node->n_open_count == 0) {
1672 			attr->sa_allocsz =
1673 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1674 		} else {
1675 			if (node->n_allocsz < attr->sa_vattr.va_size)
1676 				node->n_allocsz =
1677 				    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1678 			attr->sa_allocsz = node->n_allocsz;
1679 		}
1680 	}
1681 
1682 	mutex_exit(&node->n_mutex);
1683 
1684 	if (isdir) {
1685 		attr->sa_vattr.va_size = 0;
1686 		attr->sa_vattr.va_nlink = 1;
1687 	}
1688 
1689 	/*
1690 	 * getattr with an ofile gets any "pending" times that
1691 	 * might have been previously set via this ofile.
1692 	 * This is what makes these times "sticky".
1693 	 */
1694 	want_mask = attr->sa_mask & SMB_AT_TIMES;
1695 	if (of != NULL && want_mask != 0) {
1696 		smb_attr_t *pa;
1697 
1698 		SMB_OFILE_VALID(of);
1699 		mutex_enter(&of->f_mutex);
1700 		pa = &of->f_pending_attr;
1701 
1702 		pend_mask = pa->sa_mask;
1703 
1704 		if (want_mask & pend_mask & SMB_AT_ATIME)
1705 			attr->sa_vattr.va_atime =
1706 			    pa->sa_vattr.va_atime;
1707 		if (want_mask & pend_mask & SMB_AT_MTIME)
1708 			attr->sa_vattr.va_mtime =
1709 			    pa->sa_vattr.va_mtime;
1710 		if (want_mask & pend_mask & SMB_AT_CTIME)
1711 			attr->sa_vattr.va_ctime =
1712 			    pa->sa_vattr.va_ctime;
1713 		if (want_mask & pend_mask & SMB_AT_CRTIME)
1714 			attr->sa_crtime =
1715 			    pa->sa_crtime;
1716 
1717 		mutex_exit(&of->f_mutex);
1718 	}
1719 
1720 
1721 	return (0);
1722 }
1723 
1724 
1725 /*
1726  * Check to see if the node represents a reparse point.
1727  * If yes, whether the reparse point contains a DFS link.
1728  */
1729 static void
1730 smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr)
1731 {
1732 	nvlist_t *nvl;
1733 	nvpair_t *rec;
1734 	char *rec_type;
1735 
1736 	if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
1737 		return;
1738 
1739 	if ((nvl = reparse_init()) == NULL)
1740 		return;
1741 
1742 	if (reparse_vnode_parse(node->vp, nvl) != 0) {
1743 		reparse_free(nvl);
1744 		return;
1745 	}
1746 
1747 	node->flags |= NODE_FLAGS_REPARSE;
1748 
1749 	rec = nvlist_next_nvpair(nvl, NULL);
1750 	while (rec != NULL) {
1751 		rec_type = nvpair_name(rec);
1752 		if ((rec_type != NULL) &&
1753 		    (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) {
1754 			node->flags |= NODE_FLAGS_DFSLINK;
1755 			break;
1756 		}
1757 		rec = nvlist_next_nvpair(nvl, rec);
1758 	}
1759 
1760 	reparse_free(nvl);
1761 }
1762 
1763 /*
1764  * smb_node_init_system
1765  *
1766  * If the node represents a special system file set NODE_FLAG_SYSTEM.
1767  * System files:
1768  * - any node whose parent dnode has NODE_FLAG_SYSTEM set
1769  * - any node whose associated unnamed stream node (unode) has
1770  *   NODE_FLAG_SYSTEM set
1771  * - .$EXTEND at root of share (quota management)
1772  */
1773 static void
1774 smb_node_init_system(smb_node_t *node)
1775 {
1776 	smb_node_t *dnode = node->n_dnode;
1777 	smb_node_t *unode = node->n_unode;
1778 
1779 	if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) {
1780 		node->flags |= NODE_FLAGS_SYSTEM;
1781 		return;
1782 	}
1783 
1784 	if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) {
1785 		node->flags |= NODE_FLAGS_SYSTEM;
1786 		return;
1787 	}
1788 
1789 	if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) &&
1790 	    (strcasecmp(node->od_name, ".$EXTEND") == 0))) {
1791 		node->flags |= NODE_FLAGS_SYSTEM;
1792 	}
1793 }
1794