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