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