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