--- old/usr/src/uts/common/fs/smbsrv/smb_oplock.c	Mon Aug  5 17:26:37 2019
+++ new/usr/src/uts/common/fs/smbsrv/smb_oplock.c	Mon Aug  5 17:26:37 2019
@@ -20,773 +20,139 @@
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
- * smb_oplock_wait / smb_oplock_broadcast
- * When an oplock is being acquired, we must ensure that the acquisition
- * response is submitted to the network stack before any other operation
- * is permitted on the oplock.
- * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker
- * thread processing the command that is granting the oplock.
- * Other threads accessing the oplock will be suspended in smb_oplock_wait().
- * They will be awakened when the worker thread referenced in 'ol_xthread'
- * calls smb_oplock_broadcast().
- *
- * The purpose of this mechanism is to prevent another thread from
- * triggering an oplock break before the response conveying the grant
- * has been sent.
+ * smb1 oplock support
  */
 
 #include <smbsrv/smb_kproto.h>
-#include <sys/nbmlock.h>
 
-#define	SMB_OPLOCK_IS_EXCLUSIVE(level)		\
-	(((level) == SMB_OPLOCK_EXCLUSIVE) ||	\
-	((level) == SMB_OPLOCK_BATCH))
+#define	BATCH_OR_EXCL	(OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
 
-static int smb_oplock_install_fem(smb_node_t *);
-static void smb_oplock_uninstall_fem(smb_node_t *);
-
-static void smb_oplock_wait(smb_node_t *);
-static void smb_oplock_wait_ack(smb_node_t *, uint32_t);
-static void smb_oplock_timedout(smb_node_t *);
-
-static smb_oplock_grant_t *smb_oplock_set_grant(smb_ofile_t *, uint8_t);
-void smb_oplock_clear_grant(smb_oplock_grant_t *);
-static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *);
-static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *);
-static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *);
-static smb_oplock_grant_t *smb_oplock_get_grant(smb_oplock_t *, smb_ofile_t *);
-
-static void smb_oplock_sched_async_break(smb_oplock_grant_t *, uint8_t);
-static void smb_oplock_exec_async_break(void *);
-static void smb_oplock_break_levelII_locked(smb_node_t *);
-
 /*
- * smb_oplock_install_fem
- * Install fem monitor for cross protocol oplock breaking.
+ * Client has an open handle and requests an oplock.
+ * Convert SMB1 oplock request info in to internal form,
+ * call common oplock code, convert result to SMB1.
  */
-static int
-smb_oplock_install_fem(smb_node_t *node)
-{
-	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
-
-	if (node->n_oplock.ol_fem == B_FALSE) {
-		if (smb_fem_oplock_install(node) != 0) {
-			cmn_err(CE_NOTE, "No oplock granted: "
-			    "failed to install fem monitor %s",
-			    node->vp->v_path);
-			return (-1);
-		}
-		node->n_oplock.ol_fem = B_TRUE;
-	}
-	return (0);
-}
-
-/*
- * smb_oplock_uninstall_fem
- * Uninstall fem monitor for cross protocol oplock breaking.
- */
-static void
-smb_oplock_uninstall_fem(smb_node_t *node)
-{
-	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
-
-	if (node->n_oplock.ol_fem) {
-		smb_fem_oplock_uninstall(node);
-		node->n_oplock.ol_fem = B_FALSE;
-	}
-}
-
-/*
- * This provides a way to fully disable oplocks, i.e. for testing.
- * You _really_ do _not_ want to turn this off, because if you do,
- * the clients send you very small read requests, and a _lot_ more
- * of them.  The skc_oplock_enable parameter can be used to enable
- * or disable exclusive oplocks.  Disabling that can be helpful
- * when there are clients not responding to oplock breaks.
- */
-int smb_oplocks_enabled = 1;
-
-/*
- * smb_oplock_acquire
- *
- * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
- * but might only be granted LEVEL_II or NONE.
- *
- * If oplocks are not supported on the tree, or node, grant NONE.
- * If nobody else has the file open, grant the requested level.
- * If any of the following are true, grant NONE:
- * - there is an exclusive oplock on the node
- * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
- * - LEVEL_II oplocks are not supported for the session
- * - a BATCH oplock is requested on a named stream
- * - there are any range locks on the node (SMB writers)
- * Otherwise, grant LEVEL_II.
- *
- * ol->ol_xthread is set to the current thread to lock the oplock against
- * other operations until the acquire response is on the wire. When the
- * acquire response is on the wire, smb_oplock_broadcast() is called to
- * reset ol->ol_xthread and wake any waiting threads.
- */
 void
-smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
+smb1_oplock_acquire(smb_request_t *sr, boolean_t level2ok)
 {
-	smb_oplock_t		*ol;
-	smb_oplock_grant_t	*og;
-	list_t			*grants;
-	smb_arg_open_t		*op;
-	smb_tree_t		*tree;
-	smb_session_t		*session;
+	smb_arg_open_t *op = &sr->arg.open;
+	smb_ofile_t *ofile = sr->fid_ofile;
+	uint32_t status;
 
-	SMB_NODE_VALID(node);
-	SMB_OFILE_VALID(ofile);
-
-	ASSERT(node == SMB_OFILE_GET_NODE(ofile));
-	ASSERT(RW_LOCK_HELD(&node->n_lock));
-
-	op = &sr->sr_open;
-	tree = SMB_OFILE_GET_TREE(ofile);
-	session = SMB_OFILE_GET_SESSION(ofile);
-
-	if (smb_oplocks_enabled == 0 ||
-	    (op->op_oplock_level == SMB_OPLOCK_NONE) ||
-	    ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
-	    SMB_IS_STREAM(node))) {
+	/* Only disk trees get oplocks. */
+	if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
 		op->op_oplock_level = SMB_OPLOCK_NONE;
 		return;
 	}
 
-	ol = &node->n_oplock;
-	grants = &ol->ol_grants;
-
-	mutex_enter(&ol->ol_mutex);
-	smb_oplock_wait(node);
-
-	/*
-	 * Even if there are no other opens, we might want to
-	 * grant only a Level II (shared) oplock so we avoid
-	 * ever granting exclusive oplocks.
-	 *
-	 * Borrowing the SMB_TREE_OPLOCKS flag to enable/disable
-	 * exclusive oplocks (for now).  See skc_oplock_enable,
-	 * which can now be taken as "exclusive oplock enable".
-	 * Should rename this parameter, and/or implement a new
-	 * multi-valued parameter for oplock enables.
-	 */
-	if ((node->n_open_count > 1) ||
-	    (node->n_opening_count > 1) ||
-	    !smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
-	    smb_vop_other_opens(node->vp, ofile->f_mode)) {
-		/*
-		 * There are other opens.
-		 */
-		if ((!op->op_oplock_levelII) ||
-		    (!smb_session_levelII_oplocks(session)) ||
-		    (smb_oplock_exclusive_grant(grants) != NULL) ||
-		    (smb_lock_range_access(sr, node, 0, 0, B_FALSE))) {
-			/*
-			 * LevelII (shared) oplock not allowed,
-			 * so reply with "none".
-			 */
-			op->op_oplock_level = SMB_OPLOCK_NONE;
-			mutex_exit(&ol->ol_mutex);
-			return;
-		}
-
-		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
-	}
-
-	og = smb_oplock_set_grant(ofile, op->op_oplock_level);
-	if (smb_oplock_insert_grant(node, og) != 0) {
-		smb_oplock_clear_grant(og);
+	if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
 		op->op_oplock_level = SMB_OPLOCK_NONE;
-		mutex_exit(&ol->ol_mutex);
 		return;
 	}
 
-	ol->ol_xthread = curthread;
-	mutex_exit(&ol->ol_mutex);
-}
+	if (!smb_session_levelII_oplocks(sr->session))
+		level2ok = B_FALSE;
 
