1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2021 Tintri by DDN, Inc. All rights reserved. 14 */ 15 16 /* 17 * Dispatch function for SMB2_OPLOCK_BREAK 18 */ 19 20 #include <smbsrv/smb2_kproto.h> 21 #include <smbsrv/smb_oplock.h> 22 23 /* StructSize for the two "break" message formats. */ 24 #define SSZ_OPLOCK 24 25 #define SSZ_LEASE_ACK 36 26 #define SSZ_LEASE_BRK 44 27 28 #define NODE_FLAGS_DELETING (NODE_FLAGS_DELETE_ON_CLOSE |\ 29 NODE_FLAGS_DELETE_COMMITTED) 30 31 static const char lease_zero[UUID_LEN] = { 0 }; 32 33 static kmem_cache_t *smb_lease_cache = NULL; 34 35 void 36 smb2_lease_init() 37 { 38 if (smb_lease_cache != NULL) 39 return; 40 41 smb_lease_cache = kmem_cache_create("smb_lease_cache", 42 sizeof (smb_lease_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 43 } 44 45 void 46 smb2_lease_fini() 47 { 48 if (smb_lease_cache != NULL) { 49 kmem_cache_destroy(smb_lease_cache); 50 smb_lease_cache = NULL; 51 } 52 } 53 54 static void 55 smb2_lease_hold(smb_lease_t *ls) 56 { 57 mutex_enter(&ls->ls_mutex); 58 ls->ls_refcnt++; 59 mutex_exit(&ls->ls_mutex); 60 } 61 62 void 63 smb2_lease_rele(smb_lease_t *ls) 64 { 65 smb_llist_t *bucket; 66 67 mutex_enter(&ls->ls_mutex); 68 ls->ls_refcnt--; 69 if (ls->ls_refcnt != 0) { 70 mutex_exit(&ls->ls_mutex); 71 return; 72 } 73 mutex_exit(&ls->ls_mutex); 74 75 /* 76 * Get the list lock, then re-check the refcnt 77 * and if it's still zero, unlink & destroy. 78 */ 79 bucket = ls->ls_bucket; 80 smb_llist_enter(bucket, RW_WRITER); 81 82 mutex_enter(&ls->ls_mutex); 83 if (ls->ls_refcnt == 0) 84 smb_llist_remove(bucket, ls); 85 mutex_exit(&ls->ls_mutex); 86 87 if (ls->ls_refcnt == 0) { 88 mutex_destroy(&ls->ls_mutex); 89 kmem_cache_free(smb_lease_cache, ls); 90 } 91 92 smb_llist_exit(bucket); 93 } 94 95 /* 96 * Compute a hash from a uuid 97 * Based on mod_hash_bystr() 98 */ 99 static uint_t 100 smb_hash_uuid(const uint8_t *uuid) 101 { 102 char *k = (char *)uuid; 103 uint_t hash = 0; 104 uint_t g; 105 int i; 106 107 ASSERT(k); 108 for (i = 0; i < UUID_LEN; i++) { 109 hash = (hash << 4) + k[i]; 110 if ((g = (hash & 0xf0000000)) != 0) { 111 hash ^= (g >> 24); 112 hash ^= g; 113 } 114 } 115 return (hash); 116 } 117 118 /* 119 * Add or update a lease table entry for a new ofile. 120 * (in the per-session lease table) 121 * See [MS-SMB2] 3.3.5.9.8 122 * Handling the SMB2_CREATE_REQUEST_LEASE Create Context 123 */ 124 uint32_t 125 smb2_lease_create(smb_request_t *sr, uint8_t *clnt) 126 { 127 smb_arg_open_t *op = &sr->arg.open; 128 uint8_t *key = op->lease_key; 129 smb_ofile_t *of = sr->fid_ofile; 130 smb_hash_t *ht = sr->sr_server->sv_lease_ht; 131 smb_llist_t *bucket; 132 smb_lease_t *lease; 133 smb_lease_t *newlease; 134 size_t hashkey; 135 uint32_t status = NT_STATUS_INVALID_PARAMETER; 136 137 if (bcmp(key, lease_zero, UUID_LEN) == 0) 138 return (status); 139 140 /* 141 * Find or create, and add a ref for the new ofile. 142 */ 143 hashkey = smb_hash_uuid(key); 144 hashkey &= (ht->num_buckets - 1); 145 bucket = &ht->buckets[hashkey].b_list; 146 147 newlease = kmem_cache_alloc(smb_lease_cache, KM_SLEEP); 148 bzero(newlease, sizeof (smb_lease_t)); 149 mutex_init(&newlease->ls_mutex, NULL, MUTEX_DEFAULT, NULL); 150 newlease->ls_bucket = bucket; 151 newlease->ls_node = of->f_node; 152 newlease->ls_refcnt = 1; 153 newlease->ls_epoch = op->lease_epoch; 154 newlease->ls_version = op->lease_version; 155 bcopy(key, newlease->ls_key, UUID_LEN); 156 bcopy(clnt, newlease->ls_clnt, UUID_LEN); 157 158 smb_llist_enter(bucket, RW_WRITER); 159 for (lease = smb_llist_head(bucket); lease != NULL; 160 lease = smb_llist_next(bucket, lease)) { 161 /* 162 * Looking for this lease ID, on a node 163 * that's not being deleted. 164 */ 165 if (bcmp(lease->ls_key, key, UUID_LEN) == 0 && 166 bcmp(lease->ls_clnt, clnt, UUID_LEN) == 0 && 167 (lease->ls_node->flags & NODE_FLAGS_DELETING) == 0) 168 break; 169 } 170 if (lease != NULL) { 171 /* 172 * Found existing lease. Make sure it refers to 173 * the same node... 174 */ 175 if (lease->ls_node == of->f_node) { 176 smb2_lease_hold(lease); 177 } else { 178 /* Same lease ID, different node! */ 179 #ifdef DEBUG 180 cmn_err(CE_NOTE, "new lease on node %p (%s) " 181 "conflicts with existing node %p (%s)", 182 (void *) of->f_node, 183 of->f_node->od_name, 184 (void *) lease->ls_node, 185 lease->ls_node->od_name); 186 #endif 187 DTRACE_PROBE2(dup_lease, smb_request_t, sr, 188 smb_lease_t, lease); 189 lease = NULL; /* error */ 190 } 191 } else { 192 lease = newlease; 193 smb_llist_insert_head(bucket, lease); 194 newlease = NULL; /* don't free */ 195 } 196 smb_llist_exit(bucket); 197 198 if (newlease != NULL) { 199 mutex_destroy(&newlease->ls_mutex); 200 kmem_cache_free(smb_lease_cache, newlease); 201 } 202 203 if (lease != NULL) { 204 of->f_lease = lease; 205 status = NT_STATUS_SUCCESS; 206 } 207 208 return (status); 209 } 210 211 /* 212 * Find the lease for a given: client_uuid, lease_key 213 * Returns the lease with a new ref. 214 */ 215 smb_lease_t * 216 smb2_lease_lookup(smb_server_t *sv, uint8_t *clnt_uuid, uint8_t *lease_key) 217 { 218 smb_hash_t *ht = sv->sv_lease_ht; 219 smb_llist_t *bucket; 220 smb_lease_t *lease; 221 size_t hashkey; 222 223 hashkey = smb_hash_uuid(lease_key); 224 hashkey &= (ht->num_buckets - 1); 225 bucket = &ht->buckets[hashkey].b_list; 226 227 smb_llist_enter(bucket, RW_READER); 228 lease = smb_llist_head(bucket); 229 while (lease != NULL) { 230 if (bcmp(lease->ls_key, lease_key, UUID_LEN) == 0 && 231 bcmp(lease->ls_clnt, clnt_uuid, UUID_LEN) == 0) { 232 smb2_lease_hold(lease); 233 break; 234 } 235 lease = smb_llist_next(bucket, lease); 236 } 237 smb_llist_exit(bucket); 238 239 return (lease); 240 } 241 242 /* 243 * Find an smb_ofile_t in the current tree that shares the 244 * specified lease and has some oplock breaking flags set. 245 * If lease not found, NT_STATUS_OBJECT_NAME_NOT_FOUND. 246 * If ofile not breaking NT_STATUS_UNSUCCESSFUL. 247 * On success, ofile (held) in sr->fid_ofile. 248 */ 249 static uint32_t 250 find_breaking_ofile(smb_request_t *sr, uint8_t *lease_key) 251 { 252 smb_tree_t *tree = sr->tid_tree; 253 smb_lease_t *lease; 254 smb_llist_t *of_list; 255 smb_ofile_t *o; 256 uint32_t status = NT_STATUS_OBJECT_NAME_NOT_FOUND; 257 258 SMB_TREE_VALID(tree); 259 of_list = &tree->t_ofile_list; 260 261 smb_llist_enter(of_list, RW_READER); 262 for (o = smb_llist_head(of_list); o != NULL; 263 o = smb_llist_next(of_list, o)) { 264 265 ASSERT(o->f_magic == SMB_OFILE_MAGIC); 266 ASSERT(o->f_tree == tree); 267 268 if ((lease = o->f_lease) == NULL) 269 continue; // no lease 270 271 if (bcmp(lease->ls_key, lease_key, UUID_LEN) != 0) 272 continue; // wrong lease 273 274 /* 275 * Now we know the lease exists, so if we don't 276 * find an ofile with breaking flags, return: 277 */ 278 status = NT_STATUS_UNSUCCESSFUL; 279 280 if (o->f_oplock.og_breaking == 0) 281 continue; // not breaking 282 283 /* Found breaking ofile. */ 284 if (smb_ofile_hold(o)) { 285 sr->fid_ofile = o; 286 status = NT_STATUS_SUCCESS; 287 break; 288 } 289 } 290 smb_llist_exit(of_list); 291 292 return (status); 293 } 294 295 /* 296 * This is called by smb2_oplock_break_ack when the struct size 297 * indicates this is a lease break (SZ_LEASE). See: 298 * [MS-SMB2] 3.3.5.22.2 Processing a Lease Acknowledgment 299 */ 300 smb_sdrc_t 301 smb2_lease_break_ack(smb_request_t *sr) 302 { 303 smb_lease_t *lease; 304 smb_ofile_t *ofile; 305 uint8_t LeaseKey[UUID_LEN]; 306 uint32_t LeaseState; 307 uint32_t LeaseBreakTo; 308 uint32_t status; 309 int rc = 0; 310 311 if (sr->session->dialect < SMB_VERS_2_1) 312 return (SDRC_ERROR); 313 314 /* 315 * Decode an SMB2 Lease Acknowldgement 316 * [MS-SMB2] 2.2.24.2 317 * Note: Struct size decoded by caller. 318 */ 319 rc = smb_mbc_decodef( 320 &sr->smb_data, "6.#cl8.", 321 /* reserved 6. */ 322 UUID_LEN, /* # */ 323 LeaseKey, /* c */ 324 &LeaseState); /* l */ 325 /* duration 8. */ 326 if (rc != 0) 327 return (SDRC_ERROR); 328 329 status = find_breaking_ofile(sr, LeaseKey); 330 331 DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr); 332 if (status != 0) 333 goto errout; 334 335 /* Success, so have sr->fid_ofile and lease */ 336 ofile = sr->fid_ofile; 337 lease = ofile->f_lease; 338 339 /* 340 * Process the lease break ack. 341 * 342 * If the new LeaseState has any bits in excess of 343 * the lease state we sent in the break, error... 344 */ 345 LeaseBreakTo = (lease->ls_breaking >> BREAK_SHIFT) & 346 OPLOCK_LEVEL_CACHE_MASK; 347 if ((LeaseState & ~LeaseBreakTo) != 0) { 348 status = NT_STATUS_REQUEST_NOT_ACCEPTED; 349 goto errout; 350 } 351 352 ofile->f_oplock.og_breaking = 0; 353 lease->ls_breaking = 0; 354 355 LeaseState |= OPLOCK_LEVEL_GRANULAR; 356 status = smb_oplock_ack_break(sr, ofile, &LeaseState); 357 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 358 (void) smb2sr_go_async(sr); 359 (void) smb_oplock_wait_break(ofile->f_node, 0); 360 status = NT_STATUS_SUCCESS; 361 } 362 363 ofile->f_oplock.og_state = LeaseState; 364 lease->ls_state = LeaseState & 365 OPLOCK_LEVEL_CACHE_MASK; 366 367 errout: 368 sr->smb2_status = status; 369 DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr); 370 if (status) { 371 smb2sr_put_error(sr, status); 372 return (SDRC_SUCCESS); 373 } 374 375 /* 376 * Encode an SMB2 Lease Ack. response 377 * [MS-SMB2] 2.2.25.2 378 */ 379 LeaseState &= OPLOCK_LEVEL_CACHE_MASK; 380 (void) smb_mbc_encodef( 381 &sr->reply, "w6.#cl8.", 382 SSZ_LEASE_ACK, /* w */ 383 /* reserved 6. */ 384 UUID_LEN, /* # */ 385 LeaseKey, /* c */ 386 LeaseState); /* l */ 387 /* duration 8. */ 388 389 return (SDRC_SUCCESS); 390 391 } 392 393 /* 394 * Compose an SMB2 Lease Break Notification packet, including 395 * the SMB2 header and everything, in sr->reply. 396 * The caller will send it and free the request. 397 * 398 * [MS-SMB2] 2.2.23.2 Lease Break Notification 399 */ 400 void 401 smb2_lease_break_notification(smb_request_t *sr, uint32_t NewLevel, 402 boolean_t AckReq) 403 { 404 smb_ofile_t *ofile = sr->fid_ofile; 405 smb_oplock_grant_t *og = &ofile->f_oplock; 406 smb_lease_t *ls = ofile->f_lease; 407 uint32_t oldcache; 408 uint32_t newcache; 409 uint16_t Epoch; 410 uint16_t Flags; 411 412 /* 413 * Convert internal level to SMB2 414 */ 415 oldcache = og->og_state & OPLOCK_LEVEL_CACHE_MASK; 416 newcache = NewLevel & OPLOCK_LEVEL_CACHE_MASK; 417 if (ls->ls_version < 2) 418 Epoch = 0; 419 else 420 Epoch = ls->ls_epoch; 421 422 /* 423 * SMB2 Header 424 */ 425 sr->smb2_cmd_code = SMB2_OPLOCK_BREAK; 426 sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR; 427 sr->smb_tid = 0; 428 sr->smb_pid = 0; 429 sr->smb2_ssnid = 0; 430 sr->smb2_messageid = UINT64_MAX; 431 (void) smb2_encode_header(sr, B_FALSE); 432 433 /* 434 * SMB2 Oplock Break, variable part 435 * 436 * [MS-SMB2] says the current lease state preceeds the 437 * new lease state, but that looks like an error... 438 */ 439 Flags = AckReq ? SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED : 0; 440 (void) smb_mbc_encodef( 441 &sr->reply, "wwl#cll4.4.4.", 442 SSZ_LEASE_BRK, /* w */ 443 Epoch, /* w */ 444 Flags, /* l */ 445 SMB_LEASE_KEY_SZ, /* # */ 446 ls->ls_key, /* c */ 447 oldcache, /* cur.st l */ 448 newcache); /* new.st l */ 449 /* reserved (4.4.4.) */ 450 } 451 452 /* 453 * Client has an open handle and requests a lease. 454 * Convert SMB2 lease request info in to internal form, 455 * call common oplock code, convert result to SMB2. 456 * 457 * If necessary, "go async" here. 458 */ 459 void 460 smb2_lease_acquire(smb_request_t *sr) 461 { 462 smb_arg_open_t *op = &sr->arg.open; 463 smb_ofile_t *ofile = sr->fid_ofile; 464 smb_lease_t *lease = ofile->f_lease; 465 uint32_t status = NT_STATUS_OPLOCK_NOT_GRANTED; 466 uint32_t have, want; /* lease flags */ 467 boolean_t NewGrant = B_FALSE; 468 469 /* Only disk trees get oplocks. */ 470 ASSERT((sr->tid_tree->t_res_type & STYPE_MASK) == STYPE_DISKTREE); 471 472 /* 473 * Only plain files (for now). 474 * Later, test SMB2_CAP_DIRECTORY_LEASING 475 */ 476 if (!smb_node_is_file(ofile->f_node)) { 477 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 478 return; 479 } 480 481 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) { 482 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 483 return; 484 } 485 486 /* 487 * SMB2: Convert to internal form. 488 * Caller should have setup the lease. 489 */ 490 ASSERT(op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE); 491 ASSERT(lease != NULL); 492 if (lease == NULL) { 493 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 494 return; 495 } 496 op->op_oplock_state = OPLOCK_LEVEL_GRANULAR | 497 (op->lease_state & CACHE_RWH); 498 499 /* 500 * Tree options may force shared oplocks, 501 * in which case we reduce the request. 502 */ 503 if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) { 504 op->op_oplock_state &= ~WRITE_CACHING; 505 } 506 507 /* 508 * Disallow downgrade 509 * 510 * Note that open with a lease is not allowed to turn off 511 * any cache rights. If the client tries to "downgrade", 512 * any bits, just return the existing lease cache bits. 513 */ 514 have = lease->ls_state & CACHE_RWH; 515 want = op->op_oplock_state & CACHE_RWH; 516 if ((have & ~want) != 0) { 517 op->op_oplock_state = have | 518 OPLOCK_LEVEL_GRANULAR; 519 goto done; 520 } 521 522 /* 523 * Handle oplock requests in three parts: 524 * a: Requests with WRITE_CACHING 525 * b: Requests with HANDLE_CACHING 526 * c: Requests with READ_CACHING 527 * reducing the request before b and c. 528 * 529 * In each: first check if the lease grants the 530 * (possibly reduced) request, in which case we 531 * leave the lease unchanged and return what's 532 * granted by the lease. Otherwise, try to get 533 * the oplock, and if the succeeds, wait for any 534 * breaks, update the lease, and return. 535 */ 536 537 /* 538 * Try exclusive (request is RW or RWH) 539 */ 540 if ((op->op_oplock_state & WRITE_CACHING) != 0) { 541 want = op->op_oplock_state & CACHE_RWH; 542 if (have == want) 543 goto done; 544 545 status = smb_oplock_request(sr, ofile, 546 &op->op_oplock_state); 547 if (status == NT_STATUS_SUCCESS || 548 status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 549 NewGrant = B_TRUE; 550 goto done; 551 } 552 553 /* 554 * We did not get the exclusive oplock. 555 * 556 * There are odd rules about lease upgrade. 557 * If the existing lease grants R and the 558 * client fails to upgrade it to "RWH" 559 * (presumably due to handle conflicts) 560 * then just return the existing lease, 561 * even though upgrade to RH would work. 562 */ 563 if (have != 0) { 564 op->op_oplock_state = have | 565 OPLOCK_LEVEL_GRANULAR; 566 goto done; 567 } 568 569 /* 570 * Keep trying without write. 571 * Need to re-init op_oplock_state 572 */ 573 op->op_oplock_state = OPLOCK_LEVEL_GRANULAR | 574 (op->lease_state & CACHE_RH); 575 } 576 577 /* 578 * Try shared ("RH") 579 */ 580 if ((op->op_oplock_state & HANDLE_CACHING) != 0) { 581 want = op->op_oplock_state & CACHE_RWH; 582 if (have == want) 583 goto done; 584 585 status = smb_oplock_request(sr, ofile, 586 &op->op_oplock_state); 587 if (status == NT_STATUS_SUCCESS || 588 status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 589 NewGrant = B_TRUE; 590 goto done; 591 } 592 593 /* 594 * We did not get "RH", probably because 595 * ther were (old style) Level II oplocks. 596 * Continue, try for just read. 597 */ 598 op->op_oplock_state = OPLOCK_LEVEL_GRANULAR | 599 (op->lease_state & CACHE_R); 600 } 601 602 /* 603 * Try shared ("R") 604 */ 605 if ((op->op_oplock_state & READ_CACHING) != 0) { 606 want = op->op_oplock_state & CACHE_RWH; 607 if (have == want) 608 goto done; 609 610 status = smb_oplock_request(sr, ofile, 611 &op->op_oplock_state); 612 if (status == NT_STATUS_SUCCESS || 613 status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 614 NewGrant = B_TRUE; 615 goto done; 616 } 617 618 /* 619 * We did not get "R". 620 * Fall into "none". 621 */ 622 } 623 624 /* 625 * None of the above were able to get an oplock. 626 * The lease has no caching rights, and we didn't 627 * add any in this request. Return it as-is. 628 */ 629 op->op_oplock_state = OPLOCK_LEVEL_GRANULAR; 630 631 done: 632 if (NewGrant) { 633 /* 634 * After a new oplock grant, the status return 635 * may indicate we need to wait for breaks. 636 */ 637 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 638 (void) smb2sr_go_async(sr); 639 (void) smb_oplock_wait_break(ofile->f_node, 0); 640 status = NT_STATUS_SUCCESS; 641 } 642 ASSERT(status == NT_STATUS_SUCCESS); 643 644 /* 645 * Keep track of what we got (in ofile->f_oplock.og_state) 646 * so we'll know what we had when sending a break later. 647 * Also update the lease with the new oplock state. 648 * Also track which ofile on the lease owns the oplock. 649 * The og_dialect here is the oplock dialect, not the 650 * SMB dialect. Leasing, so SMB 2.1 (or later). 651 */ 652 ofile->f_oplock.og_dialect = SMB_VERS_2_1; 653 ofile->f_oplock.og_state = op->op_oplock_state; 654 mutex_enter(&lease->ls_mutex); 655 lease->ls_state = op->op_oplock_state & CACHE_RWH; 656 lease->ls_epoch++; 657 mutex_exit(&lease->ls_mutex); 658 } 659 660 /* 661 * Convert internal oplock state to SMB2 662 */ 663 op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE; 664 op->lease_state = lease->ls_state & CACHE_RWH; 665 op->lease_flags = (lease->ls_breaking != 0) ? 666 SMB2_LEASE_FLAG_BREAK_IN_PROGRESS : 0; 667 op->lease_epoch = lease->ls_epoch; 668 op->lease_version = lease->ls_version; 669 } 670 671 /* 672 * This ofile has a lease and is about to close. 673 * Called by smb_ofile_close when there's a lease. 674 * 675 * With leases, just one ofile on a lease owns the oplock. 676 * If an ofile with a lease is closed and it's the one that 677 * owns the oplock, try to move the oplock to another ofile 678 * on the same lease. 679 */ 680 void 681 smb2_lease_ofile_close(smb_ofile_t *ofile) 682 { 683 smb_node_t *node = ofile->f_node; 684 smb_lease_t *lease = ofile->f_lease; 685 smb_ofile_t *o; 686 687 ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock)); 688 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 689 690 /* 691 * If this ofile was not the oplock owner for this lease, 692 * we can leave things as they are. 693 */ 694 if (lease->ls_oplock_ofile != ofile) 695 return; 696 697 /* 698 * Find another ofile to which we can move the oplock. 699 * The ofile must be open and allow a new ref. 700 */ 701 FOREACH_NODE_OFILE(node, o) { 702 if (o == ofile) 703 continue; 704 if (o->f_lease != lease) 705 continue; 706 if (o->f_oplock.og_closing) 707 continue; 708 /* If we can get a hold, use this ofile. */ 709 if (smb_ofile_hold(o)) 710 break; 711 } 712 if (o == NULL) { 713 /* Normal for last close on a lease. */ 714 return; 715 } 716 smb_oplock_move(node, ofile, o); 717 718 smb_ofile_release(o); 719 } 720