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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * General Structures Layout 30 * ------------------------- 31 * 32 * This is a simplified diagram showing the relationship between most of the 33 * main structures. 34 * 35 * +-------------------+ 36 * | SMB_INFO | 37 * +-------------------+ 38 * | 39 * | 40 * v 41 * +-------------------+ +-------------------+ +-------------------+ 42 * | SESSION |<----->| SESSION |......| SESSION | 43 * +-------------------+ +-------------------+ +-------------------+ 44 * | 45 * | 46 * v 47 * +-------------------+ +-------------------+ +-------------------+ 48 * | USER |<----->| USER |......| USER | 49 * +-------------------+ +-------------------+ +-------------------+ 50 * | 51 * | 52 * v 53 * +-------------------+ +-------------------+ +-------------------+ 54 * | TREE |<----->| TREE |......| TREE | 55 * +-------------------+ +-------------------+ +-------------------+ 56 * | | 57 * | | 58 * | v 59 * | +-------+ +-------+ +-------+ 60 * | | OFILE |<----->| OFILE |......| OFILE | 61 * | +-------+ +-------+ +-------+ 62 * | 63 * | 64 * v 65 * +-------+ +------+ +------+ 66 * | ODIR |<----->| ODIR |......| ODIR | 67 * +-------+ +------+ +------+ 68 * 69 * 70 * Tree State Machine 71 * ------------------ 72 * 73 * +-----------------------------+ T0 74 * | SMB_TREE_STATE_CONNECTED |<----------- Creation/Allocation 75 * +-----------------------------+ 76 * | 77 * | T1 78 * | 79 * v 80 * +------------------------------+ 81 * | SMB_TREE_STATE_DISCONNECTING | 82 * +------------------------------+ 83 * | 84 * | T2 85 * | 86 * v 87 * +-----------------------------+ T3 88 * | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free 89 * +-----------------------------+ 90 * 91 * SMB_TREE_STATE_CONNECTED 92 * 93 * While in this state: 94 * - The tree is queued in the list of trees of its user. 95 * - References will be given out if the tree is looked up. 96 * - Files under that tree can be accessed. 97 * 98 * SMB_TREE_STATE_DISCONNECTING 99 * 100 * While in this state: 101 * - The tree is queued in the list of trees of its user. 102 * - References will not be given out if the tree is looked up. 103 * - The files and directories open under the tree are being closed. 104 * - The resources associated with the tree remain. 105 * 106 * SMB_TREE_STATE_DISCONNECTED 107 * 108 * While in this state: 109 * - The tree is queued in the list of trees of its user. 110 * - References will not be given out if the tree is looked up. 111 * - The tree has no more files and directories opened. 112 * - The resources associated with the tree remain. 113 * 114 * Transition T0 115 * 116 * This transition occurs in smb_tree_connect(). A new tree is created and 117 * added to the list of trees of a user. 118 * 119 * Transition T1 120 * 121 * This transition occurs in smb_tree_disconnect(). 122 * 123 * Transition T2 124 * 125 * This transition occurs in smb_tree_release(). The resources associated 126 * with the tree are freed as well as the tree structure. For the transition 127 * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and 128 * the reference count be zero. 129 * 130 * Comments 131 * -------- 132 * 133 * The state machine of the tree structures is controlled by 3 elements: 134 * - The list of trees of the user it belongs to. 135 * - The mutex embedded in the structure itself. 136 * - The reference count. 137 * 138 * There's a mutex embedded in the tree structure used to protect its fields 139 * and there's a lock embedded in the list of trees of a user. To 140 * increment or to decrement the reference count the mutex must be entered. 141 * To insert the tree into the list of trees of the user and to remove 142 * the tree from it, the lock must be entered in RW_WRITER mode. 143 * 144 * Rules of access to a tree structure: 145 * 146 * 1) In order to avoid deadlocks, when both (mutex and lock of the user 147 * list) have to be entered, the lock must be entered first. 148 * 149 * 2) All actions applied to a tree require a reference count. 150 * 151 * 3) There are 2 ways of getting a reference count. One is when the tree 152 * is connected. The other when the user is looked up. This translates 153 * into 2 functions: smb_tree_connect() and smb_tree_lookup_by_tid(). 154 * 155 * It should be noted that the reference count of a tree registers the 156 * number of references to the tree in other structures (such as an smb 157 * request). The reference count is not incremented in these 2 instances: 158 * 159 * 1) The tree is connected. An tree is anchored by his state. If there's 160 * no activity involving a tree currently connected, the reference 161 * count of that tree is zero. 162 * 163 * 2) The tree is queued in the list of trees of the user. The fact of 164 * being queued in that list is NOT registered by incrementing the 165 * reference count. 166 */ 167 #include <sys/fsid.h> 168 #include <smbsrv/smb_incl.h> 169 #include <smbsrv/smb_fsops.h> 170 171 /* Static functions defined further down this file. */ 172 static void smb_tree_delete(smb_tree_t *); 173 static smb_tree_t *smb_tree_lookup_head(smb_llist_t *); 174 static smb_tree_t *smb_tree_lookup_next(smb_llist_t *, smb_tree_t *); 175 176 /* 177 * smb_tree_connect 178 */ 179 smb_tree_t * 180 smb_tree_connect( 181 smb_user_t *user, 182 uint16_t access_flags, 183 char *sharename, 184 char *resource, 185 int32_t stype, 186 smb_node_t *snode, 187 fsvol_attr_t *vol_attr) 188 { 189 smb_tree_t *tree; 190 uint16_t tid; 191 192 if (smb_idpool_alloc(&user->u_tid_pool, &tid)) { 193 return (NULL); 194 } 195 196 tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP); 197 bzero(tree, sizeof (smb_tree_t)); 198 199 if (smb_idpool_constructor(&tree->t_fid_pool)) { 200 smb_idpool_free(&user->u_tid_pool, tid); 201 kmem_cache_free(user->u_server->si_cache_tree, tree); 202 return (NULL); 203 } 204 205 if (smb_idpool_constructor(&tree->t_sid_pool)) { 206 smb_idpool_destructor(&tree->t_fid_pool); 207 smb_idpool_free(&user->u_tid_pool, tid); 208 kmem_cache_free(user->u_server->si_cache_tree, tree); 209 return (NULL); 210 } 211 212 smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t), 213 offsetof(smb_ofile_t, f_lnd)); 214 215 smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t), 216 offsetof(smb_odir_t, d_lnd)); 217 218 (void) strlcpy(tree->t_sharename, sharename, 219 sizeof (tree->t_sharename)); 220 (void) strlcpy(tree->t_resource, resource, sizeof (tree->t_resource)); 221 222 mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL); 223 224 tree->t_user = user; 225 tree->t_session = user->u_session; 226 tree->t_server = user->u_server; 227 tree->t_refcnt = 1; 228 tree->t_tid = tid; 229 tree->t_access = access_flags; 230 tree->t_res_type = stype; 231 tree->t_snode = snode; 232 tree->t_state = SMB_TREE_STATE_CONNECTED; 233 tree->t_magic = SMB_TREE_MAGIC; 234 235 switch (stype & STYPE_MASK) { 236 case STYPE_DISKTREE: 237 tree->t_fsd = snode->tree_fsd; 238 239 (void) strlcpy(tree->t_typename, vol_attr->fs_typename, 240 SMB_TREE_TYPENAME_SZ); 241 (void) utf8_strupr((char *)tree->t_typename); 242 243 if (vol_attr->flags & FSOLF_READONLY) 244 tree->t_access = SMB_TREE_READ_ONLY; 245 246 tree->t_acltype = smb_fsop_acltype(snode); 247 248 if (strncasecmp(tree->t_typename, NFS, sizeof (NFS)) == 0) 249 tree->t_flags |= SMB_TREE_FLAG_NFS_MOUNTED; 250 251 if (strncasecmp(tree->t_typename, "UFS", sizeof ("UFS")) == 0) 252 tree->t_flags |= SMB_TREE_FLAG_UFS; 253 254 if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACLONCREATE)) 255 tree->t_flags |= SMB_TREE_FLAG_ACLONCREATE; 256 257 if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACEMASKONACCESS)) 258 tree->t_flags |= SMB_TREE_FLAG_ACEMASKONACCESS; 259 260 if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_CASEINSENSITIVE)) 261 tree->t_flags |= SMB_TREE_FLAG_IGNORE_CASE; 262 263 break; 264 265 case STYPE_IPC: 266 default: 267 tree->t_typename[0] = '\0'; 268 break; 269 } 270 271 smb_llist_enter(&user->u_tree_list, RW_WRITER); 272 smb_llist_insert_head(&user->u_tree_list, tree); 273 smb_llist_exit(&user->u_tree_list); 274 atomic_inc_32(&user->u_session->s_tree_cnt); 275 atomic_inc_32(&user->u_server->sv_open_trees); 276 277 return (tree); 278 } 279 280 /* 281 * smb_tree_disconnect 282 * 283 * 284 */ 285 void 286 smb_tree_disconnect( 287 smb_tree_t *tree) 288 { 289 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 290 291 mutex_enter(&tree->t_mutex); 292 ASSERT(tree->t_refcnt); 293 switch (tree->t_state) { 294 case SMB_TREE_STATE_CONNECTED: { 295 /* 296 * The tree is moved into a state indicating that the disconnect 297 * process has started. 298 */ 299 tree->t_state = SMB_TREE_STATE_DISCONNECTING; 300 mutex_exit(&tree->t_mutex); 301 atomic_dec_32(&tree->t_server->sv_open_trees); 302 /* 303 * The files opened under this tree are closed. 304 */ 305 smb_ofile_close_all(tree); 306 /* 307 * The directories opened under this tree are closed. 308 */ 309 smb_odir_close_all(tree); 310 mutex_enter(&tree->t_mutex); 311 tree->t_state = SMB_TREE_STATE_DISCONNECTED; 312 /*FALLTHRU*/ 313 } 314 case SMB_TREE_STATE_DISCONNECTED: 315 case SMB_TREE_STATE_DISCONNECTING: 316 break; 317 318 default: 319 ASSERT(0); 320 break; 321 } 322 mutex_exit(&tree->t_mutex); 323 } 324 325 /* 326 * smb_tree_disconnect_all 327 * 328 * 329 */ 330 void 331 smb_tree_disconnect_all( 332 smb_user_t *user) 333 { 334 smb_tree_t *tree; 335 336 ASSERT(user); 337 ASSERT(user->u_magic == SMB_USER_MAGIC); 338 339 tree = smb_tree_lookup_head(&user->u_tree_list); 340 while (tree) { 341 ASSERT(tree->t_user == user); 342 smb_tree_disconnect(tree); 343 smb_tree_release(tree); 344 tree = smb_tree_lookup_head(&user->u_tree_list); 345 } 346 } 347 348 /* 349 * smb_tree_close_all_by_pid 350 * 351 * 352 */ 353 void 354 smb_tree_close_all_by_pid( 355 smb_user_t *user, 356 uint16_t pid) 357 { 358 smb_tree_t *tree; 359 360 ASSERT(user); 361 ASSERT(user->u_magic == SMB_USER_MAGIC); 362 363 tree = smb_tree_lookup_head(&user->u_tree_list); 364 while (tree) { 365 smb_tree_t *next; 366 ASSERT(tree->t_user == user); 367 smb_ofile_close_all_by_pid(tree, pid); 368 smb_odir_close_all_by_pid(tree, pid); 369 next = smb_tree_lookup_next(&user->u_tree_list, tree); 370 smb_tree_release(tree); 371 tree = next; 372 } 373 } 374 375 /* 376 * smb_tree_release 377 * 378 * 379 */ 380 void 381 smb_tree_release( 382 smb_tree_t *tree) 383 { 384 ASSERT(tree); 385 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 386 387 mutex_enter(&tree->t_mutex); 388 ASSERT(tree->t_refcnt); 389 tree->t_refcnt--; 390 switch (tree->t_state) { 391 case SMB_TREE_STATE_DISCONNECTED: 392 if (tree->t_refcnt == 0) { 393 mutex_exit(&tree->t_mutex); 394 smb_tree_delete(tree); 395 return; 396 } 397 break; 398 399 case SMB_TREE_STATE_CONNECTED: 400 case SMB_TREE_STATE_DISCONNECTING: 401 break; 402 403 default: 404 ASSERT(0); 405 break; 406 } 407 mutex_exit(&tree->t_mutex); 408 } 409 410 /* 411 * Find the appropriate tree for this request. The request credentials 412 * set here override those set during uid lookup. In domain mode, the 413 * user and tree credentials should be the same. In share mode, the 414 * tree credentials (defined in the share definition) should override 415 * the user credentials. 416 */ 417 smb_tree_t * 418 smb_tree_lookup_by_tid( 419 smb_user_t *user, 420 uint16_t tid) 421 { 422 smb_tree_t *tree; 423 424 ASSERT(user); 425 ASSERT(user->u_magic == SMB_USER_MAGIC); 426 427 smb_llist_enter(&user->u_tree_list, RW_READER); 428 tree = smb_llist_head(&user->u_tree_list); 429 while (tree) { 430 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 431 ASSERT(tree->t_user == user); 432 if (tree->t_tid == tid) { 433 mutex_enter(&tree->t_mutex); 434 switch (tree->t_state) { 435 case SMB_TREE_STATE_CONNECTED: 436 /* The tree exists and is still connected. */ 437 tree->t_refcnt++; 438 mutex_exit(&tree->t_mutex); 439 smb_llist_exit(&user->u_tree_list); 440 return (tree); 441 case SMB_TREE_STATE_DISCONNECTING: 442 case SMB_TREE_STATE_DISCONNECTED: 443 /* 444 * The tree exists but is diconnected or is in 445 * the process of being destroyed. 446 */ 447 mutex_exit(&tree->t_mutex); 448 smb_llist_exit(&user->u_tree_list); 449 return (NULL); 450 default: 451 ASSERT(0); 452 mutex_exit(&tree->t_mutex); 453 smb_llist_exit(&user->u_tree_list); 454 return (NULL); 455 } 456 } 457 tree = smb_llist_next(&user->u_tree_list, tree); 458 } 459 smb_llist_exit(&user->u_tree_list); 460 return (NULL); 461 } 462 463 /* 464 * smb_tree_lookup_first_by_name 465 * 466 * This function returns the first tree in the connected state that matches the 467 * sharename passed in. If the tree provided is NULL the search starts from 468 * the beginning of the list of trees of the user. It a tree is provided the 469 * search starts just after that tree. 470 */ 471 smb_tree_t * 472 smb_tree_lookup_by_name( 473 smb_user_t *user, 474 char *sharename, 475 smb_tree_t *tree) 476 { 477 ASSERT(user); 478 ASSERT(user->u_magic == SMB_USER_MAGIC); 479 ASSERT(sharename); 480 481 smb_llist_enter(&user->u_tree_list, RW_READER); 482 483 if (tree) { 484 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 485 ASSERT(tree->t_user == user); 486 tree = smb_llist_next(&user->u_tree_list, tree); 487 } else { 488 tree = smb_llist_head(&user->u_tree_list); 489 } 490 491 while (tree) { 492 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 493 ASSERT(tree->t_user == user); 494 if (strcmp(tree->t_sharename, sharename) == 0) { 495 mutex_enter(&tree->t_mutex); 496 switch (tree->t_state) { 497 case SMB_TREE_STATE_CONNECTED: 498 /* The tree exists and is still connected. */ 499 tree->t_refcnt++; 500 mutex_exit(&tree->t_mutex); 501 smb_llist_exit(&user->u_tree_list); 502 return (tree); 503 case SMB_TREE_STATE_DISCONNECTING: 504 case SMB_TREE_STATE_DISCONNECTED: 505 /* 506 * The tree exists but is diconnected or is in 507 * the process of being destroyed. 508 */ 509 mutex_exit(&tree->t_mutex); 510 break; 511 default: 512 ASSERT(0); 513 mutex_exit(&tree->t_mutex); 514 break; 515 } 516 } 517 tree = smb_llist_next(&user->u_tree_list, tree); 518 } 519 smb_llist_exit(&user->u_tree_list); 520 return (NULL); 521 } 522 523 /* 524 * smb_tree_lookup_first_by_fsd 525 * 526 * This function returns the first tree in the connected state that matches the 527 * fsd passed in. If the tree provided is NULL the search starts from 528 * the beginning of the list of trees of the user. It a tree is provided the 529 * search starts just after that tree. 530 */ 531 smb_tree_t * 532 smb_tree_lookup_by_fsd( 533 smb_user_t *user, 534 fs_desc_t *fsd, 535 smb_tree_t *tree) 536 { 537 ASSERT(user); 538 ASSERT(user->u_magic == SMB_USER_MAGIC); 539 ASSERT(fsd); 540 541 smb_llist_enter(&user->u_tree_list, RW_READER); 542 543 if (tree) { 544 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 545 ASSERT(tree->t_user == user); 546 tree = smb_llist_next(&user->u_tree_list, tree); 547 } else { 548 tree = smb_llist_head(&user->u_tree_list); 549 } 550 551 while (tree) { 552 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 553 ASSERT(tree->t_user == user); 554 if (fsd_cmp(&tree->t_fsd, fsd) == 0) { 555 mutex_enter(&tree->t_mutex); 556 switch (tree->t_state) { 557 case SMB_TREE_STATE_CONNECTED: 558 /* The tree exists and is still connected. */ 559 tree->t_refcnt++; 560 mutex_exit(&tree->t_mutex); 561 smb_llist_exit(&user->u_tree_list); 562 return (tree); 563 case SMB_TREE_STATE_DISCONNECTING: 564 case SMB_TREE_STATE_DISCONNECTED: 565 /* 566 * The tree exists but is diconnected or is in 567 * the process of being destroyed. 568 */ 569 mutex_exit(&tree->t_mutex); 570 break; 571 default: 572 ASSERT(0); 573 mutex_exit(&tree->t_mutex); 574 break; 575 } 576 } 577 tree = smb_llist_next(&user->u_tree_list, tree); 578 } 579 smb_llist_exit(&user->u_tree_list); 580 return (NULL); 581 } 582 583 /* *************************** Static Functions ***************************** */ 584 585 /* 586 * smb_tree_delete 587 * 588 * This function releases all the resources associated with a tree. It also 589 * removes the tree the caller passes from the list of trees of the user. 590 * 591 * The tree to destroy must be in the "destroying state" and the reference count 592 * must be zero. This function assumes it's single threaded i.e. only one 593 * thread will attempt to destroy a specific tree (this condition should be met 594 * if the tree is is the "destroying state" and has a reference count of zero). 595 * 596 * Entry: 597 * tree Tree to destroy 598 * 599 * Exit: 600 * Nothing 601 * 602 * Return: 603 * Nothing 604 */ 605 static void 606 smb_tree_delete(smb_tree_t *tree) 607 { 608 ASSERT(tree); 609 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 610 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 611 ASSERT(tree->t_refcnt == 0); 612 613 /* 614 * Let's remove the tree from the list of trees of the 615 * user. This has to be done before any resources 616 * associated with the tree are released. 617 */ 618 smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER); 619 smb_llist_remove(&tree->t_user->u_tree_list, tree); 620 smb_llist_exit(&tree->t_user->u_tree_list); 621 622 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; 623 smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid); 624 atomic_dec_32(&tree->t_session->s_tree_cnt); 625 626 if (tree->t_snode) { 627 smb_node_release(tree->t_snode); 628 } 629 mutex_destroy(&tree->t_mutex); 630 /* 631 * The list of open files and open directories should be empty. 632 */ 633 smb_llist_destructor(&tree->t_ofile_list); 634 smb_llist_destructor(&tree->t_odir_list); 635 smb_idpool_destructor(&tree->t_fid_pool); 636 smb_idpool_destructor(&tree->t_sid_pool); 637 kmem_cache_free(tree->t_server->si_cache_tree, tree); 638 } 639 640 /* 641 * smb_tree_lookup_head 642 * 643 * This function returns the first tree in the list that is in the 644 * SMB_TREE_STATE_CONNECTED. A reference is taken on the tree and 645 * smb_tree_release() will have to be called for the tree returned. 646 * 647 * Entry: 648 * lst List of trees (usually the list of trees of a user) 649 * 650 * Exit: 651 * Nothing 652 * 653 * Return: 654 * NULL No tree in the SMB_TREE_STATE_CONNECTED state was found. 655 * !NULL First tree in the list in the SMB_TREE_STATE_CONNECTED state. 656 */ 657 static smb_tree_t * 658 smb_tree_lookup_head( 659 smb_llist_t *lst) 660 { 661 smb_tree_t *tree; 662 663 smb_llist_enter(lst, RW_READER); 664 tree = smb_llist_head(lst); 665 while (tree) { 666 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 667 mutex_enter(&tree->t_mutex); 668 if (tree->t_state == SMB_TREE_STATE_CONNECTED) { 669 tree->t_refcnt++; 670 mutex_exit(&tree->t_mutex); 671 break; 672 } else if ((tree->t_state == SMB_TREE_STATE_DISCONNECTING) || 673 (tree->t_state == SMB_TREE_STATE_DISCONNECTED)) { 674 mutex_exit(&tree->t_mutex); 675 tree = smb_llist_next(lst, tree); 676 } else { 677 ASSERT(0); 678 mutex_exit(&tree->t_mutex); 679 tree = smb_llist_next(lst, tree); 680 } 681 } 682 smb_llist_exit(lst); 683 684 return (tree); 685 } 686 687 /* 688 * smb_tree_lookup_next 689 * 690 * This function returns the next tree in the list that is in the 691 * SMB_TREE_STATE_CONNECTED. A reference is taken on the tree and 692 * smb_tree_release() will have to be called for the tree returned. 693 * 694 * Entry: 695 * lst List of trees (usually the list of trees of a user). 696 * tree Starting tree. 697 * 698 * Exit: 699 * Nothing 700 * 701 * Return: 702 * NULL No tree in the SMB_TREE_STATE_CONNECTED state was found. 703 * !NULL Next tree in the list in the SMB_TREE_STATE_CONNECTED state. 704 */ 705 static smb_tree_t * 706 smb_tree_lookup_next( 707 smb_llist_t *lst, 708 smb_tree_t *tree) 709 { 710 smb_tree_t *next; 711 712 ASSERT(lst); 713 ASSERT(tree); 714 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 715 ASSERT(tree->t_refcnt); 716 717 smb_llist_enter(lst, RW_READER); 718 next = smb_llist_next(lst, tree); 719 while (next) { 720 ASSERT(next->t_magic == SMB_TREE_MAGIC); 721 mutex_enter(&next->t_mutex); 722 if (next->t_state == SMB_TREE_STATE_CONNECTED) { 723 next->t_refcnt++; 724 mutex_exit(&next->t_mutex); 725 break; 726 } else if ((next->t_state == SMB_TREE_STATE_DISCONNECTING) || 727 (next->t_state == SMB_TREE_STATE_DISCONNECTED)) { 728 mutex_exit(&next->t_mutex); 729 next = smb_llist_next(lst, next); 730 } else { 731 ASSERT(0); 732 mutex_exit(&next->t_mutex); 733 next = smb_llist_next(lst, next); 734 } 735 } 736 smb_llist_exit(lst); 737 738 return (next); 739 } 740