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