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