-/*
- * smb_oplock_break
- *
- * Break granted oplocks according to the following rules:
- *
- * If there's an exclusive oplock granted on the node
- *  - if the BREAK_BATCH flags is specified and the oplock is not
- *    a batch oplock, no break is required.
- *  - if the session doesn't support LEVEL II oplocks, and 'brk' is
- *    BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
- *  - if the oplock is already breaking update the break level (if
- *    the requested break is to a lesser level), otherwise send an
- *    oplock break.
- *    Wait for acknowledgement of the break (unless NOWAIT flag is set)
- *
- * Otherwise:
- * If there are level II oplocks granted on the node, and the flags
- * indicate that they should be broken (BREAK_TO_NONE specified,
- * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
- * break request for asynchronous processing.
- *
- * Returns:
- *       0 - oplock broken (or no break required)
- *  EAGAIN - oplock break request sent and would block
- *           awaiting the reponse but NOWAIT was specified
- *
- * NB: sr == NULL when called by FEM framework.
- */
-int
-smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
-{
-	smb_oplock_t		*ol;
-	smb_oplock_grant_t	*og;
-	list_t			*grants;
-	uint32_t		timeout;
-	uint8_t			brk;
+	/* Common code checks file type. */
 
-	SMB_NODE_VALID(node);
-	ol = &node->n_oplock;
-	grants = &ol->ol_grants;
-
-	mutex_enter(&ol->ol_mutex);
-	smb_oplock_wait(node);
-
-	og = list_head(grants);
-	if (og == NULL) {
-		mutex_exit(&ol->ol_mutex);
-		return (0);
-	}
-
-	SMB_OPLOCK_GRANT_VALID(og);
-
-	/* break levelII oplocks */
-	if (og->og_level == SMB_OPLOCK_LEVEL_II) {
-		mutex_exit(&ol->ol_mutex);
-
-		if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
-		    !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
-		    !(flags & SMB_OPLOCK_BREAK_BATCH))  {
-			smb_oplock_break_levelII(node);
-		}
-		return (0);
-	}
-
-	/* break exclusive oplock */
-	if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
-	    (og->og_level != SMB_OPLOCK_BATCH)) {
-		mutex_exit(&ol->ol_mutex);
-		return (0);
-	}
-
-	if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
-	    smb_session_levelII_oplocks(og->og_session)) {
-		brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
-	} else {
-		brk = SMB_OPLOCK_BREAK_TO_NONE;
-	}
-
-	switch (ol->ol_break) {
-	case SMB_OPLOCK_NO_BREAK:
-		ol->ol_break = brk;
-		smb_oplock_sched_async_break(og, brk);
+	/*
+	 * SMB1: Convert to internal form.
+	 */
+	switch (op->op_oplock_level) {
+	case SMB_OPLOCK_BATCH:
+		op->op_oplock_state = OPLOCK_LEVEL_BATCH;
 		break;
-	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
-		if (brk == SMB_OPLOCK_BREAK_TO_NONE)
-			ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
+	case SMB_OPLOCK_EXCLUSIVE:
+		op->op_oplock_state = OPLOCK_LEVEL_ONE;
 		break;
-	case SMB_OPLOCK_BREAK_TO_NONE:
-	default:
+	case SMB_OPLOCK_LEVEL_II:
+		op->op_oplock_state = OPLOCK_LEVEL_TWO;
 		break;
+	case SMB_OPLOCK_NONE:
+	default:
+		op->op_oplock_level = SMB_OPLOCK_NONE;
+		return;
 	}
 
-	if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
-		mutex_exit(&ol->ol_mutex);
-		return (EAGAIN);
+	/*
+	 * Tree options may force shared oplocks
+	 */
+	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
+		op->op_oplock_state = OPLOCK_LEVEL_TWO;
 	}
 
-	if (sr && (sr->session == og->og_session) &&
-	    (sr->smb_uid == og->og_uid)) {
-		timeout = smb_oplock_min_timeout;
+	/*
+	 * Try exclusive first, if requested
+	 */
+	if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
+		status = smb_oplock_request(sr, ofile,
+		    &op->op_oplock_state);
 	} else {
-		timeout = smb_oplock_timeout;
+		status = NT_STATUS_OPLOCK_NOT_GRANTED;
 	}
 
