18c10a865Sas200622 /* 28c10a865Sas200622 * CDDL HEADER START 38c10a865Sas200622 * 48c10a865Sas200622 * The contents of this file are subject to the terms of the 58c10a865Sas200622 * Common Development and Distribution License (the "License"). 68c10a865Sas200622 * You may not use this file except in compliance with the License. 78c10a865Sas200622 * 88c10a865Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98c10a865Sas200622 * or http://www.opensolaris.org/os/licensing. 108c10a865Sas200622 * See the License for the specific language governing permissions 118c10a865Sas200622 * and limitations under the License. 128c10a865Sas200622 * 138c10a865Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 148c10a865Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158c10a865Sas200622 * If applicable, add the following below this CDDL HEADER, with the 168c10a865Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 178c10a865Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 188c10a865Sas200622 * 198c10a865Sas200622 * CDDL HEADER END 208c10a865Sas200622 */ 218c10a865Sas200622 /* 22148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23*a90cf9f2SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 248c10a865Sas200622 */ 25cb174861Sjoyce mcintosh 268c10a865Sas200622 /* 27cb174861Sjoyce mcintosh * smb_oplock_wait / smb_oplock_broadcast 28cb174861Sjoyce mcintosh * When an oplock is being acquired, we must ensure that the acquisition 29cb174861Sjoyce mcintosh * response is submitted to the network stack before any other operation 30cb174861Sjoyce mcintosh * is permitted on the oplock. 31cb174861Sjoyce mcintosh * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker 32cb174861Sjoyce mcintosh * thread processing the command that is granting the oplock. 33cb174861Sjoyce mcintosh * Other threads accessing the oplock will be suspended in smb_oplock_wait(). 34cb174861Sjoyce mcintosh * They will be awakened when the worker thread referenced in 'ol_xthread' 35cb174861Sjoyce mcintosh * calls smb_oplock_broadcast(). 368b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 37cb174861Sjoyce mcintosh * The purpose of this mechanism is to prevent another thread from 38cb174861Sjoyce mcintosh * triggering an oplock break before the response conveying the grant 39cb174861Sjoyce mcintosh * has been sent. 408c10a865Sas200622 */ 418c10a865Sas200622 42bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h> 43cb174861Sjoyce mcintosh #include <sys/nbmlock.h> 448c10a865Sas200622 45cb174861Sjoyce mcintosh #define SMB_OPLOCK_IS_EXCLUSIVE(level) \ 46cb174861Sjoyce mcintosh (((level) == SMB_OPLOCK_EXCLUSIVE) || \ 47cb174861Sjoyce mcintosh ((level) == SMB_OPLOCK_BATCH)) 48cb174861Sjoyce mcintosh 49cb174861Sjoyce mcintosh static int smb_oplock_install_fem(smb_node_t *); 50cb174861Sjoyce mcintosh static void smb_oplock_uninstall_fem(smb_node_t *); 51cb174861Sjoyce mcintosh 52fc724630SAlan Wright static void smb_oplock_wait(smb_node_t *); 53cb174861Sjoyce mcintosh static void smb_oplock_wait_ack(smb_node_t *, uint32_t); 54cb174861Sjoyce mcintosh static void smb_oplock_timedout(smb_node_t *); 55cb174861Sjoyce mcintosh 561fdeec65Sjoyce mcintosh static smb_oplock_grant_t *smb_oplock_set_grant(smb_ofile_t *, uint8_t); 571fdeec65Sjoyce mcintosh void smb_oplock_clear_grant(smb_oplock_grant_t *); 58cb174861Sjoyce mcintosh static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *); 59cb174861Sjoyce mcintosh static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *); 60cb174861Sjoyce mcintosh static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *); 611fdeec65Sjoyce mcintosh static smb_oplock_grant_t *smb_oplock_get_grant(smb_oplock_t *, smb_ofile_t *); 62cb174861Sjoyce mcintosh 63*a90cf9f2SGordon Ross static void smb_oplock_sched_async_break(smb_oplock_grant_t *, uint8_t); 64*a90cf9f2SGordon Ross static void smb_oplock_exec_async_break(void *); 65*a90cf9f2SGordon Ross static void smb_oplock_break_levelII_locked(smb_node_t *); 66cb174861Sjoyce mcintosh 67cb174861Sjoyce mcintosh /* 68cb174861Sjoyce mcintosh * smb_oplock_install_fem 69cb174861Sjoyce mcintosh * Install fem monitor for cross protocol oplock breaking. 70cb174861Sjoyce mcintosh */ 71cb174861Sjoyce mcintosh static int 72cb174861Sjoyce mcintosh smb_oplock_install_fem(smb_node_t *node) 73cb174861Sjoyce mcintosh { 74cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 75cb174861Sjoyce mcintosh 76cb174861Sjoyce mcintosh if (node->n_oplock.ol_fem == B_FALSE) { 77cb174861Sjoyce mcintosh if (smb_fem_oplock_install(node) != 0) { 78cb174861Sjoyce mcintosh cmn_err(CE_NOTE, "No oplock granted: " 79cb174861Sjoyce mcintosh "failed to install fem monitor %s", 80cb174861Sjoyce mcintosh node->vp->v_path); 81cb174861Sjoyce mcintosh return (-1); 82cb174861Sjoyce mcintosh } 83cb174861Sjoyce mcintosh node->n_oplock.ol_fem = B_TRUE; 84cb174861Sjoyce mcintosh } 85cb174861Sjoyce mcintosh return (0); 86cb174861Sjoyce mcintosh } 87cb174861Sjoyce mcintosh 88cb174861Sjoyce mcintosh /* 89cb174861Sjoyce mcintosh * smb_oplock_uninstall_fem 90cb174861Sjoyce mcintosh * Uninstall fem monitor for cross protocol oplock breaking. 91cb174861Sjoyce mcintosh */ 92cb174861Sjoyce mcintosh static void 93cb174861Sjoyce mcintosh smb_oplock_uninstall_fem(smb_node_t *node) 94cb174861Sjoyce mcintosh { 95cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); 96cb174861Sjoyce mcintosh 97cb174861Sjoyce mcintosh if (node->n_oplock.ol_fem) { 988622ec45SGordon Ross smb_fem_oplock_uninstall(node); 99cb174861Sjoyce mcintosh node->n_oplock.ol_fem = B_FALSE; 100cb174861Sjoyce mcintosh } 101cb174861Sjoyce mcintosh } 1028c10a865Sas200622 1038c10a865Sas200622 /* 104*a90cf9f2SGordon Ross * This provides a way to fully disable oplocks, i.e. for testing. 105*a90cf9f2SGordon Ross * You _really_ do _not_ want to turn this off, because if you do, 106*a90cf9f2SGordon Ross * the clients send you very small read requests, and a _lot_ more 107*a90cf9f2SGordon Ross * of them. The skc_oplock_enable parameter can be used to enable 108*a90cf9f2SGordon Ross * or disable exclusive oplocks. Disabling that can be helpful 109*a90cf9f2SGordon Ross * when there are clients not responding to oplock breaks. 110*a90cf9f2SGordon Ross */ 111*a90cf9f2SGordon Ross int smb_oplocks_enabled = 1; 112*a90cf9f2SGordon Ross 113*a90cf9f2SGordon Ross /* 1148c10a865Sas200622 * smb_oplock_acquire 1158c10a865Sas200622 * 116cb174861Sjoyce mcintosh * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH, 117cb174861Sjoyce mcintosh * but might only be granted LEVEL_II or NONE. 1188c10a865Sas200622 * 119cb174861Sjoyce mcintosh * If oplocks are not supported on the tree, or node, grant NONE. 120cb174861Sjoyce mcintosh * If nobody else has the file open, grant the requested level. 121cb174861Sjoyce mcintosh * If any of the following are true, grant NONE: 122cb174861Sjoyce mcintosh * - there is an exclusive oplock on the node 123cb174861Sjoyce mcintosh * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd. 124cb174861Sjoyce mcintosh * - LEVEL_II oplocks are not supported for the session 125cb174861Sjoyce mcintosh * - a BATCH oplock is requested on a named stream 126bc7c423fSGordon Ross * - there are any range locks on the node (SMB writers) 127cb174861Sjoyce mcintosh * Otherwise, grant LEVEL_II. 1288c10a865Sas200622 * 129cb174861Sjoyce mcintosh * ol->ol_xthread is set to the current thread to lock the oplock against 130cb174861Sjoyce mcintosh * other operations until the acquire response is on the wire. When the 131cb174861Sjoyce mcintosh * acquire response is on the wire, smb_oplock_broadcast() is called to 132cb174861Sjoyce mcintosh * reset ol->ol_xthread and wake any waiting threads. 1338c10a865Sas200622 */ 1342c2961f8Sjose borrego void 135cb174861Sjoyce mcintosh smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile) 1368c10a865Sas200622 { 1372c2961f8Sjose borrego smb_oplock_t *ol; 138cb174861Sjoyce mcintosh smb_oplock_grant_t *og; 139cb174861Sjoyce mcintosh list_t *grants; 140cb174861Sjoyce mcintosh smb_arg_open_t *op; 141cb174861Sjoyce mcintosh smb_tree_t *tree; 142cb174861Sjoyce mcintosh smb_session_t *session; 1438c10a865Sas200622 1442c2961f8Sjose borrego SMB_NODE_VALID(node); 145cb174861Sjoyce mcintosh SMB_OFILE_VALID(ofile); 1468c10a865Sas200622 147cb174861Sjoyce mcintosh ASSERT(node == SMB_OFILE_GET_NODE(ofile)); 148bc7c423fSGordon Ross ASSERT(RW_LOCK_HELD(&node->n_lock)); 1498c10a865Sas200622 150cb174861Sjoyce mcintosh op = &sr->sr_open; 151cb174861Sjoyce mcintosh tree = SMB_OFILE_GET_TREE(ofile); 152cb174861Sjoyce mcintosh session = SMB_OFILE_GET_SESSION(ofile); 1538c10a865Sas200622 154*a90cf9f2SGordon Ross if (smb_oplocks_enabled == 0 || 155cb174861Sjoyce mcintosh (op->op_oplock_level == SMB_OPLOCK_NONE) || 156cb174861Sjoyce mcintosh ((op->op_oplock_level == SMB_OPLOCK_BATCH) && 157cb174861Sjoyce mcintosh SMB_IS_STREAM(node))) { 1582c2961f8Sjose borrego op->op_oplock_level = SMB_OPLOCK_NONE; 1592c2961f8Sjose borrego return; 1608c10a865Sas200622 } 1618c10a865Sas200622 1622c2961f8Sjose borrego ol = &node->n_oplock; 163cb174861Sjoyce mcintosh grants = &ol->ol_grants; 1648c10a865Sas200622 165cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex); 166fc724630SAlan Wright smb_oplock_wait(node); 1672c2961f8Sjose borrego 168*a90cf9f2SGordon Ross /* 169*a90cf9f2SGordon Ross * Even if there are no other opens, we might want to 170*a90cf9f2SGordon Ross * grant only a Level II (shared) oplock so we avoid 171*a90cf9f2SGordon Ross * ever granting exclusive oplocks. 172*a90cf9f2SGordon Ross * 173*a90cf9f2SGordon Ross * Borrowing the SMB_TREE_OPLOCKS flag to enable/disable 174*a90cf9f2SGordon Ross * exclusive oplocks (for now). See skc_oplock_enable, 175*a90cf9f2SGordon Ross * which can now be taken as "exclusive oplock enable". 176*a90cf9f2SGordon Ross * Should rename this parameter, and/or implement a new 177*a90cf9f2SGordon Ross * multi-valued parameter for oplock enables. 178*a90cf9f2SGordon Ross */ 179cb174861Sjoyce mcintosh if ((node->n_open_count > 1) || 180cb174861Sjoyce mcintosh (node->n_opening_count > 1) || 181*a90cf9f2SGordon Ross !smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) || 182cb174861Sjoyce mcintosh smb_vop_other_opens(node->vp, ofile->f_mode)) { 183bc7c423fSGordon Ross /* 184bc7c423fSGordon Ross * There are other opens. 185bc7c423fSGordon Ross */ 186cb174861Sjoyce mcintosh if ((!op->op_oplock_levelII) || 187cb174861Sjoyce mcintosh (!smb_session_levelII_oplocks(session)) || 188cb174861Sjoyce mcintosh (smb_oplock_exclusive_grant(grants) != NULL) || 189bc7c423fSGordon Ross (smb_lock_range_access(sr, node, 0, 0, B_FALSE))) { 190bc7c423fSGordon Ross /* 191bc7c423fSGordon Ross * LevelII (shared) oplock not allowed, 192bc7c423fSGordon Ross * so reply with "none". 193bc7c423fSGordon Ross */ 1942c2961f8Sjose borrego op->op_oplock_level = SMB_OPLOCK_NONE; 195cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 1962c2961f8Sjose borrego return; 1972c2961f8Sjose borrego } 198cb174861Sjoyce mcintosh 199cb174861Sjoyce mcintosh op->op_oplock_level = SMB_OPLOCK_LEVEL_II; 200cb174861Sjoyce mcintosh } 201cb174861Sjoyce mcintosh 2021fdeec65Sjoyce mcintosh og = smb_oplock_set_grant(ofile, op->op_oplock_level); 203cb174861Sjoyce mcintosh if (smb_oplock_insert_grant(node, og) != 0) { 2041fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og); 205cb174861Sjoyce mcintosh op->op_oplock_level = SMB_OPLOCK_NONE; 206cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 2072c2961f8Sjose borrego return; 2082c2961f8Sjose borrego } 2098c10a865Sas200622 2102c2961f8Sjose borrego ol->ol_xthread = curthread; 211cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 2128c10a865Sas200622 } 2138c10a865Sas200622 2148c10a865Sas200622 /* 2158c10a865Sas200622 * smb_oplock_break 2168c10a865Sas200622 * 217cb174861Sjoyce mcintosh * Break granted oplocks according to the following rules: 218cb174861Sjoyce mcintosh * 219cb174861Sjoyce mcintosh * If there's an exclusive oplock granted on the node 220cb174861Sjoyce mcintosh * - if the BREAK_BATCH flags is specified and the oplock is not 221cb174861Sjoyce mcintosh * a batch oplock, no break is required. 222cb174861Sjoyce mcintosh * - if the session doesn't support LEVEL II oplocks, and 'brk' is 223cb174861Sjoyce mcintosh * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE. 224cb174861Sjoyce mcintosh * - if the oplock is already breaking update the break level (if 225cb174861Sjoyce mcintosh * the requested break is to a lesser level), otherwise send an 226cb174861Sjoyce mcintosh * oplock break. 227cb174861Sjoyce mcintosh * Wait for acknowledgement of the break (unless NOWAIT flag is set) 228cb174861Sjoyce mcintosh * 229cb174861Sjoyce mcintosh * Otherwise: 230cb174861Sjoyce mcintosh * If there are level II oplocks granted on the node, and the flags 231cb174861Sjoyce mcintosh * indicate that they should be broken (BREAK_TO_NONE specified, 232cb174861Sjoyce mcintosh * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII 233cb174861Sjoyce mcintosh * break request for asynchronous processing. 2348c10a865Sas200622 * 2352c2961f8Sjose borrego * Returns: 236cb174861Sjoyce mcintosh * 0 - oplock broken (or no break required) 237cb174861Sjoyce mcintosh * EAGAIN - oplock break request sent and would block 238cb174861Sjoyce mcintosh * awaiting the reponse but NOWAIT was specified 2398622ec45SGordon Ross * 2408622ec45SGordon Ross * NB: sr == NULL when called by FEM framework. 2418c10a865Sas200622 */ 242cb174861Sjoyce mcintosh int 243cb174861Sjoyce mcintosh smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags) 244cb174861Sjoyce mcintosh { 245cb174861Sjoyce mcintosh smb_oplock_t *ol; 246cb174861Sjoyce mcintosh smb_oplock_grant_t *og; 247cb174861Sjoyce mcintosh list_t *grants; 248cb174861Sjoyce mcintosh uint32_t timeout; 249cb174861Sjoyce mcintosh uint8_t brk; 250cb174861Sjoyce mcintosh 251cb174861Sjoyce mcintosh SMB_NODE_VALID(node); 252cb174861Sjoyce mcintosh ol = &node->n_oplock; 253cb174861Sjoyce mcintosh grants = &ol->ol_grants; 254cb174861Sjoyce mcintosh 255cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex); 256cb174861Sjoyce mcintosh smb_oplock_wait(node); 257cb174861Sjoyce mcintosh 258cb174861Sjoyce mcintosh og = list_head(grants); 259cb174861Sjoyce mcintosh if (og == NULL) { 260cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 261cb174861Sjoyce mcintosh return (0); 262cb174861Sjoyce mcintosh } 263cb174861Sjoyce mcintosh 264cb174861Sjoyce mcintosh SMB_OPLOCK_GRANT_VALID(og); 265cb174861Sjoyce mcintosh 266cb174861Sjoyce mcintosh /* break levelII oplocks */ 267cb174861Sjoyce mcintosh if (og->og_level == SMB_OPLOCK_LEVEL_II) { 268cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 269cb174861Sjoyce mcintosh 270cb174861Sjoyce mcintosh if ((flags & SMB_OPLOCK_BREAK_TO_NONE) && 271cb174861Sjoyce mcintosh !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) && 272cb174861Sjoyce mcintosh !(flags & SMB_OPLOCK_BREAK_BATCH)) { 273cb174861Sjoyce mcintosh smb_oplock_break_levelII(node); 274cb174861Sjoyce mcintosh } 275cb174861Sjoyce mcintosh return (0); 276cb174861Sjoyce mcintosh } 277cb174861Sjoyce mcintosh 278cb174861Sjoyce mcintosh /* break exclusive oplock */ 279cb174861Sjoyce mcintosh if ((flags & SMB_OPLOCK_BREAK_BATCH) && 280cb174861Sjoyce mcintosh (og->og_level != SMB_OPLOCK_BATCH)) { 281cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 282cb174861Sjoyce mcintosh return (0); 283cb174861Sjoyce mcintosh } 284cb174861Sjoyce mcintosh 285cb174861Sjoyce mcintosh if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) && 286cb174861Sjoyce mcintosh smb_session_levelII_oplocks(og->og_session)) { 287cb174861Sjoyce mcintosh brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; 288cb174861Sjoyce mcintosh } else { 289cb174861Sjoyce mcintosh brk = SMB_OPLOCK_BREAK_TO_NONE; 290cb174861Sjoyce mcintosh } 291cb174861Sjoyce mcintosh 292cb174861Sjoyce mcintosh switch (ol->ol_break) { 293cb174861Sjoyce mcintosh case SMB_OPLOCK_NO_BREAK: 294cb174861Sjoyce mcintosh ol->ol_break = brk; 295*a90cf9f2SGordon Ross smb_oplock_sched_async_break(og, brk); 296cb174861Sjoyce mcintosh break; 297cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_LEVEL_II: 298cb174861Sjoyce mcintosh if (brk == SMB_OPLOCK_BREAK_TO_NONE) 299cb174861Sjoyce mcintosh ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE; 300cb174861Sjoyce mcintosh break; 301cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_NONE: 302cb174861Sjoyce mcintosh default: 303cb174861Sjoyce mcintosh break; 304cb174861Sjoyce mcintosh } 305cb174861Sjoyce mcintosh 306cb174861Sjoyce mcintosh if (flags & SMB_OPLOCK_BREAK_NOWAIT) { 307cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 308cb174861Sjoyce mcintosh return (EAGAIN); 309cb174861Sjoyce mcintosh } 310cb174861Sjoyce mcintosh 311cb174861Sjoyce mcintosh if (sr && (sr->session == og->og_session) && 312cb174861Sjoyce mcintosh (sr->smb_uid == og->og_uid)) { 313cb174861Sjoyce mcintosh timeout = smb_oplock_min_timeout; 314cb174861Sjoyce mcintosh } else { 315cb174861Sjoyce mcintosh timeout = smb_oplock_timeout; 316cb174861Sjoyce mcintosh } 317cb174861Sjoyce mcintosh 318cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 319cb174861Sjoyce mcintosh smb_oplock_wait_ack(node, timeout); 320cb174861Sjoyce mcintosh return (0); 321cb174861Sjoyce mcintosh } 322cb174861Sjoyce mcintosh 323cb174861Sjoyce mcintosh /* 324cb174861Sjoyce mcintosh * smb_oplock_break_levelII 325cb174861Sjoyce mcintosh * 326*a90cf9f2SGordon Ross * This is called after a file is modified in some way. If there are 327*a90cf9f2SGordon Ross * LevelII (shared) oplocks, break those to none. If there is an 328*a90cf9f2SGordon Ross * exclusive oplock, there can be no LevelII oplocks, so do nothing. 329*a90cf9f2SGordon Ross * 330cb174861Sjoyce mcintosh * LevelII (shared) oplock breaks are processed asynchronously. 331cb174861Sjoyce mcintosh * Unlike exclusive oplock breaks, the thread initiating the break 332cb174861Sjoyce mcintosh * is NOT blocked while the request is processed. 333cb174861Sjoyce mcintosh * 334*a90cf9f2SGordon Ross * There may be a thread with exclusive rights to oplock state for 335*a90cf9f2SGordon Ross * this node (via ol_xthread in smb_oplock_wait) and if so, we must 336*a90cf9f2SGordon Ross * avoid breaking oplocks until that's out of the way. However, we 337*a90cf9f2SGordon Ross * really don't want to block here, so when ol_xthread is set, we'll 338*a90cf9f2SGordon Ross * just mark that a "break level II to none" is pending, and let the 339*a90cf9f2SGordon Ross * exclusive thread do this work when it's done being exclusive. 340cb174861Sjoyce mcintosh */ 341cb174861Sjoyce mcintosh void 342cb174861Sjoyce mcintosh smb_oplock_break_levelII(smb_node_t *node) 343cb174861Sjoyce mcintosh { 344*a90cf9f2SGordon Ross smb_oplock_t *ol; 345cb174861Sjoyce mcintosh 346*a90cf9f2SGordon Ross ol = &node->n_oplock; 347*a90cf9f2SGordon Ross mutex_enter(&ol->ol_mutex); 348cb174861Sjoyce mcintosh 349*a90cf9f2SGordon Ross /* Instead of: smb_oplock_wait() ... */ 350*a90cf9f2SGordon Ross if (ol->ol_xthread != NULL) { 351*a90cf9f2SGordon Ross /* Defer the call to smb_oplock_broadcast(). */ 352*a90cf9f2SGordon Ross ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE; 353*a90cf9f2SGordon Ross } else { 354*a90cf9f2SGordon Ross /* Equivalent of smb_oplock_wait() done. */ 355*a90cf9f2SGordon Ross smb_oplock_break_levelII_locked(node); 356*a90cf9f2SGordon Ross } 357cb174861Sjoyce mcintosh 358*a90cf9f2SGordon Ross mutex_exit(&ol->ol_mutex); 359cb174861Sjoyce mcintosh } 360cb174861Sjoyce mcintosh 361cb174861Sjoyce mcintosh /* 362*a90cf9f2SGordon Ross * smb_oplock_break_levelII_locked 363*a90cf9f2SGordon Ross * Internal helper for smb_oplock_break_levelII() 364cb174861Sjoyce mcintosh * 365*a90cf9f2SGordon Ross * Called with the oplock mutex already held, and _after_ 366*a90cf9f2SGordon Ross * (the equivalent of) an smb_oplock_wait(). 367cb174861Sjoyce mcintosh */ 368cb174861Sjoyce mcintosh static void 369*a90cf9f2SGordon Ross smb_oplock_break_levelII_locked(smb_node_t *node) 370cb174861Sjoyce mcintosh { 371cb174861Sjoyce mcintosh smb_oplock_t *ol; 372cb174861Sjoyce mcintosh smb_oplock_grant_t *og; 373cb174861Sjoyce mcintosh list_t *grants; 374cb174861Sjoyce mcintosh 375cb174861Sjoyce mcintosh ol = &node->n_oplock; 376*a90cf9f2SGordon Ross grants = &ol->ol_grants; 377*a90cf9f2SGordon Ross 378*a90cf9f2SGordon Ross ASSERT(MUTEX_HELD(&ol->ol_mutex)); 379*a90cf9f2SGordon Ross ASSERT(ol->ol_xthread == NULL); 380cb174861Sjoyce mcintosh 381cb174861Sjoyce mcintosh while ((og = list_head(grants)) != NULL) { 382cb174861Sjoyce mcintosh SMB_OPLOCK_GRANT_VALID(og); 383cb174861Sjoyce mcintosh 384*a90cf9f2SGordon Ross /* 385*a90cf9f2SGordon Ross * If there's an exclusive oplock, there are 386*a90cf9f2SGordon Ross * no LevelII oplocks, so do nothing. 387*a90cf9f2SGordon Ross */ 388cb174861Sjoyce mcintosh if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 389cb174861Sjoyce mcintosh break; 390cb174861Sjoyce mcintosh 391*a90cf9f2SGordon Ross smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE); 392cb174861Sjoyce mcintosh smb_oplock_remove_grant(node, og); 3931fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og); 394cb174861Sjoyce mcintosh } 395*a90cf9f2SGordon Ross } 396cb174861Sjoyce mcintosh 397*a90cf9f2SGordon Ross /* 398*a90cf9f2SGordon Ross * Schedule a call to smb_session_oplock_break 399*a90cf9f2SGordon Ross * using an smb_request on the owning session. 400*a90cf9f2SGordon Ross */ 401*a90cf9f2SGordon Ross static void 402*a90cf9f2SGordon Ross smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk) 403*a90cf9f2SGordon Ross { 404*a90cf9f2SGordon Ross smb_request_t *sr; 405*a90cf9f2SGordon Ross smb_ofile_t *ofile; 406*a90cf9f2SGordon Ross 407*a90cf9f2SGordon Ross /* 408*a90cf9f2SGordon Ross * Make sure we can get a hold on the ofile. If we can't, 409*a90cf9f2SGordon Ross * the file is closing, and there's no point scheduling an 410*a90cf9f2SGordon Ross * oplock break on it. (Also hold the tree and user.) 411*a90cf9f2SGordon Ross * These holds account for the pointers we copy into the 412*a90cf9f2SGordon Ross * smb_request fields: fid_ofile, tid_tree, uid_user. 413*a90cf9f2SGordon Ross * These holds are released via smb_request_free after 414*a90cf9f2SGordon Ross * the oplock break has been sent. 415*a90cf9f2SGordon Ross */ 416*a90cf9f2SGordon Ross ofile = og->og_ofile; 417*a90cf9f2SGordon Ross if (!smb_ofile_hold(ofile)) 418*a90cf9f2SGordon Ross return; 419*a90cf9f2SGordon Ross smb_tree_hold_internal(ofile->f_tree); 420*a90cf9f2SGordon Ross smb_user_hold_internal(ofile->f_user); 421*a90cf9f2SGordon Ross 422*a90cf9f2SGordon Ross sr = smb_request_alloc(og->og_session, 0); 423*a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_SUBMITTED; 424*a90cf9f2SGordon Ross sr->user_cr = zone_kcred(); 425*a90cf9f2SGordon Ross sr->fid_ofile = ofile; 426*a90cf9f2SGordon Ross sr->tid_tree = ofile->f_tree; 427*a90cf9f2SGordon Ross sr->uid_user = ofile->f_user; 428*a90cf9f2SGordon Ross 429*a90cf9f2SGordon Ross sr->arg.olbrk = *og; /* struct copy */ 430*a90cf9f2SGordon Ross sr->arg.olbrk.og_breaking = brk; 431*a90cf9f2SGordon Ross 432*a90cf9f2SGordon Ross (void) taskq_dispatch( 433*a90cf9f2SGordon Ross sr->sr_server->sv_worker_pool, 434*a90cf9f2SGordon Ross smb_oplock_exec_async_break, sr, TQ_SLEEP); 435*a90cf9f2SGordon Ross } 436*a90cf9f2SGordon Ross 437*a90cf9f2SGordon Ross /* 438*a90cf9f2SGordon Ross * smb_oplock_exec_async_break 439*a90cf9f2SGordon Ross * 440*a90cf9f2SGordon Ross * Called via the taskq to handle an asynchronous oplock break. 441*a90cf9f2SGordon Ross * We have a hold on the ofile, which keeps the FID here valid. 442*a90cf9f2SGordon Ross */ 443*a90cf9f2SGordon Ross static void 444*a90cf9f2SGordon Ross smb_oplock_exec_async_break(void *arg) 445*a90cf9f2SGordon Ross { 446*a90cf9f2SGordon Ross smb_request_t *sr = arg; 447*a90cf9f2SGordon Ross smb_oplock_grant_t *og = &sr->arg.olbrk; 448*a90cf9f2SGordon Ross 449*a90cf9f2SGordon Ross SMB_REQ_VALID(sr); 450*a90cf9f2SGordon Ross SMB_OPLOCK_GRANT_VALID(og); 451*a90cf9f2SGordon Ross 452*a90cf9f2SGordon Ross mutex_enter(&sr->sr_mutex); 453*a90cf9f2SGordon Ross sr->sr_worker = curthread; 454*a90cf9f2SGordon Ross sr->sr_time_active = gethrtime(); 455*a90cf9f2SGordon Ross 456*a90cf9f2SGordon Ross switch (sr->sr_state) { 457*a90cf9f2SGordon Ross case SMB_REQ_STATE_SUBMITTED: 458*a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 459*a90cf9f2SGordon Ross mutex_exit(&sr->sr_mutex); 460*a90cf9f2SGordon Ross 461*a90cf9f2SGordon Ross /* 462*a90cf9f2SGordon Ross * This is where we actually do the deferred work 463*a90cf9f2SGordon Ross * requested by smb_oplock_sched_async_break(). 464*a90cf9f2SGordon Ross */ 465*a90cf9f2SGordon Ross smb_session_oplock_break(sr, og->og_breaking); 466*a90cf9f2SGordon Ross 467*a90cf9f2SGordon Ross mutex_enter(&sr->sr_mutex); 468*a90cf9f2SGordon Ross /* FALLTHROUGH */ 469*a90cf9f2SGordon Ross 470*a90cf9f2SGordon Ross default: /* typically cancelled */ 471*a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_COMPLETED; 472*a90cf9f2SGordon Ross mutex_exit(&sr->sr_mutex); 473*a90cf9f2SGordon Ross } 474*a90cf9f2SGordon Ross 475*a90cf9f2SGordon Ross smb_request_free(sr); 476cb174861Sjoyce mcintosh } 477cb174861Sjoyce mcintosh 478cb174861Sjoyce mcintosh /* 479cb174861Sjoyce mcintosh * smb_oplock_wait_ack 480cb174861Sjoyce mcintosh * 481cb174861Sjoyce mcintosh * Timed wait for an oplock break acknowledgement (or oplock release). 482cb174861Sjoyce mcintosh */ 483cb174861Sjoyce mcintosh static void 484cb174861Sjoyce mcintosh smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout) 4858c10a865Sas200622 { 4862c2961f8Sjose borrego smb_oplock_t *ol; 4872c2961f8Sjose borrego clock_t time; 4888c10a865Sas200622 4892c2961f8Sjose borrego ol = &node->n_oplock; 490cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex); 491cb174861Sjoyce mcintosh time = MSEC_TO_TICK(timeout) + ddi_get_lbolt(); 4928c10a865Sas200622 493cb174861Sjoyce mcintosh while (ol->ol_break != SMB_OPLOCK_NO_BREAK) { 494cb174861Sjoyce mcintosh if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) { 495cb174861Sjoyce mcintosh smb_oplock_timedout(node); 4962c2961f8Sjose borrego cv_broadcast(&ol->ol_cv); 4978c10a865Sas200622 break; 4988c10a865Sas200622 } 4998c10a865Sas200622 } 500cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 5018c10a865Sas200622 } 502cb174861Sjoyce mcintosh 503cb174861Sjoyce mcintosh /* 504cb174861Sjoyce mcintosh * smb_oplock_timedout 505cb174861Sjoyce mcintosh * 506cb174861Sjoyce mcintosh * An oplock break has not been acknowledged within timeout 507cb174861Sjoyce mcintosh * 'smb_oplock_timeout'. 508cb174861Sjoyce mcintosh * Set oplock grant to the desired break level. 509cb174861Sjoyce mcintosh */ 510cb174861Sjoyce mcintosh static void 511cb174861Sjoyce mcintosh smb_oplock_timedout(smb_node_t *node) 512cb174861Sjoyce mcintosh { 513cb174861Sjoyce mcintosh smb_oplock_t *ol; 514cb174861Sjoyce mcintosh smb_oplock_grant_t *og; 515cb174861Sjoyce mcintosh list_t *grants; 516cb174861Sjoyce mcintosh 517cb174861Sjoyce mcintosh ol = &node->n_oplock; 518cb174861Sjoyce mcintosh grants = &ol->ol_grants; 519cb174861Sjoyce mcintosh 520cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex)); 521cb174861Sjoyce mcintosh 522cb174861Sjoyce mcintosh og = smb_oplock_exclusive_grant(grants); 523cb174861Sjoyce mcintosh if (og) { 524cb174861Sjoyce mcintosh switch (ol->ol_break) { 525cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_NONE: 526cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_NONE; 527cb174861Sjoyce mcintosh smb_oplock_remove_grant(node, og); 5281fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og); 529cb174861Sjoyce mcintosh break; 530cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_LEVEL_II: 531cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_LEVEL_II; 532cb174861Sjoyce mcintosh break; 533cb174861Sjoyce mcintosh default: 534cb174861Sjoyce mcintosh SMB_PANIC(); 535cb174861Sjoyce mcintosh } 536cb174861Sjoyce mcintosh } 537cb174861Sjoyce mcintosh ol->ol_break = SMB_OPLOCK_NO_BREAK; 5388c10a865Sas200622 } 5398c10a865Sas200622 5408c10a865Sas200622 /* 5418c10a865Sas200622 * smb_oplock_release 5428c10a865Sas200622 * 543cb174861Sjoyce mcintosh * Release the oplock granted on ofile 'of'. 544cb174861Sjoyce mcintosh * Wake any threads waiting for an oplock break acknowledgement for 545cb174861Sjoyce mcintosh * this oplock. 546cb174861Sjoyce mcintosh * This is called when the ofile is being closed. 5478c10a865Sas200622 */ 5482c2961f8Sjose borrego void 5492c2961f8Sjose borrego smb_oplock_release(smb_node_t *node, smb_ofile_t *of) 5508c10a865Sas200622 { 5512c2961f8Sjose borrego smb_oplock_t *ol; 552cb174861Sjoyce mcintosh smb_oplock_grant_t *og; 5538c10a865Sas200622 5542c2961f8Sjose borrego ol = &node->n_oplock; 555cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex); 556fc724630SAlan Wright smb_oplock_wait(node); 5572c2961f8Sjose borrego 5581fdeec65Sjoyce mcintosh og = smb_oplock_get_grant(ol, of); 559cb174861Sjoyce mcintosh if (og) { 560cb174861Sjoyce mcintosh smb_oplock_remove_grant(node, og); 5611fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og); 562cb174861Sjoyce mcintosh 563cb174861Sjoyce mcintosh if (ol->ol_break != SMB_OPLOCK_NO_BREAK) { 564cb174861Sjoyce mcintosh ol->ol_break = SMB_OPLOCK_NO_BREAK; 5652c2961f8Sjose borrego cv_broadcast(&ol->ol_cv); 5662c2961f8Sjose borrego } 5672c2961f8Sjose borrego } 568cb174861Sjoyce mcintosh 569cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 5708c10a865Sas200622 } 5718c10a865Sas200622 5728c10a865Sas200622 /* 573cb174861Sjoyce mcintosh * smb_oplock_ack 5748c10a865Sas200622 * 575cb174861Sjoyce mcintosh * Process oplock acknowledgement received for ofile 'of'. 576cb174861Sjoyce mcintosh * - oplock.ol_break is the break level that was requested. 577cb174861Sjoyce mcintosh * - brk is the break level being acknowledged by the client. 578cb174861Sjoyce mcintosh * 579cb174861Sjoyce mcintosh * Update the oplock grant level to the lesser of ol_break and brk. 580cb174861Sjoyce mcintosh * If the grant is now SMB_OPLOCK_NONE, remove the grant from the 581cb174861Sjoyce mcintosh * oplock's grant list and delete it. 582cb174861Sjoyce mcintosh * If the requested break level (ol_break) was NONE and the brk is 583cb174861Sjoyce mcintosh * LEVEL_II, send another oplock break (NONE). Do not wait for an 584cb174861Sjoyce mcintosh * acknowledgement. 585cb174861Sjoyce mcintosh * Wake any threads waiting for the oplock break acknowledgement. 5868c10a865Sas200622 */ 587cb174861Sjoyce mcintosh void 588cb174861Sjoyce mcintosh smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk) 5898c10a865Sas200622 { 590cb174861Sjoyce mcintosh smb_oplock_t *ol; 591cb174861Sjoyce mcintosh smb_oplock_grant_t *og; 5928c10a865Sas200622 593cb174861Sjoyce mcintosh ol = &node->n_oplock; 594cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex); 595fc724630SAlan Wright smb_oplock_wait(node); 5962c2961f8Sjose borrego 597cb174861Sjoyce mcintosh if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) || 5981fdeec65Sjoyce mcintosh ((og = smb_oplock_get_grant(ol, of)) == NULL)) { 599cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 600cb174861Sjoyce mcintosh return; 6018c10a865Sas200622 } 6028c10a865Sas200622 603cb174861Sjoyce mcintosh switch (brk) { 604cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_NONE: 605cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_NONE; 6062c2961f8Sjose borrego break; 607cb174861Sjoyce mcintosh case SMB_OPLOCK_BREAK_TO_LEVEL_II: 608cb174861Sjoyce mcintosh if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) { 609cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_LEVEL_II; 610cb174861Sjoyce mcintosh } else { 611cb174861Sjoyce mcintosh /* SMB_OPLOCK_BREAK_TO_NONE */ 612cb174861Sjoyce mcintosh og->og_level = SMB_OPLOCK_NONE; 613*a90cf9f2SGordon Ross smb_oplock_sched_async_break(og, 614*a90cf9f2SGordon Ross SMB_OPLOCK_BREAK_TO_NONE); 6152c2961f8Sjose borrego } 6162c2961f8Sjose borrego break; 6172c2961f8Sjose borrego default: 6182c2961f8Sjose borrego SMB_PANIC(); 6192c2961f8Sjose borrego } 620cb174861Sjoyce mcintosh 621cb174861Sjoyce mcintosh if (og->og_level == SMB_OPLOCK_NONE) { 622cb174861Sjoyce mcintosh smb_oplock_remove_grant(node, og); 6231fdeec65Sjoyce mcintosh smb_oplock_clear_grant(og); 624cb174861Sjoyce mcintosh } 625cb174861Sjoyce mcintosh 626cb174861Sjoyce mcintosh ol->ol_break = SMB_OPLOCK_NO_BREAK; 627cb174861Sjoyce mcintosh cv_broadcast(&ol->ol_cv); 628cb174861Sjoyce mcintosh 629cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 6308c10a865Sas200622 } 6318c10a865Sas200622 6322c2961f8Sjose borrego /* 633fc724630SAlan Wright * smb_oplock_broadcast 6342c2961f8Sjose borrego * 635*a90cf9f2SGordon Ross * Called when an open with oplock request completes. 636*a90cf9f2SGordon Ross * 637cb174861Sjoyce mcintosh * ol->ol_xthread identifies the thread that was performing an oplock 638cb174861Sjoyce mcintosh * acquire. Other threads may be blocked awaiting completion of the 639cb174861Sjoyce mcintosh * acquire. 640*a90cf9f2SGordon Ross * If the calling thread is ol_xthread, wake any waiting threads. 6412c2961f8Sjose borrego */ 642cb174861Sjoyce mcintosh void 643fc724630SAlan Wright smb_oplock_broadcast(smb_node_t *node) 6442c2961f8Sjose borrego { 6452c2961f8Sjose borrego smb_oplock_t *ol; 6462c2961f8Sjose borrego 6472c2961f8Sjose borrego SMB_NODE_VALID(node); 6482c2961f8Sjose borrego ol = &node->n_oplock; 6492c2961f8Sjose borrego 650cb174861Sjoyce mcintosh mutex_enter(&ol->ol_mutex); 6512c2961f8Sjose borrego if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) { 6522c2961f8Sjose borrego ol->ol_xthread = NULL; 653*a90cf9f2SGordon Ross if (ol->ol_brk_pending) { 654*a90cf9f2SGordon Ross ol->ol_brk_pending = 0; 655*a90cf9f2SGordon Ross smb_oplock_break_levelII_locked(node); 656*a90cf9f2SGordon Ross } 6572c2961f8Sjose borrego cv_broadcast(&ol->ol_cv); 6582c2961f8Sjose borrego } 659cb174861Sjoyce mcintosh mutex_exit(&ol->ol_mutex); 6608c10a865Sas200622 } 6618c10a865Sas200622 6622c2961f8Sjose borrego /* 6632c2961f8Sjose borrego * smb_oplock_wait 6642c2961f8Sjose borrego * 665cb174861Sjoyce mcintosh * Wait for the completion of an oplock acquire. 666cb174861Sjoyce mcintosh * If ol_xthread is not NULL and doesn't contain the pointer to the 667cb174861Sjoyce mcintosh * context of the calling thread, the caller will sleep until the 668cb174861Sjoyce mcintosh * ol_xthread is reset to NULL (via smb_oplock_broadcast()). 6692c2961f8Sjose borrego */ 6702c2961f8Sjose borrego static void 671fc724630SAlan Wright smb_oplock_wait(smb_node_t *node) 6722c2961f8Sjose borrego { 673cb174861Sjoyce mcintosh smb_oplock_t *ol; 674cb174861Sjoyce mcintosh 675cb174861Sjoyce mcintosh ol = &node->n_oplock; 676cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex)); 6772c2961f8Sjose borrego 6782c2961f8Sjose borrego if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) { 6792c2961f8Sjose borrego while (ol->ol_xthread != NULL) 680cb174861Sjoyce mcintosh cv_wait(&ol->ol_cv, &ol->ol_mutex); 6812c2961f8Sjose borrego } 6828c10a865Sas200622 } 683cb174861Sjoyce mcintosh 684cb174861Sjoyce mcintosh /* 6851fdeec65Sjoyce mcintosh * smb_oplock_set_grant 686cb174861Sjoyce mcintosh */ 687cb174861Sjoyce mcintosh static smb_oplock_grant_t * 6881fdeec65Sjoyce mcintosh smb_oplock_set_grant(smb_ofile_t *of, uint8_t level) 689cb174861Sjoyce mcintosh { 690cb174861Sjoyce mcintosh smb_oplock_grant_t *og; 691cb174861Sjoyce mcintosh 6921fdeec65Sjoyce mcintosh og = &of->f_oplock_grant; 6931fdeec65Sjoyce mcintosh 694cb174861Sjoyce mcintosh og->og_magic = SMB_OPLOCK_GRANT_MAGIC; 695*a90cf9f2SGordon Ross og->og_breaking = 0; 696cb174861Sjoyce mcintosh og->og_level = level; 697cb174861Sjoyce mcintosh og->og_ofile = of; 698cb174861Sjoyce mcintosh og->og_fid = of->f_fid; 699cb174861Sjoyce mcintosh og->og_tid = of->f_tree->t_tid; 700cb174861Sjoyce mcintosh og->og_uid = of->f_user->u_uid; 701cb174861Sjoyce mcintosh og->og_session = of->f_session; 702cb174861Sjoyce mcintosh return (og); 703cb174861Sjoyce mcintosh } 704cb174861Sjoyce mcintosh 705cb174861Sjoyce mcintosh /* 7061fdeec65Sjoyce mcintosh * smb_oplock_clear_grant 707cb174861Sjoyce mcintosh */ 708cb174861Sjoyce mcintosh void 7091fdeec65Sjoyce mcintosh smb_oplock_clear_grant(smb_oplock_grant_t *og) 710cb174861Sjoyce mcintosh { 7111fdeec65Sjoyce mcintosh bzero(og, sizeof (smb_oplock_grant_t)); 712cb174861Sjoyce mcintosh } 713cb174861Sjoyce mcintosh 714cb174861Sjoyce mcintosh /* 715cb174861Sjoyce mcintosh * smb_oplock_insert_grant 716cb174861Sjoyce mcintosh * 717cb174861Sjoyce mcintosh * If there are no grants in the oplock's list install the fem 718cb174861Sjoyce mcintosh * monitor. 719cb174861Sjoyce mcintosh * Insert the grant into the list and increment the grant count. 720cb174861Sjoyce mcintosh */ 721cb174861Sjoyce mcintosh static int 722cb174861Sjoyce mcintosh smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og) 723cb174861Sjoyce mcintosh { 724cb174861Sjoyce mcintosh smb_oplock_t *ol = &node->n_oplock; 725cb174861Sjoyce mcintosh 726cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex)); 727cb174861Sjoyce mcintosh 728cb174861Sjoyce mcintosh if (ol->ol_count == 0) { 729cb174861Sjoyce mcintosh if (smb_oplock_install_fem(node) != 0) 730cb174861Sjoyce mcintosh return (-1); 731cb174861Sjoyce mcintosh } 732cb174861Sjoyce mcintosh 733cb174861Sjoyce mcintosh list_insert_tail(&ol->ol_grants, og); 734cb174861Sjoyce mcintosh ++ol->ol_count; 735cb174861Sjoyce mcintosh return (0); 736cb174861Sjoyce mcintosh } 737cb174861Sjoyce mcintosh 738cb174861Sjoyce mcintosh /* 739cb174861Sjoyce mcintosh * smb_oplock_remove_grant 740cb174861Sjoyce mcintosh * 741cb174861Sjoyce mcintosh * Remove the oplock grant from the list, decrement the grant count 742cb174861Sjoyce mcintosh * and, if there are no other grants in the list, uninstall the fem 743cb174861Sjoyce mcintosh * monitor. 744cb174861Sjoyce mcintosh */ 745cb174861Sjoyce mcintosh static void 746cb174861Sjoyce mcintosh smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og) 747cb174861Sjoyce mcintosh { 748cb174861Sjoyce mcintosh smb_oplock_t *ol = &node->n_oplock; 749cb174861Sjoyce mcintosh 750cb174861Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex)); 751cb174861Sjoyce mcintosh ASSERT(ol->ol_count > 0); 752cb174861Sjoyce mcintosh 753cb174861Sjoyce mcintosh list_remove(&ol->ol_grants, og); 754cb174861Sjoyce mcintosh if (--ol->ol_count == 0) 755cb174861Sjoyce mcintosh smb_oplock_uninstall_fem(node); 756cb174861Sjoyce mcintosh } 757cb174861Sjoyce mcintosh 758cb174861Sjoyce mcintosh /* 759cb174861Sjoyce mcintosh * smb_oplock_exclusive_grant 760cb174861Sjoyce mcintosh * 761cb174861Sjoyce mcintosh * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists, 762cb174861Sjoyce mcintosh * return it. Otherwise return NULL. 763cb174861Sjoyce mcintosh */ 764cb174861Sjoyce mcintosh static smb_oplock_grant_t * 765cb174861Sjoyce mcintosh smb_oplock_exclusive_grant(list_t *grants) 766cb174861Sjoyce mcintosh { 767cb174861Sjoyce mcintosh smb_oplock_grant_t *og; 768cb174861Sjoyce mcintosh 769cb174861Sjoyce mcintosh og = list_head(grants); 770cb174861Sjoyce mcintosh if (og) { 771cb174861Sjoyce mcintosh SMB_OPLOCK_GRANT_VALID(og); 772cb174861Sjoyce mcintosh if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) 773cb174861Sjoyce mcintosh return (og); 774cb174861Sjoyce mcintosh } 775cb174861Sjoyce mcintosh return (NULL); 776cb174861Sjoyce mcintosh } 777cb174861Sjoyce mcintosh 778cb174861Sjoyce mcintosh /* 7791fdeec65Sjoyce mcintosh * smb_oplock_get_grant 780cb174861Sjoyce mcintosh * 781cb174861Sjoyce mcintosh * Find oplock grant corresponding to the specified ofile. 782cb174861Sjoyce mcintosh */ 783cb174861Sjoyce mcintosh static smb_oplock_grant_t * 7841fdeec65Sjoyce mcintosh smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile) 785cb174861Sjoyce mcintosh { 7861fdeec65Sjoyce mcintosh ASSERT(MUTEX_HELD(&ol->ol_mutex)); 787cb174861Sjoyce mcintosh 7881fdeec65Sjoyce mcintosh if (SMB_OFILE_OPLOCK_GRANTED(ofile)) 7891fdeec65Sjoyce mcintosh return (&ofile->f_oplock_grant); 7901fdeec65Sjoyce mcintosh else 7911fdeec65Sjoyce mcintosh return (NULL); 792cb174861Sjoyce mcintosh } 793