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