-	mutex_exit(&ol->ol_mutex);
-	smb_oplock_wait_ack(node, timeout);
-	return (0);
-}
-
-/*
- * smb_oplock_break_levelII
- *
- * This is called after a file is modified in some way.  If there are
- * LevelII (shared) oplocks, break those to none.  If there is an
- * exclusive oplock, there can be no LevelII oplocks, so do nothing.
- *
- * LevelII (shared) oplock breaks are processed asynchronously.
- * Unlike exclusive oplock breaks, the thread initiating the break
- * is NOT blocked while the request is processed.
- *
- * There may be a thread with exclusive rights to oplock state for
- * this node (via ol_xthread in smb_oplock_wait) and if so, we must
- * avoid breaking oplocks until that's out of the way.  However, we
- * really don't want to block here, so when ol_xthread is set, we'll
- * just mark that a "break level II to none" is pending, and let the
- * exclusive thread do this work when it's done being exclusive.
- */
-void
-smb_oplock_break_levelII(smb_node_t *node)
-{
-	smb_oplock_t		*ol;
-
-	ol = &node->n_oplock;
-	mutex_enter(&ol->ol_mutex);
-
-	/* Instead of: smb_oplock_wait() ... */
-	if (ol->ol_xthread != NULL) {
-		/* Defer the call to smb_oplock_broadcast(). */
-		ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE;
-	} else {
-		/* Equivalent of smb_oplock_wait() done. */
-		smb_oplock_break_levelII_locked(node);
+	/*
+	 * If exclusive failed (or tree forced shared oplocks)
+	 * and if the caller supports Level II, try shared.
+	 */
+	if (status == NT_STATUS_OPLOCK_NOT_GRANTED && level2ok) {
+		op->op_oplock_state = OPLOCK_LEVEL_TWO;
+		status = smb_oplock_request(sr, ofile,
+		    &op->op_oplock_state);
 	}
 
-	mutex_exit(&ol->ol_mutex);
-}
-
-/*
- * smb_oplock_break_levelII_locked
- * Internal helper for smb_oplock_break_levelII()
- *
- * Called with the oplock mutex already held, and _after_
- * (the equivalent of) an smb_oplock_wait().
- */
-static void
-smb_oplock_break_levelII_locked(smb_node_t *node)
-{
-	smb_oplock_t		*ol;
-	smb_oplock_grant_t	*og;
-	list_t			*grants;
-
-	ol = &node->n_oplock;
-	grants = &ol->ol_grants;
-
-	ASSERT(MUTEX_HELD(&ol->ol_mutex));
-	ASSERT(ol->ol_xthread == NULL);
-
-	while ((og = list_head(grants)) != NULL) {
-		SMB_OPLOCK_GRANT_VALID(og);
-
-		/*
-		 * If there's an exclusive oplock, there are
-		 * no LevelII oplocks, so do nothing.
-		 */
-		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
-			break;
-
-		smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE);
-		smb_oplock_remove_grant(node, og);
-		smb_oplock_clear_grant(og);
+	/*
+	 * Either of the above may have returned the
+	 * status code that says we should wait.
+	 */
+	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
+		(void) smb_oplock_wait_break(ofile->f_node, 0);
+		status = 0;
 	}
-}
 
