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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * smb_oplock_wait / smb_oplock_broadcast 28 * When an oplock is being acquired, we must ensure that the acquisition 29 * response is submitted to the network stack before any other operation 30 * is permitted on the oplock. 31 * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker 32 * thread processing the command that is granting the oplock. 33 * Other threads accessing the oplock will be suspended in smb_oplock_wait(). 34 * They will be awakened when the worker thread referenced in 'ol_xthread' 35 * calls smb_oplock_broadcast(). 36 * 37 * The purpose of this mechanism is to prevent another thread from 38 * triggering an oplock break before the response conveying the grant 39 * has been sent. 40 */ 41 42 #include <smbsrv/smb_kproto.h> 43 #include <sys/nbmlock.h> 44 45 #define SMB_OPLOCK_IS_EXCLUSIVE(level) \ 46 (((level) == SMB_OPLOCK_EXCLUSIVE) || \ 47 ((level) == SMB_OPLOCK_BATCH)) 48 49 static int smb_oplock_install_fem(smb_node_t *); 50 static void smb_oplock_uninstall_fem(smb_node_t *); 51 52 static void smb_oplock_wait(smb_node_t *); 53 static void smb_oplock_wait_ack(smb_node_t *, uint32_t); 54 static void smb_oplock_timedout(smb_node_t *); 55 56 static smb_oplock_grant_t *smb_oplock_set_grant(smb_ofile_t *, uint8_t); 57 void smb_oplock_clear_grant(smb_oplock_grant_t *); 58 static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *); 59 static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *); 60 static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *); 61 static smb_oplock_grant_t *smb_oplock_get_grant(smb_oplock_t *, smb_ofile_t *); 62 63 static void smb_oplock_sched_async_break(smb_oplock_grant_t *, uint8_t); 64 static void smb_oplock_exec_async_break(void *); 65 static void smb_oplock_break_levelII_locked(smb_node_t *); 66 67 /* 68 * smb_oplock_install_fem 69 * Install fem monitor for cross protocol oplock breaking. 70 */ 71 static int 72 smb_oplock_install_fem(smb_node_t *node) 73 { 74 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 75 76 if (node->n_oplock.ol_fem == B_FALSE) { 77 if (smb_fem_oplock_install(node) != 0) { 78 cmn_err(CE_NOTE, "No oplock granted: " 79 "failed to install fem monitor %s", 80 node->vp->v_path); 81 return (-1); 82 } 83 node->n_oplock.ol_fem = B_TRUE; 84 } 85 return (0); 86 } 87 88 /* 89 * smb_oplock_uninstall_fem 90 * Uninstall fem monitor for cross protocol oplock breaking. 91 */ 92 static void 93 smb_oplock_uninstall_fem(smb_node_t *node) 94 { 95 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 96 97 if (node->n_oplock.ol_fem) { 98 smb_fem_oplock_uninstall(node); 99 node->n_oplock.ol_fem = B_FALSE; 100 } 101 } 102 103 /* 104 * This provides a way to fully disable oplocks, i.e. for testing. 105 * You _really_ do _not_ want to turn this off, because if you do, 106 * the clients send you very small read requests, and a _lot_ more 107 * of them. The skc_oplock_enable parameter can be used to enable 108 * or disable exclusive oplocks. Disabling that can be helpful 109 * when there are clients not responding to oplock breaks. 110 */ 111 int smb_oplocks_enabled = 1; 112 113 /* 114 * smb_oplock_acquire 115 * 116 * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH, 117 * but might only be granted LEVEL_II or NONE. 118 * 119 * If oplocks are not supported on the tree, or node, grant NONE. 120 * If nobody else has the file open, grant the requested level. 121 * If any of the following are true, grant NONE: 122 * - there is an exclusive oplock on the node 123 * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd. 124 * - LEVEL_II oplocks are not supported for the session 125 * - a BATCH oplock is requested on a named stream 126 * - there are any range locks on the node (SMB writers) 127 * Otherwise, grant LEVEL_II. 128 * 129 * ol->ol_xthread is set to the current thread to lock the oplock against 130 * other operations until the acquire response is on the wire. When the 131 * acquire response is on the wire, smb_oplock_broadcast() is called to 132 * reset ol->ol_xthread and wake any waiting threads. 133 */ 134 void 135 smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile) 136 { 137 smb_oplock_t *ol; 138 smb_oplock_grant_t *og; 139 list_t *grants; 140 smb_arg_open_t *op; 141 smb_tree_t *tree; 142 smb_session_t *session; 143 144 SMB_NODE_VALID(node); 145 SMB_OFILE_VALID(ofile); 146 147 ASSERT(node == SMB_OFILE_GET_NODE(ofile)); 148 ASSERT(RW_LOCK_HELD(&node->n_lock)); 149 150 op = &sr->sr_open; 151 tree = SMB_OFILE_GET_TREE(ofile); 152 session = SMB_OFILE_GET_SESSION(ofile); 153 154 if (smb_oplocks_enabled == 0 || 155 (op->op_oplock_level == SMB_OPLOCK_NONE) || 156 ((op->op_oplock_level == SMB_OPLOCK_BATCH) && 157 SMB_IS_STREAM(node))) { 158 op->op_oplock_level = SMB_OPLOCK_NONE; 159 return; 160 } 161 162 ol = &node->n_oplock; 163 grants = &ol->ol_grants; 164 165 mutex_enter(&ol->ol_mutex); 166 smb_oplock_wait(node); 167 168 /* 169 * Even if there are no other opens, we might want to 170 * grant only a Level II (shared) oplock so we avoid 171 * ever granting exclusive oplocks. 172 * 173 * Borrowing the SMB_TREE_OPLOCKS flag to enable/disable 174 * exclusive oplocks (for now). See skc_oplock_enable, 175 * which can now be taken as "exclusive oplock enable". 176 * Should rename this parameter, and/or implement a new 177 * multi-valued parameter for oplock enables. 178 */ 179 if ((node->n_open_count > 1) || 180 (node->n_opening_count > 1) || 181 !smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) || 182 smb_vop_other_opens(node->vp, ofile->f_mode)) { 183 /* 184 * There are other opens. 185 */ 186 if ((!op->op_oplock_levelII) || 187 (!smb_session_levelII_oplocks(session)) || 188 (smb_oplock_exclusive_grant(grants) != NULL) || 189 (smb_lock_range_access(sr, node, 0, ~0, B_FALSE))) { 190 /* 191 * LevelII (shared) oplock not allowed, 192 * so reply with "none". 193 */ 194 op->op_oplock_level = SMB_OPLOCK_NONE; 195 mutex_exit(&ol->ol_mutex); 196 return; 197 } 198 199 op->op_oplock_level = SMB_OPLOCK_LEVEL_II; 200 } 201 202 og = smb_oplock_set_grant(ofile, op->op_oplock_level); 203 if (smb_oplock_insert_grant(node, og) != 0) { 204 smb_oplock_clear_grant(og); 205 op->op_oplock_level = SMB_OPLOCK_NONE; 206 mutex_exit(&ol->ol_mutex); 207 return; 208 } 209 210 ol->ol_xthread = curthread; 211 mutex_exit(&ol->ol_mutex); 212 } 213 214 /* 215 * smb_oplock_break 216 * 217 * Break granted oplocks according to the following rules: 218 * 219 * If there's an exclusive oplock granted on the node 220 * - if the BREAK_BATCH flags is specified and the oplock is not 221 * a batch oplock, no break is required. 222 * - if the session doesn't support LEVEL II oplocks, and 'brk' is 223 * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE. 224 * - if the oplock is already breaking update the break level (if 225 * the requested break is to a lesser level), otherwise send an 226 * oplock break. 227 * Wait for acknowledgement of the break (unless NOWAIT flag is set) 228 * 229 * Otherwise: 230 * If there are level II oplocks granted on the node, and the flags 231 * indicate that they should be broken (BREAK_TO_NONE specified, 232 * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII 233 * break request for asynchronous processing. 234 * 235 * Returns: 236 * 0 - oplock broken (or no break required) 237 * EAGAIN - oplock break request sent and would block 238 * awaiting the reponse but NOWAIT was specified 239 * 240 * NB: sr == NULL when called by FEM framework. 241 */ 242 int 243 smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags) 244 { 245 smb_oplock_t *ol; 246 smb_oplock_grant_t *og; 247 smb_ofile_t *ofile; 248 list_t *grants; 249 uint32_t timeout; 250 uint8_t brk; 251 252 SMB_NODE_VALID(node); 253 ol = &node->n_oplock; 254 grants = &ol->ol_grants; 255 256 mutex_enter(&ol->ol_mutex); 257 smb_oplock_wait(node); 258 259 og = list_head(grants); 260 if (og == NULL) { 261 mutex_exit(&ol->ol_mutex); 262 return (0); 263 } 264 265 SMB_OPLOCK_GRANT_VALID(og); 266 ofile = og->og_ofile; /* containing struct */ 267 268 /* break levelII oplocks */ 269 if (og->og_level == SMB_OPLOCK_LEVEL_II) { 270 mutex_exit(&ol->ol_mutex); 271 272 if ((flags & SMB_OPLOCK_BREAK_TO_NONE) && 273 !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) && 274 !(flags & SMB_OPLOCK_BREAK_BATCH)) { 275 smb_oplock_break_levelII(node); 276 } 277 return (0); 278 } 279 280 /* break exclusive oplock */ 281 if ((flags & SMB_OPLOCK_BREAK_BATCH) && 282 (og->og_level != SMB_OPLOCK_BATCH)) { 283 mutex_exit(&ol->ol_mutex); 284 return (0); 285 } 286 287 if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) && 288 smb_session_levelII_oplocks(ofile->f_session)) { 289 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; 290 } else { 291 brk = SMB_OPLOCK_BREAK_TO_NONE; 292 } 293 294 switch (ol->ol_break) { 295 case SMB_OPLOCK_NO_BREAK: 296 ol->ol_break = brk; 297 smb_oplock_sched_async_break(og, brk); 298 break; 299 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 300 if (brk == SMB_OPLOCK_BREAK_TO_NONE) 301 ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE; 302 break; 303 case SMB_OPLOCK_BREAK_TO_NONE: 304 default: 305 break; 306 } 307 308 if (flags & SMB_OPLOCK_BREAK_NOWAIT) { 309 mutex_exit(&ol->ol_mutex); 310 return (EAGAIN); 311 } 312 313 if (sr && (sr->uid_user == ofile->f_user)) { 314 timeout = smb_oplock_min_timeout; 315 } else { 316 timeout = smb_oplock_timeout; 317 } 318 319 mutex_exit(&ol->ol_mutex); 320 smb_oplock_wait_ack(node, timeout); 321 return (0); 322 } 323 324 /* 325 * smb_oplock_break_levelII 326 * 327 * This is called after a file is modified in some way. If there are 328 * LevelII (shared) oplocks, break those to none. If there is an 329 * exclusive oplock, there can be no LevelII oplocks, so do nothing. 330 * 331 * LevelII (shared) oplock breaks are processed asynchronously. 332 * Unlike exclusive oplock breaks, the thread initiating the break 333 * is NOT blocked while the request is processed. 334 * 335 * There may be a thread with exclusive rights to oplock state for 336 * this node (via ol_xthread in smb_oplock_wait) and if so, we must 337 * avoid breaking oplocks until that's out of the way. However, we 338 * really don't want to block here, so when ol_xthread is set, we'll 339 * just mark that a "break level II to none" is pending, and let the 340 * exclusive thread do this work when it's done being exclusive. 341 */ 342 void 343 smb_oplock_break_levelII(smb_node_t *node) 344 { 345 smb_oplock_t *ol; 346 347 ol = &node->n_oplock; 348 mutex_enter(&ol->ol_mutex); 349 350 /* Instead of: smb_oplock_wait() ... */ 351 if (ol->ol_xthread != NULL) { 352 /* Defer the call to smb_oplock_broadcast(). */ 353 ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE; 354 } else { 355 /* Equivalent of smb_oplock_wait() done. */ 356 smb_oplock_break_levelII_locked(node); 357 } 358 359 mutex_exit(&ol->ol_mutex); 360 } 361 362 /* 363 * smb_oplock_break_levelII_locked 364 * Internal helper for smb_oplock_break_levelII() 365 * 366 * Called with the oplock mutex already held, and _after_ 367 * (the equivalent of) an smb_oplock_wait(). 368 */ 369 static void 370 smb_oplock_break_levelII_locked(smb_node_t *node) 371 { 372 smb_oplock_t *ol; 373 smb_oplock_grant_t *og; 374 list_t *grants; 375 376 ol = &node->n_oplock; 377 grants = &ol->ol_grants; 378 379 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 380 ASSERT(ol->ol_xthread == NULL); 381 382 while ((og = list_head(grants)) != NULL) { 383 SMB_OPLOCK_GRANT_VALID(og); 384 385 /* 386 * If there's an exclusive oplock, there are 387 * no LevelII oplocks, so do nothing. 388 */ 389 if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 390 break; 391 392 smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE); 393 smb_oplock_remove_grant(node, og); 394 smb_oplock_clear_grant(og); 395 } 396 } 397 398 /* 399 * Schedule a call to smb_session_oplock_break 400 * using an smb_request on the owning session. 401 */ 402 static void 403 smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk) 404 { 405 smb_request_t *sr; 406 smb_ofile_t *ofile; 407 408 /* 409 * Make sure we can get a hold on the ofile. If we can't, 410 * the file is closing, and there's no point scheduling an 411 * oplock break on it because the close will release the 412 * oplock very soon. Same for the tree & user holds. 413 * 414 * These holds account for the pointers we copy into the 415 * smb_request fields: fid_ofile, tid_tree, uid_user. 416 * These holds are released via smb_request_free after 417 * the oplock break has been sent. 418 */ 419 ofile = og->og_ofile; /* containing struct */ 420 if (!smb_ofile_hold(ofile)) 421 return; 422 423 if ((sr = smb_request_alloc(ofile->f_session, 0)) == NULL) { 424 smb_ofile_release(ofile); 425 return; 426 } 427 428 smb_tree_hold_internal(ofile->f_tree); 429 smb_user_hold_internal(ofile->f_user); 430 431 sr->sr_state = SMB_REQ_STATE_SUBMITTED; 432 sr->user_cr = zone_kcred(); 433 sr->fid_ofile = ofile; 434 sr->tid_tree = ofile->f_tree; 435 sr->uid_user = ofile->f_user; 436 437 sr->arg.olbrk = *og; /* struct copy */ 438 sr->arg.olbrk.og_breaking = brk; 439 440 (void) taskq_dispatch( 441 sr->sr_server->sv_worker_pool, 442 smb_oplock_exec_async_break, sr, TQ_SLEEP); 443 } 444 445 /* 446 * smb_oplock_exec_async_break 447 * 448 * Called via the taskq to handle an asynchronous oplock break. 449 * We have a hold on the ofile, which keeps the FID here valid. 450 */ 451 static void 452 smb_oplock_exec_async_break(void *arg) 453 { 454 smb_request_t *sr = arg; 455 smb_oplock_grant_t *og = &sr->arg.olbrk; 456 457 SMB_REQ_VALID(sr); 458 SMB_OPLOCK_GRANT_VALID(og); 459 460 mutex_enter(&sr->sr_mutex); 461 sr->sr_worker = curthread; 462 sr->sr_time_active = gethrtime(); 463 464 switch (sr->sr_state) { 465 case SMB_REQ_STATE_SUBMITTED: 466 sr->sr_state = SMB_REQ_STATE_ACTIVE; 467 mutex_exit(&sr->sr_mutex); 468 469 /* 470 * This is where we actually do the deferred work 471 * requested by smb_oplock_sched_async_break(). 472 */ 473 smb_session_oplock_break(sr, og->og_breaking); 474 475 mutex_enter(&sr->sr_mutex); 476 /* FALLTHROUGH */ 477 478 default: /* typically cancelled */ 479 sr->sr_state = SMB_REQ_STATE_COMPLETED; 480 mutex_exit(&sr->sr_mutex); 481 } 482 483 smb_request_free(sr); 484 } 485 486 /* 487 * smb_oplock_wait_ack 488 * 489 * Timed wait for an oplock break acknowledgement (or oplock release). 490 */ 491 static void 492 smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout) 493 { 494 smb_oplock_t *ol; 495 clock_t time; 496 497 ol = &node->n_oplock; 498 mutex_enter(&ol->ol_mutex); 499 time = MSEC_TO_TICK(timeout) + ddi_get_lbolt(); 500 501 while (ol->ol_break != SMB_OPLOCK_NO_BREAK) { 502 if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) { 503 smb_oplock_timedout(node); 504 cv_broadcast(&ol->ol_cv); 505 break; 506 } 507 } 508 mutex_exit(&ol->ol_mutex); 509 } 510 511 /* 512 * smb_oplock_timedout 513 * 514 * An oplock break has not been acknowledged within timeout 515 * 'smb_oplock_timeout'. 516 * Set oplock grant to the desired break level. 517 */ 518 static void 519 smb_oplock_timedout(smb_node_t *node) 520 { 521 smb_oplock_t *ol; 522 smb_oplock_grant_t *og; 523 list_t *grants; 524 525 ol = &node->n_oplock; 526 grants = &ol->ol_grants; 527 528 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 529 530 og = smb_oplock_exclusive_grant(grants); 531 if (og) { 532 switch (ol->ol_break) { 533 case SMB_OPLOCK_BREAK_TO_NONE: 534 og->og_level = SMB_OPLOCK_NONE; 535 smb_oplock_remove_grant(node, og); 536 smb_oplock_clear_grant(og); 537 break; 538 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 539 og->og_level = SMB_OPLOCK_LEVEL_II; 540 break; 541 default: 542 SMB_PANIC(); 543 } 544 } 545 ol->ol_break = SMB_OPLOCK_NO_BREAK; 546 } 547 548 /* 549 * smb_oplock_release 550 * 551 * Release the oplock granted on ofile 'of'. 552 * Wake any threads waiting for an oplock break acknowledgement for 553 * this oplock. 554 * This is called when the ofile is being closed. 555 */ 556 void 557 smb_oplock_release(smb_node_t *node, smb_ofile_t *of) 558 { 559 smb_oplock_t *ol; 560 smb_oplock_grant_t *og; 561 562 ol = &node->n_oplock; 563 mutex_enter(&ol->ol_mutex); 564 smb_oplock_wait(node); 565 566 og = smb_oplock_get_grant(ol, of); 567 if (og) { 568 smb_oplock_remove_grant(node, og); 569 smb_oplock_clear_grant(og); 570 571 if (ol->ol_break != SMB_OPLOCK_NO_BREAK) { 572 ol->ol_break = SMB_OPLOCK_NO_BREAK; 573 cv_broadcast(&ol->ol_cv); 574 } 575 } 576 577 mutex_exit(&ol->ol_mutex); 578 } 579 580 /* 581 * smb_oplock_ack 582 * 583 * Process oplock acknowledgement received for ofile 'of'. 584 * - oplock.ol_break is the break level that was requested. 585 * - brk is the break level being acknowledged by the client. 586 * 587 * Update the oplock grant level to the lesser of ol_break and brk. 588 * If the grant is now SMB_OPLOCK_NONE, remove the grant from the 589 * oplock's grant list and delete it. 590 * If the requested break level (ol_break) was NONE and the brk is 591 * LEVEL_II, send another oplock break (NONE). Do not wait for an 592 * acknowledgement. 593 * Wake any threads waiting for the oplock break acknowledgement. 594 */ 595 void 596 smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk) 597 { 598 smb_oplock_t *ol; 599 smb_oplock_grant_t *og; 600 601 ol = &node->n_oplock; 602 mutex_enter(&ol->ol_mutex); 603 smb_oplock_wait(node); 604 605 if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) || 606 ((og = smb_oplock_get_grant(ol, of)) == NULL)) { 607 mutex_exit(&ol->ol_mutex); 608 return; 609 } 610 611 switch (brk) { 612 case SMB_OPLOCK_BREAK_TO_NONE: 613 og->og_level = SMB_OPLOCK_NONE; 614 break; 615 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 616 if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) { 617 og->og_level = SMB_OPLOCK_LEVEL_II; 618 } else { 619 /* SMB_OPLOCK_BREAK_TO_NONE */ 620 og->og_level = SMB_OPLOCK_NONE; 621 smb_oplock_sched_async_break(og, 622 SMB_OPLOCK_BREAK_TO_NONE); 623 } 624 break; 625 default: 626 SMB_PANIC(); 627 } 628 629 if (og->og_level == SMB_OPLOCK_NONE) { 630 smb_oplock_remove_grant(node, og); 631 smb_oplock_clear_grant(og); 632 } 633 634 ol->ol_break = SMB_OPLOCK_NO_BREAK; 635 cv_broadcast(&ol->ol_cv); 636 637 mutex_exit(&ol->ol_mutex); 638 } 639 640 /* 641 * smb_oplock_broadcast 642 * 643 * Called when an open with oplock request completes. 644 * 645 * ol->ol_xthread identifies the thread that was performing an oplock 646 * acquire. Other threads may be blocked awaiting completion of the 647 * acquire. 648 * If the calling thread is ol_xthread, wake any waiting threads. 649 */ 650 void 651 smb_oplock_broadcast(smb_node_t *node) 652 { 653 smb_oplock_t *ol; 654 655 SMB_NODE_VALID(node); 656 ol = &node->n_oplock; 657 658 mutex_enter(&ol->ol_mutex); 659 if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) { 660 ol->ol_xthread = NULL; 661 if (ol->ol_brk_pending) { 662 ol->ol_brk_pending = 0; 663 smb_oplock_break_levelII_locked(node); 664 } 665 cv_broadcast(&ol->ol_cv); 666 } 667 mutex_exit(&ol->ol_mutex); 668 } 669 670 /* 671 * smb_oplock_wait 672 * 673 * Wait for the completion of an oplock acquire. 674 * If ol_xthread is not NULL and doesn't contain the pointer to the 675 * context of the calling thread, the caller will sleep until the 676 * ol_xthread is reset to NULL (via smb_oplock_broadcast()). 677 */ 678 static void 679 smb_oplock_wait(smb_node_t *node) 680 { 681 smb_oplock_t *ol; 682 683 ol = &node->n_oplock; 684 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 685 686 if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) { 687 while (ol->ol_xthread != NULL) 688 cv_wait(&ol->ol_cv, &ol->ol_mutex); 689 } 690 } 691 692 /* 693 * smb_oplock_set_grant 694 */ 695 static smb_oplock_grant_t * 696 smb_oplock_set_grant(smb_ofile_t *of, uint8_t level) 697 { 698 smb_oplock_grant_t *og; 699 700 og = &of->f_oplock_grant; 701 702 og->og_magic = SMB_OPLOCK_GRANT_MAGIC; 703 og->og_breaking = 0; 704 og->og_level = level; 705 og->og_ofile = of; 706 707 return (og); 708 } 709 710 /* 711 * smb_oplock_clear_grant 712 */ 713 void 714 smb_oplock_clear_grant(smb_oplock_grant_t *og) 715 { 716 bzero(og, sizeof (smb_oplock_grant_t)); 717 } 718 719 /* 720 * smb_oplock_insert_grant 721 * 722 * If there are no grants in the oplock's list install the fem 723 * monitor. 724 * Insert the grant into the list and increment the grant count. 725 */ 726 static int 727 smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og) 728 { 729 smb_oplock_t *ol = &node->n_oplock; 730 731 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 732 733 if (ol->ol_count == 0) { 734 if (smb_oplock_install_fem(node) != 0) 735 return (-1); 736 } 737 738 list_insert_tail(&ol->ol_grants, og); 739 ++ol->ol_count; 740 return (0); 741 } 742 743 /* 744 * smb_oplock_remove_grant 745 * 746 * Remove the oplock grant from the list, decrement the grant count 747 * and, if there are no other grants in the list, uninstall the fem 748 * monitor. 749 */ 750 static void 751 smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og) 752 { 753 smb_oplock_t *ol = &node->n_oplock; 754 755 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 756 ASSERT(ol->ol_count > 0); 757 758 list_remove(&ol->ol_grants, og); 759 if (--ol->ol_count == 0) 760 smb_oplock_uninstall_fem(node); 761 } 762 763 /* 764 * smb_oplock_exclusive_grant 765 * 766 * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists, 767 * return it. Otherwise return NULL. 768 */ 769 static smb_oplock_grant_t * 770 smb_oplock_exclusive_grant(list_t *grants) 771 { 772 smb_oplock_grant_t *og; 773 774 og = list_head(grants); 775 if (og) { 776 SMB_OPLOCK_GRANT_VALID(og); 777 if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 778 return (og); 779 } 780 return (NULL); 781 } 782 783 /* 784 * smb_oplock_get_grant 785 * 786 * Find oplock grant corresponding to the specified ofile. 787 */ 788 static smb_oplock_grant_t * 789 smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile) 790 { 791 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 792 793 if (SMB_OFILE_OPLOCK_GRANTED(ofile)) 794 return (&ofile->f_oplock_grant); 795 else 796 return (NULL); 797 } 798