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 */ 24 25 /* 26 * smb_oplock_wait / smb_oplock_broadcast 27 * When an oplock is being acquired, we must ensure that the acquisition 28 * response is submitted to the network stack before any other operation 29 * is permitted on the oplock. 30 * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker 31 * thread processing the command that is granting the oplock. 32 * Other threads accessing the oplock will be suspended in smb_oplock_wait(). 33 * They will be awakened when the worker thread referenced in 'ol_xthread' 34 * calls smb_oplock_broadcast(). 35 * 36 * The purpose of this mechanism is to prevent another thread from 37 * triggering an oplock break before the response conveying the grant 38 * has been sent. 39 */ 40 41 #include <smbsrv/smb_kproto.h> 42 #include <sys/nbmlock.h> 43 #include <inet/tcp.h> 44 45 #define SMB_OPLOCK_IS_EXCLUSIVE(level) \ 46 (((level) == SMB_OPLOCK_EXCLUSIVE) || \ 47 ((level) == SMB_OPLOCK_BATCH)) 48 49 extern int smb_fem_oplock_install(smb_node_t *); 50 extern int smb_fem_oplock_uninstall(smb_node_t *); 51 52 static int smb_oplock_install_fem(smb_node_t *); 53 static void smb_oplock_uninstall_fem(smb_node_t *); 54 55 static void smb_oplock_wait(smb_node_t *); 56 static void smb_oplock_wait_ack(smb_node_t *, uint32_t); 57 static void smb_oplock_timedout(smb_node_t *); 58 59 static smb_oplock_grant_t *smb_oplock_create_grant(smb_ofile_t *, uint8_t); 60 void smb_oplock_delete_grant(smb_oplock_grant_t *); 61 static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *); 62 static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *); 63 static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *); 64 static smb_oplock_grant_t *smb_oplock_find_grant(list_t *, smb_ofile_t *); 65 66 static smb_oplock_break_t *smb_oplock_create_break(smb_node_t *); 67 static smb_oplock_break_t *smb_oplock_get_break(void); 68 static void smb_oplock_delete_break(smb_oplock_break_t *); 69 static void smb_oplock_process_levelII_break(smb_node_t *); 70 71 static void smb_oplock_break_thread(); 72 73 /* levelII oplock break requests (smb_oplock_break_t) */ 74 static boolean_t smb_oplock_initialized = B_FALSE; 75 static kmem_cache_t *smb_oplock_break_cache = NULL; 76 static kmem_cache_t *smb_oplock_grant_cache = NULL; 77 static smb_llist_t smb_oplock_breaks; 78 static smb_thread_t smb_oplock_thread; 79 80 81 /* 82 * smb_oplock_init 83 * 84 * This function is not multi-thread safe. The caller must make sure only one 85 * thread makes the call. 86 */ 87 int 88 smb_oplock_init(void) 89 { 90 int rc; 91 92 if (smb_oplock_initialized) 93 return (0); 94 95 smb_oplock_break_cache = kmem_cache_create("smb_oplock_break_cache", 96 sizeof (smb_oplock_break_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 97 98 smb_oplock_grant_cache = kmem_cache_create("smb_oplock_grant_cache", 99 sizeof (smb_oplock_grant_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 100 101 smb_llist_constructor(&smb_oplock_breaks, sizeof (smb_oplock_break_t), 102 offsetof(smb_oplock_break_t, ob_lnd)); 103 104 smb_thread_init(&smb_oplock_thread, "smb_thread_oplock_break", 105 smb_oplock_break_thread, NULL, NULL, NULL); 106 107 rc = smb_thread_start(&smb_oplock_thread); 108 if (rc != 0) { 109 smb_thread_destroy(&smb_oplock_thread); 110 smb_llist_destructor(&smb_oplock_breaks); 111 kmem_cache_destroy(smb_oplock_break_cache); 112 kmem_cache_destroy(smb_oplock_grant_cache); 113 return (rc); 114 } 115 116 smb_oplock_initialized = B_TRUE; 117 return (0); 118 } 119 120 /* 121 * smb_oplock_fini 122 * This function is not multi-thread safe. The caller must make sure only one 123 * thread makes the call. 124 */ 125 void 126 smb_oplock_fini(void) 127 { 128 smb_oplock_break_t *ob; 129 130 if (!smb_oplock_initialized) 131 return; 132 133 smb_thread_stop(&smb_oplock_thread); 134 smb_thread_destroy(&smb_oplock_thread); 135 136 while ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) { 137 SMB_OPLOCK_BREAK_VALID(ob); 138 smb_llist_remove(&smb_oplock_breaks, ob); 139 smb_oplock_delete_break(ob); 140 } 141 smb_llist_destructor(&smb_oplock_breaks); 142 143 kmem_cache_destroy(smb_oplock_break_cache); 144 kmem_cache_destroy(smb_oplock_grant_cache); 145 } 146 147 /* 148 * smb_oplock_install_fem 149 * Install fem monitor for cross protocol oplock breaking. 150 */ 151 static int 152 smb_oplock_install_fem(smb_node_t *node) 153 { 154 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 155 156 if (node->n_oplock.ol_fem == B_FALSE) { 157 if (smb_fem_oplock_install(node) != 0) { 158 cmn_err(CE_NOTE, "No oplock granted: " 159 "failed to install fem monitor %s", 160 node->vp->v_path); 161 return (-1); 162 } 163 node->n_oplock.ol_fem = B_TRUE; 164 } 165 return (0); 166 } 167 168 /* 169 * smb_oplock_uninstall_fem 170 * Uninstall fem monitor for cross protocol oplock breaking. 171 */ 172 static void 173 smb_oplock_uninstall_fem(smb_node_t *node) 174 { 175 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 176 177 if (node->n_oplock.ol_fem) { 178 if (smb_fem_oplock_uninstall(node) == 0) { 179 node->n_oplock.ol_fem = B_FALSE; 180 } else { 181 cmn_err(CE_NOTE, 182 "failed to uninstall fem monitor %s", 183 node->vp->v_path); 184 } 185 } 186 } 187 188 /* 189 * smb_oplock_acquire 190 * 191 * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH, 192 * but might only be granted LEVEL_II or NONE. 193 * 194 * If oplocks are not supported on the tree, or node, grant NONE. 195 * If nobody else has the file open, grant the requested level. 196 * If any of the following are true, grant NONE: 197 * - there is an exclusive oplock on the node 198 * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd. 199 * - LEVEL_II oplocks are not supported for the session 200 * - a BATCH oplock is requested on a named stream 201 * - there are any range locks on the node 202 * Otherwise, grant LEVEL_II. 203 * 204 * ol->ol_xthread is set to the current thread to lock the oplock against 205 * other operations until the acquire response is on the wire. When the 206 * acquire response is on the wire, smb_oplock_broadcast() is called to 207 * reset ol->ol_xthread and wake any waiting threads. 208 */ 209 void 210 smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile) 211 { 212 smb_oplock_t *ol; 213 smb_oplock_grant_t *og; 214 list_t *grants; 215 smb_arg_open_t *op; 216 smb_tree_t *tree; 217 smb_session_t *session; 218 219 SMB_NODE_VALID(node); 220 SMB_OFILE_VALID(ofile); 221 222 ASSERT(node == SMB_OFILE_GET_NODE(ofile)); 223 224 op = &sr->sr_open; 225 tree = SMB_OFILE_GET_TREE(ofile); 226 session = SMB_OFILE_GET_SESSION(ofile); 227 228 if (!smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) || 229 (op->op_oplock_level == SMB_OPLOCK_NONE) || 230 ((op->op_oplock_level == SMB_OPLOCK_BATCH) && 231 SMB_IS_STREAM(node))) { 232 op->op_oplock_level = SMB_OPLOCK_NONE; 233 return; 234 } 235 236 ol = &node->n_oplock; 237 grants = &ol->ol_grants; 238 239 mutex_enter(&ol->ol_mutex); 240 smb_oplock_wait(node); 241 242 nbl_start_crit(node->vp, RW_READER); 243 244 if ((node->n_open_count > 1) || 245 (node->n_opening_count > 1) || 246 smb_vop_other_opens(node->vp, ofile->f_mode)) { 247 if ((!op->op_oplock_levelII) || 248 (!smb_session_levelII_oplocks(session)) || 249 (smb_oplock_exclusive_grant(grants) != NULL) || 250 (smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE) != 0)) { 251 op->op_oplock_level = SMB_OPLOCK_NONE; 252 nbl_end_crit(node->vp); 253 mutex_exit(&ol->ol_mutex); 254 return; 255 } 256 257 op->op_oplock_level = SMB_OPLOCK_LEVEL_II; 258 } 259 260 nbl_end_crit(node->vp); 261 262 og = smb_oplock_create_grant(ofile, op->op_oplock_level); 263 if (smb_oplock_insert_grant(node, og) != 0) { 264 smb_oplock_delete_grant(og); 265 op->op_oplock_level = SMB_OPLOCK_NONE; 266 mutex_exit(&ol->ol_mutex); 267 return; 268 } 269 270 ol->ol_xthread = curthread; 271 mutex_exit(&ol->ol_mutex); 272 } 273 274 /* 275 * smb_oplock_break 276 * 277 * Break granted oplocks according to the following rules: 278 * 279 * If there's an exclusive oplock granted on the node 280 * - if the BREAK_BATCH flags is specified and the oplock is not 281 * a batch oplock, no break is required. 282 * - if the session doesn't support LEVEL II oplocks, and 'brk' is 283 * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE. 284 * - if the oplock is already breaking update the break level (if 285 * the requested break is to a lesser level), otherwise send an 286 * oplock break. 287 * Wait for acknowledgement of the break (unless NOWAIT flag is set) 288 * 289 * Otherwise: 290 * If there are level II oplocks granted on the node, and the flags 291 * indicate that they should be broken (BREAK_TO_NONE specified, 292 * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII 293 * break request for asynchronous processing. 294 * 295 * Returns: 296 * 0 - oplock broken (or no break required) 297 * EAGAIN - oplock break request sent and would block 298 * awaiting the reponse but NOWAIT was specified 299 */ 300 int 301 smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags) 302 { 303 smb_oplock_t *ol; 304 smb_oplock_grant_t *og; 305 list_t *grants; 306 uint32_t timeout; 307 uint8_t brk; 308 309 SMB_NODE_VALID(node); 310 ol = &node->n_oplock; 311 grants = &ol->ol_grants; 312 313 mutex_enter(&ol->ol_mutex); 314 smb_oplock_wait(node); 315 316 og = list_head(grants); 317 if (og == NULL) { 318 mutex_exit(&ol->ol_mutex); 319 return (0); 320 } 321 322 SMB_OPLOCK_GRANT_VALID(og); 323 324 /* break levelII oplocks */ 325 if (og->og_level == SMB_OPLOCK_LEVEL_II) { 326 mutex_exit(&ol->ol_mutex); 327 328 if ((flags & SMB_OPLOCK_BREAK_TO_NONE) && 329 !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) && 330 !(flags & SMB_OPLOCK_BREAK_BATCH)) { 331 smb_oplock_break_levelII(node); 332 } 333 return (0); 334 } 335 336 /* break exclusive oplock */ 337 if ((flags & SMB_OPLOCK_BREAK_BATCH) && 338 (og->og_level != SMB_OPLOCK_BATCH)) { 339 mutex_exit(&ol->ol_mutex); 340 return (0); 341 } 342 343 if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) && 344 smb_session_levelII_oplocks(og->og_session)) { 345 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; 346 } else { 347 brk = SMB_OPLOCK_BREAK_TO_NONE; 348 } 349 350 switch (ol->ol_break) { 351 case SMB_OPLOCK_NO_BREAK: 352 ol->ol_break = brk; 353 smb_session_oplock_break(og->og_session, 354 og->og_tid, og->og_fid, brk); 355 break; 356 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 357 if (brk == SMB_OPLOCK_BREAK_TO_NONE) 358 ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE; 359 break; 360 case SMB_OPLOCK_BREAK_TO_NONE: 361 default: 362 break; 363 } 364 365 if (flags & SMB_OPLOCK_BREAK_NOWAIT) { 366 mutex_exit(&ol->ol_mutex); 367 return (EAGAIN); 368 } 369 370 if (sr && (sr->session == og->og_session) && 371 (sr->smb_uid == og->og_uid)) { 372 timeout = smb_oplock_min_timeout; 373 } else { 374 timeout = smb_oplock_timeout; 375 } 376 377 mutex_exit(&ol->ol_mutex); 378 smb_oplock_wait_ack(node, timeout); 379 return (0); 380 } 381 382 /* 383 * smb_oplock_break_levelII 384 * 385 * LevelII (shared) oplock breaks are processed asynchronously. 386 * Unlike exclusive oplock breaks, the thread initiating the break 387 * is NOT blocked while the request is processed. 388 * 389 * Create an oplock_break_request and add it to the list for async 390 * processing. 391 */ 392 void 393 smb_oplock_break_levelII(smb_node_t *node) 394 { 395 smb_oplock_break_t *ob; 396 397 ob = smb_oplock_create_break(node); 398 399 smb_llist_enter(&smb_oplock_breaks, RW_WRITER); 400 smb_llist_insert_tail(&smb_oplock_breaks, ob); 401 smb_llist_exit(&smb_oplock_breaks); 402 403 smb_thread_signal(&smb_oplock_thread); 404 } 405 406 /* 407 * smb_oplock_break_thread 408 * 409 * The smb_oplock_thread is woken when an oplock break request is 410 * added to the list of pending levelII oplock break requests. 411 * Gets the oplock break request from the list, processes it and 412 * deletes it. 413 */ 414 /*ARGSUSED*/ 415 static void 416 smb_oplock_break_thread(smb_thread_t *thread, void *arg) 417 { 418 smb_oplock_break_t *ob; 419 420 while (smb_thread_continue(thread)) { 421 while ((ob = smb_oplock_get_break()) != NULL) { 422 smb_oplock_process_levelII_break(ob->ob_node); 423 smb_oplock_delete_break(ob); 424 } 425 } 426 } 427 428 /* 429 * smb_oplock_get_break 430 * 431 * Remove and return the next oplock break request from the list 432 */ 433 static smb_oplock_break_t * 434 smb_oplock_get_break(void) 435 { 436 smb_oplock_break_t *ob; 437 438 smb_llist_enter(&smb_oplock_breaks, RW_WRITER); 439 if ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) { 440 SMB_OPLOCK_BREAK_VALID(ob); 441 smb_llist_remove(&smb_oplock_breaks, ob); 442 } 443 smb_llist_exit(&smb_oplock_breaks); 444 return (ob); 445 } 446 447 /* 448 * smb_oplock_process_levelII_break 449 */ 450 void 451 smb_oplock_process_levelII_break(smb_node_t *node) 452 { 453 smb_oplock_t *ol; 454 smb_oplock_grant_t *og; 455 list_t *grants; 456 457 if (!smb_oplock_levelII) 458 return; 459 460 ol = &node->n_oplock; 461 mutex_enter(&ol->ol_mutex); 462 smb_oplock_wait(node); 463 grants = &node->n_oplock.ol_grants; 464 465 while ((og = list_head(grants)) != NULL) { 466 SMB_OPLOCK_GRANT_VALID(og); 467 468 if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 469 break; 470 471 smb_session_oplock_break(og->og_session, 472 og->og_tid, og->og_fid, SMB_OPLOCK_BREAK_TO_NONE); 473 smb_oplock_remove_grant(node, og); 474 smb_oplock_delete_grant(og); 475 } 476 477 mutex_exit(&ol->ol_mutex); 478 } 479 480 /* 481 * smb_oplock_wait_ack 482 * 483 * Timed wait for an oplock break acknowledgement (or oplock release). 484 */ 485 static void 486 smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout) 487 { 488 smb_oplock_t *ol; 489 clock_t time; 490 491 ol = &node->n_oplock; 492 mutex_enter(&ol->ol_mutex); 493 time = MSEC_TO_TICK(timeout) + ddi_get_lbolt(); 494 495 while (ol->ol_break != SMB_OPLOCK_NO_BREAK) { 496 if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) { 497 smb_oplock_timedout(node); 498 cv_broadcast(&ol->ol_cv); 499 break; 500 } 501 } 502 mutex_exit(&ol->ol_mutex); 503 } 504 505 /* 506 * smb_oplock_timedout 507 * 508 * An oplock break has not been acknowledged within timeout 509 * 'smb_oplock_timeout'. 510 * Set oplock grant to the desired break level. 511 */ 512 static void 513 smb_oplock_timedout(smb_node_t *node) 514 { 515 smb_oplock_t *ol; 516 smb_oplock_grant_t *og; 517 list_t *grants; 518 519 ol = &node->n_oplock; 520 grants = &ol->ol_grants; 521 522 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 523 524 og = smb_oplock_exclusive_grant(grants); 525 if (og) { 526 switch (ol->ol_break) { 527 case SMB_OPLOCK_BREAK_TO_NONE: 528 og->og_level = SMB_OPLOCK_NONE; 529 smb_oplock_remove_grant(node, og); 530 smb_oplock_delete_grant(og); 531 break; 532 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 533 og->og_level = SMB_OPLOCK_LEVEL_II; 534 break; 535 default: 536 SMB_PANIC(); 537 } 538 } 539 ol->ol_break = SMB_OPLOCK_NO_BREAK; 540 } 541 542 /* 543 * smb_oplock_release 544 * 545 * Release the oplock granted on ofile 'of'. 546 * Wake any threads waiting for an oplock break acknowledgement for 547 * this oplock. 548 * This is called when the ofile is being closed. 549 */ 550 void 551 smb_oplock_release(smb_node_t *node, smb_ofile_t *of) 552 { 553 smb_oplock_t *ol; 554 smb_oplock_grant_t *og; 555 list_t *grants; 556 557 ol = &node->n_oplock; 558 grants = &ol->ol_grants; 559 560 mutex_enter(&ol->ol_mutex); 561 smb_oplock_wait(node); 562 563 og = smb_oplock_find_grant(grants, of); 564 if (og) { 565 smb_oplock_remove_grant(node, og); 566 smb_oplock_delete_grant(og); 567 568 if (ol->ol_break != SMB_OPLOCK_NO_BREAK) { 569 ol->ol_break = SMB_OPLOCK_NO_BREAK; 570 cv_broadcast(&ol->ol_cv); 571 } 572 } 573 574 mutex_exit(&ol->ol_mutex); 575 } 576 577 /* 578 * smb_oplock_ack 579 * 580 * Process oplock acknowledgement received for ofile 'of'. 581 * - oplock.ol_break is the break level that was requested. 582 * - brk is the break level being acknowledged by the client. 583 * 584 * Update the oplock grant level to the lesser of ol_break and brk. 585 * If the grant is now SMB_OPLOCK_NONE, remove the grant from the 586 * oplock's grant list and delete it. 587 * If the requested break level (ol_break) was NONE and the brk is 588 * LEVEL_II, send another oplock break (NONE). Do not wait for an 589 * acknowledgement. 590 * Wake any threads waiting for the oplock break acknowledgement. 591 */ 592 void 593 smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk) 594 { 595 smb_oplock_t *ol; 596 smb_oplock_grant_t *og; 597 list_t *grants; 598 boolean_t brk_to_none = B_FALSE; 599 600 ol = &node->n_oplock; 601 grants = &ol->ol_grants; 602 603 mutex_enter(&ol->ol_mutex); 604 smb_oplock_wait(node); 605 606 if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) || 607 ((og = smb_oplock_find_grant(grants, of)) == NULL)) { 608 mutex_exit(&ol->ol_mutex); 609 return; 610 } 611 612 switch (brk) { 613 case SMB_OPLOCK_BREAK_TO_NONE: 614 og->og_level = SMB_OPLOCK_NONE; 615 break; 616 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 617 if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) { 618 og->og_level = SMB_OPLOCK_LEVEL_II; 619 } else { 620 /* SMB_OPLOCK_BREAK_TO_NONE */ 621 og->og_level = SMB_OPLOCK_NONE; 622 brk_to_none = B_TRUE; 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_delete_grant(og); 632 } 633 634 ol->ol_break = SMB_OPLOCK_NO_BREAK; 635 cv_broadcast(&ol->ol_cv); 636 637 if (brk_to_none) { 638 smb_session_oplock_break(of->f_session, 639 of->f_tree->t_tid, of->f_fid, 640 SMB_OPLOCK_BREAK_TO_NONE); 641 } 642 643 mutex_exit(&ol->ol_mutex); 644 } 645 646 /* 647 * smb_oplock_broadcast 648 * 649 * ol->ol_xthread identifies the thread that was performing an oplock 650 * acquire. Other threads may be blocked awaiting completion of the 651 * acquire. 652 * If the calling thread is ol_ol_xthread, wake any waiting threads. 653 */ 654 void 655 smb_oplock_broadcast(smb_node_t *node) 656 { 657 smb_oplock_t *ol; 658 659 SMB_NODE_VALID(node); 660 ol = &node->n_oplock; 661 662 mutex_enter(&ol->ol_mutex); 663 if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) { 664 ol->ol_xthread = NULL; 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_create_grant 694 */ 695 static smb_oplock_grant_t * 696 smb_oplock_create_grant(smb_ofile_t *of, uint8_t level) 697 { 698 smb_oplock_grant_t *og; 699 700 og = kmem_cache_alloc(smb_oplock_grant_cache, KM_SLEEP); 701 og->og_magic = SMB_OPLOCK_GRANT_MAGIC; 702 og->og_level = level; 703 og->og_ofile = of; 704 og->og_fid = of->f_fid; 705 og->og_tid = of->f_tree->t_tid; 706 og->og_uid = of->f_user->u_uid; 707 og->og_session = of->f_session; 708 return (og); 709 } 710 711 /* 712 * smb_oplock_delete_grant 713 */ 714 void 715 smb_oplock_delete_grant(smb_oplock_grant_t *og) 716 { 717 kmem_cache_free(smb_oplock_grant_cache, og); 718 } 719 720 /* 721 * smb_oplock_insert_grant 722 * 723 * If there are no grants in the oplock's list install the fem 724 * monitor. 725 * Insert the grant into the list and increment the grant count. 726 */ 727 static int 728 smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og) 729 { 730 smb_oplock_t *ol = &node->n_oplock; 731 732 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 733 734 if (ol->ol_count == 0) { 735 if (smb_oplock_install_fem(node) != 0) 736 return (-1); 737 } 738 739 list_insert_tail(&ol->ol_grants, og); 740 ++ol->ol_count; 741 return (0); 742 } 743 744 /* 745 * smb_oplock_remove_grant 746 * 747 * Remove the oplock grant from the list, decrement the grant count 748 * and, if there are no other grants in the list, uninstall the fem 749 * monitor. 750 */ 751 static void 752 smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og) 753 { 754 smb_oplock_t *ol = &node->n_oplock; 755 756 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 757 ASSERT(ol->ol_count > 0); 758 759 list_remove(&ol->ol_grants, og); 760 if (--ol->ol_count == 0) 761 smb_oplock_uninstall_fem(node); 762 } 763 764 /* 765 * smb_oplock_exclusive_grant 766 * 767 * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists, 768 * return it. Otherwise return NULL. 769 */ 770 static smb_oplock_grant_t * 771 smb_oplock_exclusive_grant(list_t *grants) 772 { 773 smb_oplock_grant_t *og; 774 775 og = list_head(grants); 776 if (og) { 777 SMB_OPLOCK_GRANT_VALID(og); 778 if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 779 return (og); 780 } 781 return (NULL); 782 } 783 784 /* 785 * smb_oplock_find_grant 786 * 787 * Find oplock grant corresponding to the specified ofile. 788 */ 789 static smb_oplock_grant_t * 790 smb_oplock_find_grant(list_t *grants, smb_ofile_t *ofile) 791 { 792 smb_oplock_grant_t *og = NULL; 793 794 for (og = list_head(grants); 795 og != NULL; 796 og = list_next(grants, og)) { 797 SMB_OPLOCK_GRANT_VALID(og); 798 if (og->og_ofile == ofile) 799 break; 800 } 801 return (og); 802 } 803 804 /* 805 * smb_oplock_create_break 806 */ 807 static smb_oplock_break_t * 808 smb_oplock_create_break(smb_node_t *node) 809 { 810 smb_oplock_break_t *ob; 811 812 ob = kmem_cache_alloc(smb_oplock_break_cache, KM_SLEEP); 813 814 smb_node_ref(node); 815 ob->ob_magic = SMB_OPLOCK_BREAK_MAGIC; 816 ob->ob_node = node; 817 818 return (ob); 819 } 820 821 /* 822 * smb_oplock_delete_break 823 */ 824 static void 825 smb_oplock_delete_break(smb_oplock_break_t *ob) 826 { 827 smb_node_release(ob->ob_node); 828 kmem_cache_free(smb_oplock_break_cache, ob); 829 } 830