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