194047d49SGordon Ross /*
294047d49SGordon Ross  * This file and its contents are supplied under the terms of the
394047d49SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
494047d49SGordon Ross  * You may only use this file in accordance with the terms of version
594047d49SGordon Ross  * 1.0 of the CDDL.
694047d49SGordon Ross  *
794047d49SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
894047d49SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
994047d49SGordon Ross  * http://www.illumos.org/license/CDDL.
1094047d49SGordon Ross  */
1194047d49SGordon Ross 
1294047d49SGordon Ross /*
13a9931e68SGordon Ross  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
14e515d096SGordon Ross  * Copyright 2021-2023 RackTop Systems, Inc.
1594047d49SGordon Ross  */
1694047d49SGordon Ross 
1794047d49SGordon Ross /*
1894047d49SGordon Ross  * (SMB1/SMB2) Server-level Oplock support.
1994047d49SGordon Ross  *
2094047d49SGordon Ross  * Conceptually, this is a separate layer on top of the
2194047d49SGordon Ross  * file system (FS) layer oplock code in smb_cmn_oplock.c.
2294047d49SGordon Ross  * If these layers were more distinct, the FS layer would
2394047d49SGordon Ross  * need to use call-back functions (installed from here)
2494047d49SGordon Ross  * to "indicate an oplock break to the server" (see below).
2594047d49SGordon Ross  * As these layers are all in the same kernel module, the
2694047d49SGordon Ross  * delivery of these break indications just uses a direct
2794047d49SGordon Ross  * function call to smb_oplock_ind_break() below.
2894047d49SGordon Ross  *
2994047d49SGordon Ross  * This layer is responsible for handling the break indication,
3094047d49SGordon Ross  * which often requires scheduling a taskq job in the server,
3194047d49SGordon Ross  * and sending an oplock break mesage to the client using
3294047d49SGordon Ross  * the appropriate protocol for the open handle affected.
3394047d49SGordon Ross  *
3494047d49SGordon Ross  * The details of composing an oplock break message, the
3594047d49SGordon Ross  * protocol-specific details of requesting an oplock, and
3694047d49SGordon Ross  * returning that oplock to the client are in the files:
3794047d49SGordon Ross  *  smb_oplock.c, smb2_oplock.c, smb2_lease.c
3894047d49SGordon Ross  */
3994047d49SGordon Ross 
4094047d49SGordon Ross #include <smbsrv/smb2_kproto.h>
4194047d49SGordon Ross #include <smbsrv/smb_oplock.h>
4294047d49SGordon Ross 
4394047d49SGordon Ross /*
4494047d49SGordon Ross  * Verify relationship between BREAK_TO_... and CACHE bits,
4594047d49SGordon Ross  * used when setting the BREAK_TO_... below.
4694047d49SGordon Ross  */
4794047d49SGordon Ross #if BREAK_TO_READ_CACHING != (READ_CACHING << BREAK_SHIFT)
4894047d49SGordon Ross #error "BREAK_TO_READ_CACHING"
4994047d49SGordon Ross #endif
5094047d49SGordon Ross #if BREAK_TO_HANDLE_CACHING != (HANDLE_CACHING << BREAK_SHIFT)
5194047d49SGordon Ross #error "BREAK_TO_HANDLE_CACHING"
5294047d49SGordon Ross #endif
5394047d49SGordon Ross #if BREAK_TO_WRITE_CACHING != (WRITE_CACHING << BREAK_SHIFT)
5494047d49SGordon Ross #error "BREAK_TO_WRITE_CACHING"
5594047d49SGordon Ross #endif
5694047d49SGordon Ross #define	CACHE_RWH (READ_CACHING | WRITE_CACHING | HANDLE_CACHING)
5794047d49SGordon Ross 
5894047d49SGordon Ross /*
5994047d49SGordon Ross  * This is the timeout used in the thread that sends an
6094047d49SGordon Ross  * oplock break and waits for the client to respond
6194047d49SGordon Ross  * before it breaks the oplock locally.
6294047d49SGordon Ross  */
6394047d49SGordon Ross int smb_oplock_timeout_ack = 30000; /* mSec. */
6494047d49SGordon Ross 
6594047d49SGordon Ross /*
6694047d49SGordon Ross  * This is the timeout used in threads that have just
6794047d49SGordon Ross  * finished some sort of oplock request and now must
6894047d49SGordon Ross  * wait for (possibly multiple) breaks to complete.
6994047d49SGordon Ross  * This value must be at least a couple seconds LONGER
7094047d49SGordon Ross  * than the ack timeout above so that I/O callers won't
7194047d49SGordon Ross  * give up waiting before the local ack timeout.
7294047d49SGordon Ross  */
7394047d49SGordon Ross int smb_oplock_timeout_def = 45000; /* mSec. */
7494047d49SGordon Ross 
7594047d49SGordon Ross static void smb_oplock_async_break(void *);
7672b35b05SGordon Ross static void smb_oplock_hdl_update(smb_request_t *sr);
7772b35b05SGordon Ross static void smb_oplock_hdl_moved(smb_ofile_t *);
7872b35b05SGordon Ross static void smb_oplock_hdl_closed(smb_ofile_t *);
79525641e8SGordon Ross static void smb_oplock_wait_break_cancel(smb_request_t *sr);
8094047d49SGordon Ross 
8194047d49SGordon Ross 
8294047d49SGordon Ross /*
8394047d49SGordon Ross  * 2.1.5.17.3 Indicating an Oplock Break to the Server
8494047d49SGordon Ross  *
8594047d49SGordon Ross  * The inputs for indicating an oplock break to the server are:
8694047d49SGordon Ross  *
8794047d49SGordon Ross  *	BreakingOplockOpen: The Open used to request the oplock
8894047d49SGordon Ross  *	  that is now breaking.
8994047d49SGordon Ross  *	 NewOplockLevel: The type of oplock the requested oplock
9094047d49SGordon Ross  *	  has been broken to.  Valid values are as follows:
9194047d49SGordon Ross  *		LEVEL_NONE (that is, no oplock)
9294047d49SGordon Ross  *		LEVEL_TWO
9394047d49SGordon Ross  *		A combination of one or more of the following flags:
9494047d49SGordon Ross  *			READ_CACHING
9594047d49SGordon Ross  *			HANDLE_CACHING
9694047d49SGordon Ross  *			WRITE_CACHING
9794047d49SGordon Ross  *	AcknowledgeRequired: A Boolean value; TRUE if the server
9894047d49SGordon Ross  *	  MUST acknowledge the oplock break, FALSE if not,
9994047d49SGordon Ross  *	  as specified in section 2.1.5.18.
10094047d49SGordon Ross  *	OplockCompletionStatus: The NTSTATUS code to return to the server.
10194047d49SGordon Ross  *
10294047d49SGordon Ross  * This algorithm simply represents the completion of an oplock request,
10394047d49SGordon Ross  * as specified in section 2.1.5.17.1 or section 2.1.5.17.2. The server
10494047d49SGordon Ross  * is expected to associate the return status from this algorithm with
10594047d49SGordon Ross  * BreakingOplockOpen, which is the Open passed in when it requested
10694047d49SGordon Ross  * the oplock that is now breaking.
10794047d49SGordon Ross  *
10894047d49SGordon Ross  * It is important to note that because several oplocks can be outstanding
10994047d49SGordon Ross  * in parallel, although this algorithm represents the completion of an
11094047d49SGordon Ross  * oplock request, it might not result in the completion of the algorithm
11194047d49SGordon Ross  * that called it. In particular, calling this algorithm will result in
11294047d49SGordon Ross  * completion of the caller only if BreakingOplockOpen is the same as the
11394047d49SGordon Ross  * Open with which the calling algorithm was itself called. To mitigate
11494047d49SGordon Ross  * confusion, each algorithm that refers to this section will specify
11594047d49SGordon Ross  * whether that algorithm's operation terminates at that point or not.
11694047d49SGordon Ross  *
11794047d49SGordon Ross  * The object store MUST return OplockCompletionStatus,
11894047d49SGordon Ross  * AcknowledgeRequired, and NewOplockLevel to the server (the algorithm is
11994047d49SGordon Ross  * as specified in section 2.1.5.17.1 and section 2.1.5.17.2).
12094047d49SGordon Ross  *
12194047d49SGordon Ross  * Implementation:
12294047d49SGordon Ross  *
12394047d49SGordon Ross  * We use two versions of this function:
12494047d49SGordon Ross  *	smb_oplock_ind_break_in_ack
12594047d49SGordon Ross  *	smb_oplock_ind_break
12694047d49SGordon Ross  *
12794047d49SGordon Ross  * The first is used when we're handling an Oplock Break Ack.
12894047d49SGordon Ross  * The second is used when other operations cause a break,
12994047d49SGordon Ross  * generally in one of the smb_oplock_break_... functions.
13094047d49SGordon Ross  *
13194047d49SGordon Ross  * Note that these are call-back functions that may be called with the
13294047d49SGordon Ross  * node ofile list rwlock held and the node oplock mutex entered, so
13394047d49SGordon Ross  * these should ONLY schedule oplock break work, and MUST NOT attempt
13494047d49SGordon Ross  * any actions that might require either of those locks.
13594047d49SGordon Ross  */
13694047d49SGordon Ross 
13794047d49SGordon Ross /*
13894047d49SGordon Ross  * smb_oplock_ind_break_in_ack
13994047d49SGordon Ross  *
14094047d49SGordon Ross  * Variant of smb_oplock_ind_break() for the oplock Ack handler.
14194047d49SGordon Ross  * When we need to indicate another oplock break from within the
14294047d49SGordon Ross  * Ack handler (during the Ack. of some previous oplock break)
14394047d49SGordon Ross  * we need to make sure this new break indication goes out only
14494047d49SGordon Ross  * AFTER the reply to the current break ack. is sent out.
14594047d49SGordon Ross  *
14694047d49SGordon Ross  * In this case, we always have an SR (the break ack) so we can
14794047d49SGordon Ross  * append the "ind break" work to the current SR and let the
14894047d49SGordon Ross  * request hander thread do this work after the reply is sent.
14994047d49SGordon Ross  * Note: this is always an SMB2 or later request, because this
15094047d49SGordon Ross  * only happens for "granular" oplocks, which are SMB2-only.
15194047d49SGordon Ross  *
15294047d49SGordon Ross  * This is mostly the same as smb_oplock_ind_break() except:
15394047d49SGordon Ross  * - The only CompletionStatus possible is STATUS_CANT_GRANT.
15494047d49SGordon Ross  * - Instead of taskq_dispatch this appends the new SR to
1557f5d80fdSGordon Ross  *   the "post work" queue on the current SR (if possible).
15694047d49SGordon Ross  *
15794047d49SGordon Ross  * Note called with the node ofile list rwlock held and
15894047d49SGordon Ross  * the oplock mutex entered.
15994047d49SGordon Ross  */
16094047d49SGordon Ross void
smb_oplock_ind_break_in_ack(smb_request_t * ack_sr,smb_ofile_t * ofile,uint32_t NewLevel,boolean_t AckRequired)16194047d49SGordon Ross smb_oplock_ind_break_in_ack(smb_request_t *ack_sr, smb_ofile_t *ofile,
16294047d49SGordon Ross     uint32_t NewLevel, boolean_t AckRequired)
16394047d49SGordon Ross {
1647f5d80fdSGordon Ross 	smb_server_t *sv = ofile->f_server;
1657f5d80fdSGordon Ross 	smb_node_t *node = ofile->f_node;
1667f5d80fdSGordon Ross 	smb_request_t *sr = NULL;
1679788d6deSGordon Ross 	taskqid_t tqid;
1687f5d80fdSGordon Ross 	boolean_t use_postwork = B_TRUE;
1697f5d80fdSGordon Ross 
1707f5d80fdSGordon Ross 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
1717f5d80fdSGordon Ross 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
17294047d49SGordon Ross 
17394047d49SGordon Ross 	/*
17494047d49SGordon Ross 	 * This should happen only with SMB2 or later,
17594047d49SGordon Ross 	 * but in case that ever changes...
17694047d49SGordon Ross 	 */
17794047d49SGordon Ross 	if (ack_sr->session->dialect < SMB_VERS_2_BASE) {
17894047d49SGordon Ross 		smb_oplock_ind_break(ofile, NewLevel,
17994047d49SGordon Ross 		    AckRequired, STATUS_CANT_GRANT);
18094047d49SGordon Ross 		return;
18194047d49SGordon Ross 	}
18294047d49SGordon Ross 
18394047d49SGordon Ross 	/*
18494047d49SGordon Ross 	 * We're going to schedule a request that will have a
18594047d49SGordon Ross 	 * reference to this ofile. Get the hold first.
18694047d49SGordon Ross 	 */
18772b35b05SGordon Ross 	if (!smb_ofile_hold_olbrk(ofile)) {
18894047d49SGordon Ross 		/* It's closing (or whatever).  Nothing to do. */
18994047d49SGordon Ross 		return;
19094047d49SGordon Ross 	}
19194047d49SGordon Ross 
19294047d49SGordon Ross 	/*
19394047d49SGordon Ross 	 * When called from Ack processing, we want to use a
1947f5d80fdSGordon Ross 	 * request on the session doing the ack, so we can
1957f5d80fdSGordon Ross 	 * append "post work" to that session.  If we can't
19694047d49SGordon Ross 	 * allocate a request on that session (because it's
1977f5d80fdSGordon Ross 	 * now disconnecting) use a request from the server
1987f5d80fdSGordon Ross 	 * session like smb_oplock_ind_break does, and then
1997f5d80fdSGordon Ross 	 * use taskq_dispatch instead of postwork.
20094047d49SGordon Ross 	 */
2017f5d80fdSGordon Ross 	sr = smb_request_alloc(ack_sr->session, 0);
2027f5d80fdSGordon Ross 	if (sr == NULL) {
2037f5d80fdSGordon Ross 		use_postwork = B_FALSE;
2047f5d80fdSGordon Ross 		sr = smb_request_alloc(sv->sv_session, 0);
2057f5d80fdSGordon Ross 	}
2067f5d80fdSGordon Ross 	if (sr == NULL) {
2077f5d80fdSGordon Ross 		/*
2087f5d80fdSGordon Ross 		 * Server must be shutting down.  We took a
2097f5d80fdSGordon Ross 		 * hold on the ofile that must be released,
2107f5d80fdSGordon Ross 		 * but we can't release here because we're
2117f5d80fdSGordon Ross 		 * called with the node ofile list entered.
2127f5d80fdSGordon Ross 		 * See smb_ofile_release_LL.
2137f5d80fdSGordon Ross 		 */
2147f5d80fdSGordon Ross 		smb_llist_post(&node->n_ofile_list, ofile,
2157f5d80fdSGordon Ross 		    smb_ofile_release_LL);
21694047d49SGordon Ross 		return;
21794047d49SGordon Ross 	}
21894047d49SGordon Ross 
2197f5d80fdSGordon Ross 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
2207f5d80fdSGordon Ross 	sr->smb2_async = B_TRUE;
2217f5d80fdSGordon Ross 	sr->user_cr = zone_kcred();
2227f5d80fdSGordon Ross 	sr->fid_ofile = ofile;
2235bcbb01cSGordon Ross 	if (ofile->f_tree != NULL) {
2247f5d80fdSGordon Ross 		sr->tid_tree = ofile->f_tree;
2257f5d80fdSGordon Ross 		smb_tree_hold_internal(sr->tid_tree);
2265bcbb01cSGordon Ross 	}
2275bcbb01cSGordon Ross 	if (ofile->f_user != NULL) {
2287f5d80fdSGordon Ross 		sr->uid_user = ofile->f_user;
2297f5d80fdSGordon Ross 		smb_user_hold_internal(sr->uid_user);
2305bcbb01cSGordon Ross 	}
2317f6a299eSGordon Ross 	if (ofile->f_lease != NULL)
2327f6a299eSGordon Ross 		NewLevel |= OPLOCK_LEVEL_GRANULAR;
2337f6a299eSGordon Ross 
2347f5d80fdSGordon Ross 	sr->arg.olbrk.NewLevel = NewLevel;
2357f5d80fdSGordon Ross 	sr->arg.olbrk.AckRequired = AckRequired;
23694047d49SGordon Ross 
2377f6a299eSGordon Ross 	/*
2387f6a299eSGordon Ross 	 * Could do this in _hdl_update but this way it's
2397f6a299eSGordon Ross 	 * visible in the dtrace fbt entry probe.
2407f6a299eSGordon Ross 	 */
2417f6a299eSGordon Ross 	sr->arg.olbrk.OldLevel = ofile->f_oplock.og_breakto;
2427f6a299eSGordon Ross 
24372b35b05SGordon Ross 	smb_oplock_hdl_update(sr);
24472b35b05SGordon Ross 
2457f5d80fdSGordon Ross 	if (use_postwork) {
2467f5d80fdSGordon Ross 		/*
2477f5d80fdSGordon Ross 		 * Using smb2_cmd_code to indicate what to call.
2487f5d80fdSGordon Ross 		 * work func. will call smb_oplock_send_brk
2497f5d80fdSGordon Ross 		 */
2507f5d80fdSGordon Ross 		sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
2517f5d80fdSGordon Ross 		smb2sr_append_postwork(ack_sr, sr);
2529788d6deSGordon Ross 		return;
2537f5d80fdSGordon Ross 	}
2549788d6deSGordon Ross 
2559788d6deSGordon Ross 	/* Will call smb_oplock_send_break */
2569788d6deSGordon Ross 	sr->smb2_status = STATUS_CANT_GRANT;
257e515d096SGordon Ross 	tqid = taskq_dispatch(sv->sv_notify_pool,
2589788d6deSGordon Ross 	    smb_oplock_async_break, sr, TQ_SLEEP);
2599788d6deSGordon Ross 	VERIFY(tqid != TASKQID_INVALID);
26094047d49SGordon Ross }
26194047d49SGordon Ross 
26294047d49SGordon Ross /*
26394047d49SGordon Ross  * smb_oplock_ind_break
26494047d49SGordon Ross  *
26594047d49SGordon Ross  * This is the function described in [MS-FSA] 2.1.5.17.3
26694047d49SGordon Ross  * which is called many places in the oplock break code.
26794047d49SGordon Ross  *
26894047d49SGordon Ross  * Schedule a request & taskq job to do oplock break work
26994047d49SGordon Ross  * as requested by the FS-level code (smb_cmn_oplock.c).
27094047d49SGordon Ross  *
27172b35b05SGordon Ross  * See also: smb_oplock_ind_break_in_ack
27272b35b05SGordon Ross  *
27394047d49SGordon Ross  * Note called with the node ofile list rwlock held and
27494047d49SGordon Ross  * the oplock mutex entered.
27594047d49SGordon Ross  */
27694047d49SGordon Ross void
smb_oplock_ind_break(smb_ofile_t * ofile,uint32_t NewLevel,boolean_t AckRequired,uint32_t CompletionStatus)27794047d49SGordon Ross smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
27894047d49SGordon Ross     boolean_t AckRequired, uint32_t CompletionStatus)
27994047d49SGordon Ross {
28094047d49SGordon Ross 	smb_server_t *sv = ofile->f_server;
281525641e8SGordon Ross 	smb_node_t *node = ofile->f_node;
28294047d49SGordon Ross 	smb_request_t *sr = NULL;
2839788d6deSGordon Ross 	taskqid_t tqid;
28494047d49SGordon Ross 
2857f5d80fdSGordon Ross 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
2867f5d80fdSGordon Ross 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
2877f5d80fdSGordon Ross 
28894047d49SGordon Ross 	/*
28994047d49SGordon Ross 	 * See notes at smb_oplock_async_break re. CompletionStatus
29094047d49SGordon Ross 	 * Check for any invalid codes here, so assert happens in
29194047d49SGordon Ross 	 * the thread passing an unexpected value.
29294047d49SGordon Ross 	 * The real work happens in a taskq job.
29394047d49SGordon Ross 	 */
29494047d49SGordon Ross 	switch (CompletionStatus) {
29594047d49SGordon Ross 
29694047d49SGordon Ross 	case NT_STATUS_SUCCESS:
29794047d49SGordon Ross 	case STATUS_CANT_GRANT:
29894047d49SGordon Ross 		/* Send break via taskq job. */
29994047d49SGordon Ross 		break;
30094047d49SGordon Ross 
30194047d49SGordon Ross 	case STATUS_NEW_HANDLE:
30272b35b05SGordon Ross 		smb_oplock_hdl_moved(ofile);
3036f8336c5SGordon Ross 		return;
3046f8336c5SGordon Ross 
30594047d49SGordon Ross 	case NT_STATUS_OPLOCK_HANDLE_CLOSED:
30672b35b05SGordon Ross 		smb_oplock_hdl_closed(ofile);
30794047d49SGordon Ross 		return;
30894047d49SGordon Ross 
30994047d49SGordon Ross 	default:
31094047d49SGordon Ross 		ASSERT(0);
31194047d49SGordon Ross 		return;
31294047d49SGordon Ross 	}
31394047d49SGordon Ross 
31494047d49SGordon Ross 	/*
31594047d49SGordon Ross 	 * We're going to schedule a request that will have a
31694047d49SGordon Ross 	 * reference to this ofile. Get the hold first.
31794047d49SGordon Ross 	 */
31872b35b05SGordon Ross 	if (!smb_ofile_hold_olbrk(ofile)) {
31994047d49SGordon Ross 		/* It's closing (or whatever).  Nothing to do. */
32094047d49SGordon Ross 		return;
32194047d49SGordon Ross 	}
32294047d49SGordon Ross 
32394047d49SGordon Ross 	/*
32494047d49SGordon Ross 	 * We need a request allocated on the session that owns
32594047d49SGordon Ross 	 * this ofile in order to safely send on that session.
32694047d49SGordon Ross 	 *
32794047d49SGordon Ross 	 * Note that while we hold a ref. on the ofile, it's
32894047d49SGordon Ross 	 * f_session will not change.  An ofile in state
32994047d49SGordon Ross 	 * _ORPHANED will have f_session == NULL, but the
33094047d49SGordon Ross 	 * f_session won't _change_ while we have a ref,
33194047d49SGordon Ross 	 * and won't be torn down under our feet.
3325bcbb01cSGordon Ross 	 * Same for f_tree and f_user
33394047d49SGordon Ross 	 *
33494047d49SGordon Ross 	 * If f_session is NULL, or it's in a state that doesn't
33594047d49SGordon Ross 	 * allow new requests, use the special "server" session.
33694047d49SGordon Ross 	 */
33794047d49SGordon Ross 	if (ofile->f_session != NULL)
33894047d49SGordon Ross 		sr = smb_request_alloc(ofile->f_session, 0);
33994047d49SGordon Ross 	if (sr == NULL)
34094047d49SGordon Ross 		sr = smb_request_alloc(sv->sv_session, 0);
341525641e8SGordon Ross 	if (sr == NULL) {
342525641e8SGordon Ross 		/*
343525641e8SGordon Ross 		 * Server must be shutting down.  We took a
344525641e8SGordon Ross 		 * hold on the ofile that must be released,
345525641e8SGordon Ross 		 * but we can't release here because we're
346525641e8SGordon Ross 		 * called with the node ofile list entered.
347525641e8SGordon Ross 		 * See smb_ofile_release_LL.
348525641e8SGordon Ross 		 */
349525641e8SGordon Ross 		smb_llist_post(&node->n_ofile_list, ofile,
350525641e8SGordon Ross 		    smb_ofile_release_LL);
351525641e8SGordon Ross 		return;
352525641e8SGordon Ross 	}
35394047d49SGordon Ross 
35494047d49SGordon Ross 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
35594047d49SGordon Ross 	sr->smb2_async = B_TRUE;
35694047d49SGordon Ross 	sr->user_cr = zone_kcred();
35794047d49SGordon Ross 	sr->fid_ofile = ofile;
3585bcbb01cSGordon Ross 	if (ofile->f_tree != NULL) {
3595bcbb01cSGordon Ross 		sr->tid_tree = ofile->f_tree;
3605bcbb01cSGordon Ross 		smb_tree_hold_internal(sr->tid_tree);
3615bcbb01cSGordon Ross 	}
3625bcbb01cSGordon Ross 	if (ofile->f_user != NULL) {
3635bcbb01cSGordon Ross 		sr->uid_user = ofile->f_user;
3645bcbb01cSGordon Ross 		smb_user_hold_internal(sr->uid_user);
3655bcbb01cSGordon Ross 	}
3667f6a299eSGordon Ross 	if (ofile->f_lease != NULL)
3677f6a299eSGordon Ross 		NewLevel |= OPLOCK_LEVEL_GRANULAR;
3687f6a299eSGordon Ross 
36994047d49SGordon Ross 	sr->arg.olbrk.NewLevel = NewLevel;
37094047d49SGordon Ross 	sr->arg.olbrk.AckRequired = AckRequired;
37194047d49SGordon Ross 	sr->smb2_status = CompletionStatus;
37294047d49SGordon Ross 
3737f6a299eSGordon Ross 	/*
3747f6a299eSGordon Ross 	 * Could do this in _hdl_update but this way it's
3757f6a299eSGordon Ross 	 * visible in the dtrace fbt entry probe.
3767f6a299eSGordon Ross 	 */
3777f6a299eSGordon Ross 	sr->arg.olbrk.OldLevel = ofile->f_oplock.og_breakto;
3787f6a299eSGordon Ross 
37972b35b05SGordon Ross 	smb_oplock_hdl_update(sr);
38072b35b05SGordon Ross 
3817f6a299eSGordon Ross 	/* Will call smb_oplock_send_break */
382e515d096SGordon Ross 	tqid = taskq_dispatch(sv->sv_notify_pool,
38394047d49SGordon Ross 	    smb_oplock_async_break, sr, TQ_SLEEP);
3849788d6deSGordon Ross 	VERIFY(tqid != TASKQID_INVALID);
38594047d49SGordon Ross }
38694047d49SGordon Ross 
38794047d49SGordon Ross /*
38894047d49SGordon Ross  * smb_oplock_async_break
38994047d49SGordon Ross  *
39094047d49SGordon Ross  * Called via the taskq to handle an asynchronous oplock break.
39194047d49SGordon Ross  * We have a hold on the ofile, which will be released in
39294047d49SGordon Ross  * smb_request_free (via sr->fid_ofile)
39394047d49SGordon Ross  *
39472b35b05SGordon Ross  * Note we may have: sr->uid_user == NULL, sr->tid_tree == NULL.
39594047d49SGordon Ross  */
39694047d49SGordon Ross static void
smb_oplock_async_break(void * arg)39794047d49SGordon Ross smb_oplock_async_break(void *arg)
39894047d49SGordon Ross {
39994047d49SGordon Ross 	smb_request_t	*sr = arg;
40094047d49SGordon Ross 	uint32_t	CompletionStatus;
40194047d49SGordon Ross 
40294047d49SGordon Ross 	SMB_REQ_VALID(sr);
40394047d49SGordon Ross 
40494047d49SGordon Ross 	CompletionStatus = sr->smb2_status;
40594047d49SGordon Ross 	sr->smb2_status = NT_STATUS_SUCCESS;
40694047d49SGordon Ross 
40794047d49SGordon Ross 	mutex_enter(&sr->sr_mutex);
40894047d49SGordon Ross 	sr->sr_worker = curthread;
40994047d49SGordon Ross 	sr->sr_state = SMB_REQ_STATE_ACTIVE;
41094047d49SGordon Ross 	mutex_exit(&sr->sr_mutex);
41194047d49SGordon Ross 
41294047d49SGordon Ross 	/*
41394047d49SGordon Ross 	 * Note that the CompletionStatus from the FS level
41494047d49SGordon Ross 	 * (smb_cmn_oplock.c) encodes what kind of action we
41594047d49SGordon Ross 	 * need to take at the SMB level.
41694047d49SGordon Ross 	 */
41794047d49SGordon Ross 	switch (CompletionStatus) {
41894047d49SGordon Ross 
41994047d49SGordon Ross 	case STATUS_CANT_GRANT:
42094047d49SGordon Ross 	case NT_STATUS_SUCCESS:
42172b35b05SGordon Ross 		smb_oplock_send_break(sr);
42294047d49SGordon Ross 		break;
42394047d49SGordon Ross 
42494047d49SGordon Ross 	default:
42594047d49SGordon Ross 		/* Checked by caller. */
42694047d49SGordon Ross 		ASSERT(0);
42794047d49SGordon Ross 		break;
42894047d49SGordon Ross 	}
42994047d49SGordon Ross 
4308d94f651SGordon Ross 	if (sr->dh_nvl_dirty) {
4318d94f651SGordon Ross 		sr->dh_nvl_dirty = B_FALSE;
4328d94f651SGordon Ross 		smb2_dh_update_nvfile(sr);
4338d94f651SGordon Ross 	}
4348d94f651SGordon Ross 
43594047d49SGordon Ross 	sr->sr_state = SMB_REQ_STATE_COMPLETED;
43694047d49SGordon Ross 	smb_request_free(sr);
43794047d49SGordon Ross }
43894047d49SGordon Ross 
43972b35b05SGordon Ross /*
44072b35b05SGordon Ross  * Send an oplock (or lease) break to the client.
44172b35b05SGordon Ross  * If we can't, then do a local break.
44272b35b05SGordon Ross  *
44372b35b05SGordon Ross  * This is called either from smb_oplock_async_break via a
44472b35b05SGordon Ross  * taskq job scheduled in smb_oplock_ind_break, or from the
44572b35b05SGordon Ross  * smb2sr_append_postwork() mechanism when we're doing a
44672b35b05SGordon Ross  * "break in ack", via smb_oplock_ind_break_in_ack.
44772b35b05SGordon Ross  *
44872b35b05SGordon Ross  * We don't always have an sr->session here, so
44972b35b05SGordon Ross  * determine the oplock type (lease etc) from
45072b35b05SGordon Ross  * f_lease and f_oplock.og_dialect etc.
45172b35b05SGordon Ross  */
45272b35b05SGordon Ross void
smb_oplock_send_break(smb_request_t * sr)45372b35b05SGordon Ross smb_oplock_send_break(smb_request_t *sr)
4546f8336c5SGordon Ross {
45572b35b05SGordon Ross 	smb_ofile_t	*ofile = sr->fid_ofile;
45672b35b05SGordon Ross 
4576f8336c5SGordon Ross 	if (ofile->f_lease != NULL)
45872b35b05SGordon Ross 		smb2_lease_send_break(sr);
45972b35b05SGordon Ross 	else if (ofile->f_oplock.og_dialect >= SMB_VERS_2_BASE)
46072b35b05SGordon Ross 		smb2_oplock_send_break(sr);
4616f8336c5SGordon Ross 	else
46272b35b05SGordon Ross 		smb1_oplock_send_break(sr);
46372b35b05SGordon Ross }
4646f8336c5SGordon Ross 
46572b35b05SGordon Ross /*
46672b35b05SGordon Ross  * Called by smb_oplock_ind_break for the case STATUS_NEW_HANDLE,
46772b35b05SGordon Ross  * which is an alias for NT_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
46872b35b05SGordon Ross  *
46972b35b05SGordon Ross  * The FS-level oplock layer calls this to update the SMB-level state
47072b35b05SGordon Ross  * when the oplock for some lease is about to move to a different
47172b35b05SGordon Ross  * ofile on the lease.
47272b35b05SGordon Ross  *
47372b35b05SGordon Ross  * To avoid later confusion, clear og_state on this ofile now.
47472b35b05SGordon Ross  * Without this, smb_oplock_move() may issue debug complaints
47572b35b05SGordon Ross  * about moving oplock state onto a non-empty oplock.
47672b35b05SGordon Ross  */
47772b35b05SGordon Ross static const smb_ofile_t invalid_ofile;
47872b35b05SGordon Ross static void
smb_oplock_hdl_moved(smb_ofile_t * ofile)47972b35b05SGordon Ross smb_oplock_hdl_moved(smb_ofile_t *ofile)
48072b35b05SGordon Ross {
48172b35b05SGordon Ross 	smb_lease_t *ls = ofile->f_lease;
48272b35b05SGordon Ross 
48372b35b05SGordon Ross 	ASSERT(ls != NULL);
48472b35b05SGordon Ross 	if (ls != NULL && ls->ls_oplock_ofile == ofile)
48572b35b05SGordon Ross 		ls->ls_oplock_ofile = (smb_ofile_t *)&invalid_ofile;
48672b35b05SGordon Ross 
48772b35b05SGordon Ross 	ofile->f_oplock.og_state = 0;
4887f6a299eSGordon Ross 	ofile->f_oplock.og_breakto = 0;
4897f6a299eSGordon Ross 	ofile->f_oplock.og_breaking = B_FALSE;
4906f8336c5SGordon Ross }
4916f8336c5SGordon Ross 
49272b35b05SGordon Ross /*
49372b35b05SGordon Ross  * See: NT_STATUS_OPLOCK_HANDLE_CLOSED above and
49472b35b05SGordon Ross  * smb_ofile_close, smb_oplock_break_CLOSE.
49572b35b05SGordon Ross  *
49672b35b05SGordon Ross  * The FS-level oplock layer calls this to update the
49772b35b05SGordon Ross  * SMB-level state when a handle loses its oplock.
49872b35b05SGordon Ross  */
49972b35b05SGordon Ross static void
smb_oplock_hdl_closed(smb_ofile_t * ofile)50072b35b05SGordon Ross smb_oplock_hdl_closed(smb_ofile_t *ofile)
50172b35b05SGordon Ross {
50272b35b05SGordon Ross 	smb_lease_t *lease = ofile->f_lease;
50372b35b05SGordon Ross 
50472b35b05SGordon Ross 	if (lease != NULL) {
50572b35b05SGordon Ross 		if (lease->ls_oplock_ofile == ofile) {
50672b35b05SGordon Ross 			/*
50772b35b05SGordon Ross 			 * smb2_lease_ofile_close should have
50872b35b05SGordon Ross 			 * moved the oplock to another ofile.
50972b35b05SGordon Ross 			 */
51072b35b05SGordon Ross 			ASSERT(0);
51172b35b05SGordon Ross 			lease->ls_oplock_ofile = NULL;
51272b35b05SGordon Ross 		}
51372b35b05SGordon Ross 	}
51472b35b05SGordon Ross 	ofile->f_oplock.og_state = 0;
5157f6a299eSGordon Ross 	ofile->f_oplock.og_breakto = 0;
5167f6a299eSGordon Ross 	ofile->f_oplock.og_breaking = B_FALSE;
51772b35b05SGordon Ross }
51894047d49SGordon Ross 
51994047d49SGordon Ross /*
52072b35b05SGordon Ross  * smb_oplock_hdl_update
52172b35b05SGordon Ross  *
52272b35b05SGordon Ross  * Called by smb_oplock_ind_break (and ...in_ack) just before we
52372b35b05SGordon Ross  * schedule smb_oplock_async_break / mb_oplock_send_break taskq job,
52472b35b05SGordon Ross  * so we can make any state changes that should happen immediately.
52572b35b05SGordon Ross  *
52672b35b05SGordon Ross  * Here, keep track of what we will send to the client.
5277f6a299eSGordon Ross  * Saves old state in arg.olbck.OldLevel
5287f6a299eSGordon Ross  *
5297f6a299eSGordon Ross  * Note that because we may be in the midst of processing an
5307f6a299eSGordon Ross  * smb_oplock_ack_break call here, the _breaking flag will be
5317f6a299eSGordon Ross  * temporarily false, and is set true again if this ack causes
5327f6a299eSGordon Ross  * another break.  This makes it tricky to know when to update
5337f6a299eSGordon Ross  * the epoch, which is not supposed to increment when there's
5347f6a299eSGordon Ross  * already an unacknowledged break out to the client.
5357f6a299eSGordon Ross  * We can recognize that by comparing ls_state vs ls_breakto.
5367f6a299eSGordon Ross  * If no unacknowledged break, ls_state == ls_breakto.
53794047d49SGordon Ross  */
53872b35b05SGordon Ross static void
smb_oplock_hdl_update(smb_request_t * sr)53972b35b05SGordon Ross smb_oplock_hdl_update(smb_request_t *sr)
54094047d49SGordon Ross {
54172b35b05SGordon Ross 	smb_ofile_t	*ofile = sr->fid_ofile;
54272b35b05SGordon Ross 	smb_lease_t	*lease = ofile->f_lease;
54372b35b05SGordon Ross 	uint32_t	NewLevel = sr->arg.olbrk.NewLevel;
54472b35b05SGordon Ross 	boolean_t	AckReq = sr->arg.olbrk.AckRequired;
54572b35b05SGordon Ross 
54672b35b05SGordon Ross #ifdef	DEBUG
54772b35b05SGordon Ross 	smb_node_t *node = ofile->f_node;
54872b35b05SGordon Ross 	ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
54972b35b05SGordon Ross 	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
55072b35b05SGordon Ross #endif
55194047d49SGordon Ross 
5527f6a299eSGordon Ross 	/* Caller sets arg.olbrk.OldLevel */
5537f6a299eSGordon Ross 	ofile->f_oplock.og_breakto = NewLevel;
5547f6a299eSGordon Ross 	ofile->f_oplock.og_breaking = B_TRUE;
5556f8336c5SGordon Ross 	if (lease != NULL) {
5567f6a299eSGordon Ross 		// If no unacknowledged break, update epoch.
5577f6a299eSGordon Ross 		if (lease->ls_breakto == lease->ls_state)
5587f6a299eSGordon Ross 			lease->ls_epoch++;
55994047d49SGordon Ross 
5607f6a299eSGordon Ross 		lease->ls_breakto = NewLevel;
5617f6a299eSGordon Ross 		lease->ls_breaking = B_TRUE;
5627f6a299eSGordon Ross 	}
56394047d49SGordon Ross 
5647f6a299eSGordon Ross 	if (!AckReq) {
56594047d49SGordon Ross 		/*
56672b35b05SGordon Ross 		 * Not expecting an Ack from the client.
56772b35b05SGordon Ross 		 * Update state immediately.
56894047d49SGordon Ross 		 */
56972b35b05SGordon Ross 		ofile->f_oplock.og_state = NewLevel;
5707f6a299eSGordon Ross 		ofile->f_oplock.og_breaking = B_FALSE;
57172b35b05SGordon Ross 		if (lease != NULL) {
5727f6a299eSGordon Ross 			lease->ls_state = NewLevel;
5737f6a299eSGordon Ross 			lease->ls_breaking = B_FALSE;
57494047d49SGordon Ross 		}
57572b35b05SGordon Ross 		if (ofile->dh_persist) {
57672b35b05SGordon Ross 			smb2_dh_update_oplock(sr, ofile);
57772b35b05SGordon Ross 		}
57872b35b05SGordon Ross 	}
57972b35b05SGordon Ross }
58072b35b05SGordon Ross 
58172b35b05SGordon Ross /*
58272b35b05SGordon Ross  * Helper for smb_ofile_close
58372b35b05SGordon Ross  *
58472b35b05SGordon Ross  * Note that a client may close an ofile in response to an
58572b35b05SGordon Ross  * oplock break or lease break intead of doing an Ack break,
58672b35b05SGordon Ross  * so this must wake anything that might be waiting on an ack.
58772b35b05SGordon Ross  */
58872b35b05SGordon Ross void
smb_oplock_close(smb_ofile_t * ofile)58972b35b05SGordon Ross smb_oplock_close(smb_ofile_t *ofile)
59072b35b05SGordon Ross {
59172b35b05SGordon Ross 	smb_node_t *node = ofile->f_node;
59294047d49SGordon Ross 
59372b35b05SGordon Ross 	smb_llist_enter(&node->n_ofile_list, RW_READER);
59472b35b05SGordon Ross 	mutex_enter(&node->n_oplock.ol_mutex);
59594047d49SGordon Ross 
59672b35b05SGordon Ross 	if (ofile->f_oplock_closing == B_FALSE) {
59772b35b05SGordon Ross 		ofile->f_oplock_closing = B_TRUE;
59894047d49SGordon Ross 
59972b35b05SGordon Ross 		if (ofile->f_lease != NULL)
60072b35b05SGordon Ross 			smb2_lease_ofile_close(ofile);
60194047d49SGordon Ross 
60272b35b05SGordon Ross 		smb_oplock_break_CLOSE(node, ofile);
60394047d49SGordon Ross 
60472b35b05SGordon Ross 		ofile->f_oplock.og_state = 0;
6057f6a299eSGordon Ross 		ofile->f_oplock.og_breakto = 0;
6067f6a299eSGordon Ross 		ofile->f_oplock.og_breaking = B_FALSE;
60772b35b05SGordon Ross 		cv_broadcast(&ofile->f_oplock.og_ack_cv);
60894047d49SGordon Ross 	}
60994047d49SGordon Ross 
61072b35b05SGordon Ross 	mutex_exit(&node->n_oplock.ol_mutex);
61172b35b05SGordon Ross 	smb_llist_exit(&node->n_ofile_list);
61294047d49SGordon Ross }
61394047d49SGordon Ross 
61494047d49SGordon Ross /*
61572b35b05SGordon Ross  * Called by smb_request_cancel() via sr->cancel_method
61672b35b05SGordon Ross  * Arg is the smb_node_t with the breaking oplock.
61794047d49SGordon Ross  */
61894047d49SGordon Ross static void
smb_oplock_wait_ack_cancel(smb_request_t * sr)61972b35b05SGordon Ross smb_oplock_wait_ack_cancel(smb_request_t *sr)
62094047d49SGordon Ross {
62172b35b05SGordon Ross 	kcondvar_t	*cvp = sr->cancel_arg2;
62272b35b05SGordon Ross 	smb_ofile_t	*ofile = sr->fid_ofile;
62372b35b05SGordon Ross 	smb_node_t	*node = ofile->f_node;
62472b35b05SGordon Ross 
62572b35b05SGordon Ross 	mutex_enter(&node->n_oplock.ol_mutex);
62672b35b05SGordon Ross 	cv_broadcast(cvp);
62772b35b05SGordon Ross 	mutex_exit(&node->n_oplock.ol_mutex);
62872b35b05SGordon Ross }
62972b35b05SGordon Ross 
63072b35b05SGordon Ross /*
63172b35b05SGordon Ross  * Wait for an oplock break ACK to arrive.  This is called after
63272b35b05SGordon Ross  * we've sent an oplock break or lease break to the client where
63372b35b05SGordon Ross  * an "Ack break" is expected back.  If we get an Ack, that will
6347f6a299eSGordon Ross  * wake us up via smb2_oplock_break_ack or smb2_lease_break_ack.
6357f6a299eSGordon Ross  *
6367f6a299eSGordon Ross  * Wait until state reduced to NewLevel (or less).
6377f6a299eSGordon Ross  * Note that in multi-break cases, we might wait here for just
6387f6a299eSGordon Ross  * one ack when another has become pending, in which case the
6397f6a299eSGordon Ross  * og_breakto might be a subset of NewLevel.  Wait until the
6407f6a299eSGordon Ross  * state field is no longer a superset of NewLevel.
64172b35b05SGordon Ross  */
64272b35b05SGordon Ross uint32_t
smb_oplock_wait_ack(smb_request_t * sr,uint32_t NewLevel)6437f6a299eSGordon Ross smb_oplock_wait_ack(smb_request_t *sr, uint32_t NewLevel)
64472b35b05SGordon Ross {
64572b35b05SGordon Ross 	smb_ofile_t	*ofile = sr->fid_ofile;
64672b35b05SGordon Ross 	smb_lease_t	*lease = ofile->f_lease;
64772b35b05SGordon Ross 	smb_node_t	*node = ofile->f_node;
64872b35b05SGordon Ross 	smb_oplock_t	*ol = &node->n_oplock;
6497f6a299eSGordon Ross 	uint32_t	*state_p;
6507f6a299eSGordon Ross 	kcondvar_t	*cv_p;
65172b35b05SGordon Ross 	clock_t		time, rv;
65272b35b05SGordon Ross 	uint32_t	status = 0;
65372b35b05SGordon Ross 	smb_req_state_t  srstate;
6547f6a299eSGordon Ross 	uint32_t	wait_mask;
65572b35b05SGordon Ross 
65672b35b05SGordon Ross 	time = ddi_get_lbolt() +
65772b35b05SGordon Ross 	    MSEC_TO_TICK(smb_oplock_timeout_ack);
65894047d49SGordon Ross 
6597f6a299eSGordon Ross 	/*
6607f6a299eSGordon Ross 	 * Wait on either lease state or oplock state
6617f6a299eSGordon Ross 	 */
66294047d49SGordon Ross 	if (lease != NULL) {
6637f6a299eSGordon Ross 		state_p = &lease->ls_state;
6647f6a299eSGordon Ross 		cv_p = &lease->ls_ack_cv;
66572b35b05SGordon Ross 	} else {
6667f6a299eSGordon Ross 		state_p = &ofile->f_oplock.og_state;
6677f6a299eSGordon Ross 		cv_p = &ofile->f_oplock.og_ack_cv;
66872b35b05SGordon Ross 	}
66972b35b05SGordon Ross 
6707f6a299eSGordon Ross 	/*
6717f6a299eSGordon Ross 	 * These are all the bits that we wait to be cleared.
6727f6a299eSGordon Ross 	 */
6737f6a299eSGordon Ross 	wait_mask = ~NewLevel & (CACHE_RWH |
6747f6a299eSGordon Ross 	    LEVEL_TWO | LEVEL_ONE | LEVEL_BATCH);
6757f6a299eSGordon Ross 
67672b35b05SGordon Ross 	/*
67772b35b05SGordon Ross 	 * Setup cancellation callback
67872b35b05SGordon Ross 	 */
67972b35b05SGordon Ross 	mutex_enter(&sr->sr_mutex);
68072b35b05SGordon Ross 	if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
68172b35b05SGordon Ross 		mutex_exit(&sr->sr_mutex);
68272b35b05SGordon Ross 		return (NT_STATUS_CANCELLED);
68372b35b05SGordon Ross 	}
68472b35b05SGordon Ross 	sr->sr_state = SMB_REQ_STATE_WAITING_OLBRK;
68572b35b05SGordon Ross 	sr->cancel_method = smb_oplock_wait_ack_cancel;
6867f6a299eSGordon Ross 	sr->cancel_arg2 = cv_p;
68772b35b05SGordon Ross 	mutex_exit(&sr->sr_mutex);
68872b35b05SGordon Ross 
68972b35b05SGordon Ross 	/*
69072b35b05SGordon Ross 	 * Enter the wait loop
69172b35b05SGordon Ross 	 */
69272b35b05SGordon Ross 	mutex_enter(&ol->ol_mutex);
6937f6a299eSGordon Ross 
6947f6a299eSGordon Ross 	while ((*state_p & wait_mask) != 0) {
6957f6a299eSGordon Ross 		rv = cv_timedwait(cv_p, &ol->ol_mutex, time);
69672b35b05SGordon Ross 		if (rv < 0) {
69772b35b05SGordon Ross 			/* cv_timewait timeout */
6983b24312dSGordon Ross 			char *fname;
6993b24312dSGordon Ross 			char *opname;
7003b24312dSGordon Ross 			int rc;
7013b24312dSGordon Ross 
7023b24312dSGordon Ross 			/*
7033b24312dSGordon Ross 			 * Get the path name of the open file
7043b24312dSGordon Ross 			 */
7053b24312dSGordon Ross 			fname = smb_srm_zalloc(sr, MAXPATHLEN);
7063b24312dSGordon Ross 			rc = smb_node_getpath(node, NULL, fname, MAXPATHLEN);
7073b24312dSGordon Ross 			if (rc != 0) {
7083b24312dSGordon Ross 				/* Not expected. Just show last part. */
7093b24312dSGordon Ross 				(void) snprintf(fname, MAXPATHLEN, "(?)/%s",
7103b24312dSGordon Ross 				    node->od_name);
7113b24312dSGordon Ross 			}
7123b24312dSGordon Ross 
7133b24312dSGordon Ross 			/*
7143b24312dSGordon Ross 			 * Get an operation name reflecting which kind of
7153b24312dSGordon Ross 			 * lease or oplock break got us here, so the log
7163b24312dSGordon Ross 			 * message will say "lease break" or whatever.
7173b24312dSGordon Ross 			 */
7183b24312dSGordon Ross 			if (lease != NULL) {
7193b24312dSGordon Ross 				opname = "lease";
7203b24312dSGordon Ross 			} else if (ofile->f_oplock.og_dialect >=
7213b24312dSGordon Ross 			    SMB_VERS_2_BASE) {
7223b24312dSGordon Ross 				opname = "oplock2";
7233b24312dSGordon Ross 			} else {
7243b24312dSGordon Ross 				opname = "oplock1";
7253b24312dSGordon Ross 			}
7263b24312dSGordon Ross 
7273b24312dSGordon Ross 			cmn_err(CE_NOTE, "!client %s %s break timeout for %s",
7283b24312dSGordon Ross 			    sr->session->ip_addr_str, opname, fname);
7293b24312dSGordon Ross 
73072b35b05SGordon Ross 			status = NT_STATUS_CANNOT_BREAK_OPLOCK;
73172b35b05SGordon Ross 			break;
73272b35b05SGordon Ross 		}
73372b35b05SGordon Ross 
73472b35b05SGordon Ross 		/*
73572b35b05SGordon Ross 		 * Check if we were woken by smb_request_cancel,
73672b35b05SGordon Ross 		 * which sets state SMB_REQ_STATE_CANCEL_PENDING
73772b35b05SGordon Ross 		 * and signals the CV.  The mutex enter/exit is
73872b35b05SGordon Ross 		 * just to ensure cache visibility of sr_state
73972b35b05SGordon Ross 		 * that was updated in smb_request_cancel.
74072b35b05SGordon Ross 		 */
74172b35b05SGordon Ross 		mutex_enter(&sr->sr_mutex);
74272b35b05SGordon Ross 		srstate = sr->sr_state;
74372b35b05SGordon Ross 		mutex_exit(&sr->sr_mutex);
74472b35b05SGordon Ross 		if (srstate != SMB_REQ_STATE_WAITING_OLBRK) {
74572b35b05SGordon Ross 			break;
74694047d49SGordon Ross 		}
74794047d49SGordon Ross 	}
74872b35b05SGordon Ross 	mutex_exit(&ol->ol_mutex);
74972b35b05SGordon Ross 
75072b35b05SGordon Ross 	/*
751*66b505f1SGordon Ross 	 * See if it completed or if it was cancelled.
75272b35b05SGordon Ross 	 */
75372b35b05SGordon Ross 	mutex_enter(&sr->sr_mutex);
754*66b505f1SGordon Ross switch_state:
75572b35b05SGordon Ross 	switch (sr->sr_state) {
75672b35b05SGordon Ross 	case SMB_REQ_STATE_WAITING_OLBRK:
757*66b505f1SGordon Ross 		/* Normal wakeup.  Keep status from above. */
75872b35b05SGordon Ross 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
75972b35b05SGordon Ross 		/* status from above */
76072b35b05SGordon Ross 		break;
76172b35b05SGordon Ross 	case SMB_REQ_STATE_CANCEL_PENDING:
762*66b505f1SGordon Ross 		/* cancel_method running. wait. */
763*66b505f1SGordon Ross 		cv_wait(&sr->sr_st_cv, &sr->sr_mutex);
764*66b505f1SGordon Ross 		goto switch_state;
765*66b505f1SGordon Ross 	case SMB_REQ_STATE_CANCELLED:
76672b35b05SGordon Ross 		status = NT_STATUS_CANCELLED;
76772b35b05SGordon Ross 		break;
76872b35b05SGordon Ross 	default:
76972b35b05SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
77072b35b05SGordon Ross 		break;
77172b35b05SGordon Ross 	}
772*66b505f1SGordon Ross 	sr->cancel_method = NULL;
773*66b505f1SGordon Ross 	sr->cancel_arg2 = NULL;
77472b35b05SGordon Ross 	mutex_exit(&sr->sr_mutex);
77572b35b05SGordon Ross 
77672b35b05SGordon Ross 	return (status);
77794047d49SGordon Ross }
77894047d49SGordon Ross 
779525641e8SGordon Ross /*
780525641e8SGordon Ross  * Called by smb_request_cancel() via sr->cancel_method
781525641e8SGordon Ross  * Arg is the smb_node_t with the breaking oplock.
782525641e8SGordon Ross  */
783525641e8SGordon Ross static void
smb_oplock_wait_break_cancel(smb_request_t * sr)784525641e8SGordon Ross smb_oplock_wait_break_cancel(smb_request_t *sr)
785525641e8SGordon Ross {
786525641e8SGordon Ross 	smb_node_t   *node = sr->cancel_arg2;
787525641e8SGordon Ross 	smb_oplock_t *ol;
788525641e8SGordon Ross 
789525641e8SGordon Ross 	SMB_NODE_VALID(node);
790525641e8SGordon Ross 	ol = &node->n_oplock;
791525641e8SGordon Ross 
792525641e8SGordon Ross 	mutex_enter(&ol->ol_mutex);
793525641e8SGordon Ross 	cv_broadcast(&ol->WaitingOpenCV);
794525641e8SGordon Ross 	mutex_exit(&ol->ol_mutex);
795525641e8SGordon Ross }
796525641e8SGordon Ross 
79794047d49SGordon Ross /*
79894047d49SGordon Ross  * Wait up to "timeout" mSec. for the current oplock "breaking" flags
79994047d49SGordon Ross  * to be cleared (by smb_oplock_ack_break or smb_oplock_break_CLOSE).
80094047d49SGordon Ross  *
80194047d49SGordon Ross  * Callers of the above public oplock functions:
80294047d49SGordon Ross  *	smb_oplock_request()
80394047d49SGordon Ross  *	smb_oplock_ack_break()
80494047d49SGordon Ross  *	smb_oplock_break_OPEN() ...
80594047d49SGordon Ross  * check for return status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS
80694047d49SGordon Ross  * and call this function to wait for the break to complete.
80794047d49SGordon Ross  *
80894047d49SGordon Ross  * Most callers should use this default timeout, which they get
80994047d49SGordon Ross  * by passing zero as the timeout arg.  This include places where
81094047d49SGordon Ross  * we're about to do something that invalidates some cache.
81194047d49SGordon Ross  */
81294047d49SGordon Ross uint32_t
smb_oplock_wait_break(smb_request_t * sr,smb_node_t * node,int timeout)813525641e8SGordon Ross smb_oplock_wait_break(smb_request_t *sr, smb_node_t *node, int timeout)
814525641e8SGordon Ross {
815525641e8SGordon Ross 	smb_oplock_t	*ol;
816525641e8SGordon Ross 	clock_t		time, rv;
817525641e8SGordon Ross 	uint32_t	status = 0;
818525641e8SGordon Ross 	smb_req_state_t  srstate;
819525641e8SGordon Ross 
820525641e8SGordon Ross 	SMB_NODE_VALID(node);
821525641e8SGordon Ross 	ol = &node->n_oplock;
822525641e8SGordon Ross 
823525641e8SGordon Ross 	if (timeout == 0)
824525641e8SGordon Ross 		timeout = smb_oplock_timeout_def;
825525641e8SGordon Ross 	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
826525641e8SGordon Ross 
827*66b505f1SGordon Ross 	/*
828*66b505f1SGordon Ross 	 * Setup cancellation callback
829*66b505f1SGordon Ross 	 */
830525641e8SGordon Ross 	mutex_enter(&sr->sr_mutex);
831525641e8SGordon Ross 	if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
832525641e8SGordon Ross 		mutex_exit(&sr->sr_mutex);
833525641e8SGordon Ross 		return (NT_STATUS_CANCELLED);
834525641e8SGordon Ross 	}
835525641e8SGordon Ross 	sr->sr_state = SMB_REQ_STATE_WAITING_OLBRK;
836525641e8SGordon Ross 	sr->cancel_method = smb_oplock_wait_break_cancel;
837525641e8SGordon Ross 	sr->cancel_arg2 = node;
838525641e8SGordon Ross 	mutex_exit(&sr->sr_mutex);
839525641e8SGordon Ross 
840525641e8SGordon Ross 	mutex_enter(&ol->ol_mutex);
841525641e8SGordon Ross 	while ((ol->ol_state & BREAK_ANY) != 0) {
842525641e8SGordon Ross 		ol->waiters++;
843525641e8SGordon Ross 		rv = cv_timedwait(&ol->WaitingOpenCV,
844525641e8SGordon Ross 		    &ol->ol_mutex, time);
845525641e8SGordon Ross 		ol->waiters--;
846525641e8SGordon Ross 		if (rv < 0) {
847525641e8SGordon Ross 			/* cv_timewait timeout */
848525641e8SGordon Ross 			status = NT_STATUS_CANNOT_BREAK_OPLOCK;
849525641e8SGordon Ross 			break;
850525641e8SGordon Ross 		}
851525641e8SGordon Ross 
852525641e8SGordon Ross 		/*
853525641e8SGordon Ross 		 * Check if we were woken by smb_request_cancel,
854525641e8SGordon Ross 		 * which sets state SMB_REQ_STATE_CANCEL_PENDING
85572b35b05SGordon Ross 		 * and signals the CV.  The mutex enter/exit is
85672b35b05SGordon Ross 		 * just to ensure cache visibility of sr_state
85772b35b05SGordon Ross 		 * that was updated in smb_request_cancel.
858525641e8SGordon Ross 		 */
859525641e8SGordon Ross 		mutex_enter(&sr->sr_mutex);
860525641e8SGordon Ross 		srstate = sr->sr_state;
861525641e8SGordon Ross 		mutex_exit(&sr->sr_mutex);
862525641e8SGordon Ross 		if (srstate != SMB_REQ_STATE_WAITING_OLBRK) {
863525641e8SGordon Ross 			break;
864525641e8SGordon Ross 		}
865525641e8SGordon Ross 	}
866525641e8SGordon Ross 	mutex_exit(&ol->ol_mutex);
867525641e8SGordon Ross 
868*66b505f1SGordon Ross 	/*
869*66b505f1SGordon Ross 	 * Check whether it completed or was cancelled.
870*66b505f1SGordon Ross 	 */
871525641e8SGordon Ross 	mutex_enter(&sr->sr_mutex);
872*66b505f1SGordon Ross switch_state:
873525641e8SGordon Ross 	switch (sr->sr_state) {
874525641e8SGordon Ross 	case SMB_REQ_STATE_WAITING_OLBRK:
875*66b505f1SGordon Ross 		/* Normal wakeup.  Keep status from above. */
876525641e8SGordon Ross 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
877525641e8SGordon Ross 		break;
878525641e8SGordon Ross 	case SMB_REQ_STATE_CANCEL_PENDING:
879*66b505f1SGordon Ross 		/* cancel_method running. wait. */
880*66b505f1SGordon Ross 		cv_wait(&sr->sr_st_cv, &sr->sr_mutex);
881*66b505f1SGordon Ross 		goto switch_state;
882*66b505f1SGordon Ross 	case SMB_REQ_STATE_CANCELLED:
883525641e8SGordon Ross 		status = NT_STATUS_CANCELLED;
884525641e8SGordon Ross 		break;
885525641e8SGordon Ross 	default:
886525641e8SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
887525641e8SGordon Ross 		break;
888525641e8SGordon Ross 	}
889*66b505f1SGordon Ross 	sr->cancel_method = NULL;
890*66b505f1SGordon Ross 	sr->cancel_arg2 = NULL;
891525641e8SGordon Ross 	mutex_exit(&sr->sr_mutex);
892525641e8SGordon Ross 
893525641e8SGordon Ross 	return (status);
894525641e8SGordon Ross }
895525641e8SGordon Ross 
896525641e8SGordon Ross /*
897525641e8SGordon Ross  * Simplified version used in smb_fem.c, like above,
898525641e8SGordon Ross  * but no smb_request_cancel stuff.
899525641e8SGordon Ross  */
900525641e8SGordon Ross uint32_t
smb_oplock_wait_break_fem(smb_node_t * node,int timeout)901525641e8SGordon Ross smb_oplock_wait_break_fem(smb_node_t *node, int timeout)  /* mSec. */
90294047d49SGordon Ross {
90394047d49SGordon Ross 	smb_oplock_t	*ol;
90494047d49SGordon Ross 	clock_t		time, rv;
90594047d49SGordon Ross 	uint32_t	status = 0;
90694047d49SGordon Ross 
90794047d49SGordon Ross 	if (timeout == 0)
90894047d49SGordon Ross 		timeout = smb_oplock_timeout_def;
90994047d49SGordon Ross 
91094047d49SGordon Ross 	SMB_NODE_VALID(node);
91194047d49SGordon Ross 	ol = &node->n_oplock;
91294047d49SGordon Ross 
91394047d49SGordon Ross 	mutex_enter(&ol->ol_mutex);
91494047d49SGordon Ross 	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
91594047d49SGordon Ross 
91694047d49SGordon Ross 	while ((ol->ol_state & BREAK_ANY) != 0) {
91794047d49SGordon Ross 		ol->waiters++;
91894047d49SGordon Ross 		rv = cv_timedwait(&ol->WaitingOpenCV,
91994047d49SGordon Ross 		    &ol->ol_mutex, time);
92094047d49SGordon Ross 		ol->waiters--;
92194047d49SGordon Ross 		if (rv < 0) {
92294047d49SGordon Ross 			status = NT_STATUS_CANNOT_BREAK_OPLOCK;
92394047d49SGordon Ross 			break;
92494047d49SGordon Ross 		}
92594047d49SGordon Ross 	}
92694047d49SGordon Ross 
92794047d49SGordon Ross 	mutex_exit(&ol->ol_mutex);
92894047d49SGordon Ross 
92994047d49SGordon Ross 	return (status);
93094047d49SGordon Ross }
931