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