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