16600Sas200622 /*
26600Sas200622 * CDDL HEADER START
36600Sas200622 *
46600Sas200622 * The contents of this file are subject to the terms of the
56600Sas200622 * Common Development and Distribution License (the "License").
66600Sas200622 * You may not use this file except in compliance with the License.
76600Sas200622 *
86600Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96600Sas200622 * or http://www.opensolaris.org/os/licensing.
106600Sas200622 * See the License for the specific language governing permissions
116600Sas200622 * and limitations under the License.
126600Sas200622 *
136600Sas200622 * When distributing Covered Code, include this CDDL HEADER in each
146600Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156600Sas200622 * If applicable, add the following below this CDDL HEADER, with the
166600Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying
176600Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner]
186600Sas200622 *
196600Sas200622 * CDDL HEADER END
206600Sas200622 */
216600Sas200622 /*
2212508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
236600Sas200622 */
2412890SJoyce.McIntosh@Sun.COM
256600Sas200622 /*
2612890SJoyce.McIntosh@Sun.COM * smb_oplock_wait / smb_oplock_broadcast
2712890SJoyce.McIntosh@Sun.COM * When an oplock is being acquired, we must ensure that the acquisition
2812890SJoyce.McIntosh@Sun.COM * response is submitted to the network stack before any other operation
2912890SJoyce.McIntosh@Sun.COM * is permitted on the oplock.
3012890SJoyce.McIntosh@Sun.COM * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker
3112890SJoyce.McIntosh@Sun.COM * thread processing the command that is granting the oplock.
3212890SJoyce.McIntosh@Sun.COM * Other threads accessing the oplock will be suspended in smb_oplock_wait().
3312890SJoyce.McIntosh@Sun.COM * They will be awakened when the worker thread referenced in 'ol_xthread'
3412890SJoyce.McIntosh@Sun.COM * calls smb_oplock_broadcast().
359231SAfshin.Ardakani@Sun.COM *
3612890SJoyce.McIntosh@Sun.COM * The purpose of this mechanism is to prevent another thread from
3712890SJoyce.McIntosh@Sun.COM * triggering an oplock break before the response conveying the grant
3812890SJoyce.McIntosh@Sun.COM * has been sent.
396600Sas200622 */
406600Sas200622
4110966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
4212890SJoyce.McIntosh@Sun.COM #include <sys/nbmlock.h>
438670SJose.Borrego@Sun.COM #include <inet/tcp.h>
446600Sas200622
4512890SJoyce.McIntosh@Sun.COM #define SMB_OPLOCK_IS_EXCLUSIVE(level) \
4612890SJoyce.McIntosh@Sun.COM (((level) == SMB_OPLOCK_EXCLUSIVE) || \
4712890SJoyce.McIntosh@Sun.COM ((level) == SMB_OPLOCK_BATCH))
4812890SJoyce.McIntosh@Sun.COM
4912890SJoyce.McIntosh@Sun.COM extern int smb_fem_oplock_install(smb_node_t *);
5012890SJoyce.McIntosh@Sun.COM extern int smb_fem_oplock_uninstall(smb_node_t *);
5112890SJoyce.McIntosh@Sun.COM
5212890SJoyce.McIntosh@Sun.COM static int smb_oplock_install_fem(smb_node_t *);
5312890SJoyce.McIntosh@Sun.COM static void smb_oplock_uninstall_fem(smb_node_t *);
5412890SJoyce.McIntosh@Sun.COM
559021Samw@Sun.COM static void smb_oplock_wait(smb_node_t *);
5612890SJoyce.McIntosh@Sun.COM static void smb_oplock_wait_ack(smb_node_t *, uint32_t);
5712890SJoyce.McIntosh@Sun.COM static void smb_oplock_timedout(smb_node_t *);
5812890SJoyce.McIntosh@Sun.COM
5912914SJoyce.McIntosh@Sun.COM static smb_oplock_grant_t *smb_oplock_set_grant(smb_ofile_t *, uint8_t);
6012914SJoyce.McIntosh@Sun.COM void smb_oplock_clear_grant(smb_oplock_grant_t *);
6112890SJoyce.McIntosh@Sun.COM static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *);
6212890SJoyce.McIntosh@Sun.COM static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *);
6312890SJoyce.McIntosh@Sun.COM static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *);
6412914SJoyce.McIntosh@Sun.COM static smb_oplock_grant_t *smb_oplock_get_grant(smb_oplock_t *, smb_ofile_t *);
6512890SJoyce.McIntosh@Sun.COM
6612890SJoyce.McIntosh@Sun.COM static smb_oplock_break_t *smb_oplock_create_break(smb_node_t *);
6712890SJoyce.McIntosh@Sun.COM static smb_oplock_break_t *smb_oplock_get_break(void);
6812890SJoyce.McIntosh@Sun.COM static void smb_oplock_delete_break(smb_oplock_break_t *);
6912890SJoyce.McIntosh@Sun.COM static void smb_oplock_process_levelII_break(smb_node_t *);
7012890SJoyce.McIntosh@Sun.COM
7112890SJoyce.McIntosh@Sun.COM static void smb_oplock_break_thread();
7212890SJoyce.McIntosh@Sun.COM
7312890SJoyce.McIntosh@Sun.COM /* levelII oplock break requests (smb_oplock_break_t) */
7412890SJoyce.McIntosh@Sun.COM static boolean_t smb_oplock_initialized = B_FALSE;
7512890SJoyce.McIntosh@Sun.COM static kmem_cache_t *smb_oplock_break_cache = NULL;
7612890SJoyce.McIntosh@Sun.COM static smb_llist_t smb_oplock_breaks;
7712890SJoyce.McIntosh@Sun.COM static smb_thread_t smb_oplock_thread;
7812890SJoyce.McIntosh@Sun.COM
796600Sas200622
806600Sas200622 /*
8112890SJoyce.McIntosh@Sun.COM * smb_oplock_init
826600Sas200622 *
8312890SJoyce.McIntosh@Sun.COM * This function is not multi-thread safe. The caller must make sure only one
8412890SJoyce.McIntosh@Sun.COM * thread makes the call.
8512890SJoyce.McIntosh@Sun.COM */
8612890SJoyce.McIntosh@Sun.COM int
smb_oplock_init(void)8712890SJoyce.McIntosh@Sun.COM smb_oplock_init(void)
8812890SJoyce.McIntosh@Sun.COM {
8912890SJoyce.McIntosh@Sun.COM int rc;
9012890SJoyce.McIntosh@Sun.COM
9112890SJoyce.McIntosh@Sun.COM if (smb_oplock_initialized)
9212890SJoyce.McIntosh@Sun.COM return (0);
9312890SJoyce.McIntosh@Sun.COM
9412890SJoyce.McIntosh@Sun.COM smb_oplock_break_cache = kmem_cache_create("smb_oplock_break_cache",
9512890SJoyce.McIntosh@Sun.COM sizeof (smb_oplock_break_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
9612890SJoyce.McIntosh@Sun.COM
9712890SJoyce.McIntosh@Sun.COM smb_llist_constructor(&smb_oplock_breaks, sizeof (smb_oplock_break_t),
9812890SJoyce.McIntosh@Sun.COM offsetof(smb_oplock_break_t, ob_lnd));
9912890SJoyce.McIntosh@Sun.COM
10012890SJoyce.McIntosh@Sun.COM smb_thread_init(&smb_oplock_thread, "smb_thread_oplock_break",
101*13138SJose.Borrego@Sun.COM smb_oplock_break_thread, NULL);
10212890SJoyce.McIntosh@Sun.COM
10312890SJoyce.McIntosh@Sun.COM rc = smb_thread_start(&smb_oplock_thread);
10412890SJoyce.McIntosh@Sun.COM if (rc != 0) {
10512890SJoyce.McIntosh@Sun.COM smb_thread_destroy(&smb_oplock_thread);
10612890SJoyce.McIntosh@Sun.COM smb_llist_destructor(&smb_oplock_breaks);
10712890SJoyce.McIntosh@Sun.COM kmem_cache_destroy(smb_oplock_break_cache);
10812890SJoyce.McIntosh@Sun.COM return (rc);
10912890SJoyce.McIntosh@Sun.COM }
11012890SJoyce.McIntosh@Sun.COM
11112890SJoyce.McIntosh@Sun.COM smb_oplock_initialized = B_TRUE;
11212890SJoyce.McIntosh@Sun.COM return (0);
11312890SJoyce.McIntosh@Sun.COM }
11412890SJoyce.McIntosh@Sun.COM
11512890SJoyce.McIntosh@Sun.COM /*
11612890SJoyce.McIntosh@Sun.COM * smb_oplock_fini
11712890SJoyce.McIntosh@Sun.COM * This function is not multi-thread safe. The caller must make sure only one
11812890SJoyce.McIntosh@Sun.COM * thread makes the call.
1196600Sas200622 */
12012890SJoyce.McIntosh@Sun.COM void
smb_oplock_fini(void)12112890SJoyce.McIntosh@Sun.COM smb_oplock_fini(void)
12212890SJoyce.McIntosh@Sun.COM {
12312890SJoyce.McIntosh@Sun.COM smb_oplock_break_t *ob;
12412890SJoyce.McIntosh@Sun.COM
12512890SJoyce.McIntosh@Sun.COM if (!smb_oplock_initialized)
12612890SJoyce.McIntosh@Sun.COM return;
12712890SJoyce.McIntosh@Sun.COM
12812890SJoyce.McIntosh@Sun.COM smb_thread_stop(&smb_oplock_thread);
12912890SJoyce.McIntosh@Sun.COM smb_thread_destroy(&smb_oplock_thread);
13012890SJoyce.McIntosh@Sun.COM
13112890SJoyce.McIntosh@Sun.COM while ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) {
13212890SJoyce.McIntosh@Sun.COM SMB_OPLOCK_BREAK_VALID(ob);
13312890SJoyce.McIntosh@Sun.COM smb_llist_remove(&smb_oplock_breaks, ob);
13412890SJoyce.McIntosh@Sun.COM smb_oplock_delete_break(ob);
13512890SJoyce.McIntosh@Sun.COM }
13612890SJoyce.McIntosh@Sun.COM smb_llist_destructor(&smb_oplock_breaks);
13712890SJoyce.McIntosh@Sun.COM
13812890SJoyce.McIntosh@Sun.COM kmem_cache_destroy(smb_oplock_break_cache);
13912890SJoyce.McIntosh@Sun.COM }
14012890SJoyce.McIntosh@Sun.COM
14112890SJoyce.McIntosh@Sun.COM /*
14212890SJoyce.McIntosh@Sun.COM * smb_oplock_install_fem
14312890SJoyce.McIntosh@Sun.COM * Install fem monitor for cross protocol oplock breaking.
14412890SJoyce.McIntosh@Sun.COM */
14512890SJoyce.McIntosh@Sun.COM static int
smb_oplock_install_fem(smb_node_t * node)14612890SJoyce.McIntosh@Sun.COM smb_oplock_install_fem(smb_node_t *node)
14712890SJoyce.McIntosh@Sun.COM {
14812890SJoyce.McIntosh@Sun.COM ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
14912890SJoyce.McIntosh@Sun.COM
15012890SJoyce.McIntosh@Sun.COM if (node->n_oplock.ol_fem == B_FALSE) {
15112890SJoyce.McIntosh@Sun.COM if (smb_fem_oplock_install(node) != 0) {
15212890SJoyce.McIntosh@Sun.COM cmn_err(CE_NOTE, "No oplock granted: "
15312890SJoyce.McIntosh@Sun.COM "failed to install fem monitor %s",
15412890SJoyce.McIntosh@Sun.COM node->vp->v_path);
15512890SJoyce.McIntosh@Sun.COM return (-1);
15612890SJoyce.McIntosh@Sun.COM }
15712890SJoyce.McIntosh@Sun.COM node->n_oplock.ol_fem = B_TRUE;
15812890SJoyce.McIntosh@Sun.COM }
15912890SJoyce.McIntosh@Sun.COM return (0);
16012890SJoyce.McIntosh@Sun.COM }
16112890SJoyce.McIntosh@Sun.COM
16212890SJoyce.McIntosh@Sun.COM /*
16312890SJoyce.McIntosh@Sun.COM * smb_oplock_uninstall_fem
16412890SJoyce.McIntosh@Sun.COM * Uninstall fem monitor for cross protocol oplock breaking.
16512890SJoyce.McIntosh@Sun.COM */
16612890SJoyce.McIntosh@Sun.COM static void
smb_oplock_uninstall_fem(smb_node_t * node)16712890SJoyce.McIntosh@Sun.COM smb_oplock_uninstall_fem(smb_node_t *node)
16812890SJoyce.McIntosh@Sun.COM {
16912890SJoyce.McIntosh@Sun.COM ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
17012890SJoyce.McIntosh@Sun.COM
17112890SJoyce.McIntosh@Sun.COM if (node->n_oplock.ol_fem) {
17212890SJoyce.McIntosh@Sun.COM if (smb_fem_oplock_uninstall(node) == 0) {
17312890SJoyce.McIntosh@Sun.COM node->n_oplock.ol_fem = B_FALSE;
17412890SJoyce.McIntosh@Sun.COM } else {
17512890SJoyce.McIntosh@Sun.COM cmn_err(CE_NOTE,
17612890SJoyce.McIntosh@Sun.COM "failed to uninstall fem monitor %s",
17712890SJoyce.McIntosh@Sun.COM node->vp->v_path);
17812890SJoyce.McIntosh@Sun.COM }
17912890SJoyce.McIntosh@Sun.COM }
18012890SJoyce.McIntosh@Sun.COM }
1816600Sas200622
1826600Sas200622 /*
1836600Sas200622 * smb_oplock_acquire
1846600Sas200622 *
18512890SJoyce.McIntosh@Sun.COM * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
18612890SJoyce.McIntosh@Sun.COM * but might only be granted LEVEL_II or NONE.
1876600Sas200622 *
18812890SJoyce.McIntosh@Sun.COM * If oplocks are not supported on the tree, or node, grant NONE.
18912890SJoyce.McIntosh@Sun.COM * If nobody else has the file open, grant the requested level.
19012890SJoyce.McIntosh@Sun.COM * If any of the following are true, grant NONE:
19112890SJoyce.McIntosh@Sun.COM * - there is an exclusive oplock on the node
19212890SJoyce.McIntosh@Sun.COM * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
19312890SJoyce.McIntosh@Sun.COM * - LEVEL_II oplocks are not supported for the session
19412890SJoyce.McIntosh@Sun.COM * - a BATCH oplock is requested on a named stream
19512890SJoyce.McIntosh@Sun.COM * - there are any range locks on the node
19612890SJoyce.McIntosh@Sun.COM * Otherwise, grant LEVEL_II.
1976600Sas200622 *
19812890SJoyce.McIntosh@Sun.COM * ol->ol_xthread is set to the current thread to lock the oplock against
19912890SJoyce.McIntosh@Sun.COM * other operations until the acquire response is on the wire. When the
20012890SJoyce.McIntosh@Sun.COM * acquire response is on the wire, smb_oplock_broadcast() is called to
20112890SJoyce.McIntosh@Sun.COM * reset ol->ol_xthread and wake any waiting threads.
2026600Sas200622 */
2038934SJose.Borrego@Sun.COM void
smb_oplock_acquire(smb_request_t * sr,smb_node_t * node,smb_ofile_t * ofile)20412890SJoyce.McIntosh@Sun.COM smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
2056600Sas200622 {
20612890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol;
20712890SJoyce.McIntosh@Sun.COM smb_oplock_grant_t *og;
20812890SJoyce.McIntosh@Sun.COM list_t *grants;
20912890SJoyce.McIntosh@Sun.COM smb_arg_open_t *op;
21012890SJoyce.McIntosh@Sun.COM smb_tree_t *tree;
21112890SJoyce.McIntosh@Sun.COM smb_session_t *session;
2128934SJose.Borrego@Sun.COM
2138934SJose.Borrego@Sun.COM SMB_NODE_VALID(node);
21412890SJoyce.McIntosh@Sun.COM SMB_OFILE_VALID(ofile);
2158934SJose.Borrego@Sun.COM
21612890SJoyce.McIntosh@Sun.COM ASSERT(node == SMB_OFILE_GET_NODE(ofile));
2178934SJose.Borrego@Sun.COM
21812890SJoyce.McIntosh@Sun.COM op = &sr->sr_open;
21912890SJoyce.McIntosh@Sun.COM tree = SMB_OFILE_GET_TREE(ofile);
22012890SJoyce.McIntosh@Sun.COM session = SMB_OFILE_GET_SESSION(ofile);
2218934SJose.Borrego@Sun.COM
22212890SJoyce.McIntosh@Sun.COM if (!smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
22312890SJoyce.McIntosh@Sun.COM (op->op_oplock_level == SMB_OPLOCK_NONE) ||
22412890SJoyce.McIntosh@Sun.COM ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
22512890SJoyce.McIntosh@Sun.COM SMB_IS_STREAM(node))) {
2268934SJose.Borrego@Sun.COM op->op_oplock_level = SMB_OPLOCK_NONE;
2278934SJose.Borrego@Sun.COM return;
2288934SJose.Borrego@Sun.COM }
2298934SJose.Borrego@Sun.COM
2308934SJose.Borrego@Sun.COM ol = &node->n_oplock;
23112890SJoyce.McIntosh@Sun.COM grants = &ol->ol_grants;
2328934SJose.Borrego@Sun.COM
23312890SJoyce.McIntosh@Sun.COM mutex_enter(&ol->ol_mutex);
23412890SJoyce.McIntosh@Sun.COM smb_oplock_wait(node);
23512890SJoyce.McIntosh@Sun.COM
23612890SJoyce.McIntosh@Sun.COM nbl_start_crit(node->vp, RW_READER);
2376600Sas200622
23812890SJoyce.McIntosh@Sun.COM if ((node->n_open_count > 1) ||
23912890SJoyce.McIntosh@Sun.COM (node->n_opening_count > 1) ||
24012890SJoyce.McIntosh@Sun.COM smb_vop_other_opens(node->vp, ofile->f_mode)) {
24112890SJoyce.McIntosh@Sun.COM if ((!op->op_oplock_levelII) ||
24212890SJoyce.McIntosh@Sun.COM (!smb_session_levelII_oplocks(session)) ||
24312890SJoyce.McIntosh@Sun.COM (smb_oplock_exclusive_grant(grants) != NULL) ||
24412890SJoyce.McIntosh@Sun.COM (smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE) != 0)) {
24512890SJoyce.McIntosh@Sun.COM op->op_oplock_level = SMB_OPLOCK_NONE;
24612890SJoyce.McIntosh@Sun.COM nbl_end_crit(node->vp);
24712890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
2489021Samw@Sun.COM return;
2499021Samw@Sun.COM }
25012890SJoyce.McIntosh@Sun.COM
25112890SJoyce.McIntosh@Sun.COM op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
25212890SJoyce.McIntosh@Sun.COM }
25312890SJoyce.McIntosh@Sun.COM
25412890SJoyce.McIntosh@Sun.COM nbl_end_crit(node->vp);
25512890SJoyce.McIntosh@Sun.COM
25612914SJoyce.McIntosh@Sun.COM og = smb_oplock_set_grant(ofile, op->op_oplock_level);
25712890SJoyce.McIntosh@Sun.COM if (smb_oplock_insert_grant(node, og) != 0) {
25812914SJoyce.McIntosh@Sun.COM smb_oplock_clear_grant(og);
25912890SJoyce.McIntosh@Sun.COM op->op_oplock_level = SMB_OPLOCK_NONE;
26012890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
26112890SJoyce.McIntosh@Sun.COM return;
26212890SJoyce.McIntosh@Sun.COM }
26312890SJoyce.McIntosh@Sun.COM
26412890SJoyce.McIntosh@Sun.COM ol->ol_xthread = curthread;
26512890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
26612890SJoyce.McIntosh@Sun.COM }
26712890SJoyce.McIntosh@Sun.COM
26812890SJoyce.McIntosh@Sun.COM /*
26912890SJoyce.McIntosh@Sun.COM * smb_oplock_break
27012890SJoyce.McIntosh@Sun.COM *
27112890SJoyce.McIntosh@Sun.COM * Break granted oplocks according to the following rules:
27212890SJoyce.McIntosh@Sun.COM *
27312890SJoyce.McIntosh@Sun.COM * If there's an exclusive oplock granted on the node
27412890SJoyce.McIntosh@Sun.COM * - if the BREAK_BATCH flags is specified and the oplock is not
27512890SJoyce.McIntosh@Sun.COM * a batch oplock, no break is required.
27612890SJoyce.McIntosh@Sun.COM * - if the session doesn't support LEVEL II oplocks, and 'brk' is
27712890SJoyce.McIntosh@Sun.COM * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
27812890SJoyce.McIntosh@Sun.COM * - if the oplock is already breaking update the break level (if
27912890SJoyce.McIntosh@Sun.COM * the requested break is to a lesser level), otherwise send an
28012890SJoyce.McIntosh@Sun.COM * oplock break.
28112890SJoyce.McIntosh@Sun.COM * Wait for acknowledgement of the break (unless NOWAIT flag is set)
28212890SJoyce.McIntosh@Sun.COM *
28312890SJoyce.McIntosh@Sun.COM * Otherwise:
28412890SJoyce.McIntosh@Sun.COM * If there are level II oplocks granted on the node, and the flags
28512890SJoyce.McIntosh@Sun.COM * indicate that they should be broken (BREAK_TO_NONE specified,
28612890SJoyce.McIntosh@Sun.COM * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
28712890SJoyce.McIntosh@Sun.COM * break request for asynchronous processing.
28812890SJoyce.McIntosh@Sun.COM *
28912890SJoyce.McIntosh@Sun.COM * Returns:
29012890SJoyce.McIntosh@Sun.COM * 0 - oplock broken (or no break required)
29112890SJoyce.McIntosh@Sun.COM * EAGAIN - oplock break request sent and would block
29212890SJoyce.McIntosh@Sun.COM * awaiting the reponse but NOWAIT was specified
29312890SJoyce.McIntosh@Sun.COM */
29412890SJoyce.McIntosh@Sun.COM int
smb_oplock_break(smb_request_t * sr,smb_node_t * node,uint32_t flags)29512890SJoyce.McIntosh@Sun.COM smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
29612890SJoyce.McIntosh@Sun.COM {
29712890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol;
29812890SJoyce.McIntosh@Sun.COM smb_oplock_grant_t *og;
29912890SJoyce.McIntosh@Sun.COM list_t *grants;
30012890SJoyce.McIntosh@Sun.COM uint32_t timeout;
30112890SJoyce.McIntosh@Sun.COM uint8_t brk;
30212890SJoyce.McIntosh@Sun.COM
30312890SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node);
30412890SJoyce.McIntosh@Sun.COM ol = &node->n_oplock;
30512890SJoyce.McIntosh@Sun.COM grants = &ol->ol_grants;
30612890SJoyce.McIntosh@Sun.COM
30712890SJoyce.McIntosh@Sun.COM mutex_enter(&ol->ol_mutex);
30812890SJoyce.McIntosh@Sun.COM smb_oplock_wait(node);
30912890SJoyce.McIntosh@Sun.COM
31012890SJoyce.McIntosh@Sun.COM og = list_head(grants);
31112890SJoyce.McIntosh@Sun.COM if (og == NULL) {
31212890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
31312890SJoyce.McIntosh@Sun.COM return (0);
31412890SJoyce.McIntosh@Sun.COM }
31512890SJoyce.McIntosh@Sun.COM
31612890SJoyce.McIntosh@Sun.COM SMB_OPLOCK_GRANT_VALID(og);
31712890SJoyce.McIntosh@Sun.COM
31812890SJoyce.McIntosh@Sun.COM /* break levelII oplocks */
31912890SJoyce.McIntosh@Sun.COM if (og->og_level == SMB_OPLOCK_LEVEL_II) {
32012890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
32112890SJoyce.McIntosh@Sun.COM
32212890SJoyce.McIntosh@Sun.COM if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
32312890SJoyce.McIntosh@Sun.COM !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
32412890SJoyce.McIntosh@Sun.COM !(flags & SMB_OPLOCK_BREAK_BATCH)) {
32512890SJoyce.McIntosh@Sun.COM smb_oplock_break_levelII(node);
32612890SJoyce.McIntosh@Sun.COM }
32712890SJoyce.McIntosh@Sun.COM return (0);
32812890SJoyce.McIntosh@Sun.COM }
32912890SJoyce.McIntosh@Sun.COM
33012890SJoyce.McIntosh@Sun.COM /* break exclusive oplock */
33112890SJoyce.McIntosh@Sun.COM if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
33212890SJoyce.McIntosh@Sun.COM (og->og_level != SMB_OPLOCK_BATCH)) {
33312890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
33412890SJoyce.McIntosh@Sun.COM return (0);
33512890SJoyce.McIntosh@Sun.COM }
33612890SJoyce.McIntosh@Sun.COM
33712890SJoyce.McIntosh@Sun.COM if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
33812890SJoyce.McIntosh@Sun.COM smb_session_levelII_oplocks(og->og_session)) {
33912890SJoyce.McIntosh@Sun.COM brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
34012890SJoyce.McIntosh@Sun.COM } else {
34112890SJoyce.McIntosh@Sun.COM brk = SMB_OPLOCK_BREAK_TO_NONE;
34212890SJoyce.McIntosh@Sun.COM }
34312890SJoyce.McIntosh@Sun.COM
34412890SJoyce.McIntosh@Sun.COM switch (ol->ol_break) {
34512890SJoyce.McIntosh@Sun.COM case SMB_OPLOCK_NO_BREAK:
34612890SJoyce.McIntosh@Sun.COM ol->ol_break = brk;
34712890SJoyce.McIntosh@Sun.COM smb_session_oplock_break(og->og_session,
34812890SJoyce.McIntosh@Sun.COM og->og_tid, og->og_fid, brk);
3499021Samw@Sun.COM break;
35012890SJoyce.McIntosh@Sun.COM case SMB_OPLOCK_BREAK_TO_LEVEL_II:
35112890SJoyce.McIntosh@Sun.COM if (brk == SMB_OPLOCK_BREAK_TO_NONE)
35212890SJoyce.McIntosh@Sun.COM ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
35312890SJoyce.McIntosh@Sun.COM break;
35412890SJoyce.McIntosh@Sun.COM case SMB_OPLOCK_BREAK_TO_NONE:
35512890SJoyce.McIntosh@Sun.COM default:
35612890SJoyce.McIntosh@Sun.COM break;
35712890SJoyce.McIntosh@Sun.COM }
35812890SJoyce.McIntosh@Sun.COM
35912890SJoyce.McIntosh@Sun.COM if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
36012890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
36112890SJoyce.McIntosh@Sun.COM return (EAGAIN);
36212890SJoyce.McIntosh@Sun.COM }
36312890SJoyce.McIntosh@Sun.COM
36412890SJoyce.McIntosh@Sun.COM if (sr && (sr->session == og->og_session) &&
36512890SJoyce.McIntosh@Sun.COM (sr->smb_uid == og->og_uid)) {
36612890SJoyce.McIntosh@Sun.COM timeout = smb_oplock_min_timeout;
36712890SJoyce.McIntosh@Sun.COM } else {
36812890SJoyce.McIntosh@Sun.COM timeout = smb_oplock_timeout;
36912890SJoyce.McIntosh@Sun.COM }
37012890SJoyce.McIntosh@Sun.COM
37112890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
37212890SJoyce.McIntosh@Sun.COM smb_oplock_wait_ack(node, timeout);
37312890SJoyce.McIntosh@Sun.COM return (0);
37412890SJoyce.McIntosh@Sun.COM }
37512890SJoyce.McIntosh@Sun.COM
37612890SJoyce.McIntosh@Sun.COM /*
37712890SJoyce.McIntosh@Sun.COM * smb_oplock_break_levelII
37812890SJoyce.McIntosh@Sun.COM *
37912890SJoyce.McIntosh@Sun.COM * LevelII (shared) oplock breaks are processed asynchronously.
38012890SJoyce.McIntosh@Sun.COM * Unlike exclusive oplock breaks, the thread initiating the break
38112890SJoyce.McIntosh@Sun.COM * is NOT blocked while the request is processed.
38212890SJoyce.McIntosh@Sun.COM *
38312890SJoyce.McIntosh@Sun.COM * Create an oplock_break_request and add it to the list for async
38412890SJoyce.McIntosh@Sun.COM * processing.
38512890SJoyce.McIntosh@Sun.COM */
38612890SJoyce.McIntosh@Sun.COM void
smb_oplock_break_levelII(smb_node_t * node)38712890SJoyce.McIntosh@Sun.COM smb_oplock_break_levelII(smb_node_t *node)
38812890SJoyce.McIntosh@Sun.COM {
38912890SJoyce.McIntosh@Sun.COM smb_oplock_break_t *ob;
39012890SJoyce.McIntosh@Sun.COM
39112890SJoyce.McIntosh@Sun.COM ob = smb_oplock_create_break(node);
39212890SJoyce.McIntosh@Sun.COM
39312890SJoyce.McIntosh@Sun.COM smb_llist_enter(&smb_oplock_breaks, RW_WRITER);
39412890SJoyce.McIntosh@Sun.COM smb_llist_insert_tail(&smb_oplock_breaks, ob);
39512890SJoyce.McIntosh@Sun.COM smb_llist_exit(&smb_oplock_breaks);
39612890SJoyce.McIntosh@Sun.COM
39712890SJoyce.McIntosh@Sun.COM smb_thread_signal(&smb_oplock_thread);
39812890SJoyce.McIntosh@Sun.COM }
39912890SJoyce.McIntosh@Sun.COM
40012890SJoyce.McIntosh@Sun.COM /*
40112890SJoyce.McIntosh@Sun.COM * smb_oplock_break_thread
40212890SJoyce.McIntosh@Sun.COM *
40312890SJoyce.McIntosh@Sun.COM * The smb_oplock_thread is woken when an oplock break request is
40412890SJoyce.McIntosh@Sun.COM * added to the list of pending levelII oplock break requests.
40512890SJoyce.McIntosh@Sun.COM * Gets the oplock break request from the list, processes it and
40612890SJoyce.McIntosh@Sun.COM * deletes it.
40712890SJoyce.McIntosh@Sun.COM */
40812890SJoyce.McIntosh@Sun.COM /*ARGSUSED*/
40912890SJoyce.McIntosh@Sun.COM static void
smb_oplock_break_thread(smb_thread_t * thread,void * arg)41012890SJoyce.McIntosh@Sun.COM smb_oplock_break_thread(smb_thread_t *thread, void *arg)
41112890SJoyce.McIntosh@Sun.COM {
41212890SJoyce.McIntosh@Sun.COM smb_oplock_break_t *ob;
41312890SJoyce.McIntosh@Sun.COM
41412890SJoyce.McIntosh@Sun.COM while (smb_thread_continue(thread)) {
41512890SJoyce.McIntosh@Sun.COM while ((ob = smb_oplock_get_break()) != NULL) {
41612890SJoyce.McIntosh@Sun.COM smb_oplock_process_levelII_break(ob->ob_node);
41712890SJoyce.McIntosh@Sun.COM smb_oplock_delete_break(ob);
41812890SJoyce.McIntosh@Sun.COM }
41912890SJoyce.McIntosh@Sun.COM }
42012890SJoyce.McIntosh@Sun.COM }
42112890SJoyce.McIntosh@Sun.COM
42212890SJoyce.McIntosh@Sun.COM /*
42312890SJoyce.McIntosh@Sun.COM * smb_oplock_get_break
42412890SJoyce.McIntosh@Sun.COM *
42512890SJoyce.McIntosh@Sun.COM * Remove and return the next oplock break request from the list
42612890SJoyce.McIntosh@Sun.COM */
42712890SJoyce.McIntosh@Sun.COM static smb_oplock_break_t *
smb_oplock_get_break(void)42812890SJoyce.McIntosh@Sun.COM smb_oplock_get_break(void)
42912890SJoyce.McIntosh@Sun.COM {
43012890SJoyce.McIntosh@Sun.COM smb_oplock_break_t *ob;
43112890SJoyce.McIntosh@Sun.COM
43212890SJoyce.McIntosh@Sun.COM smb_llist_enter(&smb_oplock_breaks, RW_WRITER);
43312890SJoyce.McIntosh@Sun.COM if ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) {
43412890SJoyce.McIntosh@Sun.COM SMB_OPLOCK_BREAK_VALID(ob);
43512890SJoyce.McIntosh@Sun.COM smb_llist_remove(&smb_oplock_breaks, ob);
43612890SJoyce.McIntosh@Sun.COM }
43712890SJoyce.McIntosh@Sun.COM smb_llist_exit(&smb_oplock_breaks);
43812890SJoyce.McIntosh@Sun.COM return (ob);
43912890SJoyce.McIntosh@Sun.COM }
44012890SJoyce.McIntosh@Sun.COM
44112890SJoyce.McIntosh@Sun.COM /*
44212890SJoyce.McIntosh@Sun.COM * smb_oplock_process_levelII_break
44312890SJoyce.McIntosh@Sun.COM */
44412890SJoyce.McIntosh@Sun.COM void
smb_oplock_process_levelII_break(smb_node_t * node)44512890SJoyce.McIntosh@Sun.COM smb_oplock_process_levelII_break(smb_node_t *node)
44612890SJoyce.McIntosh@Sun.COM {
44712890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol;
44812890SJoyce.McIntosh@Sun.COM smb_oplock_grant_t *og;
44912890SJoyce.McIntosh@Sun.COM list_t *grants;
45012890SJoyce.McIntosh@Sun.COM
45112890SJoyce.McIntosh@Sun.COM if (!smb_oplock_levelII)
45212890SJoyce.McIntosh@Sun.COM return;
45312890SJoyce.McIntosh@Sun.COM
45412890SJoyce.McIntosh@Sun.COM ol = &node->n_oplock;
45512890SJoyce.McIntosh@Sun.COM mutex_enter(&ol->ol_mutex);
45612890SJoyce.McIntosh@Sun.COM smb_oplock_wait(node);
45712890SJoyce.McIntosh@Sun.COM grants = &node->n_oplock.ol_grants;
45812890SJoyce.McIntosh@Sun.COM
45912890SJoyce.McIntosh@Sun.COM while ((og = list_head(grants)) != NULL) {
46012890SJoyce.McIntosh@Sun.COM SMB_OPLOCK_GRANT_VALID(og);
46112890SJoyce.McIntosh@Sun.COM
46212890SJoyce.McIntosh@Sun.COM if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
46312890SJoyce.McIntosh@Sun.COM break;
46412890SJoyce.McIntosh@Sun.COM
46512890SJoyce.McIntosh@Sun.COM smb_session_oplock_break(og->og_session,
46612890SJoyce.McIntosh@Sun.COM og->og_tid, og->og_fid, SMB_OPLOCK_BREAK_TO_NONE);
46712890SJoyce.McIntosh@Sun.COM smb_oplock_remove_grant(node, og);
46812914SJoyce.McIntosh@Sun.COM smb_oplock_clear_grant(og);
46912890SJoyce.McIntosh@Sun.COM }
47012890SJoyce.McIntosh@Sun.COM
47112890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
47212890SJoyce.McIntosh@Sun.COM }
47312890SJoyce.McIntosh@Sun.COM
47412890SJoyce.McIntosh@Sun.COM /*
47512890SJoyce.McIntosh@Sun.COM * smb_oplock_wait_ack
47612890SJoyce.McIntosh@Sun.COM *
47712890SJoyce.McIntosh@Sun.COM * Timed wait for an oplock break acknowledgement (or oplock release).
47812890SJoyce.McIntosh@Sun.COM */
47912890SJoyce.McIntosh@Sun.COM static void
smb_oplock_wait_ack(smb_node_t * node,uint32_t timeout)48012890SJoyce.McIntosh@Sun.COM smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
48112890SJoyce.McIntosh@Sun.COM {
48212890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol;
48312890SJoyce.McIntosh@Sun.COM clock_t time;
48412890SJoyce.McIntosh@Sun.COM
48512890SJoyce.McIntosh@Sun.COM ol = &node->n_oplock;
48612890SJoyce.McIntosh@Sun.COM mutex_enter(&ol->ol_mutex);
48712890SJoyce.McIntosh@Sun.COM time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
48812890SJoyce.McIntosh@Sun.COM
48912890SJoyce.McIntosh@Sun.COM while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
49012890SJoyce.McIntosh@Sun.COM if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
49112890SJoyce.McIntosh@Sun.COM smb_oplock_timedout(node);
49212890SJoyce.McIntosh@Sun.COM cv_broadcast(&ol->ol_cv);
49312890SJoyce.McIntosh@Sun.COM break;
49412890SJoyce.McIntosh@Sun.COM }
49512890SJoyce.McIntosh@Sun.COM }
49612890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
49712890SJoyce.McIntosh@Sun.COM }
49812890SJoyce.McIntosh@Sun.COM
49912890SJoyce.McIntosh@Sun.COM /*
50012890SJoyce.McIntosh@Sun.COM * smb_oplock_timedout
50112890SJoyce.McIntosh@Sun.COM *
50212890SJoyce.McIntosh@Sun.COM * An oplock break has not been acknowledged within timeout
50312890SJoyce.McIntosh@Sun.COM * 'smb_oplock_timeout'.
50412890SJoyce.McIntosh@Sun.COM * Set oplock grant to the desired break level.
50512890SJoyce.McIntosh@Sun.COM */
50612890SJoyce.McIntosh@Sun.COM static void
smb_oplock_timedout(smb_node_t * node)50712890SJoyce.McIntosh@Sun.COM smb_oplock_timedout(smb_node_t *node)
50812890SJoyce.McIntosh@Sun.COM {
50912890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol;
51012890SJoyce.McIntosh@Sun.COM smb_oplock_grant_t *og;
51112890SJoyce.McIntosh@Sun.COM list_t *grants;
51212890SJoyce.McIntosh@Sun.COM
51312890SJoyce.McIntosh@Sun.COM ol = &node->n_oplock;
51412890SJoyce.McIntosh@Sun.COM grants = &ol->ol_grants;
51512890SJoyce.McIntosh@Sun.COM
51612890SJoyce.McIntosh@Sun.COM ASSERT(MUTEX_HELD(&ol->ol_mutex));
51712890SJoyce.McIntosh@Sun.COM
51812890SJoyce.McIntosh@Sun.COM og = smb_oplock_exclusive_grant(grants);
51912890SJoyce.McIntosh@Sun.COM if (og) {
52012890SJoyce.McIntosh@Sun.COM switch (ol->ol_break) {
52112890SJoyce.McIntosh@Sun.COM case SMB_OPLOCK_BREAK_TO_NONE:
52212890SJoyce.McIntosh@Sun.COM og->og_level = SMB_OPLOCK_NONE;
52312890SJoyce.McIntosh@Sun.COM smb_oplock_remove_grant(node, og);
52412914SJoyce.McIntosh@Sun.COM smb_oplock_clear_grant(og);
52512890SJoyce.McIntosh@Sun.COM break;
52612890SJoyce.McIntosh@Sun.COM case SMB_OPLOCK_BREAK_TO_LEVEL_II:
52712890SJoyce.McIntosh@Sun.COM og->og_level = SMB_OPLOCK_LEVEL_II;
52812890SJoyce.McIntosh@Sun.COM break;
52912890SJoyce.McIntosh@Sun.COM default:
53012890SJoyce.McIntosh@Sun.COM SMB_PANIC();
53112890SJoyce.McIntosh@Sun.COM }
53212890SJoyce.McIntosh@Sun.COM }
53312890SJoyce.McIntosh@Sun.COM ol->ol_break = SMB_OPLOCK_NO_BREAK;
53412890SJoyce.McIntosh@Sun.COM }
53512890SJoyce.McIntosh@Sun.COM
53612890SJoyce.McIntosh@Sun.COM /*
53712890SJoyce.McIntosh@Sun.COM * smb_oplock_release
53812890SJoyce.McIntosh@Sun.COM *
53912890SJoyce.McIntosh@Sun.COM * Release the oplock granted on ofile 'of'.
54012890SJoyce.McIntosh@Sun.COM * Wake any threads waiting for an oplock break acknowledgement for
54112890SJoyce.McIntosh@Sun.COM * this oplock.
54212890SJoyce.McIntosh@Sun.COM * This is called when the ofile is being closed.
54312890SJoyce.McIntosh@Sun.COM */
54412890SJoyce.McIntosh@Sun.COM void
smb_oplock_release(smb_node_t * node,smb_ofile_t * of)54512890SJoyce.McIntosh@Sun.COM smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
54612890SJoyce.McIntosh@Sun.COM {
54712890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol;
54812890SJoyce.McIntosh@Sun.COM smb_oplock_grant_t *og;
54912890SJoyce.McIntosh@Sun.COM
55012890SJoyce.McIntosh@Sun.COM ol = &node->n_oplock;
55112890SJoyce.McIntosh@Sun.COM mutex_enter(&ol->ol_mutex);
55212890SJoyce.McIntosh@Sun.COM smb_oplock_wait(node);
55312890SJoyce.McIntosh@Sun.COM
55412914SJoyce.McIntosh@Sun.COM og = smb_oplock_get_grant(ol, of);
55512890SJoyce.McIntosh@Sun.COM if (og) {
55612890SJoyce.McIntosh@Sun.COM smb_oplock_remove_grant(node, og);
55712914SJoyce.McIntosh@Sun.COM smb_oplock_clear_grant(og);
55812890SJoyce.McIntosh@Sun.COM
55912890SJoyce.McIntosh@Sun.COM if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
56012890SJoyce.McIntosh@Sun.COM ol->ol_break = SMB_OPLOCK_NO_BREAK;
56112890SJoyce.McIntosh@Sun.COM cv_broadcast(&ol->ol_cv);
56212890SJoyce.McIntosh@Sun.COM }
56312890SJoyce.McIntosh@Sun.COM }
56412890SJoyce.McIntosh@Sun.COM
56512890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
56612890SJoyce.McIntosh@Sun.COM }
56712890SJoyce.McIntosh@Sun.COM
56812890SJoyce.McIntosh@Sun.COM /*
56912890SJoyce.McIntosh@Sun.COM * smb_oplock_ack
57012890SJoyce.McIntosh@Sun.COM *
57112890SJoyce.McIntosh@Sun.COM * Process oplock acknowledgement received for ofile 'of'.
57212890SJoyce.McIntosh@Sun.COM * - oplock.ol_break is the break level that was requested.
57312890SJoyce.McIntosh@Sun.COM * - brk is the break level being acknowledged by the client.
57412890SJoyce.McIntosh@Sun.COM *
57512890SJoyce.McIntosh@Sun.COM * Update the oplock grant level to the lesser of ol_break and brk.
57612890SJoyce.McIntosh@Sun.COM * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
57712890SJoyce.McIntosh@Sun.COM * oplock's grant list and delete it.
57812890SJoyce.McIntosh@Sun.COM * If the requested break level (ol_break) was NONE and the brk is
57912890SJoyce.McIntosh@Sun.COM * LEVEL_II, send another oplock break (NONE). Do not wait for an
58012890SJoyce.McIntosh@Sun.COM * acknowledgement.
58112890SJoyce.McIntosh@Sun.COM * Wake any threads waiting for the oplock break acknowledgement.
58212890SJoyce.McIntosh@Sun.COM */
58312890SJoyce.McIntosh@Sun.COM void
smb_oplock_ack(smb_node_t * node,smb_ofile_t * of,uint8_t brk)58412890SJoyce.McIntosh@Sun.COM smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
58512890SJoyce.McIntosh@Sun.COM {
58612890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol;
58712890SJoyce.McIntosh@Sun.COM smb_oplock_grant_t *og;
58812890SJoyce.McIntosh@Sun.COM boolean_t brk_to_none = B_FALSE;
58912890SJoyce.McIntosh@Sun.COM
59012890SJoyce.McIntosh@Sun.COM ol = &node->n_oplock;
59112890SJoyce.McIntosh@Sun.COM mutex_enter(&ol->ol_mutex);
59212890SJoyce.McIntosh@Sun.COM smb_oplock_wait(node);
59312890SJoyce.McIntosh@Sun.COM
59412890SJoyce.McIntosh@Sun.COM if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
59512914SJoyce.McIntosh@Sun.COM ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
59612890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
59712890SJoyce.McIntosh@Sun.COM return;
59812890SJoyce.McIntosh@Sun.COM }
59912890SJoyce.McIntosh@Sun.COM
60012890SJoyce.McIntosh@Sun.COM switch (brk) {
60112890SJoyce.McIntosh@Sun.COM case SMB_OPLOCK_BREAK_TO_NONE:
60212890SJoyce.McIntosh@Sun.COM og->og_level = SMB_OPLOCK_NONE;
60312890SJoyce.McIntosh@Sun.COM break;
60412890SJoyce.McIntosh@Sun.COM case SMB_OPLOCK_BREAK_TO_LEVEL_II:
60512890SJoyce.McIntosh@Sun.COM if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
60612890SJoyce.McIntosh@Sun.COM og->og_level = SMB_OPLOCK_LEVEL_II;
60712890SJoyce.McIntosh@Sun.COM } else {
60812890SJoyce.McIntosh@Sun.COM /* SMB_OPLOCK_BREAK_TO_NONE */
60912890SJoyce.McIntosh@Sun.COM og->og_level = SMB_OPLOCK_NONE;
61012890SJoyce.McIntosh@Sun.COM brk_to_none = B_TRUE;
61112890SJoyce.McIntosh@Sun.COM }
6129021Samw@Sun.COM break;
6139021Samw@Sun.COM default:
6149021Samw@Sun.COM SMB_PANIC();
6159021Samw@Sun.COM }
6169021Samw@Sun.COM
61712890SJoyce.McIntosh@Sun.COM if (og->og_level == SMB_OPLOCK_NONE) {
61812890SJoyce.McIntosh@Sun.COM smb_oplock_remove_grant(node, og);
61912914SJoyce.McIntosh@Sun.COM smb_oplock_clear_grant(og);
62012890SJoyce.McIntosh@Sun.COM }
6216600Sas200622
62212890SJoyce.McIntosh@Sun.COM ol->ol_break = SMB_OPLOCK_NO_BREAK;
62312890SJoyce.McIntosh@Sun.COM cv_broadcast(&ol->ol_cv);
6246600Sas200622
62512890SJoyce.McIntosh@Sun.COM if (brk_to_none) {
62612890SJoyce.McIntosh@Sun.COM smb_session_oplock_break(of->f_session,
62712890SJoyce.McIntosh@Sun.COM of->f_tree->t_tid, of->f_fid,
62812890SJoyce.McIntosh@Sun.COM SMB_OPLOCK_BREAK_TO_NONE);
62912890SJoyce.McIntosh@Sun.COM }
6306600Sas200622
63112890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
6326600Sas200622 }
6336600Sas200622
6346600Sas200622 /*
63512890SJoyce.McIntosh@Sun.COM * smb_oplock_broadcast
6366600Sas200622 *
63712890SJoyce.McIntosh@Sun.COM * ol->ol_xthread identifies the thread that was performing an oplock
63812890SJoyce.McIntosh@Sun.COM * acquire. Other threads may be blocked awaiting completion of the
63912890SJoyce.McIntosh@Sun.COM * acquire.
64012890SJoyce.McIntosh@Sun.COM * If the calling thread is ol_ol_xthread, wake any waiting threads.
6416600Sas200622 */
6428934SJose.Borrego@Sun.COM void
smb_oplock_broadcast(smb_node_t * node)64312890SJoyce.McIntosh@Sun.COM smb_oplock_broadcast(smb_node_t *node)
6448934SJose.Borrego@Sun.COM {
6458934SJose.Borrego@Sun.COM smb_oplock_t *ol;
6466600Sas200622
6478934SJose.Borrego@Sun.COM SMB_NODE_VALID(node);
6488934SJose.Borrego@Sun.COM ol = &node->n_oplock;
6498934SJose.Borrego@Sun.COM
65012890SJoyce.McIntosh@Sun.COM mutex_enter(&ol->ol_mutex);
6518934SJose.Borrego@Sun.COM if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
6528934SJose.Borrego@Sun.COM ol->ol_xthread = NULL;
6539021Samw@Sun.COM cv_broadcast(&ol->ol_cv);
6546600Sas200622 }
65512890SJoyce.McIntosh@Sun.COM mutex_exit(&ol->ol_mutex);
6568934SJose.Borrego@Sun.COM }
6576600Sas200622
6588934SJose.Borrego@Sun.COM /*
6598934SJose.Borrego@Sun.COM * smb_oplock_wait
6608934SJose.Borrego@Sun.COM *
66112890SJoyce.McIntosh@Sun.COM * Wait for the completion of an oplock acquire.
66212890SJoyce.McIntosh@Sun.COM * If ol_xthread is not NULL and doesn't contain the pointer to the
66312890SJoyce.McIntosh@Sun.COM * context of the calling thread, the caller will sleep until the
66412890SJoyce.McIntosh@Sun.COM * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
6658934SJose.Borrego@Sun.COM */
6668934SJose.Borrego@Sun.COM static void
smb_oplock_wait(smb_node_t * node)6679021Samw@Sun.COM smb_oplock_wait(smb_node_t *node)
6688934SJose.Borrego@Sun.COM {
66912890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol;
67012890SJoyce.McIntosh@Sun.COM
67112890SJoyce.McIntosh@Sun.COM ol = &node->n_oplock;
67212890SJoyce.McIntosh@Sun.COM ASSERT(MUTEX_HELD(&ol->ol_mutex));
6738934SJose.Borrego@Sun.COM
6748934SJose.Borrego@Sun.COM if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
6758934SJose.Borrego@Sun.COM while (ol->ol_xthread != NULL)
67612890SJoyce.McIntosh@Sun.COM cv_wait(&ol->ol_cv, &ol->ol_mutex);
6776600Sas200622 }
6786600Sas200622 }
67912890SJoyce.McIntosh@Sun.COM
68012890SJoyce.McIntosh@Sun.COM /*
68112914SJoyce.McIntosh@Sun.COM * smb_oplock_set_grant
68212890SJoyce.McIntosh@Sun.COM */
68312890SJoyce.McIntosh@Sun.COM static smb_oplock_grant_t *
smb_oplock_set_grant(smb_ofile_t * of,uint8_t level)68412914SJoyce.McIntosh@Sun.COM smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
68512890SJoyce.McIntosh@Sun.COM {
68612890SJoyce.McIntosh@Sun.COM smb_oplock_grant_t *og;
68712890SJoyce.McIntosh@Sun.COM
68812914SJoyce.McIntosh@Sun.COM og = &of->f_oplock_grant;
68912914SJoyce.McIntosh@Sun.COM
69012890SJoyce.McIntosh@Sun.COM og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
69112890SJoyce.McIntosh@Sun.COM og->og_level = level;
69212890SJoyce.McIntosh@Sun.COM og->og_ofile = of;
69312890SJoyce.McIntosh@Sun.COM og->og_fid = of->f_fid;
69412890SJoyce.McIntosh@Sun.COM og->og_tid = of->f_tree->t_tid;
69512890SJoyce.McIntosh@Sun.COM og->og_uid = of->f_user->u_uid;
69612890SJoyce.McIntosh@Sun.COM og->og_session = of->f_session;
69712890SJoyce.McIntosh@Sun.COM return (og);
69812890SJoyce.McIntosh@Sun.COM }
69912890SJoyce.McIntosh@Sun.COM
70012890SJoyce.McIntosh@Sun.COM /*
70112914SJoyce.McIntosh@Sun.COM * smb_oplock_clear_grant
70212890SJoyce.McIntosh@Sun.COM */
70312890SJoyce.McIntosh@Sun.COM void
smb_oplock_clear_grant(smb_oplock_grant_t * og)70412914SJoyce.McIntosh@Sun.COM smb_oplock_clear_grant(smb_oplock_grant_t *og)
70512890SJoyce.McIntosh@Sun.COM {
70612914SJoyce.McIntosh@Sun.COM bzero(og, sizeof (smb_oplock_grant_t));
70712890SJoyce.McIntosh@Sun.COM }
70812890SJoyce.McIntosh@Sun.COM
70912890SJoyce.McIntosh@Sun.COM /*
71012890SJoyce.McIntosh@Sun.COM * smb_oplock_insert_grant
71112890SJoyce.McIntosh@Sun.COM *
71212890SJoyce.McIntosh@Sun.COM * If there are no grants in the oplock's list install the fem
71312890SJoyce.McIntosh@Sun.COM * monitor.
71412890SJoyce.McIntosh@Sun.COM * Insert the grant into the list and increment the grant count.
71512890SJoyce.McIntosh@Sun.COM */
71612890SJoyce.McIntosh@Sun.COM static int
smb_oplock_insert_grant(smb_node_t * node,smb_oplock_grant_t * og)71712890SJoyce.McIntosh@Sun.COM smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
71812890SJoyce.McIntosh@Sun.COM {
71912890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol = &node->n_oplock;
72012890SJoyce.McIntosh@Sun.COM
72112890SJoyce.McIntosh@Sun.COM ASSERT(MUTEX_HELD(&ol->ol_mutex));
72212890SJoyce.McIntosh@Sun.COM
72312890SJoyce.McIntosh@Sun.COM if (ol->ol_count == 0) {
72412890SJoyce.McIntosh@Sun.COM if (smb_oplock_install_fem(node) != 0)
72512890SJoyce.McIntosh@Sun.COM return (-1);
72612890SJoyce.McIntosh@Sun.COM }
72712890SJoyce.McIntosh@Sun.COM
72812890SJoyce.McIntosh@Sun.COM list_insert_tail(&ol->ol_grants, og);
72912890SJoyce.McIntosh@Sun.COM ++ol->ol_count;
73012890SJoyce.McIntosh@Sun.COM return (0);
73112890SJoyce.McIntosh@Sun.COM }
73212890SJoyce.McIntosh@Sun.COM
73312890SJoyce.McIntosh@Sun.COM /*
73412890SJoyce.McIntosh@Sun.COM * smb_oplock_remove_grant
73512890SJoyce.McIntosh@Sun.COM *
73612890SJoyce.McIntosh@Sun.COM * Remove the oplock grant from the list, decrement the grant count
73712890SJoyce.McIntosh@Sun.COM * and, if there are no other grants in the list, uninstall the fem
73812890SJoyce.McIntosh@Sun.COM * monitor.
73912890SJoyce.McIntosh@Sun.COM */
74012890SJoyce.McIntosh@Sun.COM static void
smb_oplock_remove_grant(smb_node_t * node,smb_oplock_grant_t * og)74112890SJoyce.McIntosh@Sun.COM smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
74212890SJoyce.McIntosh@Sun.COM {
74312890SJoyce.McIntosh@Sun.COM smb_oplock_t *ol = &node->n_oplock;
74412890SJoyce.McIntosh@Sun.COM
74512890SJoyce.McIntosh@Sun.COM ASSERT(MUTEX_HELD(&ol->ol_mutex));
74612890SJoyce.McIntosh@Sun.COM ASSERT(ol->ol_count > 0);
74712890SJoyce.McIntosh@Sun.COM
74812890SJoyce.McIntosh@Sun.COM list_remove(&ol->ol_grants, og);
74912890SJoyce.McIntosh@Sun.COM if (--ol->ol_count == 0)
75012890SJoyce.McIntosh@Sun.COM smb_oplock_uninstall_fem(node);
75112890SJoyce.McIntosh@Sun.COM }
75212890SJoyce.McIntosh@Sun.COM
75312890SJoyce.McIntosh@Sun.COM /*
75412890SJoyce.McIntosh@Sun.COM * smb_oplock_exclusive_grant
75512890SJoyce.McIntosh@Sun.COM *
75612890SJoyce.McIntosh@Sun.COM * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
75712890SJoyce.McIntosh@Sun.COM * return it. Otherwise return NULL.
75812890SJoyce.McIntosh@Sun.COM */
75912890SJoyce.McIntosh@Sun.COM static smb_oplock_grant_t *
smb_oplock_exclusive_grant(list_t * grants)76012890SJoyce.McIntosh@Sun.COM smb_oplock_exclusive_grant(list_t *grants)
76112890SJoyce.McIntosh@Sun.COM {
76212890SJoyce.McIntosh@Sun.COM smb_oplock_grant_t *og;
76312890SJoyce.McIntosh@Sun.COM
76412890SJoyce.McIntosh@Sun.COM og = list_head(grants);
76512890SJoyce.McIntosh@Sun.COM if (og) {
76612890SJoyce.McIntosh@Sun.COM SMB_OPLOCK_GRANT_VALID(og);
76712890SJoyce.McIntosh@Sun.COM if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
76812890SJoyce.McIntosh@Sun.COM return (og);
76912890SJoyce.McIntosh@Sun.COM }
77012890SJoyce.McIntosh@Sun.COM return (NULL);
77112890SJoyce.McIntosh@Sun.COM }
77212890SJoyce.McIntosh@Sun.COM
77312890SJoyce.McIntosh@Sun.COM /*
77412914SJoyce.McIntosh@Sun.COM * smb_oplock_get_grant
77512890SJoyce.McIntosh@Sun.COM *
77612890SJoyce.McIntosh@Sun.COM * Find oplock grant corresponding to the specified ofile.
77712890SJoyce.McIntosh@Sun.COM */
77812890SJoyce.McIntosh@Sun.COM static smb_oplock_grant_t *
smb_oplock_get_grant(smb_oplock_t * ol,smb_ofile_t * ofile)77912914SJoyce.McIntosh@Sun.COM smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
78012890SJoyce.McIntosh@Sun.COM {
78112914SJoyce.McIntosh@Sun.COM ASSERT(MUTEX_HELD(&ol->ol_mutex));
78212890SJoyce.McIntosh@Sun.COM
78312914SJoyce.McIntosh@Sun.COM if (SMB_OFILE_OPLOCK_GRANTED(ofile))
78412914SJoyce.McIntosh@Sun.COM return (&ofile->f_oplock_grant);
78512914SJoyce.McIntosh@Sun.COM else
78612914SJoyce.McIntosh@Sun.COM return (NULL);
78712890SJoyce.McIntosh@Sun.COM }
78812890SJoyce.McIntosh@Sun.COM
78912890SJoyce.McIntosh@Sun.COM /*
79012890SJoyce.McIntosh@Sun.COM * smb_oplock_create_break
79112890SJoyce.McIntosh@Sun.COM */
79212890SJoyce.McIntosh@Sun.COM static smb_oplock_break_t *
smb_oplock_create_break(smb_node_t * node)79312890SJoyce.McIntosh@Sun.COM smb_oplock_create_break(smb_node_t *node)
79412890SJoyce.McIntosh@Sun.COM {
79512890SJoyce.McIntosh@Sun.COM smb_oplock_break_t *ob;
79612890SJoyce.McIntosh@Sun.COM
79712890SJoyce.McIntosh@Sun.COM ob = kmem_cache_alloc(smb_oplock_break_cache, KM_SLEEP);
79812890SJoyce.McIntosh@Sun.COM
79912890SJoyce.McIntosh@Sun.COM smb_node_ref(node);
80012890SJoyce.McIntosh@Sun.COM ob->ob_magic = SMB_OPLOCK_BREAK_MAGIC;
80112890SJoyce.McIntosh@Sun.COM ob->ob_node = node;
80212890SJoyce.McIntosh@Sun.COM
80312890SJoyce.McIntosh@Sun.COM return (ob);
80412890SJoyce.McIntosh@Sun.COM }
80512890SJoyce.McIntosh@Sun.COM
80612890SJoyce.McIntosh@Sun.COM /*
80712890SJoyce.McIntosh@Sun.COM * smb_oplock_delete_break
80812890SJoyce.McIntosh@Sun.COM */
80912890SJoyce.McIntosh@Sun.COM static void
smb_oplock_delete_break(smb_oplock_break_t * ob)81012890SJoyce.McIntosh@Sun.COM smb_oplock_delete_break(smb_oplock_break_t *ob)
81112890SJoyce.McIntosh@Sun.COM {
81212890SJoyce.McIntosh@Sun.COM smb_node_release(ob->ob_node);
81312890SJoyce.McIntosh@Sun.COM kmem_cache_free(smb_oplock_break_cache, ob);
81412890SJoyce.McIntosh@Sun.COM }
815