xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision 6600:4e63bcd27ae9)
1*6600Sas200622 /*
2*6600Sas200622  * CDDL HEADER START
3*6600Sas200622  *
4*6600Sas200622  * The contents of this file are subject to the terms of the
5*6600Sas200622  * Common Development and Distribution License (the "License").
6*6600Sas200622  * You may not use this file except in compliance with the License.
7*6600Sas200622  *
8*6600Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6600Sas200622  * or http://www.opensolaris.org/os/licensing.
10*6600Sas200622  * See the License for the specific language governing permissions
11*6600Sas200622  * and limitations under the License.
12*6600Sas200622  *
13*6600Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
14*6600Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6600Sas200622  * If applicable, add the following below this CDDL HEADER, with the
16*6600Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
17*6600Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6600Sas200622  *
19*6600Sas200622  * CDDL HEADER END
20*6600Sas200622  */
21*6600Sas200622 /*
22*6600Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*6600Sas200622  * Use is subject to license terms.
24*6600Sas200622  */
25*6600Sas200622 
26*6600Sas200622 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*6600Sas200622 
28*6600Sas200622 /*
29*6600Sas200622  * SMB Locking library functions.
30*6600Sas200622  */
31*6600Sas200622 
32*6600Sas200622 #include <smbsrv/smb_incl.h>
33*6600Sas200622 #include <smbsrv/smb_fsops.h>
34*6600Sas200622 
35*6600Sas200622 /*
36*6600Sas200622  * Oplock functionality enable/disable
37*6600Sas200622  */
38*6600Sas200622 
39*6600Sas200622 /*
40*6600Sas200622  *	Magic		0xFF 'S' 'M' 'B'
41*6600Sas200622  *	smb_com 	a byte, the "first" command
42*6600Sas200622  *	Error		a 4-byte union, ignored in a request
43*6600Sas200622  *	smb_flg		a one byte set of eight flags
44*6600Sas200622  *	smb_flg2	a two byte set of 16 flags
45*6600Sas200622  *	.		twelve reserved bytes, have a role
46*6600Sas200622  *			in connectionless transports (IPX, UDP?)
47*6600Sas200622  *	smb_tid		a 16-bit tree ID, a mount point sorta,
48*6600Sas200622  *			0xFFFF is this command does not have
49*6600Sas200622  *			or require a tree context
50*6600Sas200622  *	smb_pid		a 16-bit process ID
51*6600Sas200622  *	smb_uid		a 16-bit user ID, specific to this "session"
52*6600Sas200622  *			and mapped to a system (bona-fide) UID
53*6600Sas200622  *	smb_mid		a 16-bit multiplex ID, used to differentiate
54*6600Sas200622  *			multiple simultaneous requests from the same
55*6600Sas200622  *			process (pid) (ref RPC "xid")
56*6600Sas200622  *
57*6600Sas200622  * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
58*6600Sas200622  *
59*6600Sas200622  *  Client Request                     Description
60*6600Sas200622  *  ================================== =================================
61*6600Sas200622  *
62*6600Sas200622  *  UCHAR WordCount;                   Count of parameter words = 8
63*6600Sas200622  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF = none
64*6600Sas200622  *  UCHAR AndXReserved;                Reserved (must be 0)
65*6600Sas200622  *  USHORT AndXOffset;                 Offset to next command WordCount
66*6600Sas200622  *  USHORT Fid;                        File handle
67*6600Sas200622  *  UCHAR LockType;                    See LockType table below
68*6600Sas200622  *  UCHAR OplockLevel;                 The new oplock level
69*6600Sas200622  *  ULONG Timeout;                     Milliseconds to wait for unlock
70*6600Sas200622  *  USHORT NumberOfUnlocks;            Num. unlock range structs following
71*6600Sas200622  *  USHORT NumberOfLocks;              Num. lock range structs following
72*6600Sas200622  *  USHORT ByteCount;                  Count of data bytes
73*6600Sas200622  *  LOCKING_ANDX_RANGE Unlocks[];      Unlock ranges
74*6600Sas200622  *  LOCKING_ANDX_RANGE Locks[];        Lock ranges
75*6600Sas200622  *
76*6600Sas200622  *  LockType Flag Name            Value Description
77*6600Sas200622  *  ============================  ===== ================================
78*6600Sas200622  *
79*6600Sas200622  *  LOCKING_ANDX_SHARED_LOCK      0x01  Read-only lock
80*6600Sas200622  *  LOCKING_ANDX_OPLOCK_RELEASE   0x02  Oplock break notification
81*6600Sas200622  *  LOCKING_ANDX_CHANGE_LOCKTYPE  0x04  Change lock type
82*6600Sas200622  *  LOCKING_ANDX_CANCEL_LOCK      0x08  Cancel outstanding request
83*6600Sas200622  *  LOCKING_ANDX_LARGE_FILES      0x10  Large file locking format
84*6600Sas200622  *
85*6600Sas200622  *  LOCKING_ANDX_RANGE Format
86*6600Sas200622  *  =====================================================================
87*6600Sas200622  *
88*6600Sas200622  *  USHORT Pid;                        PID of process "owning" lock
89*6600Sas200622  *  ULONG Offset;                      Offset to bytes to [un]lock
90*6600Sas200622  *  ULONG Length;                      Number of bytes to [un]lock
91*6600Sas200622  *
92*6600Sas200622  *  Large File LOCKING_ANDX_RANGE Format
93*6600Sas200622  *  =====================================================================
94*6600Sas200622  *
95*6600Sas200622  *  USHORT Pid;                        PID of process "owning" lock
96*6600Sas200622  *  USHORT Pad;                        Pad to DWORD align (mbz)
97*6600Sas200622  *  ULONG OffsetHigh;                  Offset to bytes to [un]lock
98*6600Sas200622  *                                      (high)
99*6600Sas200622  *  ULONG OffsetLow;                   Offset to bytes to [un]lock (low)
100*6600Sas200622  *  ULONG LengthHigh;                  Number of bytes to [un]lock
101*6600Sas200622  *                                      (high)
102*6600Sas200622  *  ULONG LengthLow;                   Number of bytes to [un]lock (low)
103*6600Sas200622  *
104*6600Sas200622  *  Server Response                    Description
105*6600Sas200622  *  ================================== =================================
106*6600Sas200622  *
107*6600Sas200622  *  UCHAR WordCount;                   Count of parameter words = 2
108*6600Sas200622  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
109*6600Sas200622  *                                      none
110*6600Sas200622  *  UCHAR AndXReserved;                Reserved (must be 0)
111*6600Sas200622  *  USHORT AndXOffset;                 Offset to next command WordCount
112*6600Sas200622  *  USHORT ByteCount;                  Count of data bytes = 0
113*6600Sas200622  *
114*6600Sas200622  */
115*6600Sas200622 
116*6600Sas200622 /*
117*6600Sas200622  * smb_oplock_acquire
118*6600Sas200622  *
119*6600Sas200622  * Attempt to acquire an oplock. Note that the oplock granted may be
120*6600Sas200622  * none, i.e. the oplock was not granted.
121*6600Sas200622  *
122*6600Sas200622  * Grant an oplock to the requestor if this session is the only one
123*6600Sas200622  * that has the file open, regardless of the number of instances of
124*6600Sas200622  * the file opened by this session.
125*6600Sas200622  *
126*6600Sas200622  * However, if there is no oplock on this file and there is already
127*6600Sas200622  * at least one open, we will not grant an oplock, even if the only
128*6600Sas200622  * existing opens are from the same client.  This is "server discretion."
129*6600Sas200622  *
130*6600Sas200622  * An oplock may need to be broken in order for one to be granted, and
131*6600Sas200622  * depending on what action is taken by the other client (unlock or close),
132*6600Sas200622  * an oplock may or may not be granted.  (The breaking of an oplock is
133*6600Sas200622  * done earlier in the calling path.)
134*6600Sas200622  *
135*6600Sas200622  * XXX: Node synchronization is not yet implemented.  However, racing
136*6600Sas200622  * opens are handled thus:
137*6600Sas200622  *
138*6600Sas200622  * A racing oplock acquire can happen in the open path between
139*6600Sas200622  * smb_oplock_break() and smb_fsop_open(), but no later.  (Once
140*6600Sas200622  * the file is open via smb_fsop_open()/VOP_OPEN,
141*6600Sas200622  * smb_fsop_oplock_install() will not be able to install an oplock,
142*6600Sas200622  * which requires an open count of 1.)
143*6600Sas200622  *
144*6600Sas200622  * Hence, we can safely break any oplock that came in after the
145*6600Sas200622  * smb_oplock_break() done previously in the open path, knowing that
146*6600Sas200622  * no other racing oplock acquisitions should be able to succeed
147*6600Sas200622  * because we already have the file open (see above).
148*6600Sas200622  *
149*6600Sas200622  * The type of oplock being requested is passed in op->my_flags.  The result
150*6600Sas200622  * is also returned in op->my_flags.
151*6600Sas200622  *
152*6600Sas200622  * (Note that exclusive and batch oplocks are treated interchangeably.)
153*6600Sas200622  *
154*6600Sas200622  * The Returns NT status codes:
155*6600Sas200622  *	NT_STATUS_SUCCESS
156*6600Sas200622  *	NT_STATUS_CONNECTION_DISCONNECTED
157*6600Sas200622  */
158*6600Sas200622 DWORD
159*6600Sas200622 smb_oplock_acquire(
160*6600Sas200622     smb_request_t	*sr,
161*6600Sas200622     smb_ofile_t		*of,
162*6600Sas200622     struct open_param	*op)
163*6600Sas200622 {
164*6600Sas200622 	smb_node_t		*node;
165*6600Sas200622 	unsigned int		level;
166*6600Sas200622 
167*6600Sas200622 	ASSERT(sr);
168*6600Sas200622 	ASSERT(of);
169*6600Sas200622 	ASSERT(op);
170*6600Sas200622 	ASSERT(op->fqi.last_attr.sa_vattr.va_type == VREG);
171*6600Sas200622 
172*6600Sas200622 	level = op->my_flags & MYF_OPLOCK_MASK;
173*6600Sas200622 
174*6600Sas200622 	op->my_flags &= ~MYF_OPLOCK_MASK;
175*6600Sas200622 
176*6600Sas200622 	if ((sr->sr_cfg->skc_oplock_enable == 0) ||
177*6600Sas200622 	    (fsd_chkcap(&of->f_tree->t_fsd, FSOLF_DISABLE_OPLOCKS) > 0))
178*6600Sas200622 		return (NT_STATUS_SUCCESS);
179*6600Sas200622 
180*6600Sas200622 	if (!((MYF_IS_EXCLUSIVE_OPLOCK(level)) ||
181*6600Sas200622 	    (MYF_IS_BATCH_OPLOCK(level))))
182*6600Sas200622 		return (NT_STATUS_SUCCESS);
183*6600Sas200622 
184*6600Sas200622 	node = of->f_node;
185*6600Sas200622 
186*6600Sas200622 	smb_rwx_rwenter(&node->n_lock, RW_WRITER);
187*6600Sas200622 
188*6600Sas200622 	if (EXCLUSIVE_OPLOCK_IN_FORCE(node) ||
189*6600Sas200622 	    BATCH_OPLOCK_IN_FORCE(node)) {
190*6600Sas200622 
191*6600Sas200622 		smb_rwx_rwexit(&node->n_lock);
192*6600Sas200622 
193*6600Sas200622 		if (SMB_SAME_SESSION(sr->session,
194*6600Sas200622 		    node->n_oplock.op_ofile->f_session)) {
195*6600Sas200622 			op->my_flags |= level;
196*6600Sas200622 			return (NT_STATUS_SUCCESS);
197*6600Sas200622 		} else if (SMB_ATTR_ONLY_OPEN(op)) {
198*6600Sas200622 			ASSERT(!(op->my_flags & MYF_OPLOCK_MASK));
199*6600Sas200622 			return (NT_STATUS_SUCCESS);
200*6600Sas200622 		}
201*6600Sas200622 
202*6600Sas200622 		smb_oplock_break(node);
203*6600Sas200622 
204*6600Sas200622 		smb_rwx_rwenter(&node->n_lock, RW_WRITER);
205*6600Sas200622 	}
206*6600Sas200622 
207*6600Sas200622 	if (smb_fsop_oplock_install(node, of->f_mode) != 0) {
208*6600Sas200622 		smb_rwx_rwexit(&node->n_lock);
209*6600Sas200622 		return (NT_STATUS_SUCCESS);
210*6600Sas200622 	}
211*6600Sas200622 
212*6600Sas200622 	node->n_oplock.op_ofile = of;
213*6600Sas200622 	node->n_oplock.op_ipaddr = sr->session->ipaddr;
214*6600Sas200622 	node->n_oplock.op_kid = sr->session->s_kid;
215*6600Sas200622 	node->flags &= ~NODE_OPLOCKS_IN_FORCE;
216*6600Sas200622 
217*6600Sas200622 	if (MYF_IS_EXCLUSIVE_OPLOCK(level))
218*6600Sas200622 		node->flags |= NODE_EXCLUSIVE_OPLOCK;
219*6600Sas200622 
220*6600Sas200622 	if (MYF_IS_BATCH_OPLOCK(level))
221*6600Sas200622 		node->flags |= NODE_BATCH_OPLOCK;
222*6600Sas200622 
223*6600Sas200622 	op->my_flags |= level;
224*6600Sas200622 
225*6600Sas200622 	smb_rwx_rwexit(&node->n_lock);
226*6600Sas200622 
227*6600Sas200622 	return (NT_STATUS_SUCCESS);
228*6600Sas200622 }
229*6600Sas200622 
230*6600Sas200622 /*
231*6600Sas200622  * smb_oplock_break
232*6600Sas200622  *
233*6600Sas200622  * The oplock break may succeed for multiple reasons: file close, oplock
234*6600Sas200622  * release, holder connection dropped, requesting client disconnect etc.
235*6600Sas200622  * Whatever the reason, the oplock should be broken when this function
236*6600Sas200622  * returns. The exceptions are when the client making this request gets
237*6600Sas200622  * disconnected or when another client is handling the break and it gets
238*6600Sas200622  * disconnected.
239*6600Sas200622  *
240*6600Sas200622  * Returns NT status codes:
241*6600Sas200622  *	NT_STATUS_SUCCESS                  No oplock in force, i.e. the
242*6600Sas200622  *						oplock has been broken.
243*6600Sas200622  *	NT_STATUS_CONNECTION_DISCONNECTED  Requesting client disconnected.
244*6600Sas200622  *	NT_STATUS_INTERNAL_ERROR
245*6600Sas200622  */
246*6600Sas200622 
247*6600Sas200622 void
248*6600Sas200622 smb_oplock_break(smb_node_t *node)
249*6600Sas200622 {
250*6600Sas200622 	smb_session_t		*oplock_session;
251*6600Sas200622 	smb_ofile_t		*oplock_ofile;
252*6600Sas200622 	struct mbuf_chain	mbc;
253*6600Sas200622 	int			retries = 0;
254*6600Sas200622 	clock_t			elapsed_time;
255*6600Sas200622 	clock_t			max_time;
256*6600Sas200622 	boolean_t		flag;
257*6600Sas200622 
258*6600Sas200622 	smb_rwx_rwenter(&node->n_lock, RW_WRITER);
259*6600Sas200622 
260*6600Sas200622 	if (!OPLOCKS_IN_FORCE(node)) {
261*6600Sas200622 		smb_rwx_rwexit(&node->n_lock);
262*6600Sas200622 		return;
263*6600Sas200622 	}
264*6600Sas200622 
265*6600Sas200622 	if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
266*6600Sas200622 		elapsed_time = 0;
267*6600Sas200622 		max_time = MSEC_TO_TICK(smb_oplock_timeout * OPLOCK_RETRIES);
268*6600Sas200622 		/*
269*6600Sas200622 		 * Another client is already attempting to break the oplock.
270*6600Sas200622 		 * We wait for it to finish. If the caller was trying to
271*6600Sas200622 		 * acquire an oplock, he should retry in case the client's
272*6600Sas200622 		 * connection was dropped while trying to break the oplock.
273*6600Sas200622 		 *
274*6600Sas200622 		 * If the holder's connection has been dropped, we yield to
275*6600Sas200622 		 * allow the thread handling the break to detect it and set
276*6600Sas200622 		 * the flags.
277*6600Sas200622 		 */
278*6600Sas200622 		while ((node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) &&
279*6600Sas200622 		    (elapsed_time < max_time)) {
280*6600Sas200622 			clock_t	timeleft;
281*6600Sas200622 
282*6600Sas200622 			timeleft = smb_rwx_rwwait(&node->n_lock, max_time);
283*6600Sas200622 			if (timeleft == -1) {
284*6600Sas200622 				elapsed_time = max_time;
285*6600Sas200622 			} else {
286*6600Sas200622 				elapsed_time += max_time - timeleft;
287*6600Sas200622 			}
288*6600Sas200622 		}
289*6600Sas200622 		/*
290*6600Sas200622 		 * If there are no oplocks in force we're done.
291*6600Sas200622 		 */
292*6600Sas200622 		if (!OPLOCKS_IN_FORCE(node)) {
293*6600Sas200622 			smb_rwx_rwexit(&node->n_lock);
294*6600Sas200622 			return;
295*6600Sas200622 		} else {
296*6600Sas200622 			/*
297*6600Sas200622 			 * This is an anomalous condition.
298*6600Sas200622 			 * Cancel/release the oplock.
299*6600Sas200622 			 */
300*6600Sas200622 			smb_oplock_release(node, B_TRUE);
301*6600Sas200622 			smb_rwx_rwexit(&node->n_lock);
302*6600Sas200622 			return;
303*6600Sas200622 		}
304*6600Sas200622 	}
305*6600Sas200622 
306*6600Sas200622 	oplock_ofile = node->n_oplock.op_ofile;
307*6600Sas200622 	ASSERT(oplock_ofile);
308*6600Sas200622 
309*6600Sas200622 	oplock_session = oplock_ofile->f_session;
310*6600Sas200622 	ASSERT(oplock_session);
311*6600Sas200622 
312*6600Sas200622 	/*
313*6600Sas200622 	 * Start oplock break.
314*6600Sas200622 	 */
315*6600Sas200622 
316*6600Sas200622 	node->n_oplock.op_flags |= OPLOCK_FLAG_BREAKING;
317*6600Sas200622 
318*6600Sas200622 	smb_rwx_rwexit(&node->n_lock);
319*6600Sas200622 
320*6600Sas200622 	max_time = MSEC_TO_TICK(smb_oplock_timeout);
321*6600Sas200622 	do {
322*6600Sas200622 		MBC_INIT(&mbc, MLEN);
323*6600Sas200622 		(void) smb_encode_mbc(&mbc, "Mb19.wwwwbb3.ww10.",
324*6600Sas200622 		    SMB_COM_LOCKING_ANDX, oplock_ofile->f_tree->t_tid,
325*6600Sas200622 		    0xffff, 0, 0xffff, 8, 0xff, oplock_ofile->f_fid,
326*6600Sas200622 		    LOCKING_ANDX_OPLOCK_RELEASE);
327*6600Sas200622 
328*6600Sas200622 		flag = B_TRUE;
329*6600Sas200622 		smb_rwx_rwenter(&oplock_session->s_lock, RW_WRITER);
330*6600Sas200622 		while (flag) {
331*6600Sas200622 			switch (oplock_session->s_state) {
332*6600Sas200622 			case SMB_SESSION_STATE_DISCONNECTED:
333*6600Sas200622 			case SMB_SESSION_STATE_TERMINATED:
334*6600Sas200622 				smb_rwx_rwexit(&oplock_session->s_lock);
335*6600Sas200622 				smb_rwx_rwenter(&node->n_lock, RW_WRITER);
336*6600Sas200622 
337*6600Sas200622 				node->flags &= ~NODE_OPLOCKS_IN_FORCE;
338*6600Sas200622 				node->n_oplock.op_flags &=
339*6600Sas200622 				    ~OPLOCK_FLAG_BREAKING;
340*6600Sas200622 				node->n_oplock.op_ofile = NULL;
341*6600Sas200622 				node->n_oplock.op_ipaddr = 0;
342*6600Sas200622 				node->n_oplock.op_kid = 0;
343*6600Sas200622 
344*6600Sas200622 				smb_rwx_rwexit(&node->n_lock);
345*6600Sas200622 
346*6600Sas200622 				return;
347*6600Sas200622 
348*6600Sas200622 			case SMB_SESSION_STATE_OPLOCK_BREAKING:
349*6600Sas200622 				flag = B_FALSE;
350*6600Sas200622 				break;
351*6600Sas200622 
352*6600Sas200622 			case SMB_SESSION_STATE_NEGOTIATED:
353*6600Sas200622 				oplock_session->s_state =
354*6600Sas200622 				    SMB_SESSION_STATE_OPLOCK_BREAKING;
355*6600Sas200622 				flag = B_FALSE;
356*6600Sas200622 				break;
357*6600Sas200622 
358*6600Sas200622 			default:
359*6600Sas200622 				(void) smb_rwx_rwwait(&oplock_session->s_lock,
360*6600Sas200622 				    -1);
361*6600Sas200622 				break;
362*6600Sas200622 			}
363*6600Sas200622 		}
364*6600Sas200622 		smb_rwx_rwexit(&oplock_session->s_lock);
365*6600Sas200622 
366*6600Sas200622 		(void) smb_session_send(oplock_session, 0, &mbc);
367*6600Sas200622 
368*6600Sas200622 		elapsed_time = 0;
369*6600Sas200622 
370*6600Sas200622 		smb_rwx_rwenter(&node->n_lock, RW_WRITER);
371*6600Sas200622 		while ((node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) &&
372*6600Sas200622 		    (elapsed_time < max_time)) {
373*6600Sas200622 			clock_t	timeleft;
374*6600Sas200622 
375*6600Sas200622 			timeleft = smb_rwx_rwwait(&node->n_lock, max_time);
376*6600Sas200622 			if (timeleft == -1) {
377*6600Sas200622 				elapsed_time = max_time;
378*6600Sas200622 			} else {
379*6600Sas200622 				elapsed_time += max_time - timeleft;
380*6600Sas200622 			}
381*6600Sas200622 		}
382*6600Sas200622 
383*6600Sas200622 		if (!OPLOCKS_IN_FORCE(node)) {
384*6600Sas200622 			/*
385*6600Sas200622 			 * smb_oplock_release() was called
386*6600Sas200622 			 */
387*6600Sas200622 			smb_rwx_rwexit(&node->n_lock);
388*6600Sas200622 			return;
389*6600Sas200622 		}
390*6600Sas200622 	} while (++retries < OPLOCK_RETRIES);
391*6600Sas200622 
392*6600Sas200622 	/*
393*6600Sas200622 	 * Retries exhausted and timed out.
394*6600Sas200622 	 * Cancel the oplock and continue.
395*6600Sas200622 	 */
396*6600Sas200622 
397*6600Sas200622 	smb_oplock_release(node, B_TRUE);
398*6600Sas200622 
399*6600Sas200622 	smb_rwx_rwexit(&node->n_lock);
400*6600Sas200622 }
401*6600Sas200622 
402*6600Sas200622 /*
403*6600Sas200622  * smb_oplock_release
404*6600Sas200622  *
405*6600Sas200622  * This function uninstalls the FEM oplock monitors and
406*6600Sas200622  * clears all flags in relation to an oplock on the
407*6600Sas200622  * given node.
408*6600Sas200622  *
409*6600Sas200622  * The function can be called with the node->n_lock held
410*6600Sas200622  * or not held.
411*6600Sas200622  */
412*6600Sas200622 
413*6600Sas200622 void /*ARGSUSED*/
414*6600Sas200622 smb_oplock_release(smb_node_t *node, boolean_t have_rwx)
415*6600Sas200622 {
416*6600Sas200622 	if (!have_rwx)
417*6600Sas200622 		smb_rwx_rwenter(&node->n_lock, RW_WRITER);
418*6600Sas200622 
419*6600Sas200622 	if (!OPLOCKS_IN_FORCE(node)) {
420*6600Sas200622 		if (!have_rwx)
421*6600Sas200622 			smb_rwx_rwexit(&node->n_lock);
422*6600Sas200622 		return;
423*6600Sas200622 	}
424*6600Sas200622 
425*6600Sas200622 	smb_fsop_oplock_uninstall(node);
426*6600Sas200622 
427*6600Sas200622 	node->flags &= ~NODE_OPLOCKS_IN_FORCE;
428*6600Sas200622 	node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING;
429*6600Sas200622 	node->n_oplock.op_ofile = NULL;
430*6600Sas200622 	node->n_oplock.op_ipaddr = 0;
431*6600Sas200622 	node->n_oplock.op_kid = 0;
432*6600Sas200622 
433*6600Sas200622 	if (!have_rwx)
434*6600Sas200622 		smb_rwx_rwexit(&node->n_lock);
435*6600Sas200622 }
436*6600Sas200622 
437*6600Sas200622 /*
438*6600Sas200622  * smb_oplock_conflict
439*6600Sas200622  *
440*6600Sas200622  * The two checks on "session" and "op" are primarily for the open path.
441*6600Sas200622  * Other CIFS functions may call smb_oplock_conflict() with a session
442*6600Sas200622  * pointer so as to do the session check.
443*6600Sas200622  */
444*6600Sas200622 
445*6600Sas200622 boolean_t
446*6600Sas200622 smb_oplock_conflict(smb_node_t *node, smb_session_t *session,
447*6600Sas200622     struct open_param *op)
448*6600Sas200622 {
449*6600Sas200622 	smb_session_t		*oplock_session;
450*6600Sas200622 	smb_ofile_t		*oplock_ofile;
451*6600Sas200622 
452*6600Sas200622 	smb_rwx_rwenter(&node->n_lock, RW_READER);
453*6600Sas200622 
454*6600Sas200622 	if (!OPLOCKS_IN_FORCE(node)) {
455*6600Sas200622 		smb_rwx_rwexit(&node->n_lock);
456*6600Sas200622 		return (B_FALSE);
457*6600Sas200622 	}
458*6600Sas200622 
459*6600Sas200622 	oplock_ofile = node->n_oplock.op_ofile;
460*6600Sas200622 	ASSERT(oplock_ofile);
461*6600Sas200622 
462*6600Sas200622 	oplock_session = oplock_ofile->f_session;
463*6600Sas200622 	ASSERT(oplock_session);
464*6600Sas200622 
465*6600Sas200622 	if (SMB_SAME_SESSION(session, oplock_session)) {
466*6600Sas200622 		smb_rwx_rwexit(&node->n_lock);
467*6600Sas200622 		return (B_FALSE);
468*6600Sas200622 	}
469*6600Sas200622 
470*6600Sas200622 	if (SMB_ATTR_ONLY_OPEN(op)) {
471*6600Sas200622 		smb_rwx_rwexit(&node->n_lock);
472*6600Sas200622 		return (B_FALSE);
473*6600Sas200622 	}
474*6600Sas200622 
475*6600Sas200622 	smb_rwx_rwexit(&node->n_lock);
476*6600Sas200622 	return (B_TRUE);
477*6600Sas200622 }
478