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 2007 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(smb_info.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(smb_info.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(smb_info.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_refcnt = 1; 227 tree->t_tid = tid; 228 tree->t_access = access_flags; 229 tree->t_res_type = stype; 230 tree->t_snode = snode; 231 tree->t_state = SMB_TREE_STATE_CONNECTED; 232 tree->t_magic = SMB_TREE_MAGIC; 233 234 switch (stype & STYPE_MASK) { 235 case STYPE_DISKTREE: 236 tree->t_fsd = snode->tree_fsd; 237 238 (void) strlcpy(tree->t_typename, vol_attr->fs_typename, 239 SMB_TREE_TYPENAME_SZ); 240 (void) utf8_strupr((char *)tree->t_typename); 241 242 if (vol_attr->flags & FSOLF_READONLY) 243 tree->t_access = SMB_TREE_READ_ONLY; 244 245 tree->t_acltype = smb_fsop_acltype(snode); 246 247 if (strncasecmp(tree->t_typename, NFS, sizeof (NFS)) == 0) 248 tree->t_flags |= SMB_TREE_FLAG_NFS_MOUNTED; 249 250 if (strncasecmp(tree->t_typename, "UFS", sizeof ("UFS")) == 0) 251 tree->t_flags |= SMB_TREE_FLAG_UFS; 252 253 if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACLONCREATE)) 254 tree->t_flags |= SMB_TREE_FLAG_ACLONCREATE; 255 256 if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACEMASKONACCESS)) 257 tree->t_flags |= SMB_TREE_FLAG_ACEMASKONACCESS; 258 259 if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_CASEINSENSITIVE)) 260 tree->t_flags |= SMB_TREE_FLAG_IGNORE_CASE; 261 262 break; 263 264 case STYPE_IPC: 265 default: 266 tree->t_typename[0] = '\0'; 267 break; 268 } 269 270 smb_llist_enter(&user->u_tree_list, RW_WRITER); 271 smb_llist_insert_head(&user->u_tree_list, tree); 272 smb_llist_exit(&user->u_tree_list); 273 atomic_inc_32(&user->u_session->s_tree_cnt); 274 atomic_inc_32(&smb_info.open_trees); 275 276 return (tree); 277 } 278 279 /* 280 * smb_tree_disconnect 281 * 282 * 283 */ 284 void 285 smb_tree_disconnect( 286 smb_tree_t *tree) 287 { 288 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 289 290 mutex_enter(&tree->t_mutex); 291 ASSERT(tree->t_refcnt); 292 switch (tree->t_state) { 293 case SMB_TREE_STATE_CONNECTED: { 294 /* 295 * The tree is moved into a state indicating that the disconnect 296 * process has started. 297 */ 298 tree->t_state = SMB_TREE_STATE_DISCONNECTING; 299 mutex_exit(&tree->t_mutex); 300 atomic_dec_32(&smb_info.open_trees); 301 /* 302 * The files opened under this tree are closed. 303 */ 304 smb_ofile_close_all(tree); 305 /* 306 * The directories opened under this tree are closed. 307 */ 308 smb_odir_close_all(tree); 309 mutex_enter(&tree->t_mutex); 310 tree->t_state = SMB_TREE_STATE_DISCONNECTED; 311 /*FALLTHRU*/ 312 } 313 case SMB_TREE_STATE_DISCONNECTED: 314 case SMB_TREE_STATE_DISCONNECTING: 315 break; 316 317 default: 318 ASSERT(0); 319 break; 320 } 321 mutex_exit(&tree->t_mutex); 322 } 323 324 /* 325 * smb_tree_disconnect_all 326 * 327 * 328 */ 329 void 330 smb_tree_disconnect_all( 331 smb_user_t *user) 332 { 333 smb_tree_t *tree; 334 335 ASSERT(user); 336 ASSERT(user->u_magic == SMB_USER_MAGIC); 337 338 tree = smb_tree_lookup_head(&user->u_tree_list); 339 while (tree) { 340 ASSERT(tree->t_user == user); 341 smb_tree_disconnect(tree); 342 smb_tree_release(tree); 343 tree = smb_tree_lookup_head(&user->u_tree_list); 344 } 345 } 346 347 /* 348 * smb_tree_close_all_by_pid 349 * 350 * 351 */ 352 void 353 smb_tree_close_all_by_pid( 354 smb_user_t *user, 355 uint16_t pid) 356 { 357 smb_tree_t *tree; 358 359 ASSERT(user); 360 ASSERT(user->u_magic == SMB_USER_MAGIC); 361 362 tree = smb_tree_lookup_head(&user->u_tree_list); 363 while (tree) { 364 smb_tree_t *next; 365 ASSERT(tree->t_user == user); 366 smb_ofile_close_all_by_pid(tree, pid); 367 smb_odir_close_all_by_pid(tree, pid); 368 next = smb_tree_lookup_next(&user->u_tree_list, tree); 369 smb_tree_release(tree); 370 tree = next; 371 } 372 } 373 374 /* 375 * smb_tree_release 376 * 377 * 378 */ 379 void 380 smb_tree_release( 381 smb_tree_t *tree) 382 { 383 ASSERT(tree); 384 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 385 386 mutex_enter(&tree->t_mutex); 387 ASSERT(tree->t_refcnt); 388 tree->t_refcnt--; 389 switch (tree->t_state) { 390 case SMB_TREE_STATE_DISCONNECTED: 391 if (tree->t_refcnt == 0) { 392 mutex_exit(&tree->t_mutex); 393 smb_tree_delete(tree); 394 return; 395 } 396 break; 397 398 case SMB_TREE_STATE_CONNECTED: 399 case SMB_TREE_STATE_DISCONNECTING: 400 break; 401 402 default: 403 ASSERT(0); 404 break; 405 } 406 mutex_exit(&tree->t_mutex); 407 } 408 409 /* 410 * Find the appropriate tree for this request. The request credentials 411 * set here override those set during uid lookup. In domain mode, the 412 * user and tree credentials should be the same. In share mode, the 413 * tree credentials (defined in the share definition) should override 414 * the user credentials. 415 */ 416 smb_tree_t * 417 smb_tree_lookup_by_tid( 418 smb_user_t *user, 419 uint16_t tid) 420 { 421 smb_tree_t *tree; 422 423 ASSERT(user); 424 ASSERT(user->u_magic == SMB_USER_MAGIC); 425 426 smb_llist_enter(&user->u_tree_list, RW_READER); 427 tree = smb_llist_head(&user->u_tree_list); 428 while (tree) { 429 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 430 ASSERT(tree->t_user == user); 431 if (tree->t_tid == tid) { 432 mutex_enter(&tree->t_mutex); 433 switch (tree->t_state) { 434 case SMB_TREE_STATE_CONNECTED: 435 /* The tree exists and is still connected. */ 436 tree->t_refcnt++; 437 mutex_exit(&tree->t_mutex); 438 smb_llist_exit(&user->u_tree_list); 439 return (tree); 440 case SMB_TREE_STATE_DISCONNECTING: 441 case SMB_TREE_STATE_DISCONNECTED: 442 /* 443 * The tree exists but is diconnected or is in 444 * the process of being destroyed. 445 */ 446 mutex_exit(&tree->t_mutex); 447 smb_llist_exit(&user->u_tree_list); 448 return (NULL); 449 default: 450 ASSERT(0); 451 mutex_exit(&tree->t_mutex); 452 smb_llist_exit(&user->u_tree_list); 453 return (NULL); 454 } 455 } 456 tree = smb_llist_next(&user->u_tree_list, tree); 457 } 458 smb_llist_exit(&user->u_tree_list); 459 return (NULL); 460 } 461 462 /* 463 * smb_tree_lookup_first_by_name 464 * 465 * This function returns the first tree in the connected state that matches the 466 * sharename passed in. If the tree provided is NULL the search starts from 467 * the beginning of the list of trees of the user. It a tree is provided the 468 * search starts just after that tree. 469 */ 470 smb_tree_t * 471 smb_tree_lookup_by_name( 472 smb_user_t *user, 473 char *sharename, 474 smb_tree_t *tree) 475 { 476 ASSERT(user); 477 ASSERT(user->u_magic == SMB_USER_MAGIC); 478 ASSERT(sharename); 479 480 smb_llist_enter(&user->u_tree_list, RW_READER); 481 482 if (tree) { 483 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 484 ASSERT(tree->t_user == user); 485 tree = smb_llist_next(&user->u_tree_list, tree); 486 } else { 487 tree = smb_llist_head(&user->u_tree_list); 488 } 489 490 while (tree) { 491 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 492 ASSERT(tree->t_user == user); 493 if (strcmp(tree->t_sharename, sharename) == 0) { 494 mutex_enter(&tree->t_mutex); 495 switch (tree->t_state) { 496 case SMB_TREE_STATE_CONNECTED: 497 /* The tree exists and is still connected. */ 498 tree->t_refcnt++; 499 mutex_exit(&tree->t_mutex); 500 smb_llist_exit(&user->u_tree_list); 501 return (tree); 502 case SMB_TREE_STATE_DISCONNECTING: 503 case SMB_TREE_STATE_DISCONNECTED: 504 /* 505 * The tree exists but is diconnected or is in 506 * the process of being destroyed. 507 */ 508 mutex_exit(&tree->t_mutex); 509 break; 510 default: 511 ASSERT(0); 512 mutex_exit(&tree->t_mutex); 513 break; 514 } 515 } 516 tree = smb_llist_next(&user->u_tree_list, tree); 517 } 518 smb_llist_exit(&user->u_tree_list); 519 return (NULL); 520 } 521 522 /* 523 * smb_tree_lookup_first_by_fsd 524 * 525 * This function returns the first tree in the connected state that matches the 526 * fsd passed in. If the tree provided is NULL the search starts from 527 * the beginning of the list of trees of the user. It a tree is provided the 528 * search starts just after that tree. 529 */ 530 smb_tree_t * 531 smb_tree_lookup_by_fsd( 532 smb_user_t *user, 533 fs_desc_t *fsd, 534 smb_tree_t *tree) 535 { 536 ASSERT(user); 537 ASSERT(user->u_magic == SMB_USER_MAGIC); 538 ASSERT(fsd); 539 540 smb_llist_enter(&user->u_tree_list, RW_READER); 541 542 if (tree) { 543 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 544 ASSERT(tree->t_user == user); 545 tree = smb_llist_next(&user->u_tree_list, tree); 546 } else { 547 tree = smb_llist_head(&user->u_tree_list); 548 } 549 550 while (tree) { 551 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 552 ASSERT(tree->t_user == user); 553 if (fsd_cmp(&tree->t_fsd, fsd) == 0) { 554 mutex_enter(&tree->t_mutex); 555 switch (tree->t_state) { 556 case SMB_TREE_STATE_CONNECTED: 557 /* The tree exists and is still connected. */ 558 tree->t_refcnt++; 559 mutex_exit(&tree->t_mutex); 560 smb_llist_exit(&user->u_tree_list); 561 return (tree); 562 case SMB_TREE_STATE_DISCONNECTING: 563 case SMB_TREE_STATE_DISCONNECTED: 564 /* 565 * The tree exists but is diconnected or is in 566 * the process of being destroyed. 567 */ 568 mutex_exit(&tree->t_mutex); 569 break; 570 default: 571 ASSERT(0); 572 mutex_exit(&tree->t_mutex); 573 break; 574 } 575 } 576 tree = smb_llist_next(&user->u_tree_list, tree); 577 } 578 smb_llist_exit(&user->u_tree_list); 579 return (NULL); 580 } 581 582 /* *************************** Static Functions ***************************** */ 583 584 /* 585 * smb_tree_delete 586 * 587 * This function releases all the resources associated with a tree. It also 588 * removes the tree the caller passes from the list of trees of the user. 589 * 590 * The tree to destroy must be in the "destroying state" and the reference count 591 * must be zero. This function assumes it's single threaded i.e. only one 592 * thread will attempt to destroy a specific tree (this condition should be met 593 * if the tree is is the "destroying state" and has a reference count of zero). 594 * 595 * Entry: 596 * tree Tree to destroy 597 * 598 * Exit: 599 * Nothing 600 * 601 * Return: 602 * Nothing 603 */ 604 static void 605 smb_tree_delete(smb_tree_t *tree) 606 { 607 ASSERT(tree); 608 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 609 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 610 ASSERT(tree->t_refcnt == 0); 611 612 /* 613 * Let's remove the tree from the list of trees of the 614 * user. This has to be done before any resources 615 * associated with the tree are released. 616 */ 617 smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER); 618 smb_llist_remove(&tree->t_user->u_tree_list, tree); 619 smb_llist_exit(&tree->t_user->u_tree_list); 620 621 tree->t_magic = (uint32_t)~SMB_TREE_MAGIC; 622 smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid); 623 atomic_dec_32(&tree->t_session->s_tree_cnt); 624 625 if (tree->t_snode) { 626 smb_node_release(tree->t_snode); 627 } 628 mutex_destroy(&tree->t_mutex); 629 /* 630 * The list of open files and open directories should be empty. 631 */ 632 smb_llist_destructor(&tree->t_ofile_list); 633 smb_llist_destructor(&tree->t_odir_list); 634 smb_idpool_destructor(&tree->t_fid_pool); 635 smb_idpool_destructor(&tree->t_sid_pool); 636 kmem_cache_free(smb_info.si_cache_tree, tree); 637 } 638 639 /* 640 * smb_tree_lookup_head 641 * 642 * This function returns the first tree in the list that is in the 643 * SMB_TREE_STATE_CONNECTED. A reference is taken on the tree and 644 * smb_tree_release() will have to be called for the tree returned. 645 * 646 * Entry: 647 * lst List of trees (usually the list of trees of a user) 648 * 649 * Exit: 650 * Nothing 651 * 652 * Return: 653 * NULL No tree in the SMB_TREE_STATE_CONNECTED state was found. 654 * !NULL First tree in the list in the SMB_TREE_STATE_CONNECTED state. 655 */ 656 static smb_tree_t * 657 smb_tree_lookup_head( 658 smb_llist_t *lst) 659 { 660 smb_tree_t *tree; 661 662 smb_llist_enter(lst, RW_READER); 663 tree = smb_llist_head(lst); 664 while (tree) { 665 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 666 mutex_enter(&tree->t_mutex); 667 if (tree->t_state == SMB_TREE_STATE_CONNECTED) { 668 tree->t_refcnt++; 669 mutex_exit(&tree->t_mutex); 670 break; 671 } else if ((tree->t_state == SMB_TREE_STATE_DISCONNECTING) || 672 (tree->t_state == SMB_TREE_STATE_DISCONNECTED)) { 673 mutex_exit(&tree->t_mutex); 674 tree = smb_llist_next(lst, tree); 675 } else { 676 ASSERT(0); 677 mutex_exit(&tree->t_mutex); 678 tree = smb_llist_next(lst, tree); 679 } 680 } 681 smb_llist_exit(lst); 682 683 return (tree); 684 } 685 686 /* 687 * smb_tree_lookup_next 688 * 689 * This function returns the next tree in the list that is in the 690 * SMB_TREE_STATE_CONNECTED. A reference is taken on the tree and 691 * smb_tree_release() will have to be called for the tree returned. 692 * 693 * Entry: 694 * lst List of trees (usually the list of trees of a user). 695 * tree Starting tree. 696 * 697 * Exit: 698 * Nothing 699 * 700 * Return: 701 * NULL No tree in the SMB_TREE_STATE_CONNECTED state was found. 702 * !NULL Next tree in the list in the SMB_TREE_STATE_CONNECTED state. 703 */ 704 static smb_tree_t * 705 smb_tree_lookup_next( 706 smb_llist_t *lst, 707 smb_tree_t *tree) 708 { 709 smb_tree_t *next; 710 711 ASSERT(lst); 712 ASSERT(tree); 713 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 714 ASSERT(tree->t_refcnt); 715 716 smb_llist_enter(lst, RW_READER); 717 next = smb_llist_next(lst, tree); 718 while (next) { 719 ASSERT(next->t_magic == SMB_TREE_MAGIC); 720 mutex_enter(&next->t_mutex); 721 if (next->t_state == SMB_TREE_STATE_CONNECTED) { 722 next->t_refcnt++; 723 mutex_exit(&next->t_mutex); 724 break; 725 } else if ((next->t_state == SMB_TREE_STATE_DISCONNECTING) || 726 (next->t_state == SMB_TREE_STATE_DISCONNECTED)) { 727 mutex_exit(&next->t_mutex); 728 next = smb_llist_next(lst, next); 729 } else { 730 ASSERT(0); 731 mutex_exit(&next->t_mutex); 732 next = smb_llist_next(lst, next); 733 } 734 } 735 smb_llist_exit(lst); 736 737 return (next); 738 } 739