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, NULL, 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 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 218 op = &sr->sr_open; 219 tree = SMB_OFILE_GET_TREE(ofile); 220 session = SMB_OFILE_GET_SESSION(ofile); 221 222 if (!smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) || 223 (op->op_oplock_level == SMB_OPLOCK_NONE) || 224 ((op->op_oplock_level == SMB_OPLOCK_BATCH) && 225 SMB_IS_STREAM(node))) { 226 op->op_oplock_level = SMB_OPLOCK_NONE; 227 return; 228 } 229 230 ol = &node->n_oplock; 231 grants = &ol->ol_grants; 232 233 mutex_enter(&ol->ol_mutex); 234 smb_oplock_wait(node); 235 236 nbl_start_crit(node->vp, RW_READER); 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 if ((!op->op_oplock_levelII) || 242 (!smb_session_levelII_oplocks(session)) || 243 (smb_oplock_exclusive_grant(grants) != NULL) || 244 (smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE) != 0)) { 245 op->op_oplock_level = SMB_OPLOCK_NONE; 246 nbl_end_crit(node->vp); 247 mutex_exit(&ol->ol_mutex); 248 return; 249 } 250 251 op->op_oplock_level = SMB_OPLOCK_LEVEL_II; 252 } 253 254 nbl_end_crit(node->vp); 255 256 og = smb_oplock_set_grant(ofile, op->op_oplock_level); 257 if (smb_oplock_insert_grant(node, og) != 0) { 258 smb_oplock_clear_grant(og); 259 op->op_oplock_level = SMB_OPLOCK_NONE; 260 mutex_exit(&ol->ol_mutex); 261 return; 262 } 263 264 ol->ol_xthread = curthread; 265 mutex_exit(&ol->ol_mutex); 266 } 267 268 /* 269 * smb_oplock_break 270 * 271 * Break granted oplocks according to the following rules: 272 * 273 * If there's an exclusive oplock granted on the node 274 * - if the BREAK_BATCH flags is specified and the oplock is not 275 * a batch oplock, no break is required. 276 * - if the session doesn't support LEVEL II oplocks, and 'brk' is 277 * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE. 278 * - if the oplock is already breaking update the break level (if 279 * the requested break is to a lesser level), otherwise send an 280 * oplock break. 281 * Wait for acknowledgement of the break (unless NOWAIT flag is set) 282 * 283 * Otherwise: 284 * If there are level II oplocks granted on the node, and the flags 285 * indicate that they should be broken (BREAK_TO_NONE specified, 286 * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII 287 * break request for asynchronous processing. 288 * 289 * Returns: 290 * 0 - oplock broken (or no break required) 291 * EAGAIN - oplock break request sent and would block 292 * awaiting the reponse but NOWAIT was specified 293 */ 294 int 295 smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags) 296 { 297 smb_oplock_t *ol; 298 smb_oplock_grant_t *og; 299 list_t *grants; 300 uint32_t timeout; 301 uint8_t brk; 302 303 SMB_NODE_VALID(node); 304 ol = &node->n_oplock; 305 grants = &ol->ol_grants; 306 307 mutex_enter(&ol->ol_mutex); 308 smb_oplock_wait(node); 309 310 og = list_head(grants); 311 if (og == NULL) { 312 mutex_exit(&ol->ol_mutex); 313 return (0); 314 } 315 316 SMB_OPLOCK_GRANT_VALID(og); 317 318 /* break levelII oplocks */ 319 if (og->og_level == SMB_OPLOCK_LEVEL_II) { 320 mutex_exit(&ol->ol_mutex); 321 322 if ((flags & SMB_OPLOCK_BREAK_TO_NONE) && 323 !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) && 324 !(flags & SMB_OPLOCK_BREAK_BATCH)) { 325 smb_oplock_break_levelII(node); 326 } 327 return (0); 328 } 329 330 /* break exclusive oplock */ 331 if ((flags & SMB_OPLOCK_BREAK_BATCH) && 332 (og->og_level != SMB_OPLOCK_BATCH)) { 333 mutex_exit(&ol->ol_mutex); 334 return (0); 335 } 336 337 if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) && 338 smb_session_levelII_oplocks(og->og_session)) { 339 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; 340 } else { 341 brk = SMB_OPLOCK_BREAK_TO_NONE; 342 } 343 344 switch (ol->ol_break) { 345 case SMB_OPLOCK_NO_BREAK: 346 ol->ol_break = brk; 347 smb_session_oplock_break(og->og_session, 348 og->og_tid, og->og_fid, brk); 349 break; 350 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 351 if (brk == SMB_OPLOCK_BREAK_TO_NONE) 352 ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE; 353 break; 354 case SMB_OPLOCK_BREAK_TO_NONE: 355 default: 356 break; 357 } 358 359 if (flags & SMB_OPLOCK_BREAK_NOWAIT) { 360 mutex_exit(&ol->ol_mutex); 361 return (EAGAIN); 362 } 363 364 if (sr && (sr->session == og->og_session) && 365 (sr->smb_uid == og->og_uid)) { 366 timeout = smb_oplock_min_timeout; 367 } else { 368 timeout = smb_oplock_timeout; 369 } 370 371 mutex_exit(&ol->ol_mutex); 372 smb_oplock_wait_ack(node, timeout); 373 return (0); 374 } 375 376 /* 377 * smb_oplock_break_levelII 378 * 379 * LevelII (shared) oplock breaks are processed asynchronously. 380 * Unlike exclusive oplock breaks, the thread initiating the break 381 * is NOT blocked while the request is processed. 382 * 383 * Create an oplock_break_request and add it to the list for async 384 * processing. 385 */ 386 void 387 smb_oplock_break_levelII(smb_node_t *node) 388 { 389 smb_oplock_break_t *ob; 390 391 ob = smb_oplock_create_break(node); 392 393 smb_llist_enter(&smb_oplock_breaks, RW_WRITER); 394 smb_llist_insert_tail(&smb_oplock_breaks, ob); 395 smb_llist_exit(&smb_oplock_breaks); 396 397 smb_thread_signal(&smb_oplock_thread); 398 } 399 400 /* 401 * smb_oplock_break_thread 402 * 403 * The smb_oplock_thread is woken when an oplock break request is 404 * added to the list of pending levelII oplock break requests. 405 * Gets the oplock break request from the list, processes it and 406 * deletes it. 407 */ 408 /*ARGSUSED*/ 409 static void 410 smb_oplock_break_thread(smb_thread_t *thread, void *arg) 411 { 412 smb_oplock_break_t *ob; 413 414 while (smb_thread_continue(thread)) { 415 while ((ob = smb_oplock_get_break()) != NULL) { 416 smb_oplock_process_levelII_break(ob->ob_node); 417 smb_oplock_delete_break(ob); 418 } 419 } 420 } 421 422 /* 423 * smb_oplock_get_break 424 * 425 * Remove and return the next oplock break request from the list 426 */ 427 static smb_oplock_break_t * 428 smb_oplock_get_break(void) 429 { 430 smb_oplock_break_t *ob; 431 432 smb_llist_enter(&smb_oplock_breaks, RW_WRITER); 433 if ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) { 434 SMB_OPLOCK_BREAK_VALID(ob); 435 smb_llist_remove(&smb_oplock_breaks, ob); 436 } 437 smb_llist_exit(&smb_oplock_breaks); 438 return (ob); 439 } 440 441 /* 442 * smb_oplock_process_levelII_break 443 */ 444 void 445 smb_oplock_process_levelII_break(smb_node_t *node) 446 { 447 smb_oplock_t *ol; 448 smb_oplock_grant_t *og; 449 list_t *grants; 450 451 if (!smb_oplock_levelII) 452 return; 453 454 ol = &node->n_oplock; 455 mutex_enter(&ol->ol_mutex); 456 smb_oplock_wait(node); 457 grants = &node->n_oplock.ol_grants; 458 459 while ((og = list_head(grants)) != NULL) { 460 SMB_OPLOCK_GRANT_VALID(og); 461 462 if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 463 break; 464 465 smb_session_oplock_break(og->og_session, 466 og->og_tid, og->og_fid, SMB_OPLOCK_BREAK_TO_NONE); 467 smb_oplock_remove_grant(node, og); 468 smb_oplock_clear_grant(og); 469 } 470 471 mutex_exit(&ol->ol_mutex); 472 } 473 474 /* 475 * smb_oplock_wait_ack 476 * 477 * Timed wait for an oplock break acknowledgement (or oplock release). 478 */ 479 static void 480 smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout) 481 { 482 smb_oplock_t *ol; 483 clock_t time; 484 485 ol = &node->n_oplock; 486 mutex_enter(&ol->ol_mutex); 487 time = MSEC_TO_TICK(timeout) + ddi_get_lbolt(); 488 489 while (ol->ol_break != SMB_OPLOCK_NO_BREAK) { 490 if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) { 491 smb_oplock_timedout(node); 492 cv_broadcast(&ol->ol_cv); 493 break; 494 } 495 } 496 mutex_exit(&ol->ol_mutex); 497 } 498 499 /* 500 * smb_oplock_timedout 501 * 502 * An oplock break has not been acknowledged within timeout 503 * 'smb_oplock_timeout'. 504 * Set oplock grant to the desired break level. 505 */ 506 static void 507 smb_oplock_timedout(smb_node_t *node) 508 { 509 smb_oplock_t *ol; 510 smb_oplock_grant_t *og; 511 list_t *grants; 512 513 ol = &node->n_oplock; 514 grants = &ol->ol_grants; 515 516 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 517 518 og = smb_oplock_exclusive_grant(grants); 519 if (og) { 520 switch (ol->ol_break) { 521 case SMB_OPLOCK_BREAK_TO_NONE: 522 og->og_level = SMB_OPLOCK_NONE; 523 smb_oplock_remove_grant(node, og); 524 smb_oplock_clear_grant(og); 525 break; 526 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 527 og->og_level = SMB_OPLOCK_LEVEL_II; 528 break; 529 default: 530 SMB_PANIC(); 531 } 532 } 533 ol->ol_break = SMB_OPLOCK_NO_BREAK; 534 } 535 536 /* 537 * smb_oplock_release 538 * 539 * Release the oplock granted on ofile 'of'. 540 * Wake any threads waiting for an oplock break acknowledgement for 541 * this oplock. 542 * This is called when the ofile is being closed. 543 */ 544 void 545 smb_oplock_release(smb_node_t *node, smb_ofile_t *of) 546 { 547 smb_oplock_t *ol; 548 smb_oplock_grant_t *og; 549 550 ol = &node->n_oplock; 551 mutex_enter(&ol->ol_mutex); 552 smb_oplock_wait(node); 553 554 og = smb_oplock_get_grant(ol, of); 555 if (og) { 556 smb_oplock_remove_grant(node, og); 557 smb_oplock_clear_grant(og); 558 559 if (ol->ol_break != SMB_OPLOCK_NO_BREAK) { 560 ol->ol_break = SMB_OPLOCK_NO_BREAK; 561 cv_broadcast(&ol->ol_cv); 562 } 563 } 564 565 mutex_exit(&ol->ol_mutex); 566 } 567 568 /* 569 * smb_oplock_ack 570 * 571 * Process oplock acknowledgement received for ofile 'of'. 572 * - oplock.ol_break is the break level that was requested. 573 * - brk is the break level being acknowledged by the client. 574 * 575 * Update the oplock grant level to the lesser of ol_break and brk. 576 * If the grant is now SMB_OPLOCK_NONE, remove the grant from the 577 * oplock's grant list and delete it. 578 * If the requested break level (ol_break) was NONE and the brk is 579 * LEVEL_II, send another oplock break (NONE). Do not wait for an 580 * acknowledgement. 581 * Wake any threads waiting for the oplock break acknowledgement. 582 */ 583 void 584 smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk) 585 { 586 smb_oplock_t *ol; 587 smb_oplock_grant_t *og; 588 boolean_t brk_to_none = B_FALSE; 589 590 ol = &node->n_oplock; 591 mutex_enter(&ol->ol_mutex); 592 smb_oplock_wait(node); 593 594 if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) || 595 ((og = smb_oplock_get_grant(ol, of)) == NULL)) { 596 mutex_exit(&ol->ol_mutex); 597 return; 598 } 599 600 switch (brk) { 601 case SMB_OPLOCK_BREAK_TO_NONE: 602 og->og_level = SMB_OPLOCK_NONE; 603 break; 604 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 605 if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) { 606 og->og_level = SMB_OPLOCK_LEVEL_II; 607 } else { 608 /* SMB_OPLOCK_BREAK_TO_NONE */ 609 og->og_level = SMB_OPLOCK_NONE; 610 brk_to_none = B_TRUE; 611 } 612 break; 613 default: 614 SMB_PANIC(); 615 } 616 617 if (og->og_level == SMB_OPLOCK_NONE) { 618 smb_oplock_remove_grant(node, og); 619 smb_oplock_clear_grant(og); 620 } 621 622 ol->ol_break = SMB_OPLOCK_NO_BREAK; 623 cv_broadcast(&ol->ol_cv); 624 625 if (brk_to_none) { 626 smb_session_oplock_break(of->f_session, 627 of->f_tree->t_tid, of->f_fid, 628 SMB_OPLOCK_BREAK_TO_NONE); 629 } 630 631 mutex_exit(&ol->ol_mutex); 632 } 633 634 /* 635 * smb_oplock_broadcast 636 * 637 * ol->ol_xthread identifies the thread that was performing an oplock 638 * acquire. Other threads may be blocked awaiting completion of the 639 * acquire. 640 * If the calling thread is ol_ol_xthread, wake any waiting threads. 641 */ 642 void 643 smb_oplock_broadcast(smb_node_t *node) 644 { 645 smb_oplock_t *ol; 646 647 SMB_NODE_VALID(node); 648 ol = &node->n_oplock; 649 650 mutex_enter(&ol->ol_mutex); 651 if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) { 652 ol->ol_xthread = NULL; 653 cv_broadcast(&ol->ol_cv); 654 } 655 mutex_exit(&ol->ol_mutex); 656 } 657 658 /* 659 * smb_oplock_wait 660 * 661 * Wait for the completion of an oplock acquire. 662 * If ol_xthread is not NULL and doesn't contain the pointer to the 663 * context of the calling thread, the caller will sleep until the 664 * ol_xthread is reset to NULL (via smb_oplock_broadcast()). 665 */ 666 static void 667 smb_oplock_wait(smb_node_t *node) 668 { 669 smb_oplock_t *ol; 670 671 ol = &node->n_oplock; 672 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 673 674 if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) { 675 while (ol->ol_xthread != NULL) 676 cv_wait(&ol->ol_cv, &ol->ol_mutex); 677 } 678 } 679 680 /* 681 * smb_oplock_set_grant 682 */ 683 static smb_oplock_grant_t * 684 smb_oplock_set_grant(smb_ofile_t *of, uint8_t level) 685 { 686 smb_oplock_grant_t *og; 687 688 og = &of->f_oplock_grant; 689 690 og->og_magic = SMB_OPLOCK_GRANT_MAGIC; 691 og->og_level = level; 692 og->og_ofile = of; 693 og->og_fid = of->f_fid; 694 og->og_tid = of->f_tree->t_tid; 695 og->og_uid = of->f_user->u_uid; 696 og->og_session = of->f_session; 697 return (og); 698 } 699 700 /* 701 * smb_oplock_clear_grant 702 */ 703 void 704 smb_oplock_clear_grant(smb_oplock_grant_t *og) 705 { 706 bzero(og, sizeof (smb_oplock_grant_t)); 707 } 708 709 /* 710 * smb_oplock_insert_grant 711 * 712 * If there are no grants in the oplock's list install the fem 713 * monitor. 714 * Insert the grant into the list and increment the grant count. 715 */ 716 static int 717 smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og) 718 { 719 smb_oplock_t *ol = &node->n_oplock; 720 721 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 722 723 if (ol->ol_count == 0) { 724 if (smb_oplock_install_fem(node) != 0) 725 return (-1); 726 } 727 728 list_insert_tail(&ol->ol_grants, og); 729 ++ol->ol_count; 730 return (0); 731 } 732 733 /* 734 * smb_oplock_remove_grant 735 * 736 * Remove the oplock grant from the list, decrement the grant count 737 * and, if there are no other grants in the list, uninstall the fem 738 * monitor. 739 */ 740 static void 741 smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og) 742 { 743 smb_oplock_t *ol = &node->n_oplock; 744 745 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 746 ASSERT(ol->ol_count > 0); 747 748 list_remove(&ol->ol_grants, og); 749 if (--ol->ol_count == 0) 750 smb_oplock_uninstall_fem(node); 751 } 752 753 /* 754 * smb_oplock_exclusive_grant 755 * 756 * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists, 757 * return it. Otherwise return NULL. 758 */ 759 static smb_oplock_grant_t * 760 smb_oplock_exclusive_grant(list_t *grants) 761 { 762 smb_oplock_grant_t *og; 763 764 og = list_head(grants); 765 if (og) { 766 SMB_OPLOCK_GRANT_VALID(og); 767 if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 768 return (og); 769 } 770 return (NULL); 771 } 772 773 /* 774 * smb_oplock_get_grant 775 * 776 * Find oplock grant corresponding to the specified ofile. 777 */ 778 static smb_oplock_grant_t * 779 smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile) 780 { 781 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 782 783 if (SMB_OFILE_OPLOCK_GRANTED(ofile)) 784 return (&ofile->f_oplock_grant); 785 else 786 return (NULL); 787 } 788 789 /* 790 * smb_oplock_create_break 791 */ 792 static smb_oplock_break_t * 793 smb_oplock_create_break(smb_node_t *node) 794 { 795 smb_oplock_break_t *ob; 796 797 ob = kmem_cache_alloc(smb_oplock_break_cache, KM_SLEEP); 798 799 smb_node_ref(node); 800 ob->ob_magic = SMB_OPLOCK_BREAK_MAGIC; 801 ob->ob_node = node; 802 803 return (ob); 804 } 805 806 /* 807 * smb_oplock_delete_break 808 */ 809 static void 810 smb_oplock_delete_break(smb_oplock_break_t *ob) 811 { 812 smb_node_release(ob->ob_node); 813 kmem_cache_free(smb_oplock_break_cache, ob); 814 } 815