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 #pragma ident "@(#)smb_node.c 1.9 08/08/07 SMI" 27 28 /* 29 * SMB Node State Machine 30 * ---------------------- 31 * 32 * +----------------------------+ T0 33 * | SMB_NODE_STATE_AVAILABLE |<----------- Creation/Allocation 34 * +----------------------------+ 35 * | 36 * | T1 37 * | 38 * v 39 * +-----------------------------+ T2 40 * | SMB_NODE_STATE_DESTROYING |----------> Deletion/Free 41 * +-----------------------------+ 42 * 43 * Transition T0 44 * 45 * This transition occurs in smb_node_lookup(). If the node looked for is 46 * not found in the has table a new node is created. The reference count is 47 * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 48 * 49 * Transition T1 50 * 51 * This transition occurs in smb_node_release(). If the reference count 52 * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 53 * reference count will be given out for that node. 54 * 55 * Transition T2 56 * 57 * This transition occurs in smb_node_release(). The structure is deleted. 58 * 59 * Comments 60 * -------- 61 * 62 * The reason the smb node has 2 states is the following synchronization 63 * rule: 64 * 65 * There's a mutex embedded in the node used to protect its fields and 66 * there's a lock embedded in the bucket of the hash table the node belongs 67 * to. To increment or to decrement the reference count the mutex must be 68 * entered. To insert the node into the bucket and to remove it from the 69 * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 70 * lock) have to be entered, the lock has always to be entered first then 71 * the mutex. This prevents a deadlock between smb_node_lookup() and 72 * smb_node_release() from occurring. However, in smb_node_release() when the 73 * reference count drops to zero and triggers the deletion of the node, the 74 * mutex has to be released before entering the lock of the bucket (to 75 * remove the node). This creates a window during which the node that is 76 * about to be freed could be given out by smb_node_lookup(). To close that 77 * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 78 * releasing the mutex. That way, even if smb_node_lookup() finds it, the 79 * state will indicate that the node should be treated as non existent (of 80 * course the state of the node should be tested/updated under the 81 * protection of the mutex). 82 */ 83 #include <smbsrv/smb_incl.h> 84 #include <smbsrv/smb_fsops.h> 85 #include <sys/pathname.h> 86 #include <sys/sdt.h> 87 #include <sys/nbmlock.h> 88 89 uint32_t smb_is_executable(char *path); 90 static void smb_node_delete_on_close(smb_node_t *node); 91 92 #define VALIDATE_DIR_NODE(_dir_, _node_) \ 93 ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 94 ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 95 ASSERT((_dir_)->dir_snode != (_node_)); 96 97 static boolean_t smb_node_initialized = B_FALSE; 98 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 99 100 /* 101 * smb_node_init 102 * 103 * Initialization of the SMB node layer. 104 * 105 * This function is not multi-thread safe. The caller must make sure only one 106 * thread makes the call. 107 */ 108 int 109 smb_node_init(void) 110 { 111 int i; 112 113 if (smb_node_initialized) 114 return (0); 115 116 for (i = 0; i <= SMBND_HASH_MASK; i++) { 117 smb_llist_constructor(&smb_node_hash_table[i], 118 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 119 } 120 smb_node_initialized = B_TRUE; 121 return (0); 122 } 123 124 /* 125 * smb_node_fini 126 * 127 * This function is not multi-thread safe. The caller must make sure only one 128 * thread makes the call. 129 */ 130 void 131 smb_node_fini(void) 132 { 133 int i; 134 135 if (!smb_node_initialized) 136 return; 137 138 #ifdef DEBUG 139 for (i = 0; i <= SMBND_HASH_MASK; i++) { 140 smb_node_t *node; 141 142 /* 143 * The following sequence is just intended for sanity check. 144 * This will have to be modified when the code goes into 145 * production. 146 * 147 * The SMB node hash table should be emtpy at this point. If the 148 * hash table is not empty a panic will be triggered. 149 * 150 * The reason why SMB nodes are still remaining in the hash 151 * table is problably due to a mismatch between calls to 152 * smb_node_lookup() and smb_node_release(). You must track that 153 * down. 154 */ 155 node = smb_llist_head(&smb_node_hash_table[i]); 156 ASSERT(node == NULL); 157 } 158 #endif 159 160 for (i = 0; i <= SMBND_HASH_MASK; i++) { 161 smb_llist_destructor(&smb_node_hash_table[i]); 162 } 163 smb_node_initialized = B_FALSE; 164 } 165 166 /* 167 * smb_node_lookup() 168 * 169 * NOTE: This routine should only be called by the file system interface layer, 170 * and not by SMB. 171 * 172 * smb_node_lookup() is called upon successful lookup, mkdir, and create 173 * (for both non-streams and streams). In each of these cases, a held vnode is 174 * passed into this routine. If a new smb_node is created it will take its 175 * own hold on the vnode. The caller's hold therefore still belongs to, and 176 * should be released by, the caller. 177 * 178 * A reference is taken on the smb_node whether found in the hash table 179 * or newly created. 180 * 181 * If an smb_node needs to be created, a reference is also taken on the 182 * dir_snode (if passed in). 183 * 184 * See smb_node_release() for details on the release of these references. 185 */ 186 187 /*ARGSUSED*/ 188 smb_node_t * 189 smb_node_lookup( 190 struct smb_request *sr, 191 struct open_param *op, 192 cred_t *cred, 193 vnode_t *vp, 194 char *od_name, 195 smb_node_t *dir_snode, 196 smb_node_t *unnamed_node, 197 smb_attr_t *attr) 198 { 199 smb_llist_t *node_hdr; 200 smb_node_t *node; 201 uint32_t hashkey = 0; 202 fsid_t fsid; 203 int error; 204 krw_t lock_mode; 205 vnode_t *unnamed_vp = NULL; 206 207 /* 208 * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 209 * because the node may not yet exist. We also do not want to call 210 * it with the list lock held. 211 */ 212 213 if (unnamed_node) 214 unnamed_vp = unnamed_node->vp; 215 216 /* 217 * This getattr is performed on behalf of the server 218 * that's why kcred is used not the user's cred 219 */ 220 attr->sa_mask = SMB_AT_ALL; 221 error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred); 222 if (error) 223 return (NULL); 224 225 if (sr && sr->tid_tree) { 226 /* 227 * The fsid for a file is that of the tree, even 228 * if the file resides in a different mountpoint 229 * under the share. 230 */ 231 fsid = SMB_TREE_FSID(sr->tid_tree); 232 } else { 233 /* 234 * This should be getting executed only for the 235 * tree root smb_node. 236 */ 237 fsid = vp->v_vfsp->vfs_fsid; 238 } 239 240 hashkey = fsid.val[0] + attr->sa_vattr.va_nodeid; 241 hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 242 node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; 243 lock_mode = RW_READER; 244 245 smb_llist_enter(node_hdr, lock_mode); 246 for (;;) { 247 node = list_head(&node_hdr->ll_list); 248 while (node) { 249 ASSERT(node->n_magic == SMB_NODE_MAGIC); 250 ASSERT(node->n_hash_bucket == node_hdr); 251 if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 252 smb_rwx_xenter(&node->n_lock); 253 DTRACE_PROBE1(smb_node_lookup_hit, 254 smb_node_t *, node); 255 switch (node->n_state) { 256 case SMB_NODE_STATE_AVAILABLE: 257 /* The node was found. */ 258 node->n_refcnt++; 259 if ((node->dir_snode == NULL) && 260 (dir_snode != NULL) && 261 (strcmp(od_name, "..") != 0) && 262 (strcmp(od_name, ".") != 0)) { 263 VALIDATE_DIR_NODE(dir_snode, 264 node); 265 node->dir_snode = dir_snode; 266 smb_node_ref(dir_snode); 267 } 268 node->attr = *attr; 269 node->n_size = attr->sa_vattr.va_size; 270 271 smb_audit_node(node); 272 smb_rwx_xexit(&node->n_lock); 273 smb_llist_exit(node_hdr); 274 return (node); 275 276 case SMB_NODE_STATE_DESTROYING: 277 /* 278 * Although the node exists it is about 279 * to be destroyed. We act as it hasn't 280 * been found. 281 */ 282 smb_rwx_xexit(&node->n_lock); 283 break; 284 default: 285 /* 286 * Although the node exists it is in an 287 * unknown state. We act as it hasn't 288 * been found. 289 */ 290 ASSERT(0); 291 smb_rwx_xexit(&node->n_lock); 292 break; 293 } 294 } 295 node = smb_llist_next(node_hdr, node); 296 } 297 if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 298 lock_mode = RW_WRITER; 299 continue; 300 } 301 break; 302 } 303 node = kmem_cache_alloc(sr->sr_server->si_cache_node, KM_SLEEP); 304 bzero(node, sizeof (smb_node_t)); 305 306 node->n_state = SMB_NODE_STATE_AVAILABLE; 307 node->n_hash_bucket = node_hdr; 308 node->n_sr = sr; 309 node->vp = vp; 310 VN_HOLD(node->vp); 311 node->n_hashkey = hashkey; 312 node->n_refcnt = 1; 313 node->attr = *attr; 314 node->flags |= NODE_FLAGS_ATTR_VALID; 315 node->n_size = node->attr.sa_vattr.va_size; 316 node->n_orig_session_id = sr->session->s_kid; 317 node->n_orig_uid = crgetuid(sr->user_cr); 318 node->n_cache = sr->sr_server->si_cache_node; 319 320 ASSERT(od_name); 321 (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 322 323 smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 324 offsetof(smb_ofile_t, f_nnd)); 325 smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 326 offsetof(smb_lock_t, l_lnd)); 327 328 329 if (strcmp(od_name, XATTR_DIR) == 0) 330 node->flags |= NODE_XATTR_DIR; 331 if (op) 332 node->flags |= smb_is_executable(op->fqi.last_comp); 333 334 if (dir_snode) { 335 smb_node_ref(dir_snode); 336 node->dir_snode = dir_snode; 337 ASSERT(dir_snode->dir_snode != node); 338 ASSERT((dir_snode->vp->v_xattrdir) || 339 (dir_snode->vp->v_type == VDIR)); 340 } 341 342 if (unnamed_node) { 343 smb_node_ref(unnamed_node); 344 node->unnamed_stream_node = unnamed_node; 345 } 346 347 smb_rwx_init(&node->n_lock); 348 node->n_magic = SMB_NODE_MAGIC; 349 smb_audit_buf_node_create(node); 350 DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 351 smb_audit_node(node); 352 smb_llist_insert_head(node_hdr, node); 353 354 smb_llist_exit(node_hdr); 355 return (node); 356 } 357 358 /* 359 * smb_stream_node_lookup() 360 * 361 * Note: stream_name (the name that will be stored in the "od_name" field 362 * of a stream's smb_node) is the same as the on-disk name for the stream 363 * except that it does not have SMB_STREAM_PREFIX prepended. 364 */ 365 366 smb_node_t * 367 smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, 368 vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr) 369 { 370 smb_node_t *xattrdir_node; 371 smb_node_t *snode; 372 smb_attr_t tmp_attr; 373 374 xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 375 fnode, NULL, &tmp_attr); 376 377 if (xattrdir_node == NULL) 378 return (NULL); 379 380 snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 381 fnode, ret_attr); 382 383 (void) smb_node_release(xattrdir_node); 384 return (snode); 385 } 386 387 388 /* 389 * This function should be called whenever a reference is needed on an 390 * smb_node pointer. The copy of an smb_node pointer from one non-local 391 * data structure to another requires a reference to be taken on the smb_node 392 * (unless the usage is localized). Each data structure deallocation routine 393 * will call smb_node_release() on its smb_node pointers. 394 * 395 * In general, an smb_node pointer residing in a structure should never be 396 * stale. A node pointer may be NULL, however, and care should be taken 397 * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 398 * Care also needs to be taken with respect to racing deallocations of a 399 * structure. 400 */ 401 402 void 403 smb_node_ref(smb_node_t *node) 404 { 405 ASSERT(node); 406 ASSERT(node->n_magic == SMB_NODE_MAGIC); 407 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 408 409 smb_rwx_xenter(&node->n_lock); 410 node->n_refcnt++; 411 ASSERT(node->n_refcnt); 412 DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 413 smb_audit_node(node); 414 smb_rwx_xexit(&node->n_lock); 415 } 416 417 /* 418 * smb_node_lookup() takes a hold on an smb_node, whether found in the 419 * hash table or newly created. This hold is expected to be released 420 * in the following manner. 421 * 422 * smb_node_lookup() takes an address of an smb_node pointer. This should 423 * be getting passed down via a lookup (whether path name or component), mkdir, 424 * create. If the original smb_node pointer resides in a data structure, then 425 * the deallocation routine for the data structure is responsible for calling 426 * smb_node_release() on the smb_node pointer. Alternatively, 427 * smb_node_release() can be called as soon as the smb_node pointer is no longer 428 * needed. In this case, callers are responsible for setting an embedded 429 * pointer to NULL if it is known that the last reference is being released. 430 * 431 * If the passed-in address of the smb_node pointer belongs to a local variable, 432 * then the caller with the local variable should call smb_node_release() 433 * directly. 434 * 435 * smb_node_release() itself will call smb_node_release() on a node's dir_snode, 436 * as smb_node_lookup() takes a hold on dir_snode. 437 */ 438 void 439 smb_node_release(smb_node_t *node) 440 { 441 ASSERT(node); 442 ASSERT(node->n_magic == SMB_NODE_MAGIC); 443 444 smb_rwx_xenter(&node->n_lock); 445 ASSERT(node->n_refcnt); 446 DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 447 if (--node->n_refcnt == 0) { 448 switch (node->n_state) { 449 450 case SMB_NODE_STATE_AVAILABLE: 451 node->n_state = SMB_NODE_STATE_DESTROYING; 452 smb_rwx_xexit(&node->n_lock); 453 454 smb_llist_enter(node->n_hash_bucket, RW_WRITER); 455 smb_llist_remove(node->n_hash_bucket, node); 456 smb_llist_exit(node->n_hash_bucket); 457 458 /* 459 * Check if the file was deleted 460 */ 461 smb_node_delete_on_close(node); 462 node->n_magic = (uint32_t)~SMB_NODE_MAGIC; 463 464 /* These lists should be empty. */ 465 smb_llist_destructor(&node->n_ofile_list); 466 smb_llist_destructor(&node->n_lock_list); 467 468 if (node->dir_snode) { 469 ASSERT(node->dir_snode->n_magic == 470 SMB_NODE_MAGIC); 471 smb_node_release(node->dir_snode); 472 } 473 474 if (node->unnamed_stream_node) { 475 ASSERT(node->unnamed_stream_node->n_magic == 476 SMB_NODE_MAGIC); 477 smb_node_release(node->unnamed_stream_node); 478 } 479 480 ASSERT(node->vp); 481 VN_RELE(node->vp); 482 483 smb_audit_buf_node_destroy(node); 484 smb_rwx_destroy(&node->n_lock); 485 kmem_cache_free(node->n_cache, node); 486 return; 487 488 default: 489 ASSERT(0); 490 break; 491 } 492 } 493 smb_audit_node(node); 494 smb_rwx_xexit(&node->n_lock); 495 } 496 497 static void 498 smb_node_delete_on_close(smb_node_t *node) 499 { 500 smb_node_t *d_snode; 501 int rc = 0; 502 503 d_snode = node->dir_snode; 504 if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 505 506 node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 507 ASSERT(node->od_name != NULL); 508 if (node->attr.sa_vattr.va_type == VDIR) 509 rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 510 d_snode, node->od_name, 1); 511 else 512 rc = smb_fsop_remove(0, node->delete_on_close_cred, 513 d_snode, node->od_name, 1); 514 smb_cred_rele(node->delete_on_close_cred); 515 } 516 if (rc != 0) 517 cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 518 node->od_name, rc); 519 DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 520 } 521 522 /* 523 * smb_node_rename() 524 * 525 */ 526 int 527 smb_node_rename( 528 smb_node_t *from_dir_snode, 529 smb_node_t *ret_snode, 530 smb_node_t *to_dir_snode, 531 char *to_name) 532 { 533 ASSERT(from_dir_snode); 534 ASSERT(to_dir_snode); 535 ASSERT(ret_snode); 536 ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 537 ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 538 ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC); 539 ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE); 540 ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE); 541 ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE); 542 543 smb_node_ref(to_dir_snode); 544 smb_rwx_xenter(&ret_snode->n_lock); 545 ret_snode->dir_snode = to_dir_snode; 546 smb_rwx_xexit(&ret_snode->n_lock); 547 ASSERT(to_dir_snode->dir_snode != ret_snode); 548 ASSERT((to_dir_snode->vp->v_xattrdir) || 549 (to_dir_snode->vp->v_type == VDIR)); 550 smb_node_release(from_dir_snode); 551 552 (void) strcpy(ret_snode->od_name, to_name); 553 554 /* 555 * XXX Need to update attributes? 556 */ 557 558 return (0); 559 } 560 561 int 562 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 563 { 564 smb_attr_t va; 565 int error; 566 uint32_t hashkey; 567 smb_llist_t *node_hdr; 568 smb_node_t *node; 569 570 /* 571 * Take an explicit hold on rootdir. This goes with the 572 * corresponding release in smb_node_root_fini()/smb_node_release(). 573 */ 574 VN_HOLD(vp); 575 576 va.sa_mask = SMB_AT_ALL; 577 error = smb_vop_getattr(vp, NULL, &va, 0, kcred); 578 if (error) { 579 VN_RELE(vp); 580 return (error); 581 } 582 583 hashkey = vp->v_vfsp->vfs_fsid.val[0] + va.sa_vattr.va_nodeid; 584 hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 585 node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; 586 587 node = kmem_cache_alloc(sv->si_cache_node, KM_SLEEP); 588 bzero(node, sizeof (smb_node_t)); 589 590 node->n_state = SMB_NODE_STATE_AVAILABLE; 591 node->n_hash_bucket = node_hdr; 592 node->vp = vp; 593 node->n_hashkey = hashkey; 594 node->n_refcnt = 1; 595 node->attr = va; 596 node->flags |= NODE_FLAGS_ATTR_VALID; 597 node->n_size = node->attr.sa_vattr.va_size; 598 node->n_cache = sv->si_cache_node; 599 (void) strlcpy(node->od_name, ROOTVOL, sizeof (node->od_name)); 600 601 smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 602 offsetof(smb_ofile_t, f_nnd)); 603 smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 604 offsetof(smb_lock_t, l_lnd)); 605 606 smb_rwx_init(&node->n_lock); 607 node->n_magic = SMB_NODE_MAGIC; 608 smb_audit_buf_node_create(node); 609 610 sv->si_root_smb_node = node; 611 612 smb_audit_node(node); 613 smb_llist_enter(node_hdr, RW_WRITER); 614 smb_llist_insert_head(node_hdr, node); 615 smb_llist_exit(node_hdr); 616 617 *root = node; 618 619 return (0); 620 } 621 622 /* 623 * smb_node_get_size 624 */ 625 u_offset_t 626 smb_node_get_size(smb_node_t *node, smb_attr_t *attr) 627 { 628 u_offset_t size; 629 630 if (attr->sa_vattr.va_type == VDIR) 631 return (0); 632 633 smb_rwx_xenter(&node->n_lock); 634 if (node && (node->flags & NODE_FLAGS_SET_SIZE)) 635 size = node->n_size; 636 else 637 size = attr->sa_vattr.va_size; 638 smb_rwx_xexit(&node->n_lock); 639 return (size); 640 } 641 642 static int 643 timeval_cmp(timestruc_t *a, timestruc_t *b) 644 { 645 if (a->tv_sec < b->tv_sec) 646 return (-1); 647 if (a->tv_sec > b->tv_sec) 648 return (1); 649 /* Seconds are equal compare tv_nsec */ 650 if (a->tv_nsec < b->tv_nsec) 651 return (-1); 652 return (a->tv_nsec > b->tv_nsec); 653 } 654 655 /* 656 * smb_node_set_time 657 * 658 * This function will update the time stored in the node and 659 * set the appropriate flags. If there is nothing to update, 660 * the function will return without any updates. The update 661 * is only in the node level and the attribute in the file system 662 * will be updated when client close the file. 663 */ 664 void 665 smb_node_set_time(struct smb_node *node, struct timestruc *crtime, 666 struct timestruc *mtime, struct timestruc *atime, 667 struct timestruc *ctime, unsigned int what) 668 { 669 if (what == 0) 670 return; 671 672 if ((what & SMB_AT_CRTIME && crtime == 0) || 673 (what & SMB_AT_MTIME && mtime == 0) || 674 (what & SMB_AT_ATIME && atime == 0) || 675 (what & SMB_AT_CTIME && ctime == 0)) 676 return; 677 678 smb_rwx_xenter(&node->n_lock); 679 680 if ((what & SMB_AT_CRTIME) && 681 timeval_cmp((timestruc_t *)&node->attr.sa_crtime, 682 crtime) != 0) { 683 node->what |= SMB_AT_CRTIME; 684 node->attr.sa_crtime = *((timestruc_t *)crtime); 685 } 686 687 if ((what & SMB_AT_MTIME) && 688 timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime, 689 mtime) != 0) { 690 node->what |= SMB_AT_MTIME; 691 node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime); 692 } 693 694 if ((what & SMB_AT_ATIME) && 695 timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime, 696 atime) != 0) { 697 node->what |= SMB_AT_ATIME; 698 node->attr.sa_vattr.va_atime = *((timestruc_t *)atime); 699 } 700 701 /* 702 * The ctime handling is trickier. It has three scenarios. 703 * 1. Only ctime need to be set and it is the same as the ctime 704 * stored in the node. (update not necessary) 705 * 2. The ctime is the same as the ctime stored in the node but 706 * is not the only time need to be set. (update required) 707 * 3. The ctime need to be set and is not the same as the ctime 708 * stored in the node. (update required) 709 * Unlike other time setting, the ctime needs to be set even when 710 * it is the same as the ctime in the node if there are other time 711 * needs to be set (#2). This will ensure the ctime not being 712 * updated when other times are being updated in the file system. 713 * 714 * Retained file rules: 715 * 716 * 1. Don't add SMB_AT_CTIME to node->what by default because the 717 * request will be rejected by filesystem 718 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e. 719 * any request for changing ctime on these files should have 720 * been already rejected 721 */ 722 node->what |= SMB_AT_CTIME; 723 if (what & SMB_AT_CTIME) { 724 if ((what == SMB_AT_CTIME) && 725 timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime, 726 ctime) == 0) { 727 node->what &= ~SMB_AT_CTIME; 728 } else { 729 gethrestime(&node->attr.sa_vattr.va_ctime); 730 } 731 } else { 732 gethrestime(&node->attr.sa_vattr.va_ctime); 733 } 734 smb_rwx_xexit(&node->n_lock); 735 } 736 737 738 timestruc_t * 739 smb_node_get_crtime(smb_node_t *node) 740 { 741 return ((timestruc_t *)&node->attr.sa_crtime); 742 } 743 744 timestruc_t * 745 smb_node_get_atime(smb_node_t *node) 746 { 747 return ((timestruc_t *)&node->attr.sa_vattr.va_atime); 748 } 749 750 timestruc_t * 751 smb_node_get_ctime(smb_node_t *node) 752 { 753 return ((timestruc_t *)&node->attr.sa_vattr.va_ctime); 754 } 755 756 timestruc_t * 757 smb_node_get_mtime(smb_node_t *node) 758 { 759 return ((timestruc_t *)&node->attr.sa_vattr.va_mtime); 760 } 761 762 /* 763 * smb_node_set_dosattr 764 * 765 * Parse the specified DOS attributes and, if they have been modified, 766 * update the node cache. This call should be followed by a 767 * smb_sync_fsattr() call to write the attribute changes to filesystem. 768 */ 769 void 770 smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr) 771 { 772 uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE | 773 FILE_ATTRIBUTE_READONLY | 774 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 775 776 smb_rwx_xenter(&node->n_lock); 777 if (node->attr.sa_dosattr != mode) { 778 node->attr.sa_dosattr = mode; 779 node->what |= SMB_AT_DOSATTR; 780 } 781 smb_rwx_xexit(&node->n_lock); 782 } 783 784 /* 785 * smb_node_get_dosattr() 786 * 787 * This function is used to provide clients with information as to whether 788 * the readonly bit is set. Hence both the node attribute cache (which 789 * reflects the on-disk attributes) and node->readonly_creator (which 790 * reflects whether a readonly set is pending from a readonly create) are 791 * checked. In the latter case, the readonly attribute should be visible to 792 * all clients even though the readonly creator fid is immune to the readonly 793 * bit until close. 794 */ 795 796 uint32_t 797 smb_node_get_dosattr(smb_node_t *node) 798 { 799 uint32_t dosattr = node->attr.sa_dosattr; 800 801 if (node->readonly_creator) 802 dosattr |= FILE_ATTRIBUTE_READONLY; 803 804 if (!dosattr) 805 dosattr = FILE_ATTRIBUTE_NORMAL; 806 807 return (dosattr); 808 } 809 810 int 811 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr) 812 { 813 int rc = -1; 814 815 smb_rwx_xenter(&node->n_lock); 816 if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) && 817 !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) { 818 crhold(cr); 819 node->delete_on_close_cred = cr; 820 node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 821 rc = 0; 822 } 823 smb_rwx_xexit(&node->n_lock); 824 return (rc); 825 } 826 827 void 828 smb_node_reset_delete_on_close(smb_node_t *node) 829 { 830 smb_rwx_xenter(&node->n_lock); 831 if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 832 node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 833 crfree(node->delete_on_close_cred); 834 node->delete_on_close_cred = NULL; 835 } 836 smb_rwx_xexit(&node->n_lock); 837 } 838 839 /* 840 * smb_node_open_check 841 * 842 * check file sharing rules for current open request 843 * against all existing opens for a file. 844 * 845 * Returns NT_STATUS_SHARING_VIOLATION if there is any 846 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 847 */ 848 uint32_t 849 smb_node_open_check(struct smb_node *node, cred_t *cr, 850 uint32_t desired_access, uint32_t share_access) 851 { 852 smb_ofile_t *of; 853 uint32_t status; 854 855 ASSERT(node); 856 ASSERT(node->n_magic == SMB_NODE_MAGIC); 857 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 858 859 smb_llist_enter(&node->n_ofile_list, RW_READER); 860 of = smb_llist_head(&node->n_ofile_list); 861 while (of) { 862 status = smb_ofile_open_check(of, cr, desired_access, 863 share_access); 864 865 switch (status) { 866 case NT_STATUS_INVALID_HANDLE: 867 case NT_STATUS_SUCCESS: 868 of = smb_llist_next(&node->n_ofile_list, of); 869 break; 870 default: 871 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 872 smb_llist_exit(&node->n_ofile_list); 873 return (status); 874 } 875 } 876 877 smb_llist_exit(&node->n_ofile_list); 878 return (NT_STATUS_SUCCESS); 879 } 880 881 uint32_t 882 smb_node_rename_check(struct smb_node *node) 883 { 884 struct smb_ofile *of; 885 uint32_t status; 886 887 ASSERT(node); 888 ASSERT(node->n_magic == SMB_NODE_MAGIC); 889 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 890 891 /* 892 * Intra-CIFS check 893 */ 894 895 smb_llist_enter(&node->n_ofile_list, RW_READER); 896 of = smb_llist_head(&node->n_ofile_list); 897 while (of) { 898 status = smb_ofile_rename_check(of); 899 900 switch (status) { 901 case NT_STATUS_INVALID_HANDLE: 902 case NT_STATUS_SUCCESS: 903 of = smb_llist_next(&node->n_ofile_list, of); 904 break; 905 default: 906 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 907 smb_llist_exit(&node->n_ofile_list); 908 return (status); 909 } 910 } 911 smb_llist_exit(&node->n_ofile_list); 912 913 /* 914 * system-wide share check 915 */ 916 917 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 918 return (NT_STATUS_SHARING_VIOLATION); 919 else 920 return (NT_STATUS_SUCCESS); 921 } 922 923 uint32_t 924 smb_node_delete_check(smb_node_t *node) 925 { 926 smb_ofile_t *of; 927 uint32_t status; 928 929 ASSERT(node); 930 ASSERT(node->n_magic == SMB_NODE_MAGIC); 931 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 932 933 if (node->attr.sa_vattr.va_type == VDIR) 934 return (NT_STATUS_SUCCESS); 935 936 /* 937 * intra-CIFS check 938 */ 939 940 smb_llist_enter(&node->n_ofile_list, RW_READER); 941 of = smb_llist_head(&node->n_ofile_list); 942 while (of) { 943 status = smb_ofile_delete_check(of); 944 945 switch (status) { 946 case NT_STATUS_INVALID_HANDLE: 947 case NT_STATUS_SUCCESS: 948 of = smb_llist_next(&node->n_ofile_list, of); 949 break; 950 default: 951 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 952 smb_llist_exit(&node->n_ofile_list); 953 return (status); 954 } 955 } 956 smb_llist_exit(&node->n_ofile_list); 957 958 /* 959 * system-wide share check 960 */ 961 962 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 963 return (NT_STATUS_SHARING_VIOLATION); 964 else 965 return (NT_STATUS_SUCCESS); 966 } 967 968 /* 969 * smb_node_start_crit() 970 * 971 * Enter critical region for share reservations. 972 * See comments above smb_fsop_shrlock(). 973 */ 974 975 void 976 smb_node_start_crit(smb_node_t *node, krw_t mode) 977 { 978 rw_enter(&node->n_share_lock, mode); 979 nbl_start_crit(node->vp, mode); 980 } 981 982 /* 983 * smb_node_end_crit() 984 * 985 * Exit critical region for share reservations. 986 */ 987 988 void 989 smb_node_end_crit(smb_node_t *node) 990 { 991 nbl_end_crit(node->vp); 992 rw_exit(&node->n_share_lock); 993 } 994 995 int 996 smb_node_in_crit(smb_node_t *node) 997 { 998 return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock)); 999 } 1000