xref: /titanic_44/usr/src/uts/common/fs/smbsrv/smb_node.c (revision 5fd03bc0f2e00e7ba02316c2e08f45d52aab15db)
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 
700 	/*
701 	 * system-wide share check
702 	 */
703 	if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
704 		return (NT_STATUS_SHARING_VIOLATION);
705 	else
706 		return (NT_STATUS_SUCCESS);
707 }
708 
709 uint32_t
710 smb_node_delete_check(smb_node_t *node)
711 {
712 	smb_ofile_t	*of;
713 	uint32_t	status;
714 
715 	SMB_NODE_VALID(node);
716 
717 	if (smb_node_is_dir(node))
718 		return (NT_STATUS_SUCCESS);
719 
720 	if (smb_node_is_reparse(node))
721 		return (NT_STATUS_ACCESS_DENIED);
722 
723 	/*
724 	 * intra-CIFS check
725 	 */
726 	smb_llist_enter(&node->n_ofile_list, RW_READER);
727 	of = smb_llist_head(&node->n_ofile_list);
728 	while (of) {
729 		status = smb_ofile_delete_check(of);
730 
731 		switch (status) {
732 		case NT_STATUS_INVALID_HANDLE:
733 		case NT_STATUS_SUCCESS:
734 			of = smb_llist_next(&node->n_ofile_list, of);
735 			break;
736 		default:
737 			ASSERT(status == NT_STATUS_SHARING_VIOLATION);
738 			smb_llist_exit(&node->n_ofile_list);
739 			return (status);
740 		}
741 	}
742 	smb_llist_exit(&node->n_ofile_list);
743 
744 	/*
745 	 * system-wide share check
746 	 */
747 	if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
748 		return (NT_STATUS_SHARING_VIOLATION);
749 	else
750 		return (NT_STATUS_SUCCESS);
751 }
752 
753 /*
754  * smb_node_share_check
755  *
756  * Returns: TRUE    - ofiles have non-zero share access
757  *          B_FALSE - ofile with share access NONE.
758  */
759 boolean_t
760 smb_node_share_check(smb_node_t *node)
761 {
762 	smb_ofile_t	*of;
763 	boolean_t	status = B_TRUE;
764 
765 	SMB_NODE_VALID(node);
766 
767 	smb_llist_enter(&node->n_ofile_list, RW_READER);
768 	of = smb_llist_head(&node->n_ofile_list);
769 	if (of)
770 		status = smb_ofile_share_check(of);
771 	smb_llist_exit(&node->n_ofile_list);
772 
773 	return (status);
774 }
775 
776 /*
777  * SMB Change Notification
778  */
779 
780 void
781 smb_node_fcn_subscribe(smb_node_t *node, smb_request_t *sr)
782 {
783 	smb_node_fcn_t		*fcn = &node->n_fcn;
784 
785 	mutex_enter(&fcn->fcn_mutex);
786 	if (fcn->fcn_count == 0)
787 		smb_fem_fcn_install(node);
788 	fcn->fcn_count++;
789 	list_insert_tail(&fcn->fcn_watchers, sr);
790 	mutex_exit(&fcn->fcn_mutex);
791 }
792 
793 void
794 smb_node_fcn_unsubscribe(smb_node_t *node, smb_request_t *sr)
795 {
796 	smb_node_fcn_t		*fcn = &node->n_fcn;
797 
798 	mutex_enter(&fcn->fcn_mutex);
799 	list_remove(&fcn->fcn_watchers, sr);
800 	fcn->fcn_count--;
801 	if (fcn->fcn_count == 0)
802 		smb_fem_fcn_uninstall(node);
803 	mutex_exit(&fcn->fcn_mutex);
804 }
805 
806 void
807 smb_node_notify_change(smb_node_t *node, uint_t action, const char *name)
808 {
809 	SMB_NODE_VALID(node);
810 
811 	smb_notify_event(node, action, name);
812 
813 	/*
814 	 * These two events come as a pair:
815 	 *   FILE_ACTION_RENAMED_OLD_NAME
816 	 *   FILE_ACTION_RENAMED_NEW_NAME
817 	 * Only do the parent notify for "new".
818 	 */
819 	if (action == FILE_ACTION_RENAMED_OLD_NAME)
820 		return;
821 
822 	smb_node_notify_parents(node);
823 }
824 
825 /*
826  * smb_node_notify_parents
827  *
828  * Iterate up the directory tree notifying any parent
829  * directories that are being watched for changes in
830  * their sub directories.
831  * Stop at the root node, which has a NULL parent node.
832  */
833 void
834 smb_node_notify_parents(smb_node_t *dnode)
835 {
836 	smb_node_t *pnode;	/* parent */
837 
838 	SMB_NODE_VALID(dnode);
839 	pnode = dnode->n_dnode;
840 
841 	while (pnode != NULL) {
842 		SMB_NODE_VALID(pnode);
843 		smb_notify_event(pnode, 0, dnode->od_name);
844 		/* cd .. */
845 		dnode = pnode;
846 		pnode = dnode->n_dnode;
847 	}
848 }
849 
850 /*
851  * smb_node_start_crit()
852  *
853  * Enter critical region for share reservations.
854  * See comments above smb_fsop_shrlock().
855  */
856 void
857 smb_node_start_crit(smb_node_t *node, krw_t mode)
858 {
859 	rw_enter(&node->n_lock, mode);
860 	nbl_start_crit(node->vp, mode);
861 }
862 
863 /*
864  * smb_node_end_crit()
865  *
866  * Exit critical region for share reservations.
867  */
868 void
869 smb_node_end_crit(smb_node_t *node)
870 {
871 	nbl_end_crit(node->vp);
872 	rw_exit(&node->n_lock);
873 }
874 
875 int
876 smb_node_in_crit(smb_node_t *node)
877 {
878 	return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
879 }
880 
881 void
882 smb_node_rdlock(smb_node_t *node)
883 {
884 	rw_enter(&node->n_lock, RW_READER);
885 }
886 
887 void
888 smb_node_wrlock(smb_node_t *node)
889 {
890 	rw_enter(&node->n_lock, RW_WRITER);
891 }
892 
893 void
894 smb_node_unlock(smb_node_t *node)
895 {
896 	rw_exit(&node->n_lock);
897 }
898 
899 void
900 smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
901 {
902 	SMB_NODE_VALID(node);
903 
904 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
905 	smb_llist_insert_tail(&node->n_ofile_list, of);
906 	smb_llist_exit(&node->n_ofile_list);
907 }
908 
909 void
910 smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
911 {
912 	SMB_NODE_VALID(node);
913 
914 	smb_llist_enter(&node->n_ofile_list, RW_WRITER);
915 	smb_llist_remove(&node->n_ofile_list, of);
916 	smb_llist_exit(&node->n_ofile_list);
917 }
918 
919 /*
920  * smb_node_inc_open_ofiles
921  */
922 void
923 smb_node_inc_open_ofiles(smb_node_t *node)
924 {
925 	SMB_NODE_VALID(node);
926 	atomic_inc_32(&node->n_open_count);
927 }
928 
929 /*
930  * smb_node_dec_open_ofiles
931  * returns new value
932  */
933 uint32_t
934 smb_node_dec_open_ofiles(smb_node_t *node)
935 {
936 	SMB_NODE_VALID(node);
937 	return (atomic_dec_32_nv(&node->n_open_count));
938 }
939 
940 /*
941  * smb_node_inc_opening_count
942  */
943 void
944 smb_node_inc_opening_count(smb_node_t *node)
945 {
946 	SMB_NODE_VALID(node);
947 	atomic_inc_32(&node->n_opening_count);
948 }
949 
950 /*
951  * smb_node_dec_opening_count
952  */
953 void
954 smb_node_dec_opening_count(smb_node_t *node)
955 {
956 	SMB_NODE_VALID(node);
957 	atomic_dec_32(&node->n_opening_count);
958 }
959 
960 /*
961  * smb_node_getmntpath
962  */
963 int
964 smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen)
965 {
966 	vnode_t *vp, *root_vp;
967 	vfs_t *vfsp;
968 	int err;
969 
970 	ASSERT(node);
971 	ASSERT(node->vp);
972 	ASSERT(node->vp->v_vfsp);
973 
974 	vp = node->vp;
975 	vfsp = vp->v_vfsp;
976 
977 	if (VFS_ROOT(vfsp, &root_vp))
978 		return (ENOENT);
979 
980 	VN_HOLD(vp);
981 
982 	/* NULL is passed in as we want to start at "/" */
983 	err = vnodetopath(NULL, root_vp, buf, buflen, kcred);
984 
985 	VN_RELE(vp);
986 	VN_RELE(root_vp);
987 	return (err);
988 }
989 
990 /*
991  * smb_node_getshrpath
992  *
993  * Determine the absolute pathname of 'node' within the share (tree).
994  * For example if the node represents file "test1.txt" in directory
995  * "dir1" the pathname would be: \dir1\test1.txt
996  */
997 int
998 smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree,
999     char *buf, uint32_t buflen)
1000 {
1001 	int rc;
1002 
1003 	ASSERT(node);
1004 	ASSERT(tree);
1005 	ASSERT(tree->t_snode);
1006 
1007 	rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen);
1008 	(void) strsubst(buf, '/', '\\');
1009 	return (rc);
1010 }
1011 
1012 /*
1013  * smb_node_getpath
1014  *
1015  * Determine the absolute pathname of 'node' from 'rootvp'.
1016  *
1017  * Using vnodetopath is only reliable for directory nodes (due to
1018  * its reliance on the DNLC for non-directory nodes). Thus, if node
1019  * represents a file, construct the pathname for the parent dnode
1020  * and append filename.
1021  * If node represents a named stream, construct the pathname for the
1022  * associated unnamed stream and append the stream name.
1023  *
1024  * The pathname returned in buf will be '/' separated.
1025  */
1026 int
1027 smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen)
1028 {
1029 	int rc;
1030 	vnode_t *vp;
1031 	smb_node_t *unode, *dnode;
1032 
1033 	unode = (SMB_IS_STREAM(node)) ? node->n_unode : node;
1034 	dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode;
1035 
1036 	/* find path to directory node */
1037 	vp = dnode->vp;
1038 	VN_HOLD(vp);
1039 	if (rootvp) {
1040 		VN_HOLD(rootvp);
1041 		rc = vnodetopath(rootvp, vp, buf, buflen, kcred);
1042 		VN_RELE(rootvp);
1043 	} else {
1044 		rc = vnodetopath(NULL, vp, buf, buflen, kcred);
1045 	}
1046 	VN_RELE(vp);
1047 
1048 	if (rc != 0)
1049 		return (rc);
1050 
1051 	/* append filename if necessary */
1052 	if (!smb_node_is_dir(unode)) {
1053 		if (buf[strlen(buf) - 1] != '/')
1054 			(void) strlcat(buf, "/", buflen);
1055 		(void) strlcat(buf, unode->od_name, buflen);
1056 	}
1057 
1058 	/* append named stream name if necessary */
1059 	if (SMB_IS_STREAM(node))
1060 		(void) strlcat(buf, node->od_name, buflen);
1061 
1062 	return (rc);
1063 }
1064 
1065 /*
1066  * smb_node_alloc
1067  */
1068 static smb_node_t *
1069 smb_node_alloc(
1070     char	*od_name,
1071     vnode_t	*vp,
1072     smb_llist_t	*bucket,
1073     uint32_t	hashkey)
1074 {
1075 	smb_node_t	*node;
1076 	vnode_t		*root_vp;
1077 
1078 	node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
1079 
1080 	if (node->n_audit_buf != NULL)
1081 		node->n_audit_buf->anb_index = 0;
1082 
1083 	node->flags = 0;
1084 	VN_HOLD(vp);
1085 	node->vp = vp;
1086 	node->n_refcnt = 1;
1087 	node->n_hash_bucket = bucket;
1088 	node->n_hashkey = hashkey;
1089 	node->n_pending_dosattr = 0;
1090 	node->n_open_count = 0;
1091 	node->n_allocsz = 0;
1092 	node->n_dnode = NULL;
1093 	node->n_unode = NULL;
1094 	node->delete_on_close_cred = NULL;
1095 	node->n_delete_on_close_flags = 0;
1096 	node->n_oplock.ol_fem = B_FALSE;
1097 	node->n_oplock.ol_xthread = NULL;
1098 	node->n_oplock.ol_count = 0;
1099 	node->n_oplock.ol_break = SMB_OPLOCK_NO_BREAK;
1100 
1101 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
1102 	if (strcmp(od_name, XATTR_DIR) == 0)
1103 		node->flags |= NODE_XATTR_DIR;
1104 
1105 	if (VFS_ROOT(vp->v_vfsp, &root_vp) == 0) {
1106 		if (vp == root_vp)
1107 			node->flags |= NODE_FLAGS_VFSROOT;
1108 		VN_RELE(root_vp);
1109 	}
1110 
1111 	node->n_state = SMB_NODE_STATE_AVAILABLE;
1112 	node->n_magic = SMB_NODE_MAGIC;
1113 
1114 	return (node);
1115 }
1116 
1117 /*
1118  * smb_node_free
1119  */
1120 static void
1121 smb_node_free(smb_node_t *node)
1122 {
1123 	SMB_NODE_VALID(node);
1124 
1125 	node->n_magic = 0;
1126 	VERIFY(!list_link_active(&node->n_lnd));
1127 	VERIFY(node->n_lock_list.ll_count == 0);
1128 	VERIFY(node->n_ofile_list.ll_count == 0);
1129 	VERIFY(node->n_oplock.ol_count == 0);
1130 	VERIFY(node->n_oplock.ol_xthread == NULL);
1131 	VERIFY(node->n_oplock.ol_fem == B_FALSE);
1132 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
1133 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
1134 	VN_RELE(node->vp);
1135 	kmem_cache_free(smb_node_cache, node);
1136 }
1137 
1138 /*
1139  * smb_node_constructor
1140  */
1141 static int
1142 smb_node_constructor(void *buf, void *un, int kmflags)
1143 {
1144 	_NOTE(ARGUNUSED(kmflags, un))
1145 
1146 	smb_node_t	*node = (smb_node_t *)buf;
1147 
1148 	bzero(node, sizeof (smb_node_t));
1149 
1150 	smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
1151 	    offsetof(smb_ofile_t, f_nnd));
1152 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
1153 	    offsetof(smb_lock_t, l_lnd));
1154 	mutex_init(&node->n_fcn.fcn_mutex, NULL, MUTEX_DEFAULT, NULL);
1155 	list_create(&node->n_fcn.fcn_watchers, sizeof (smb_request_t),
1156 	    offsetof(smb_request_t, sr_ncr.nc_lnd));
1157 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
1158 	mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL);
1159 	list_create(&node->n_oplock.ol_grants, sizeof (smb_oplock_grant_t),
1160 	    offsetof(smb_oplock_grant_t, og_lnd));
1161 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
1162 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
1163 	smb_node_create_audit_buf(node, kmflags);
1164 	return (0);
1165 }
1166 
1167 /*
1168  * smb_node_destructor
1169  */
1170 static void
1171 smb_node_destructor(void *buf, void *un)
1172 {
1173 	_NOTE(ARGUNUSED(un))
1174 
1175 	smb_node_t	*node = (smb_node_t *)buf;
1176 
1177 	smb_node_destroy_audit_buf(node);
1178 	mutex_destroy(&node->n_mutex);
1179 	rw_destroy(&node->n_lock);
1180 	cv_destroy(&node->n_oplock.ol_cv);
1181 	mutex_destroy(&node->n_oplock.ol_mutex);
1182 	list_destroy(&node->n_fcn.fcn_watchers);
1183 	mutex_destroy(&node->n_fcn.fcn_mutex);
1184 	smb_llist_destructor(&node->n_lock_list);
1185 	smb_llist_destructor(&node->n_ofile_list);
1186 	list_destroy(&node->n_oplock.ol_grants);
1187 }
1188 
1189 /*
1190  * smb_node_create_audit_buf
1191  */
1192 static void
1193 smb_node_create_audit_buf(smb_node_t *node, int kmflags)
1194 {
1195 	smb_audit_buf_node_t	*abn;
1196 
1197 	if (smb_audit_flags & SMB_AUDIT_NODE) {
1198 		abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
1199 		abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
1200 		node->n_audit_buf = abn;
1201 	}
1202 }
1203 
1204 /*
1205  * smb_node_destroy_audit_buf
1206  */
1207 static void
1208 smb_node_destroy_audit_buf(smb_node_t *node)
1209 {
1210 	if (node->n_audit_buf != NULL) {
1211 		kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
1212 		node->n_audit_buf = NULL;
1213 	}
1214 }
1215 
1216 /*
1217  * smb_node_audit
1218  *
1219  * This function saves the calling stack in the audit buffer of the node passed
1220  * in.
1221  */
1222 static void
1223 smb_node_audit(smb_node_t *node)
1224 {
1225 	smb_audit_buf_node_t	*abn;
1226 	smb_audit_record_node_t	*anr;
1227 
1228 	if (node->n_audit_buf) {
1229 		abn = node->n_audit_buf;
1230 		anr = abn->anb_records;
1231 		anr += abn->anb_index;
1232 		abn->anb_index++;
1233 		abn->anb_index &= abn->anb_max_index;
1234 		anr->anr_refcnt = node->n_refcnt;
1235 		anr->anr_depth = getpcstack(anr->anr_stack,
1236 		    SMB_AUDIT_STACK_DEPTH);
1237 	}
1238 }
1239 
1240 static smb_llist_t *
1241 smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
1242 {
1243 	uint32_t	hashkey;
1244 
1245 	hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
1246 	hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
1247 	*phashkey = hashkey;
1248 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
1249 }
1250 
1251 boolean_t
1252 smb_node_is_file(smb_node_t *node)
1253 {
1254 	SMB_NODE_VALID(node);
1255 	return (node->vp->v_type == VREG);
1256 }
1257 
1258 boolean_t
1259 smb_node_is_dir(smb_node_t *node)
1260 {
1261 	SMB_NODE_VALID(node);
1262 	return ((node->vp->v_type == VDIR) ||
1263 	    (node->flags & NODE_FLAGS_DFSLINK));
1264 }
1265 
1266 boolean_t
1267 smb_node_is_symlink(smb_node_t *node)
1268 {
1269 	SMB_NODE_VALID(node);
1270 	return ((node->vp->v_type == VLNK) &&
1271 	    ((node->flags & NODE_FLAGS_REPARSE) == 0));
1272 }
1273 
1274 boolean_t
1275 smb_node_is_dfslink(smb_node_t *node)
1276 {
1277 	SMB_NODE_VALID(node);
1278 	return ((node->vp->v_type == VLNK) &&
1279 	    (node->flags & NODE_FLAGS_DFSLINK));
1280 }
1281 
1282 boolean_t
1283 smb_node_is_reparse(smb_node_t *node)
1284 {
1285 	SMB_NODE_VALID(node);
1286 	return ((node->vp->v_type == VLNK) &&
1287 	    (node->flags & NODE_FLAGS_REPARSE));
1288 }
1289 
1290 boolean_t
1291 smb_node_is_vfsroot(smb_node_t *node)
1292 {
1293 	SMB_NODE_VALID(node);
1294 	return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT);
1295 }
1296 
1297 boolean_t
1298 smb_node_is_system(smb_node_t *node)
1299 {
1300 	SMB_NODE_VALID(node);
1301 	return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM);
1302 }
1303 
1304 /*
1305  * smb_node_file_is_readonly
1306  *
1307  * Checks if the file (which node represents) is marked readonly
1308  * in the filesystem. No account is taken of any pending readonly
1309  * in the node, which must be handled by the callers.
1310  * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY)
1311  */
1312 boolean_t
1313 smb_node_file_is_readonly(smb_node_t *node)
1314 {
1315 	smb_attr_t attr;
1316 
1317 	if (node == NULL)
1318 		return (B_FALSE);	/* pipes */
1319 
1320 	if (node->n_pending_dosattr & FILE_ATTRIBUTE_READONLY)
1321 		return (B_TRUE);
1322 
1323 	bzero(&attr, sizeof (smb_attr_t));
1324 	attr.sa_mask = SMB_AT_DOSATTR;
1325 	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
1326 	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
1327 }
1328 
1329 /*
1330  * smb_node_setattr
1331  *
1332  * The sr may be NULL, for example when closing an ofile.
1333  * The ofile may be NULL, for example when a client request
1334  * specifies the file by pathname.
1335  *
1336  * Returns: errno
1337  *
1338  * Timestamps
1339  *
1340  * Windows and Unix have different models for timestamp updates.
1341  * [MS-FSA 2.1.5.14 Server Requests Setting of File Information]
1342  *
1343  * An open "handle" in Windows can control whether and when
1344  * any timestamp updates happen for that handle.  For example,
1345  * timestamps set via some handle are no longer updated by I/O
1346  * operations on that handle.  In Unix we don't really have any
1347  * way to avoid the timestamp updates that the file system does.
1348  * Therefore, we need to make some compromises, and simulate the
1349  * more important parts of the Windows file system semantics.
1350  *
1351  * For example, when an SMB client sets file times, set those
1352  * times in the file system (so the change will be visible to
1353  * other clients, at least until they change again) but we also
1354  * make those times "sticky" in our open handle, and reapply
1355  * those times when the handle is closed.  That reapply on close
1356  * simulates the Windows behavior where the timestamp updates
1357  * would be discontinued after they were set.  These "sticky"
1358  * attributes are returned in any query on the handle where
1359  * they are stored.
1360  *
1361  * Other than the above, the file system layer takes care of the
1362  * normal time stamp updates, such as updating the mtime after a
1363  * write, and ctime after an attribute change.
1364  *
1365  * Dos Attributes are stored persistently, but with a twist:
1366  * In Windows, when you set the "read-only" bit on some file,
1367  * existing writable handles to that file continue to have
1368  * write access.  (because access check happens at open)
1369  * If we were to set the read-only bit directly, we would
1370  * cause errors in subsequent writes on any of our open
1371  * (and writable) file handles.  So here too, we have to
1372  * simulate the Windows behavior.  We keep the read-only
1373  * bit "pending" in the smb_node (so it will be visible in
1374  * any new opens of the file) and apply it on close.
1375  *
1376  * File allocation size is also simulated, and not persistent.
1377  * When the file allocation size is set it is first rounded up
1378  * to block size. If the file size is smaller than the allocation
1379  * size the file is truncated by setting the filesize to allocsz.
1380  */
1381 int
1382 smb_node_setattr(smb_request_t *sr, smb_node_t *node,
1383     cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
1384 {
1385 	int rc;
1386 	uint_t times_mask;
1387 	smb_attr_t tmp_attr;
1388 
1389 	SMB_NODE_VALID(node);
1390 
1391 	/* set attributes specified in attr */
1392 	if (attr->sa_mask == 0)
1393 		return (0);  /* nothing to do (caller bug?) */
1394 
1395 	/*
1396 	 * Allocation size and EOF position interact.
1397 	 * We don't persistently store the allocation size
1398 	 * but make it look like we do while there are opens.
1399 	 * Note: We update the caller's attr in the cases
1400 	 * where they're setting only one of allocsz|size.
1401 	 */
1402 	switch (attr->sa_mask & (SMB_AT_ALLOCSZ | SMB_AT_SIZE)) {
1403 
1404 	case SMB_AT_ALLOCSZ:
1405 		/*
1406 		 * Setting the allocation size but not EOF position.
1407 		 * Get the current EOF in tmp_attr and (if necessary)
1408 		 * truncate to the (rounded up) allocation size.
1409 		 */
1410 		bzero(&tmp_attr, sizeof (smb_attr_t));
1411 		tmp_attr.sa_mask = SMB_AT_SIZE;
1412 		rc = smb_fsop_getattr(NULL, kcred, node, &tmp_attr);
1413 		if (rc != 0)
1414 			return (rc);
1415 		attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
1416 		if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) {
1417 			/* truncate the file to allocsz */
1418 			attr->sa_vattr.va_size = attr->sa_allocsz;
1419 			attr->sa_mask |= SMB_AT_SIZE;
1420 		}
1421 		break;
1422 
1423 	case SMB_AT_SIZE:
1424 		/*
1425 		 * Setting the EOF position but not allocation size.
1426 		 * If the new EOF position would be greater than
1427 		 * the allocation size, increase the latter.
1428 		 */
1429 		if (node->n_allocsz < attr->sa_vattr.va_size) {
1430 			attr->sa_mask |= SMB_AT_ALLOCSZ;
1431 			attr->sa_allocsz =
1432 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1433 		}
1434 		break;
1435 
1436 	case SMB_AT_ALLOCSZ | SMB_AT_SIZE:
1437 		/*
1438 		 * Setting both.  Increase alloc size if needed.
1439 		 */
1440 		if (attr->sa_allocsz < attr->sa_vattr.va_size)
1441 			attr->sa_allocsz =
1442 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1443 		break;
1444 
1445 	default:
1446 		break;
1447 	}
1448 
1449 	/*
1450 	 * If we have an open file, and we set the size,
1451 	 * then set the "written" flag so that at close,
1452 	 * we can force an mtime update.
1453 	 */
1454 	if (of != NULL && (attr->sa_mask & SMB_AT_SIZE) != 0)
1455 		of->f_written = B_TRUE;
1456 
1457 	/*
1458 	 * When operating on an open file, some settable attributes
1459 	 * become "sticky" in the open file object until close.
1460 	 * (see above re. timestamps)
1461 	 */
1462 	times_mask = attr->sa_mask & SMB_AT_TIMES;
1463 	if (of != NULL && times_mask != 0) {
1464 		smb_attr_t *pa;
1465 
1466 		SMB_OFILE_VALID(of);
1467 		mutex_enter(&of->f_mutex);
1468 		pa = &of->f_pending_attr;
1469 
1470 		pa->sa_mask |= times_mask;
1471 
1472 		if (times_mask & SMB_AT_ATIME)
1473 			pa->sa_vattr.va_atime =
1474 			    attr->sa_vattr.va_atime;
1475 		if (times_mask & SMB_AT_MTIME)
1476 			pa->sa_vattr.va_mtime =
1477 			    attr->sa_vattr.va_mtime;
1478 		if (times_mask & SMB_AT_CTIME)
1479 			pa->sa_vattr.va_ctime =
1480 			    attr->sa_vattr.va_ctime;
1481 		if (times_mask & SMB_AT_CRTIME)
1482 			pa->sa_crtime =
1483 			    attr->sa_crtime;
1484 
1485 		mutex_exit(&of->f_mutex);
1486 		/*
1487 		 * The f_pending_attr times are reapplied in
1488 		 * smb_ofile_close().
1489 		 */
1490 	}
1491 
1492 	/*
1493 	 * After this point, tmp_attr is what we will actually
1494 	 * store in the file system _now_, which may differ
1495 	 * from the callers attr and f_pending_attr w.r.t.
1496 	 * the DOS readonly flag etc.
1497 	 */
1498 	bcopy(attr, &tmp_attr, sizeof (tmp_attr));
1499 	if (attr->sa_mask & (SMB_AT_DOSATTR | SMB_AT_ALLOCSZ)) {
1500 		mutex_enter(&node->n_mutex);
1501 		if ((attr->sa_mask & SMB_AT_DOSATTR) != 0) {
1502 			tmp_attr.sa_dosattr &= smb_vop_dosattr_settable;
1503 			if (((tmp_attr.sa_dosattr &
1504 			    FILE_ATTRIBUTE_READONLY) != 0) &&
1505 			    (node->n_open_count != 0)) {
1506 				/* Delay setting readonly */
1507 				node->n_pending_dosattr =
1508 				    tmp_attr.sa_dosattr;
1509 				tmp_attr.sa_dosattr &=
1510 				    ~FILE_ATTRIBUTE_READONLY;
1511 			} else {
1512 				node->n_pending_dosattr = 0;
1513 			}
1514 		}
1515 		/*
1516 		 * Simulate n_allocsz persistence only while
1517 		 * there are opens.  See smb_node_getattr
1518 		 */
1519 		if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0 &&
1520 		    node->n_open_count != 0)
1521 			node->n_allocsz = attr->sa_allocsz;
1522 		mutex_exit(&node->n_mutex);
1523 	}
1524 
1525 	rc = smb_fsop_setattr(sr, cr, node, &tmp_attr);
1526 	if (rc != 0)
1527 		return (rc);
1528 
1529 	if (node->n_dnode != NULL) {
1530 		smb_node_notify_change(node->n_dnode,
1531 		    FILE_ACTION_MODIFIED, node->od_name);
1532 	}
1533 
1534 	return (0);
1535 }
1536 
1537 /*
1538  * smb_node_getattr
1539  *
1540  * Get attributes from the file system and apply any smb-specific
1541  * overrides for size, dos attributes and timestamps
1542  *
1543  * When node->n_pending_readonly is set on a node, pretend that
1544  * we've already set this node readonly at the filesystem level.
1545  * We can't actually do that until all writable handles are closed
1546  * or those writable handles would suddenly loose their access.
1547  *
1548  * Returns: errno
1549  */
1550 int
1551 smb_node_getattr(smb_request_t *sr, smb_node_t *node, cred_t *cr,
1552     smb_ofile_t *of, smb_attr_t *attr)
1553 {
1554 	int rc;
1555 	uint_t want_mask, pend_mask;
1556 	boolean_t isdir;
1557 
1558 	SMB_NODE_VALID(node);
1559 
1560 	/* Deal with some interdependencies */
1561 	if (attr->sa_mask & SMB_AT_ALLOCSZ)
1562 		attr->sa_mask |= SMB_AT_SIZE;
1563 	if (attr->sa_mask & SMB_AT_DOSATTR)
1564 		attr->sa_mask |= SMB_AT_TYPE;
1565 
1566 	rc = smb_fsop_getattr(sr, cr, node, attr);
1567 	if (rc != 0)
1568 		return (rc);
1569 
1570 	isdir = smb_node_is_dir(node);
1571 
1572 	mutex_enter(&node->n_mutex);
1573 
1574 	/*
1575 	 * When there are open handles, and one of them has
1576 	 * set the DOS readonly flag (in n_pending_dosattr),
1577 	 * it will not have been stored in the file system.
1578 	 * In this case use n_pending_dosattr. Note that
1579 	 * n_pending_dosattr has only the settable bits,
1580 	 * (setattr masks it with smb_vop_dosattr_settable)
1581 	 * so we need to keep any non-settable bits we got
1582 	 * from the file-system above.
1583 	 */
1584 	if (attr->sa_mask & SMB_AT_DOSATTR) {
1585 		if (node->n_pending_dosattr) {
1586 			attr->sa_dosattr &= ~smb_vop_dosattr_settable;
1587 			attr->sa_dosattr |= node->n_pending_dosattr;
1588 		}
1589 		if (attr->sa_dosattr == 0) {
1590 			attr->sa_dosattr = (isdir) ?
1591 			    FILE_ATTRIBUTE_DIRECTORY:
1592 			    FILE_ATTRIBUTE_NORMAL;
1593 		}
1594 	}
1595 
1596 	/*
1597 	 * Also fix-up sa_allocsz, which is not persistent.
1598 	 * When there are no open files, allocsz is faked.
1599 	 * While there are open files, we pretend we have a
1600 	 * persistent allocation size in n_allocsz, and
1601 	 * keep that up-to-date here, increasing it when
1602 	 * we see the file size grow past it.
1603 	 */
1604 	if (attr->sa_mask & SMB_AT_ALLOCSZ) {
1605 		if (isdir) {
1606 			attr->sa_allocsz = 0;
1607 		} else if (node->n_open_count == 0) {
1608 			attr->sa_allocsz =
1609 			    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1610 		} else {
1611 			if (node->n_allocsz < attr->sa_vattr.va_size)
1612 				node->n_allocsz =
1613 				    SMB_ALLOCSZ(attr->sa_vattr.va_size);
1614 			attr->sa_allocsz = node->n_allocsz;
1615 		}
1616 	}
1617 
1618 	mutex_exit(&node->n_mutex);
1619 
1620 	if (isdir) {
1621 		attr->sa_vattr.va_size = 0;
1622 		attr->sa_vattr.va_nlink = 1;
1623 	}
1624 
1625 	/*
1626 	 * getattr with an ofile gets any "pending" times that
1627 	 * might have been previously set via this ofile.
1628 	 * This is what makes these times "sticky".
1629 	 */
1630 	want_mask = attr->sa_mask & SMB_AT_TIMES;
1631 	if (of != NULL && want_mask != 0) {
1632 		smb_attr_t *pa;
1633 
1634 		SMB_OFILE_VALID(of);
1635 		mutex_enter(&of->f_mutex);
1636 		pa = &of->f_pending_attr;
1637 
1638 		pend_mask = pa->sa_mask;
1639 
1640 		if (want_mask & pend_mask & SMB_AT_ATIME)
1641 			attr->sa_vattr.va_atime =
1642 			    pa->sa_vattr.va_atime;
1643 		if (want_mask & pend_mask & SMB_AT_MTIME)
1644 			attr->sa_vattr.va_mtime =
1645 			    pa->sa_vattr.va_mtime;
1646 		if (want_mask & pend_mask & SMB_AT_CTIME)
1647 			attr->sa_vattr.va_ctime =
1648 			    pa->sa_vattr.va_ctime;
1649 		if (want_mask & pend_mask & SMB_AT_CRTIME)
1650 			attr->sa_crtime =
1651 			    pa->sa_crtime;
1652 
1653 		mutex_exit(&of->f_mutex);
1654 	}
1655 
1656 
1657 	return (0);
1658 }
1659 
1660 
1661 /*
1662  * Check to see if the node represents a reparse point.
1663  * If yes, whether the reparse point contains a DFS link.
1664  */
1665 static void
1666 smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr)
1667 {
1668 	nvlist_t *nvl;
1669 	nvpair_t *rec;
1670 	char *rec_type;
1671 
1672 	if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
1673 		return;
1674 
1675 	if ((nvl = reparse_init()) == NULL)
1676 		return;
1677 
1678 	if (reparse_vnode_parse(node->vp, nvl) != 0) {
1679 		reparse_free(nvl);
1680 		return;
1681 	}
1682 
1683 	node->flags |= NODE_FLAGS_REPARSE;
1684 
1685 	rec = nvlist_next_nvpair(nvl, NULL);
1686 	while (rec != NULL) {
1687 		rec_type = nvpair_name(rec);
1688 		if ((rec_type != NULL) &&
1689 		    (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) {
1690 			node->flags |= NODE_FLAGS_DFSLINK;
1691 			break;
1692 		}
1693 		rec = nvlist_next_nvpair(nvl, rec);
1694 	}
1695 
1696 	reparse_free(nvl);
1697 }
1698 
1699 /*
1700  * smb_node_init_system
1701  *
1702  * If the node represents a special system file set NODE_FLAG_SYSTEM.
1703  * System files:
1704  * - any node whose parent dnode has NODE_FLAG_SYSTEM set
1705  * - any node whose associated unnamed stream node (unode) has
1706  *   NODE_FLAG_SYSTEM set
1707  * - .$EXTEND at root of share (quota management)
1708  */
1709 static void
1710 smb_node_init_system(smb_node_t *node)
1711 {
1712 	smb_node_t *dnode = node->n_dnode;
1713 	smb_node_t *unode = node->n_unode;
1714 
1715 	if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) {
1716 		node->flags |= NODE_FLAGS_SYSTEM;
1717 		return;
1718 	}
1719 
1720 	if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) {
1721 		node->flags |= NODE_FLAGS_SYSTEM;
1722 		return;
1723 	}
1724 
1725 	if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) &&
1726 	    (strcasecmp(node->od_name, ".$EXTEND") == 0))) {
1727 		node->flags |= NODE_FLAGS_SYSTEM;
1728 	}
1729 }
1730