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 * Copyright 2014 Nexenta Systems, Inc. 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 void smb_oplock_sched_async_break(smb_oplock_grant_t *, uint8_t); 64 static void smb_oplock_exec_async_break(void *); 65 static void smb_oplock_break_levelII_locked(smb_node_t *); 66 67 /* 68 * smb_oplock_install_fem 69 * Install fem monitor for cross protocol oplock breaking. 70 */ 71 static int 72 smb_oplock_install_fem(smb_node_t *node) 73 { 74 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 75 76 if (node->n_oplock.ol_fem == B_FALSE) { 77 if (smb_fem_oplock_install(node) != 0) { 78 cmn_err(CE_NOTE, "No oplock granted: " 79 "failed to install fem monitor %s", 80 node->vp->v_path); 81 return (-1); 82 } 83 node->n_oplock.ol_fem = B_TRUE; 84 } 85 return (0); 86 } 87 88 /* 89 * smb_oplock_uninstall_fem 90 * Uninstall fem monitor for cross protocol oplock breaking. 91 */ 92 static void 93 smb_oplock_uninstall_fem(smb_node_t *node) 94 { 95 ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 96 97 if (node->n_oplock.ol_fem) { 98 smb_fem_oplock_uninstall(node); 99 node->n_oplock.ol_fem = B_FALSE; 100 } 101 } 102 103 /* 104 * This provides a way to fully disable oplocks, i.e. for testing. 105 * You _really_ do _not_ want to turn this off, because if you do, 106 * the clients send you very small read requests, and a _lot_ more 107 * of them. The skc_oplock_enable parameter can be used to enable 108 * or disable exclusive oplocks. Disabling that can be helpful 109 * when there are clients not responding to oplock breaks. 110 */ 111 int smb_oplocks_enabled = 1; 112 113 /* 114 * smb_oplock_acquire 115 * 116 * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH, 117 * but might only be granted LEVEL_II or NONE. 118 * 119 * If oplocks are not supported on the tree, or node, grant NONE. 120 * If nobody else has the file open, grant the requested level. 121 * If any of the following are true, grant NONE: 122 * - there is an exclusive oplock on the node 123 * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd. 124 * - LEVEL_II oplocks are not supported for the session 125 * - a BATCH oplock is requested on a named stream 126 * - there are any range locks on the node (SMB writers) 127 * Otherwise, grant LEVEL_II. 128 * 129 * ol->ol_xthread is set to the current thread to lock the oplock against 130 * other operations until the acquire response is on the wire. When the 131 * acquire response is on the wire, smb_oplock_broadcast() is called to 132 * reset ol->ol_xthread and wake any waiting threads. 133 */ 134 void 135 smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile) 136 { 137 smb_oplock_t *ol; 138 smb_oplock_grant_t *og; 139 list_t *grants; 140 smb_arg_open_t *op; 141 smb_tree_t *tree; 142 smb_session_t *session; 143 144 SMB_NODE_VALID(node); 145 SMB_OFILE_VALID(ofile); 146 147 ASSERT(node == SMB_OFILE_GET_NODE(ofile)); 148 ASSERT(RW_LOCK_HELD(&node->n_lock)); 149 150 op = &sr->sr_open; 151 tree = SMB_OFILE_GET_TREE(ofile); 152 session = SMB_OFILE_GET_SESSION(ofile); 153 154 if (smb_oplocks_enabled == 0 || 155 (op->op_oplock_level == SMB_OPLOCK_NONE) || 156 ((op->op_oplock_level == SMB_OPLOCK_BATCH) && 157 SMB_IS_STREAM(node))) { 158 op->op_oplock_level = SMB_OPLOCK_NONE; 159 return; 160 } 161 162 ol = &node->n_oplock; 163 grants = &ol->ol_grants; 164 165 mutex_enter(&ol->ol_mutex); 166 smb_oplock_wait(node); 167 168 /* 169 * Even if there are no other opens, we might want to 170 * grant only a Level II (shared) oplock so we avoid 171 * ever granting exclusive oplocks. 172 * 173 * Borrowing the SMB_TREE_OPLOCKS flag to enable/disable 174 * exclusive oplocks (for now). See skc_oplock_enable, 175 * which can now be taken as "exclusive oplock enable". 176 * Should rename this parameter, and/or implement a new 177 * multi-valued parameter for oplock enables. 178 */ 179 if ((node->n_open_count > 1) || 180 (node->n_opening_count > 1) || 181 !smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) || 182 smb_vop_other_opens(node->vp, ofile->f_mode)) { 183 /* 184 * There are other opens. 185 */ 186 if ((!op->op_oplock_levelII) || 187 (!smb_session_levelII_oplocks(session)) || 188 (smb_oplock_exclusive_grant(grants) != NULL) || 189 (smb_lock_range_access(sr, node, 0, 0, B_FALSE))) { 190 /* 191 * LevelII (shared) oplock not allowed, 192 * so reply with "none". 193 */ 194 op->op_oplock_level = SMB_OPLOCK_NONE; 195 mutex_exit(&ol->ol_mutex); 196 return; 197 } 198 199 op->op_oplock_level = SMB_OPLOCK_LEVEL_II; 200 } 201 202 og = smb_oplock_set_grant(ofile, op->op_oplock_level); 203 if (smb_oplock_insert_grant(node, og) != 0) { 204 smb_oplock_clear_grant(og); 205 op->op_oplock_level = SMB_OPLOCK_NONE; 206 mutex_exit(&ol->ol_mutex); 207 return; 208 } 209 210 ol->ol_xthread = curthread; 211 mutex_exit(&ol->ol_mutex); 212 } 213 214 /* 215 * smb_oplock_break 216 * 217 * Break granted oplocks according to the following rules: 218 * 219 * If there's an exclusive oplock granted on the node 220 * - if the BREAK_BATCH flags is specified and the oplock is not 221 * a batch oplock, no break is required. 222 * - if the session doesn't support LEVEL II oplocks, and 'brk' is 223 * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE. 224 * - if the oplock is already breaking update the break level (if 225 * the requested break is to a lesser level), otherwise send an 226 * oplock break. 227 * Wait for acknowledgement of the break (unless NOWAIT flag is set) 228 * 229 * Otherwise: 230 * If there are level II oplocks granted on the node, and the flags 231 * indicate that they should be broken (BREAK_TO_NONE specified, 232 * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII 233 * break request for asynchronous processing. 234 * 235 * Returns: 236 * 0 - oplock broken (or no break required) 237 * EAGAIN - oplock break request sent and would block 238 * awaiting the reponse but NOWAIT was specified 239 * 240 * NB: sr == NULL when called by FEM framework. 241 */ 242 int 243 smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags) 244 { 245 smb_oplock_t *ol; 246 smb_oplock_grant_t *og; 247 list_t *grants; 248 uint32_t timeout; 249 uint8_t brk; 250 251 SMB_NODE_VALID(node); 252 ol = &node->n_oplock; 253 grants = &ol->ol_grants; 254 255 mutex_enter(&ol->ol_mutex); 256 smb_oplock_wait(node); 257 258 og = list_head(grants); 259 if (og == NULL) { 260 mutex_exit(&ol->ol_mutex); 261 return (0); 262 } 263 264 SMB_OPLOCK_GRANT_VALID(og); 265 266 /* break levelII oplocks */ 267 if (og->og_level == SMB_OPLOCK_LEVEL_II) { 268 mutex_exit(&ol->ol_mutex); 269 270 if ((flags & SMB_OPLOCK_BREAK_TO_NONE) && 271 !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) && 272 !(flags & SMB_OPLOCK_BREAK_BATCH)) { 273 smb_oplock_break_levelII(node); 274 } 275 return (0); 276 } 277 278 /* break exclusive oplock */ 279 if ((flags & SMB_OPLOCK_BREAK_BATCH) && 280 (og->og_level != SMB_OPLOCK_BATCH)) { 281 mutex_exit(&ol->ol_mutex); 282 return (0); 283 } 284 285 if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) && 286 smb_session_levelII_oplocks(og->og_session)) { 287 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; 288 } else { 289 brk = SMB_OPLOCK_BREAK_TO_NONE; 290 } 291 292 switch (ol->ol_break) { 293 case SMB_OPLOCK_NO_BREAK: 294 ol->ol_break = brk; 295 smb_oplock_sched_async_break(og, brk); 296 break; 297 case SMB_OPLOCK_BREAK_TO_LEVEL_II: 298 if (brk == SMB_OPLOCK_BREAK_TO_NONE) 299 ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE; 300 break; 301 case SMB_OPLOCK_BREAK_TO_NONE: 302 default: 303 break; 304 } 305 306 if (flags & SMB_OPLOCK_BREAK_NOWAIT) { 307 mutex_exit(&ol->ol_mutex); 308 return (EAGAIN); 309 } 310 311 if (sr && (sr->session == og->og_session) && 312 (sr->smb_uid == og->og_uid)) { 313 timeout = smb_oplock_min_timeout; 314 } else { 315 timeout = smb_oplock_timeout; 316 } 317 318 mutex_exit(&ol->ol_mutex); 319 smb_oplock_wait_ack(node, timeout); 320 return (0); 321 } 322 323 /* 324 * smb_oplock_break_levelII 325 * 326 * This is called after a file is modified in some way. If there are 327 * LevelII (shared) oplocks, break those to none. If there is an 328 * exclusive oplock, there can be no LevelII oplocks, so do nothing. 329 * 330 * LevelII (shared) oplock breaks are processed asynchronously. 331 * Unlike exclusive oplock breaks, the thread initiating the break 332 * is NOT blocked while the request is processed. 333 * 334 * There may be a thread with exclusive rights to oplock state for 335 * this node (via ol_xthread in smb_oplock_wait) and if so, we must 336 * avoid breaking oplocks until that's out of the way. However, we 337 * really don't want to block here, so when ol_xthread is set, we'll 338 * just mark that a "break level II to none" is pending, and let the 339 * exclusive thread do this work when it's done being exclusive. 340 */ 341 void 342 smb_oplock_break_levelII(smb_node_t *node) 343 { 344 smb_oplock_t *ol; 345 346 ol = &node->n_oplock; 347 mutex_enter(&ol->ol_mutex); 348 349 /* Instead of: smb_oplock_wait() ... */ 350 if (ol->ol_xthread != NULL) { 351 /* Defer the call to smb_oplock_broadcast(). */ 352 ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE; 353 } else { 354 /* Equivalent of smb_oplock_wait() done. */ 355 smb_oplock_break_levelII_locked(node); 356 } 357 358 mutex_exit(&ol->ol_mutex); 359 } 360 361 /* 362 * smb_oplock_break_levelII_locked 363 * Internal helper for smb_oplock_break_levelII() 364 * 365 * Called with the oplock mutex already held, and _after_ 366 * (the equivalent of) an smb_oplock_wait(). 367 */ 368 static void 369 smb_oplock_break_levelII_locked(smb_node_t *node) 370 { 371 smb_oplock_t *ol; 372 smb_oplock_grant_t *og; 373 list_t *grants; 374 375 ol = &node->n_oplock; 376 grants = &ol->ol_grants; 377 378 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 379 ASSERT(ol->ol_xthread == NULL); 380 381 while ((og = list_head(grants)) != NULL) { 382 SMB_OPLOCK_GRANT_VALID(og); 383 384 /* 385 * If there's an exclusive oplock, there are 386 * no LevelII oplocks, so do nothing. 387 */ 388 if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 389 break; 390 391 smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE); 392 smb_oplock_remove_grant(node, og); 393 smb_oplock_clear_grant(og); 394 } 395 } 396 397 /* 398 * Schedule a call to smb_session_oplock_break 399 * using an smb_request on the owning session. 400 */ 401 static void 402 smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk) 403 { 404 smb_request_t *sr; 405 smb_ofile_t *ofile; 406 407 /* 408 * Make sure we can get a hold on the ofile. If we can't, 409 * the file is closing, and there's no point scheduling an 410 * oplock break on it. (Also hold the tree and user.) 411 * These holds account for the pointers we copy into the 412 * smb_request fields: fid_ofile, tid_tree, uid_user. 413 * These holds are released via smb_request_free after 414 * the oplock break has been sent. 415 */ 416 ofile = og->og_ofile; 417 if (!smb_ofile_hold(ofile)) 418 return; 419 smb_tree_hold_internal(ofile->f_tree); 420 smb_user_hold_internal(ofile->f_user); 421 422 sr = smb_request_alloc(og->og_session, 0); 423 sr->sr_state = SMB_REQ_STATE_SUBMITTED; 424 sr->user_cr = zone_kcred(); 425 sr->fid_ofile = ofile; 426 sr->tid_tree = ofile->f_tree; 427 sr->uid_user = ofile->f_user; 428 429 sr->arg.olbrk = *og; /* struct copy */ 430 sr->arg.olbrk.og_breaking = brk; 431 432 (void) taskq_dispatch( 433 sr->sr_server->sv_worker_pool, 434 smb_oplock_exec_async_break, sr, TQ_SLEEP); 435 } 436 437 /* 438 * smb_oplock_exec_async_break 439 * 440 * Called via the taskq to handle an asynchronous oplock break. 441 * We have a hold on the ofile, which keeps the FID here valid. 442 */ 443 static void 444 smb_oplock_exec_async_break(void *arg) 445 { 446 smb_request_t *sr = arg; 447 smb_oplock_grant_t *og = &sr->arg.olbrk; 448 449 SMB_REQ_VALID(sr); 450 SMB_OPLOCK_GRANT_VALID(og); 451 452 mutex_enter(&sr->sr_mutex); 453 sr->sr_worker = curthread; 454 sr->sr_time_active = gethrtime(); 455 456 switch (sr->sr_state) { 457 case SMB_REQ_STATE_SUBMITTED: 458 sr->sr_state = SMB_REQ_STATE_ACTIVE; 459 mutex_exit(&sr->sr_mutex); 460 461 /* 462 * This is where we actually do the deferred work 463 * requested by smb_oplock_sched_async_break(). 464 */ 465 smb_session_oplock_break(sr, og->og_breaking); 466 467 mutex_enter(&sr->sr_mutex); 468 /* FALLTHROUGH */ 469 470 default: /* typically cancelled */ 471 sr->sr_state = SMB_REQ_STATE_COMPLETED; 472 mutex_exit(&sr->sr_mutex); 473 } 474 475 smb_request_free(sr); 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 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 smb_oplock_sched_async_break(og, 614 SMB_OPLOCK_BREAK_TO_NONE); 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 mutex_exit(&ol->ol_mutex); 630 } 631 632 /* 633 * smb_oplock_broadcast 634 * 635 * Called when an open with oplock request completes. 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_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 if (ol->ol_brk_pending) { 654 ol->ol_brk_pending = 0; 655 smb_oplock_break_levelII_locked(node); 656 } 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_breaking = 0; 696 og->og_level = level; 697 og->og_ofile = of; 698 og->og_fid = of->f_fid; 699 og->og_tid = of->f_tree->t_tid; 700 og->og_uid = of->f_user->u_uid; 701 og->og_session = of->f_session; 702 return (og); 703 } 704 705 /* 706 * smb_oplock_clear_grant 707 */ 708 void 709 smb_oplock_clear_grant(smb_oplock_grant_t *og) 710 { 711 bzero(og, sizeof (smb_oplock_grant_t)); 712 } 713 714 /* 715 * smb_oplock_insert_grant 716 * 717 * If there are no grants in the oplock's list install the fem 718 * monitor. 719 * Insert the grant into the list and increment the grant count. 720 */ 721 static int 722 smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og) 723 { 724 smb_oplock_t *ol = &node->n_oplock; 725 726 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 727 728 if (ol->ol_count == 0) { 729 if (smb_oplock_install_fem(node) != 0) 730 return (-1); 731 } 732 733 list_insert_tail(&ol->ol_grants, og); 734 ++ol->ol_count; 735 return (0); 736 } 737 738 /* 739 * smb_oplock_remove_grant 740 * 741 * Remove the oplock grant from the list, decrement the grant count 742 * and, if there are no other grants in the list, uninstall the fem 743 * monitor. 744 */ 745 static void 746 smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og) 747 { 748 smb_oplock_t *ol = &node->n_oplock; 749 750 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 751 ASSERT(ol->ol_count > 0); 752 753 list_remove(&ol->ol_grants, og); 754 if (--ol->ol_count == 0) 755 smb_oplock_uninstall_fem(node); 756 } 757 758 /* 759 * smb_oplock_exclusive_grant 760 * 761 * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists, 762 * return it. Otherwise return NULL. 763 */ 764 static smb_oplock_grant_t * 765 smb_oplock_exclusive_grant(list_t *grants) 766 { 767 smb_oplock_grant_t *og; 768 769 og = list_head(grants); 770 if (og) { 771 SMB_OPLOCK_GRANT_VALID(og); 772 if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 773 return (og); 774 } 775 return (NULL); 776 } 777 778 /* 779 * smb_oplock_get_grant 780 * 781 * Find oplock grant corresponding to the specified ofile. 782 */ 783 static smb_oplock_grant_t * 784 smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile) 785 { 786 ASSERT(MUTEX_HELD(&ol->ol_mutex)); 787 788 if (SMB_OFILE_OPLOCK_GRANTED(ofile)) 789 return (&ofile->f_oplock_grant); 790 else 791 return (NULL); 792 } 793