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 * (SMB1/SMB2) Server-level Oplock support. 18 * 19 * Conceptually, this is a separate layer on top of the 20 * file system (FS) layer oplock code in smb_cmn_oplock.c. 21 * If these layers were more distinct, the FS layer would 22 * need to use call-back functions (installed from here) 23 * to "indicate an oplock break to the server" (see below). 24 * As these layers are all in the same kernel module, the 25 * delivery of these break indications just uses a direct 26 * function call to smb_oplock_ind_break() below. 27 * 28 * This layer is responsible for handling the break indication, 29 * which often requires scheduling a taskq job in the server, 30 * and sending an oplock break mesage to the client using 31 * the appropriate protocol for the open handle affected. 32 * 33 * The details of composing an oplock break message, the 34 * protocol-specific details of requesting an oplock, and 35 * returning that oplock to the client are in the files: 36 * smb_oplock.c, smb2_oplock.c, smb2_lease.c 37 */ 38 39 #include <smbsrv/smb2_kproto.h> 40 #include <smbsrv/smb_oplock.h> 41 42 /* 43 * Verify relationship between BREAK_TO_... and CACHE bits, 44 * used when setting the BREAK_TO_... below. 45 */ 46 #if BREAK_TO_READ_CACHING != (READ_CACHING << BREAK_SHIFT) 47 #error "BREAK_TO_READ_CACHING" 48 #endif 49 #if BREAK_TO_HANDLE_CACHING != (HANDLE_CACHING << BREAK_SHIFT) 50 #error "BREAK_TO_HANDLE_CACHING" 51 #endif 52 #if BREAK_TO_WRITE_CACHING != (WRITE_CACHING << BREAK_SHIFT) 53 #error "BREAK_TO_WRITE_CACHING" 54 #endif 55 #define CACHE_RWH (READ_CACHING | WRITE_CACHING | HANDLE_CACHING) 56 57 /* 58 * This is the timeout used in the thread that sends an 59 * oplock break and waits for the client to respond 60 * before it breaks the oplock locally. 61 */ 62 int smb_oplock_timeout_ack = 30000; /* mSec. */ 63 64 /* 65 * This is the timeout used in threads that have just 66 * finished some sort of oplock request and now must 67 * wait for (possibly multiple) breaks to complete. 68 * This value must be at least a couple seconds LONGER 69 * than the ack timeout above so that I/O callers won't 70 * give up waiting before the local ack timeout. 71 */ 72 int smb_oplock_timeout_def = 45000; /* mSec. */ 73 74 static void smb_oplock_async_break(void *); 75 static void smb_oplock_hdl_clear(smb_ofile_t *); 76 77 78 /* 79 * 2.1.5.17.3 Indicating an Oplock Break to the Server 80 * 81 * The inputs for indicating an oplock break to the server are: 82 * 83 * BreakingOplockOpen: The Open used to request the oplock 84 * that is now breaking. 85 * NewOplockLevel: The type of oplock the requested oplock 86 * has been broken to. Valid values are as follows: 87 * LEVEL_NONE (that is, no oplock) 88 * LEVEL_TWO 89 * A combination of one or more of the following flags: 90 * READ_CACHING 91 * HANDLE_CACHING 92 * WRITE_CACHING 93 * AcknowledgeRequired: A Boolean value; TRUE if the server 94 * MUST acknowledge the oplock break, FALSE if not, 95 * as specified in section 2.1.5.18. 96 * OplockCompletionStatus: The NTSTATUS code to return to the server. 97 * 98 * This algorithm simply represents the completion of an oplock request, 99 * as specified in section 2.1.5.17.1 or section 2.1.5.17.2. The server 100 * is expected to associate the return status from this algorithm with 101 * BreakingOplockOpen, which is the Open passed in when it requested 102 * the oplock that is now breaking. 103 * 104 * It is important to note that because several oplocks can be outstanding 105 * in parallel, although this algorithm represents the completion of an 106 * oplock request, it might not result in the completion of the algorithm 107 * that called it. In particular, calling this algorithm will result in 108 * completion of the caller only if BreakingOplockOpen is the same as the 109 * Open with which the calling algorithm was itself called. To mitigate 110 * confusion, each algorithm that refers to this section will specify 111 * whether that algorithm's operation terminates at that point or not. 112 * 113 * The object store MUST return OplockCompletionStatus, 114 * AcknowledgeRequired, and NewOplockLevel to the server (the algorithm is 115 * as specified in section 2.1.5.17.1 and section 2.1.5.17.2). 116 * 117 * Implementation: 118 * 119 * We use two versions of this function: 120 * smb_oplock_ind_break_in_ack 121 * smb_oplock_ind_break 122 * 123 * The first is used when we're handling an Oplock Break Ack. 124 * The second is used when other operations cause a break, 125 * generally in one of the smb_oplock_break_... functions. 126 * 127 * Note that these are call-back functions that may be called with the 128 * node ofile list rwlock held and the node oplock mutex entered, so 129 * these should ONLY schedule oplock break work, and MUST NOT attempt 130 * any actions that might require either of those locks. 131 */ 132 133 /* 134 * smb_oplock_ind_break_in_ack 135 * 136 * Variant of smb_oplock_ind_break() for the oplock Ack handler. 137 * When we need to indicate another oplock break from within the 138 * Ack handler (during the Ack. of some previous oplock break) 139 * we need to make sure this new break indication goes out only 140 * AFTER the reply to the current break ack. is sent out. 141 * 142 * In this case, we always have an SR (the break ack) so we can 143 * append the "ind break" work to the current SR and let the 144 * request hander thread do this work after the reply is sent. 145 * Note: this is always an SMB2 or later request, because this 146 * only happens for "granular" oplocks, which are SMB2-only. 147 * 148 * This is mostly the same as smb_oplock_ind_break() except: 149 * - The only CompletionStatus possible is STATUS_CANT_GRANT. 150 * - Instead of taskq_dispatch this appends the new SR to 151 * the "post work" queue on the current SR. 152 * 153 * Note called with the node ofile list rwlock held and 154 * the oplock mutex entered. 155 */ 156 void 157 smb_oplock_ind_break_in_ack(smb_request_t *ack_sr, smb_ofile_t *ofile, 158 uint32_t NewLevel, boolean_t AckRequired) 159 { 160 smb_request_t *new_sr; 161 162 /* 163 * This should happen only with SMB2 or later, 164 * but in case that ever changes... 165 */ 166 if (ack_sr->session->dialect < SMB_VERS_2_BASE) { 167 smb_oplock_ind_break(ofile, NewLevel, 168 AckRequired, STATUS_CANT_GRANT); 169 return; 170 } 171 172 /* 173 * We're going to schedule a request that will have a 174 * reference to this ofile. Get the hold first. 175 */ 176 if (ofile->f_oplock.og_closing || 177 !smb_ofile_hold_olbrk(ofile)) { 178 /* It's closing (or whatever). Nothing to do. */ 179 return; 180 } 181 182 /* 183 * When called from Ack processing, we want to use a 184 * request on the session doing the ack. If we can't 185 * allocate a request on that session (because it's 186 * now disconnecting) just fall-back to the normal 187 * oplock break code path which deals with that. 188 * Once we have a request on the ack session, that 189 * session won't go away until the request is done. 190 */ 191 new_sr = smb_request_alloc(ack_sr->session, 0); 192 if (new_sr == NULL) { 193 smb_oplock_ind_break(ofile, NewLevel, 194 AckRequired, STATUS_CANT_GRANT); 195 smb_ofile_release(ofile); 196 return; 197 } 198 199 new_sr->sr_state = SMB_REQ_STATE_SUBMITTED; 200 new_sr->smb2_async = B_TRUE; 201 new_sr->user_cr = zone_kcred(); 202 new_sr->fid_ofile = ofile; 203 if (ofile->f_tree != NULL) { 204 new_sr->tid_tree = ofile->f_tree; 205 smb_tree_hold_internal(ofile->f_tree); 206 } 207 if (ofile->f_user != NULL) { 208 new_sr->uid_user = ofile->f_user; 209 smb_user_hold_internal(ofile->f_user); 210 } 211 new_sr->arg.olbrk.NewLevel = NewLevel; 212 new_sr->arg.olbrk.AckRequired = AckRequired; 213 214 /* 215 * Using smb2_cmd_code to indicate what to call. 216 * work func. will call smb_oplock_send_brk 217 */ 218 new_sr->smb2_cmd_code = SMB2_OPLOCK_BREAK; 219 smb2sr_append_postwork(ack_sr, new_sr); 220 } 221 222 /* 223 * smb_oplock_ind_break 224 * 225 * This is the function described in [MS-FSA] 2.1.5.17.3 226 * which is called many places in the oplock break code. 227 * 228 * Schedule a request & taskq job to do oplock break work 229 * as requested by the FS-level code (smb_cmn_oplock.c). 230 * 231 * Note called with the node ofile list rwlock held and 232 * the oplock mutex entered. 233 */ 234 void 235 smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel, 236 boolean_t AckRequired, uint32_t CompletionStatus) 237 { 238 smb_server_t *sv = ofile->f_server; 239 smb_request_t *sr = NULL; 240 241 /* 242 * See notes at smb_oplock_async_break re. CompletionStatus 243 * Check for any invalid codes here, so assert happens in 244 * the thread passing an unexpected value. 245 * The real work happens in a taskq job. 246 */ 247 switch (CompletionStatus) { 248 249 case NT_STATUS_SUCCESS: 250 case STATUS_CANT_GRANT: 251 /* Send break via taskq job. */ 252 break; 253 254 case STATUS_NEW_HANDLE: 255 case NT_STATUS_OPLOCK_HANDLE_CLOSED: 256 smb_oplock_hdl_clear(ofile); 257 return; 258 259 default: 260 ASSERT(0); 261 return; 262 } 263 264 /* 265 * We're going to schedule a request that will have a 266 * reference to this ofile. Get the hold first. 267 */ 268 if (ofile->f_oplock.og_closing || 269 !smb_ofile_hold_olbrk(ofile)) { 270 /* It's closing (or whatever). Nothing to do. */ 271 return; 272 } 273 274 /* 275 * We need a request allocated on the session that owns 276 * this ofile in order to safely send on that session. 277 * 278 * Note that while we hold a ref. on the ofile, it's 279 * f_session will not change. An ofile in state 280 * _ORPHANED will have f_session == NULL, but the 281 * f_session won't _change_ while we have a ref, 282 * and won't be torn down under our feet. 283 * Same for f_tree and f_user 284 * 285 * If f_session is NULL, or it's in a state that doesn't 286 * allow new requests, use the special "server" session. 287 */ 288 if (ofile->f_session != NULL) 289 sr = smb_request_alloc(ofile->f_session, 0); 290 if (sr == NULL) 291 sr = smb_request_alloc(sv->sv_session, 0); 292 293 sr->sr_state = SMB_REQ_STATE_SUBMITTED; 294 sr->smb2_async = B_TRUE; 295 sr->user_cr = zone_kcred(); 296 sr->fid_ofile = ofile; 297 if (ofile->f_tree != NULL) { 298 sr->tid_tree = ofile->f_tree; 299 smb_tree_hold_internal(sr->tid_tree); 300 } 301 if (ofile->f_user != NULL) { 302 sr->uid_user = ofile->f_user; 303 smb_user_hold_internal(sr->uid_user); 304 } 305 sr->arg.olbrk.NewLevel = NewLevel; 306 sr->arg.olbrk.AckRequired = AckRequired; 307 sr->smb2_status = CompletionStatus; 308 309 (void) taskq_dispatch( 310 sv->sv_worker_pool, 311 smb_oplock_async_break, sr, TQ_SLEEP); 312 } 313 314 /* 315 * smb_oplock_async_break 316 * 317 * Called via the taskq to handle an asynchronous oplock break. 318 * We have a hold on the ofile, which will be released in 319 * smb_request_free (via sr->fid_ofile) 320 * 321 * Note we have: sr->uid_user == NULL, sr->tid_tree == NULL. 322 * Nothing called here needs those. 323 * 324 * Note that NewLevel as provided by the FS up-call does NOT 325 * include the GRANULAR flag. The SMB level is expected to 326 * keep track of how each oplock was acquired (by lease or 327 * traditional oplock request) and put the GRANULAR flag 328 * back into the oplock state when calling down to the 329 * FS-level code. Also note that the lease break message 330 * carries only the cache flags, not the GRANULAR flag. 331 */ 332 static void 333 smb_oplock_async_break(void *arg) 334 { 335 smb_request_t *sr = arg; 336 uint32_t CompletionStatus; 337 338 SMB_REQ_VALID(sr); 339 340 CompletionStatus = sr->smb2_status; 341 sr->smb2_status = NT_STATUS_SUCCESS; 342 343 mutex_enter(&sr->sr_mutex); 344 sr->sr_worker = curthread; 345 sr->sr_state = SMB_REQ_STATE_ACTIVE; 346 mutex_exit(&sr->sr_mutex); 347 348 /* 349 * Note that the CompletionStatus from the FS level 350 * (smb_cmn_oplock.c) encodes what kind of action we 351 * need to take at the SMB level. 352 */ 353 switch (CompletionStatus) { 354 355 case STATUS_CANT_GRANT: 356 case NT_STATUS_SUCCESS: 357 smb_oplock_send_brk(sr); 358 break; 359 360 default: 361 /* Checked by caller. */ 362 ASSERT(0); 363 break; 364 } 365 366 if (sr->dh_nvl_dirty) { 367 sr->dh_nvl_dirty = B_FALSE; 368 smb2_dh_update_nvfile(sr); 369 } 370 371 sr->sr_state = SMB_REQ_STATE_COMPLETED; 372 smb_request_free(sr); 373 } 374 375 #ifdef DEBUG 376 int smb_oplock_debug_wait = 0; 377 #endif 378 379 /* 380 * Send an oplock break over the wire, or if we can't, 381 * then process the oplock break locally. 382 * 383 * Note that we have sr->fid_ofile here but all the other 384 * normal sr members may be NULL: uid_user, tid_tree. 385 * Also sr->session may or may not be the same session as 386 * the ofile came from (ofile->f_session) depending on 387 * whether this is a "live" open or an orphaned DH, 388 * where ofile->f_session will be NULL. 389 * 390 * Given that we don't always have a session, we determine 391 * the oplock type (lease etc) from f_oplock.og_dialect. 392 */ 393 void 394 smb_oplock_send_brk(smb_request_t *sr) 395 { 396 smb_ofile_t *ofile; 397 smb_lease_t *lease; 398 uint32_t NewLevel; 399 boolean_t AckReq; 400 uint32_t status; 401 int rc; 402 403 ofile = sr->fid_ofile; 404 NewLevel = sr->arg.olbrk.NewLevel; 405 AckReq = sr->arg.olbrk.AckRequired; 406 lease = ofile->f_lease; 407 408 /* 409 * Build the break message in sr->reply. 410 * It's free'd in smb_request_free(). 411 * Also updates the lease and NewLevel. 412 */ 413 sr->reply.max_bytes = MLEN; 414 if (ofile->f_oplock.og_dialect >= SMB_VERS_2_BASE) { 415 if (lease != NULL) { 416 /* 417 * Oplock state has changed, so 418 * update the epoch. 419 */ 420 mutex_enter(&lease->ls_mutex); 421 lease->ls_epoch++; 422 mutex_exit(&lease->ls_mutex); 423 424 /* Note, needs "old" state in og_state */ 425 smb2_lease_break_notification(sr, 426 (NewLevel & CACHE_RWH), AckReq); 427 NewLevel |= OPLOCK_LEVEL_GRANULAR; 428 } else { 429 smb2_oplock_break_notification(sr, NewLevel); 430 } 431 } else { 432 /* 433 * SMB1 clients should only get Level II oplocks if they 434 * set the capability indicating they know about them. 435 */ 436 if (NewLevel == OPLOCK_LEVEL_TWO && 437 ofile->f_oplock.og_dialect < NT_LM_0_12) 438 NewLevel = OPLOCK_LEVEL_NONE; 439 smb1_oplock_break_notification(sr, NewLevel); 440 } 441 442 /* 443 * Keep track of what we last sent to the client, 444 * preserving the GRANULAR flag (if a lease). 445 * If we're expecting an ACK, set og_breaking 446 * (and maybe lease->ls_breaking) so we can 447 * later find the ofile with breaks pending. 448 */ 449 if (AckReq) { 450 uint32_t BreakTo; 451 452 if (lease != NULL) { 453 BreakTo = (NewLevel & CACHE_RWH) << BREAK_SHIFT; 454 if (BreakTo == 0) 455 BreakTo = BREAK_TO_NO_CACHING; 456 lease->ls_breaking = BreakTo; 457 } else { 458 if ((NewLevel & LEVEL_TWO_OPLOCK) != 0) 459 BreakTo = BREAK_TO_TWO; 460 else 461 BreakTo = BREAK_TO_NONE; 462 } 463 /* Will update og_state in ack. */ 464 ofile->f_oplock.og_breaking = BreakTo; 465 } else { 466 if (lease != NULL) 467 lease->ls_state = NewLevel & CACHE_RWH; 468 ofile->f_oplock.og_state = NewLevel; 469 470 if (ofile->dh_persist) { 471 smb2_dh_update_oplock(sr, ofile); 472 } 473 } 474 475 /* 476 * Try to send the break message to the client. 477 * When we get to multi-channel, this is supposed to 478 * try to send on every channel before giving up. 479 */ 480 if (sr->session == ofile->f_session) 481 rc = smb_session_send(sr->session, 0, &sr->reply); 482 else 483 rc = ENOTCONN; 484 485 if (rc == 0) { 486 /* 487 * OK, we were able to send the break message. 488 * If no ack. required, we're done. 489 */ 490 if (!AckReq) 491 return; 492 493 /* 494 * We're expecting an ACK. Wait in this thread 495 * so we can log clients that don't respond. 496 * 497 * If debugging, may want to break after a 498 * short wait to look into why we might be 499 * holding up progress. (i.e. locks?) 500 */ 501 #ifdef DEBUG 502 if (smb_oplock_debug_wait > 0) { 503 status = smb_oplock_wait_break(ofile->f_node, 504 smb_oplock_debug_wait); 505 if (status == 0) 506 return; 507 cmn_err(CE_NOTE, "clnt %s oplock break wait debug", 508 sr->session->ip_addr_str); 509 debug_enter("oplock_wait"); 510 } 511 #endif 512 status = smb_oplock_wait_break(ofile->f_node, 513 smb_oplock_timeout_ack); 514 if (status == 0) 515 return; 516 517 cmn_err(CE_NOTE, "clnt %s oplock break timeout", 518 sr->session->ip_addr_str); 519 DTRACE_PROBE1(break_timeout, smb_ofile_t, ofile); 520 521 /* 522 * Will do local ack below. Note, after timeout, 523 * do a break to none or "no caching" regardless 524 * of what the passed in cache level was. 525 * That means: clear all except GRANULAR. 526 */ 527 NewLevel &= OPLOCK_LEVEL_GRANULAR; 528 } else { 529 /* 530 * We were unable to send the oplock break request. 531 * Generally, that means we have no connection to this 532 * client right now, and this ofile will have state 533 * SMB_OFILE_STATE_ORPHANED. We either close the handle 534 * or break the oplock locally, in which case the client 535 * gets the updated oplock state when they reconnect. 536 * Decide whether to keep or close. 537 * 538 * Relevant [MS-SMB2] sections: 539 * 540 * 3.3.4.6 Object Store Indicates an Oplock Break 541 * If Open.Connection is NULL, Open.IsResilient is FALSE, 542 * Open.IsDurable is FALSE and Open.IsPersistent is FALSE, 543 * the server SHOULD close the Open as specified in... 544 * 545 * 3.3.4.7 Object Store Indicates a Lease Break 546 * If Open.Connection is NULL, the server MUST close the 547 * Open as specified in ... for the following cases: 548 * - Open.IsResilient is FALSE, Open.IsDurable is FALSE, 549 * and Open.IsPersistent is FALSE. 550 * - Lease.BreakToLeaseState does not contain 551 * ...HANDLE_CACHING and Open.IsDurable is TRUE. 552 * If Lease.LeaseOpens is empty, (... local ack to "none"). 553 */ 554 555 /* 556 * See similar logic in smb_dh_should_save 557 */ 558 switch (ofile->dh_vers) { 559 case SMB2_RESILIENT: 560 break; /* keep DH */ 561 562 case SMB2_DURABLE_V2: 563 if (ofile->dh_persist) 564 break; /* keep DH */ 565 /* FALLTHROUGH */ 566 case SMB2_DURABLE_V1: 567 /* IS durable (v1 or v2) */ 568 if ((NewLevel & (OPLOCK_LEVEL_BATCH | 569 OPLOCK_LEVEL_CACHE_HANDLE)) != 0) 570 break; /* keep DH */ 571 /* FALLTHROUGH */ 572 case SMB2_NOT_DURABLE: 573 default: 574 smb_ofile_close(ofile, 0); 575 return; 576 } 577 /* Keep this ofile (durable handle). */ 578 579 if (!AckReq) { 580 /* Nothing more to do. */ 581 return; 582 } 583 } 584 585 /* 586 * We get here after either an oplock break ack timeout, 587 * or a send failure for a durable handle type that we 588 * preserve rather than just close. Do local ack. 589 */ 590 ofile->f_oplock.og_breaking = 0; 591 if (lease != NULL) 592 lease->ls_breaking = 0; 593 594 status = smb_oplock_ack_break(sr, ofile, &NewLevel); 595 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 596 /* Not expecting this status return. */ 597 cmn_err(CE_NOTE, "clnt local oplock ack wait?"); 598 (void) smb_oplock_wait_break(ofile->f_node, 599 smb_oplock_timeout_ack); 600 status = 0; 601 } 602 if (status != 0) { 603 cmn_err(CE_NOTE, "clnt local oplock ack, " 604 "status=0x%x", status); 605 } 606 607 /* Update og_state as if we heard from the client. */ 608 ofile->f_oplock.og_state = NewLevel; 609 if (lease != NULL) { 610 lease->ls_state = NewLevel & CACHE_RWH; 611 } 612 613 if (ofile->dh_persist) { 614 smb2_dh_update_oplock(sr, ofile); 615 } 616 } 617 618 /* 619 * See: NT_STATUS_OPLOCK_HANDLE_CLOSED above, 620 * and: STATUS_NEW_HANDLE 621 * 622 * The FS-level oplock layer calls this to update the 623 * SMB-level state when a handle loses its oplock. 624 */ 625 static void 626 smb_oplock_hdl_clear(smb_ofile_t *ofile) 627 { 628 smb_lease_t *lease = ofile->f_lease; 629 630 if (lease != NULL) { 631 if (lease->ls_oplock_ofile == ofile) { 632 /* Last close on the lease. */ 633 lease->ls_oplock_ofile = NULL; 634 } 635 } 636 ofile->f_oplock.og_state = 0; 637 ofile->f_oplock.og_breaking = 0; 638 } 639 640 /* 641 * Wait up to "timeout" mSec. for the current oplock "breaking" flags 642 * to be cleared (by smb_oplock_ack_break or smb_oplock_break_CLOSE). 643 * 644 * Callers of the above public oplock functions: 645 * smb_oplock_request() 646 * smb_oplock_ack_break() 647 * smb_oplock_break_OPEN() ... 648 * check for return status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS 649 * and call this function to wait for the break to complete. 650 * 651 * Most callers should use this default timeout, which they get 652 * by passing zero as the timeout arg. This include places where 653 * we're about to do something that invalidates some cache. 654 */ 655 uint32_t 656 smb_oplock_wait_break(smb_node_t *node, int timeout) /* mSec. */ 657 { 658 smb_oplock_t *ol; 659 clock_t time, rv; 660 uint32_t status = 0; 661 662 if (timeout == 0) 663 timeout = smb_oplock_timeout_def; 664 665 SMB_NODE_VALID(node); 666 ol = &node->n_oplock; 667 668 mutex_enter(&ol->ol_mutex); 669 time = MSEC_TO_TICK(timeout) + ddi_get_lbolt(); 670 671 while ((ol->ol_state & BREAK_ANY) != 0) { 672 ol->waiters++; 673 rv = cv_timedwait(&ol->WaitingOpenCV, 674 &ol->ol_mutex, time); 675 ol->waiters--; 676 if (rv < 0) { 677 status = NT_STATUS_CANNOT_BREAK_OPLOCK; 678 break; 679 } 680 } 681 682 mutex_exit(&ol->ol_mutex); 683 684 return (status); 685 } 686