-/*
- * Schedule a call to smb_session_oplock_break
- * using an smb_request on the owning session.
- */
-static void
-smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk)
-{
-	smb_request_t		*sr;
-	smb_ofile_t		*ofile;
-
 	/*
-	 * Make sure we can get a hold on the ofile.  If we can't,
-	 * the file is closing, and there's no point scheduling an
-	 * oplock break on it.  (Also hold the tree and user.)
-	 * These holds account for the pointers we copy into the
-	 * smb_request fields: fid_ofile, tid_tree, uid_user.
-	 * These holds are released via smb_request_free after
-	 * the oplock break has been sent.
+	 * Keep track of what we got (in ofile->f_oplock.og_state)
+	 * so we'll know what we had when sending a break later.
+	 * The og_dialect here is the oplock dialect, which may be
+	 * different than SMB dialect.  Pre-NT clients did not
+	 * support "Level II" oplocks.  If we're talking to a
+	 * client that didn't set the CAP_LEVEL_II_OPLOCKS in
+	 * its capabilities, let og_dialect = LANMAN2_1.
 	 */
-	ofile = og->og_ofile;
-	if (!smb_ofile_hold(ofile))
+	ofile->f_oplock.og_dialect = (level2ok) ?
+	    NT_LM_0_12 : LANMAN2_1;
+	switch (status) {
+	case NT_STATUS_SUCCESS:
+		ofile->f_oplock.og_state = op->op_oplock_state;
+		break;
+	case NT_STATUS_OPLOCK_NOT_GRANTED:
+		ofile->f_oplock.og_state = 0;
+		op->op_oplock_level = SMB_OPLOCK_NONE;
 		return;
-	smb_tree_hold_internal(ofile->f_tree);
-	smb_user_hold_internal(ofile->f_user);
-
-	sr = smb_request_alloc(og->og_session, 0);
-	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
-	sr->user_cr = zone_kcred();
-	sr->fid_ofile = ofile;
-	sr->tid_tree = ofile->f_tree;
-	sr->uid_user = ofile->f_user;
-
-	sr->arg.olbrk = *og; /* struct copy */
-	sr->arg.olbrk.og_breaking = brk;
-
-	(void) taskq_dispatch(
-	    sr->sr_server->sv_worker_pool,
-	    smb_oplock_exec_async_break, sr, TQ_SLEEP);
-}
-
-/*
- * smb_oplock_exec_async_break
- *
- * Called via the taskq to handle an asynchronous oplock break.
- * We have a hold on the ofile, which keeps the FID here valid.
- */
-static void
-smb_oplock_exec_async_break(void *arg)
-{
-	smb_request_t *sr = arg;
-	smb_oplock_grant_t *og = &sr->arg.olbrk;
-
-	SMB_REQ_VALID(sr);
-	SMB_OPLOCK_GRANT_VALID(og);
-
-	mutex_enter(&sr->sr_mutex);
-	sr->sr_worker = curthread;
-	sr->sr_time_active = gethrtime();
-
-	switch (sr->sr_state) {
-	case SMB_REQ_STATE_SUBMITTED:
-		sr->sr_state = SMB_REQ_STATE_ACTIVE;
-		mutex_exit(&sr->sr_mutex);
-
-		/*
-		 * This is where we actually do the deferred work
-		 * requested by smb_oplock_sched_async_break().
-		 */
-		smb_session_oplock_break(sr, og->og_breaking);
-
-		mutex_enter(&sr->sr_mutex);
-		/* FALLTHROUGH */
-
-	default: /* typically cancelled */
-		sr->sr_state = SMB_REQ_STATE_COMPLETED;
-		mutex_exit(&sr->sr_mutex);
-	}
-
-	smb_request_free(sr);
-}
-
-/*
- * smb_oplock_wait_ack
- *
- * Timed wait for an oplock break acknowledgement (or oplock release).
- */
-static void
-smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
-{
-	smb_oplock_t	*ol;
-	clock_t		time;
-
-	ol = &node->n_oplock;
-	mutex_enter(&ol->ol_mutex);
-	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
-
-	while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
-		if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
-			smb_oplock_timedout(node);
-			cv_broadcast(&ol->ol_cv);
-			break;
-		}
-	}
-	mutex_exit(&ol->ol_mutex);
-}
-
-/*
- * smb_oplock_timedout
- *
- * An oplock break has not been acknowledged within timeout
- * 'smb_oplock_timeout'.
- * Set oplock grant to the desired break level.
- */
-static void
-smb_oplock_timedout(smb_node_t *node)
-{
-	smb_oplock_t		*ol;
-	smb_oplock_grant_t	*og;
-	list_t			*grants;
-
-	ol = &node->n_oplock;
-	grants = &ol->ol_grants;
-
-	ASSERT(MUTEX_HELD(&ol->ol_mutex));
-
-	og = smb_oplock_exclusive_grant(grants);
-	if (og) {
-		switch (ol->ol_break) {
-		case SMB_OPLOCK_BREAK_TO_NONE:
-			og->og_level = SMB_OPLOCK_NONE;
-			smb_oplock_remove_grant(node, og);
-			smb_oplock_clear_grant(og);
-			break;
-		case SMB_OPLOCK_BREAK_TO_LEVEL_II:
-			og->og_level = SMB_OPLOCK_LEVEL_II;
-			break;
-		default:
-			SMB_PANIC();
-		}
-	}
-	ol->ol_break = SMB_OPLOCK_NO_BREAK;
-}
-
-/*
- * smb_oplock_release
- *
- * Release the oplock granted on ofile 'of'.
- * Wake any threads waiting for an oplock break acknowledgement for
- * this oplock.
- * This is called when the ofile is being closed.
- */
-void
-smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
-{
-	smb_oplock_t		*ol;
-	smb_oplock_grant_t	*og;
-
-	ol = &node->n_oplock;
-	mutex_enter(&ol->ol_mutex);
-	smb_oplock_wait(node);
-
-	og = smb_oplock_get_grant(ol, of);
-	if (og) {
-		smb_oplock_remove_grant(node, og);
-		smb_oplock_clear_grant(og);
-
-		if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
-			ol->ol_break = SMB_OPLOCK_NO_BREAK;
-			cv_broadcast(&ol->ol_cv);
-		}
-	}
-
-	mutex_exit(&ol->ol_mutex);
-}
-
-/*
- * smb_oplock_ack
- *
- * Process oplock acknowledgement received for ofile 'of'.
- * - oplock.ol_break is the break level that was requested.
- * - brk is the break level being acknowledged by the client.
- *
- * Update the oplock grant level to the lesser of ol_break and brk.
- * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
- * oplock's grant list and delete it.
- * If the requested break level (ol_break) was NONE and the brk is
- * LEVEL_II, send another oplock break (NONE). Do not wait for an
- * acknowledgement.
- * Wake any threads waiting for the oplock break acknowledgement.
- */
-void
-smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
-{
-	smb_oplock_t		*ol;
-	smb_oplock_grant_t	*og;
-
-	ol = &node->n_oplock;
-	mutex_enter(&ol->ol_mutex);
-	smb_oplock_wait(node);
-
-	if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
-	    ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
-		mutex_exit(&ol->ol_mutex);
+	default:
+		/* Caller did not check args sufficiently? */
+		cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
+		    sr->session->ip_addr_str, status);
+		ofile->f_oplock.og_state = 0;
+		op->op_oplock_level = SMB_OPLOCK_NONE;
 		return;
 	}
 
