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