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