-	switch (brk) {
-	case SMB_OPLOCK_BREAK_TO_NONE:
-		og->og_level = SMB_OPLOCK_NONE;
-		break;
-	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
-		if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
-			og->og_level = SMB_OPLOCK_LEVEL_II;
-		} else {
-			/* SMB_OPLOCK_BREAK_TO_NONE */
-			og->og_level = SMB_OPLOCK_NONE;
-			smb_oplock_sched_async_break(og,
-			    SMB_OPLOCK_BREAK_TO_NONE);
-		}
-		break;
-	default:
-		SMB_PANIC();
+	/*
+	 * Have STATUS_SUCCESS
+	 * Convert internal oplock state to SMB1
+	 */
+	if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
+		op->op_oplock_level = SMB_OPLOCK_BATCH;
+	} else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
+		op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
+	} else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
+		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
+	} else {
+		op->op_oplock_level = SMB_OPLOCK_NONE;
 	}
-
-	if (og->og_level == SMB_OPLOCK_NONE) {
-		smb_oplock_remove_grant(node, og);
-		smb_oplock_clear_grant(og);
-	}
-
-	ol->ol_break = SMB_OPLOCK_NO_BREAK;
-	cv_broadcast(&ol->ol_cv);
-
-	mutex_exit(&ol->ol_mutex);
-}
-
-/*
- * smb_oplock_broadcast
- *
- * Called when an open with oplock request completes.
- *
- * ol->ol_xthread identifies the thread that was performing an oplock
- * acquire. Other threads may be blocked awaiting completion of the
- * acquire.
- * If the calling thread is ol_xthread, wake any waiting threads.
- */
-void
-smb_oplock_broadcast(smb_node_t *node)
-{
-	smb_oplock_t	*ol;
-
-	SMB_NODE_VALID(node);
-	ol = &node->n_oplock;
-
-	mutex_enter(&ol->ol_mutex);
-	if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
-		ol->ol_xthread = NULL;
-		if (ol->ol_brk_pending) {
-			ol->ol_brk_pending = 0;
-			smb_oplock_break_levelII_locked(node);
-		}
-		cv_broadcast(&ol->ol_cv);
-	}
-	mutex_exit(&ol->ol_mutex);
-}
-
-/*
- * smb_oplock_wait
- *
- * Wait for the completion of an oplock acquire.
- * If ol_xthread is not NULL and doesn't contain the pointer to the
- * context of the calling thread, the caller will sleep until the
- * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
- */
-static void
-smb_oplock_wait(smb_node_t *node)
-{
-	smb_oplock_t	*ol;
-
-	ol = &node->n_oplock;
-	ASSERT(MUTEX_HELD(&ol->ol_mutex));
-
-	if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
-		while (ol->ol_xthread != NULL)
-			cv_wait(&ol->ol_cv, &ol->ol_mutex);
-	}
-}
-
-/*
- * smb_oplock_set_grant
- */
-static smb_oplock_grant_t *
-smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
-{
-	smb_oplock_grant_t	*og;
-
-	og = &of->f_oplock_grant;
-
-	og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
-	og->og_breaking = 0;
-	og->og_level = level;
-	og->og_ofile = of;
-	og->og_fid = of->f_fid;
-	og->og_tid = of->f_tree->t_tid;
-	og->og_uid = of->f_user->u_uid;
-	og->og_session = of->f_session;
-	return (og);
-}
-
-/*
- * smb_oplock_clear_grant
- */
-void
-smb_oplock_clear_grant(smb_oplock_grant_t *og)
-{
-	bzero(og, sizeof (smb_oplock_grant_t));
-}
-
-/*
- * smb_oplock_insert_grant
- *
- * If there are no grants in the oplock's list install the fem
- * monitor.
- * Insert the grant into the list and increment the grant count.
- */
-static int
-smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
-{
-	smb_oplock_t *ol = &node->n_oplock;
-
-	ASSERT(MUTEX_HELD(&ol->ol_mutex));
-
-	if (ol->ol_count == 0) {
-		if (smb_oplock_install_fem(node) != 0)
-			return (-1);
-	}
-
-	list_insert_tail(&ol->ol_grants, og);
-	++ol->ol_count;
-	return (0);
-}
-
-/*
- * smb_oplock_remove_grant
- *
- * Remove the oplock grant from the list, decrement the grant count
- * and, if there are no other grants in the list, uninstall the fem
- * monitor.
- */
-static void
-smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
-{
-	smb_oplock_t *ol = &node->n_oplock;
-
-	ASSERT(MUTEX_HELD(&ol->ol_mutex));
-	ASSERT(ol->ol_count > 0);
-
-	list_remove(&ol->ol_grants, og);
-	if (--ol->ol_count == 0)
-		smb_oplock_uninstall_fem(node);
-}
-
-/*
- * smb_oplock_exclusive_grant
- *
- * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
- * return it. Otherwise return NULL.
- */
-static smb_oplock_grant_t *
-smb_oplock_exclusive_grant(list_t *grants)
-{
-	smb_oplock_grant_t	*og;
-
-	og = list_head(grants);
-	if (og) {
-		SMB_OPLOCK_GRANT_VALID(og);
-		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
-			return (og);
-	}
-	return (NULL);
-}
-
-/*
- * smb_oplock_get_grant
- *
- * Find oplock grant corresponding to the specified ofile.
- */
-static smb_oplock_grant_t *
-smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
-{
-	ASSERT(MUTEX_HELD(&ol->ol_mutex));
-
-	if (SMB_OFILE_OPLOCK_GRANTED(ofile))
-		return (&ofile->f_oplock_grant);
-	else
-		return (NULL);
 }
