xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision 10966:37e5dcdf36d3)
16600Sas200622 /*
26600Sas200622  * CDDL HEADER START
36600Sas200622  *
46600Sas200622  * The contents of this file are subject to the terms of the
56600Sas200622  * Common Development and Distribution License (the "License").
66600Sas200622  * You may not use this file except in compliance with the License.
76600Sas200622  *
86600Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96600Sas200622  * or http://www.opensolaris.org/os/licensing.
106600Sas200622  * See the License for the specific language governing permissions
116600Sas200622  * and limitations under the License.
126600Sas200622  *
136600Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
146600Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156600Sas200622  * If applicable, add the following below this CDDL HEADER, with the
166600Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
176600Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
186600Sas200622  *
196600Sas200622  * CDDL HEADER END
206600Sas200622  */
216600Sas200622 /*
228670SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
236600Sas200622  * Use is subject to license terms.
246600Sas200622  */
256600Sas200622 /*
266600Sas200622  * SMB Locking library functions.
279231SAfshin.Ardakani@Sun.COM  *
289231SAfshin.Ardakani@Sun.COM  * You will notice that the functions in this file exit the lock of the session
299231SAfshin.Ardakani@Sun.COM  * and reenter it before returning. They even assume that the lock has been
309231SAfshin.Ardakani@Sun.COM  * entered in READER mode. The reason for that is a potential deadlock that may
319231SAfshin.Ardakani@Sun.COM  * occur when an oplock needs to be broken and the function
329231SAfshin.Ardakani@Sun.COM  * smb_session_break_oplock() is called. It should be noticed that the mutex of
339231SAfshin.Ardakani@Sun.COM  * the smb node, the oplock of which needs to be broken, is also exited before
349231SAfshin.Ardakani@Sun.COM  * calling smb_session_break_oplock(). The reason for that is the same: avoiding
359231SAfshin.Ardakani@Sun.COM  * a deadlock. That complexity is due to the fact that the lock of the session
369231SAfshin.Ardakani@Sun.COM  * is held during the treatment of a request. That complexity will go away when
379231SAfshin.Ardakani@Sun.COM  * that is not the case anymore.
386600Sas200622  */
396600Sas200622 
40*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
416600Sas200622 #include <smbsrv/smb_fsops.h>
428670SJose.Borrego@Sun.COM #include <inet/tcp.h>
436600Sas200622 
449021Samw@Sun.COM static void smb_oplock_wait(smb_node_t *);
456600Sas200622 
466600Sas200622 /*
476600Sas200622  *	Magic		0xFF 'S' 'M' 'B'
486600Sas200622  *	smb_com 	a byte, the "first" command
496600Sas200622  *	Error		a 4-byte union, ignored in a request
506600Sas200622  *	smb_flg		a one byte set of eight flags
516600Sas200622  *	smb_flg2	a two byte set of 16 flags
526600Sas200622  *	.		twelve reserved bytes, have a role
536600Sas200622  *			in connectionless transports (IPX, UDP?)
546600Sas200622  *	smb_tid		a 16-bit tree ID, a mount point sorta,
556600Sas200622  *			0xFFFF is this command does not have
566600Sas200622  *			or require a tree context
576600Sas200622  *	smb_pid		a 16-bit process ID
586600Sas200622  *	smb_uid		a 16-bit user ID, specific to this "session"
596600Sas200622  *			and mapped to a system (bona-fide) UID
606600Sas200622  *	smb_mid		a 16-bit multiplex ID, used to differentiate
616600Sas200622  *			multiple simultaneous requests from the same
626600Sas200622  *			process (pid) (ref RPC "xid")
636600Sas200622  *
646600Sas200622  * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
656600Sas200622  *
666600Sas200622  *  Client Request                     Description
676600Sas200622  *  ================================== =================================
686600Sas200622  *
696600Sas200622  *  UCHAR WordCount;                   Count of parameter words = 8
706600Sas200622  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF = none
716600Sas200622  *  UCHAR AndXReserved;                Reserved (must be 0)
726600Sas200622  *  USHORT AndXOffset;                 Offset to next command WordCount
736600Sas200622  *  USHORT Fid;                        File handle
746600Sas200622  *  UCHAR LockType;                    See LockType table below
756600Sas200622  *  UCHAR OplockLevel;                 The new oplock level
766600Sas200622  *  ULONG Timeout;                     Milliseconds to wait for unlock
776600Sas200622  *  USHORT NumberOfUnlocks;            Num. unlock range structs following
786600Sas200622  *  USHORT NumberOfLocks;              Num. lock range structs following
796600Sas200622  *  USHORT ByteCount;                  Count of data bytes
806600Sas200622  *  LOCKING_ANDX_RANGE Unlocks[];      Unlock ranges
816600Sas200622  *  LOCKING_ANDX_RANGE Locks[];        Lock ranges
826600Sas200622  *
836600Sas200622  *  LockType Flag Name            Value Description
846600Sas200622  *  ============================  ===== ================================
856600Sas200622  *
866600Sas200622  *  LOCKING_ANDX_SHARED_LOCK      0x01  Read-only lock
876600Sas200622  *  LOCKING_ANDX_OPLOCK_RELEASE   0x02  Oplock break notification
886600Sas200622  *  LOCKING_ANDX_CHANGE_LOCKTYPE  0x04  Change lock type
896600Sas200622  *  LOCKING_ANDX_CANCEL_LOCK      0x08  Cancel outstanding request
906600Sas200622  *  LOCKING_ANDX_LARGE_FILES      0x10  Large file locking format
916600Sas200622  *
926600Sas200622  *  LOCKING_ANDX_RANGE Format
936600Sas200622  *  =====================================================================
946600Sas200622  *
956600Sas200622  *  USHORT Pid;                        PID of process "owning" lock
966600Sas200622  *  ULONG Offset;                      Offset to bytes to [un]lock
976600Sas200622  *  ULONG Length;                      Number of bytes to [un]lock
986600Sas200622  *
996600Sas200622  *  Large File LOCKING_ANDX_RANGE Format
1006600Sas200622  *  =====================================================================
1016600Sas200622  *
1026600Sas200622  *  USHORT Pid;                        PID of process "owning" lock
1036600Sas200622  *  USHORT Pad;                        Pad to DWORD align (mbz)
1046600Sas200622  *  ULONG OffsetHigh;                  Offset to bytes to [un]lock
1056600Sas200622  *                                      (high)
1066600Sas200622  *  ULONG OffsetLow;                   Offset to bytes to [un]lock (low)
1076600Sas200622  *  ULONG LengthHigh;                  Number of bytes to [un]lock
1086600Sas200622  *                                      (high)
1096600Sas200622  *  ULONG LengthLow;                   Number of bytes to [un]lock (low)
1106600Sas200622  *
1116600Sas200622  *  Server Response                    Description
1126600Sas200622  *  ================================== =================================
1136600Sas200622  *
1146600Sas200622  *  UCHAR WordCount;                   Count of parameter words = 2
1156600Sas200622  *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
1166600Sas200622  *                                      none
1176600Sas200622  *  UCHAR AndXReserved;                Reserved (must be 0)
1186600Sas200622  *  USHORT AndXOffset;                 Offset to next command WordCount
1196600Sas200622  *  USHORT ByteCount;                  Count of data bytes = 0
1206600Sas200622  *
1216600Sas200622  */
1226600Sas200622 
1236600Sas200622 /*
1246600Sas200622  * smb_oplock_acquire
1256600Sas200622  *
1266600Sas200622  * Attempt to acquire an oplock. Note that the oplock granted may be
1278934SJose.Borrego@Sun.COM  * none, i.e. the oplock was not granted. The result of the acquisition is
1288934SJose.Borrego@Sun.COM  * provided in ol->ol_level.
1296600Sas200622  *
1306600Sas200622  * Grant an oplock to the requestor if this session is the only one
1316600Sas200622  * that has the file open, regardless of the number of instances of
1326600Sas200622  * the file opened by this session.
1336600Sas200622  *
1346600Sas200622  * However, if there is no oplock on this file and there is already
1356600Sas200622  * at least one open, we will not grant an oplock, even if the only
1366600Sas200622  * existing opens are from the same client.  This is "server discretion."
1376600Sas200622  *
1386600Sas200622  * An oplock may need to be broken in order for one to be granted, and
1396600Sas200622  * depending on what action is taken by the other client (unlock or close),
1406600Sas200622  * an oplock may or may not be granted.  (The breaking of an oplock is
1416600Sas200622  * done earlier in the calling path.)
1426600Sas200622  */
1438934SJose.Borrego@Sun.COM void
1448934SJose.Borrego@Sun.COM smb_oplock_acquire(smb_node_t *node, smb_ofile_t *of, open_param_t *op)
1456600Sas200622 {
1468934SJose.Borrego@Sun.COM 	smb_session_t	*session;
1478934SJose.Borrego@Sun.COM 	smb_oplock_t	*ol;
1488934SJose.Borrego@Sun.COM 	clock_t		time;
1498934SJose.Borrego@Sun.COM 
1508934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
1518934SJose.Borrego@Sun.COM 	SMB_OFILE_VALID(of);
1528934SJose.Borrego@Sun.COM 
1538934SJose.Borrego@Sun.COM 	ASSERT(node == SMB_OFILE_GET_NODE(of));
1548934SJose.Borrego@Sun.COM 
1558934SJose.Borrego@Sun.COM 	session = SMB_OFILE_GET_SESSION(of);
1568934SJose.Borrego@Sun.COM 
1578934SJose.Borrego@Sun.COM 	if (!smb_session_oplocks_enable(session) ||
1588934SJose.Borrego@Sun.COM 	    smb_tree_has_feature(SMB_OFILE_GET_TREE(of), SMB_TREE_NO_OPLOCKS)) {
1598934SJose.Borrego@Sun.COM 		op->op_oplock_level = SMB_OPLOCK_NONE;
1608934SJose.Borrego@Sun.COM 		return;
1618934SJose.Borrego@Sun.COM 	}
1628934SJose.Borrego@Sun.COM 
1638934SJose.Borrego@Sun.COM 	ol = &node->n_oplock;
1648934SJose.Borrego@Sun.COM 	time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt();
1658934SJose.Borrego@Sun.COM 
1668934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
1676600Sas200622 
1689021Samw@Sun.COM 	switch (node->n_state) {
1699021Samw@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
1709021Samw@Sun.COM 		if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id) {
1719021Samw@Sun.COM 			mutex_exit(&node->n_mutex);
1729021Samw@Sun.COM 			return;
1739021Samw@Sun.COM 		}
1749021Samw@Sun.COM 		break;
1759021Samw@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
1769021Samw@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
1779021Samw@Sun.COM 		break;
1789021Samw@Sun.COM 	default:
1799021Samw@Sun.COM 		SMB_PANIC();
1809021Samw@Sun.COM 	}
1819021Samw@Sun.COM 
1828934SJose.Borrego@Sun.COM 	for (;;) {
1838934SJose.Borrego@Sun.COM 		int	rc;
1846600Sas200622 
1859021Samw@Sun.COM 		smb_oplock_wait(node);
1866600Sas200622 
1878934SJose.Borrego@Sun.COM 		if (node->n_state == SMB_NODE_STATE_AVAILABLE) {
1888934SJose.Borrego@Sun.COM 			if ((op->op_oplock_level == SMB_OPLOCK_LEVEL_II) ||
1898934SJose.Borrego@Sun.COM 			    (op->op_oplock_level == SMB_OPLOCK_NONE) ||
1908934SJose.Borrego@Sun.COM 			    (node->n_open_count > 1)) {
1918934SJose.Borrego@Sun.COM 				mutex_exit(&node->n_mutex);
1928934SJose.Borrego@Sun.COM 				op->op_oplock_level = SMB_OPLOCK_NONE;
1938934SJose.Borrego@Sun.COM 				return;
1948934SJose.Borrego@Sun.COM 			}
1958934SJose.Borrego@Sun.COM 			ol->ol_ofile = of;
1968934SJose.Borrego@Sun.COM 			ol->ol_sess_id = SMB_SESSION_GET_ID(session);
1978934SJose.Borrego@Sun.COM 			ol->ol_level = op->op_oplock_level;
1988934SJose.Borrego@Sun.COM 			ol->ol_xthread = curthread;
1998934SJose.Borrego@Sun.COM 			node->n_state = SMB_NODE_STATE_OPLOCK_GRANTED;
2008934SJose.Borrego@Sun.COM 			mutex_exit(&node->n_mutex);
2018934SJose.Borrego@Sun.COM 			if (smb_fsop_oplock_install(node, of->f_mode) == 0) {
2028934SJose.Borrego@Sun.COM 				smb_ofile_set_oplock_granted(of);
2038934SJose.Borrego@Sun.COM 				return;
2048934SJose.Borrego@Sun.COM 			}
2058934SJose.Borrego@Sun.COM 			mutex_enter(&node->n_mutex);
2068934SJose.Borrego@Sun.COM 			ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED);
2078934SJose.Borrego@Sun.COM 			node->n_state = SMB_NODE_STATE_AVAILABLE;
2088934SJose.Borrego@Sun.COM 			ol->ol_xthread = NULL;
2098934SJose.Borrego@Sun.COM 			op->op_oplock_level = SMB_OPLOCK_NONE;
2109021Samw@Sun.COM 			cv_broadcast(&ol->ol_cv);
2118934SJose.Borrego@Sun.COM 			break;
2126600Sas200622 		}
2136600Sas200622 
2148934SJose.Borrego@Sun.COM 		if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) {
2158934SJose.Borrego@Sun.COM 			if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id)
2168934SJose.Borrego@Sun.COM 				break;
2178934SJose.Borrego@Sun.COM 			node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING;
2189231SAfshin.Ardakani@Sun.COM 			mutex_exit(&node->n_mutex);
2198934SJose.Borrego@Sun.COM 			smb_session_oplock_break(
2208934SJose.Borrego@Sun.COM 			    SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile);
2219231SAfshin.Ardakani@Sun.COM 			mutex_enter(&node->n_mutex);
2229231SAfshin.Ardakani@Sun.COM 			continue;
2238934SJose.Borrego@Sun.COM 		}
2246600Sas200622 
2258934SJose.Borrego@Sun.COM 		ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING);
2268934SJose.Borrego@Sun.COM 
2278934SJose.Borrego@Sun.COM 		rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time);
2286600Sas200622 
2298934SJose.Borrego@Sun.COM 		if (rc == -1) {
2308934SJose.Borrego@Sun.COM 			/*
2318934SJose.Borrego@Sun.COM 			 * Oplock release timed out.
2328934SJose.Borrego@Sun.COM 			 */
2338934SJose.Borrego@Sun.COM 			if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) {
2348934SJose.Borrego@Sun.COM 				node->n_state = SMB_NODE_STATE_AVAILABLE;
2358934SJose.Borrego@Sun.COM 				ol->ol_xthread = curthread;
2368934SJose.Borrego@Sun.COM 				mutex_exit(&node->n_mutex);
2378934SJose.Borrego@Sun.COM 				smb_fsop_oplock_uninstall(node);
2388934SJose.Borrego@Sun.COM 				mutex_enter(&node->n_mutex);
2398934SJose.Borrego@Sun.COM 				ol->ol_xthread = NULL;
2409021Samw@Sun.COM 				cv_broadcast(&ol->ol_cv);
2418934SJose.Borrego@Sun.COM 			}
2428934SJose.Borrego@Sun.COM 		}
2438934SJose.Borrego@Sun.COM 	}
2448934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
2456600Sas200622 }
2466600Sas200622 
2476600Sas200622 /*
2486600Sas200622  * smb_oplock_break
2496600Sas200622  *
2506600Sas200622  * The oplock break may succeed for multiple reasons: file close, oplock
2516600Sas200622  * release, holder connection dropped, requesting client disconnect etc.
2528934SJose.Borrego@Sun.COM  *
2538934SJose.Borrego@Sun.COM  * Returns:
2546600Sas200622  *
2558934SJose.Borrego@Sun.COM  *	B_TRUE	The oplock is broken.
2568934SJose.Borrego@Sun.COM  *	B_FALSE	The oplock is being broken. This is returned if nowait is set
2578934SJose.Borrego@Sun.COM  *		to B_TRUE;
2586600Sas200622  */
2598934SJose.Borrego@Sun.COM boolean_t
2609021Samw@Sun.COM smb_oplock_break(smb_node_t *node, smb_session_t *session, boolean_t nowait)
2618934SJose.Borrego@Sun.COM {
2628934SJose.Borrego@Sun.COM 	smb_oplock_t	*ol;
2638934SJose.Borrego@Sun.COM 	clock_t		time;
2646600Sas200622 
2658934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
2668934SJose.Borrego@Sun.COM 	ol = &node->n_oplock;
2678934SJose.Borrego@Sun.COM 	time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt();
2686600Sas200622 
2699021Samw@Sun.COM 	if (session != NULL) {
2709021Samw@Sun.COM 		mutex_enter(&node->n_mutex);
2719021Samw@Sun.COM 		if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id) {
2729021Samw@Sun.COM 			mutex_exit(&node->n_mutex);
2739021Samw@Sun.COM 			return (B_TRUE);
2749021Samw@Sun.COM 		}
2759021Samw@Sun.COM 	} else {
2769021Samw@Sun.COM 		mutex_enter(&node->n_mutex);
2776600Sas200622 	}
2786600Sas200622 
2798934SJose.Borrego@Sun.COM 	for (;;) {
2808934SJose.Borrego@Sun.COM 		int	rc;
2818934SJose.Borrego@Sun.COM 
2829021Samw@Sun.COM 		smb_oplock_wait(node);
2836600Sas200622 
2848934SJose.Borrego@Sun.COM 		if (node->n_state == SMB_NODE_STATE_AVAILABLE) {
2858934SJose.Borrego@Sun.COM 			mutex_exit(&node->n_mutex);
2868934SJose.Borrego@Sun.COM 			return (B_TRUE);
2876600Sas200622 		}
2888934SJose.Borrego@Sun.COM 
2898934SJose.Borrego@Sun.COM 		if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) {
2908934SJose.Borrego@Sun.COM 			node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING;
2919021Samw@Sun.COM 			mutex_exit(&node->n_mutex);
2928934SJose.Borrego@Sun.COM 			smb_session_oplock_break(
2938934SJose.Borrego@Sun.COM 			    SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile);
2949021Samw@Sun.COM 			mutex_enter(&node->n_mutex);
2959231SAfshin.Ardakani@Sun.COM 			continue;
2966600Sas200622 		}
2976600Sas200622 
2988934SJose.Borrego@Sun.COM 		ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING);
2998934SJose.Borrego@Sun.COM 		if (nowait) {
3008934SJose.Borrego@Sun.COM 			mutex_exit(&node->n_mutex);
3018934SJose.Borrego@Sun.COM 			return (B_FALSE);
3028934SJose.Borrego@Sun.COM 		}
3038934SJose.Borrego@Sun.COM 		rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time);
3048934SJose.Borrego@Sun.COM 		if (rc == -1) {
3058934SJose.Borrego@Sun.COM 			/*
3068934SJose.Borrego@Sun.COM 			 * Oplock release timed out.
3078934SJose.Borrego@Sun.COM 			 */
3088934SJose.Borrego@Sun.COM 			if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) {
3098934SJose.Borrego@Sun.COM 				node->n_state = SMB_NODE_STATE_AVAILABLE;
3108934SJose.Borrego@Sun.COM 				ol->ol_xthread = curthread;
3118934SJose.Borrego@Sun.COM 				mutex_exit(&node->n_mutex);
3128934SJose.Borrego@Sun.COM 				smb_fsop_oplock_uninstall(node);
3138934SJose.Borrego@Sun.COM 				mutex_enter(&node->n_mutex);
3148934SJose.Borrego@Sun.COM 				ol->ol_xthread = NULL;
3159021Samw@Sun.COM 				cv_broadcast(&ol->ol_cv);
3166600Sas200622 				break;
3176600Sas200622 			}
3186600Sas200622 		}
3198934SJose.Borrego@Sun.COM 	}
3208934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
3218934SJose.Borrego@Sun.COM 	return (B_TRUE);
3226600Sas200622 }
3236600Sas200622 
3246600Sas200622 /*
3256600Sas200622  * smb_oplock_release
3266600Sas200622  *
3278934SJose.Borrego@Sun.COM  * This function releases the oplock on the node passed in. If other threads
3288934SJose.Borrego@Sun.COM  * were waiting for the oplock to be released they are signaled.
3296600Sas200622  */
3308934SJose.Borrego@Sun.COM void
3318934SJose.Borrego@Sun.COM smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
3328934SJose.Borrego@Sun.COM {
3338934SJose.Borrego@Sun.COM 	smb_oplock_t	*ol;
3346600Sas200622 
3358934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
3368934SJose.Borrego@Sun.COM 	ol = &node->n_oplock;
3378934SJose.Borrego@Sun.COM 
3388934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
3399021Samw@Sun.COM 	smb_oplock_wait(node);
3408934SJose.Borrego@Sun.COM 	switch (node->n_state) {
3418934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
3428934SJose.Borrego@Sun.COM 		break;
3436600Sas200622 
3448934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
3458934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
3468934SJose.Borrego@Sun.COM 		if (ol->ol_ofile == of) {
3478934SJose.Borrego@Sun.COM 			node->n_state = SMB_NODE_STATE_AVAILABLE;
3488934SJose.Borrego@Sun.COM 			ol->ol_xthread = curthread;
3498934SJose.Borrego@Sun.COM 			mutex_exit(&node->n_mutex);
3508934SJose.Borrego@Sun.COM 			smb_fsop_oplock_uninstall(node);
3518934SJose.Borrego@Sun.COM 			mutex_enter(&node->n_mutex);
3528934SJose.Borrego@Sun.COM 			ol->ol_xthread = NULL;
3539021Samw@Sun.COM 			cv_broadcast(&ol->ol_cv);
3548934SJose.Borrego@Sun.COM 		}
3558934SJose.Borrego@Sun.COM 		break;
3566600Sas200622 
3578934SJose.Borrego@Sun.COM 	default:
3588934SJose.Borrego@Sun.COM 		SMB_PANIC();
3598934SJose.Borrego@Sun.COM 	}
3608934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
3616600Sas200622 }
3626600Sas200622 
3636600Sas200622 /*
3646600Sas200622  * smb_oplock_conflict
3656600Sas200622  *
3666600Sas200622  * The two checks on "session" and "op" are primarily for the open path.
3679021Samw@Sun.COM  * Other SMB functions may call smb_oplock_conflict() with a session
3686600Sas200622  * pointer so as to do the session check.
3696600Sas200622  */
3706600Sas200622 boolean_t
3718934SJose.Borrego@Sun.COM smb_oplock_conflict(smb_node_t *node, smb_session_t *session, open_param_t *op)
3726600Sas200622 {
3738934SJose.Borrego@Sun.COM 	boolean_t	rb;
3748934SJose.Borrego@Sun.COM 
3758934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
3768934SJose.Borrego@Sun.COM 	SMB_SESSION_VALID(session);
3776600Sas200622 
3788934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
3799021Samw@Sun.COM 	smb_oplock_wait(node);
3808934SJose.Borrego@Sun.COM 	switch (node->n_state) {
3818934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_AVAILABLE:
3828934SJose.Borrego@Sun.COM 		rb = B_FALSE;
3838934SJose.Borrego@Sun.COM 		break;
3848934SJose.Borrego@Sun.COM 
3858934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_GRANTED:
3868934SJose.Borrego@Sun.COM 	case SMB_NODE_STATE_OPLOCK_BREAKING:
3878934SJose.Borrego@Sun.COM 		if (SMB_SESSION_GET_ID(session) == node->n_oplock.ol_sess_id) {
3888934SJose.Borrego@Sun.COM 			rb = B_FALSE;
3898934SJose.Borrego@Sun.COM 			break;
3908934SJose.Borrego@Sun.COM 		}
3916600Sas200622 
3928934SJose.Borrego@Sun.COM 		if (op != NULL) {
3938934SJose.Borrego@Sun.COM 			if (((op->desired_access & ~(FILE_READ_ATTRIBUTES |
3948934SJose.Borrego@Sun.COM 			    FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) &&
3958934SJose.Borrego@Sun.COM 			    (op->create_disposition != FILE_SUPERSEDE) &&
3968934SJose.Borrego@Sun.COM 			    (op->create_disposition != FILE_OVERWRITE)) {
3978934SJose.Borrego@Sun.COM 				/* Attributs only */
3988934SJose.Borrego@Sun.COM 				rb = B_FALSE;
3998934SJose.Borrego@Sun.COM 				break;
4008934SJose.Borrego@Sun.COM 			}
4018934SJose.Borrego@Sun.COM 		}
4028934SJose.Borrego@Sun.COM 		rb = B_TRUE;
4038934SJose.Borrego@Sun.COM 		break;
4048934SJose.Borrego@Sun.COM 
4058934SJose.Borrego@Sun.COM 	default:
4068934SJose.Borrego@Sun.COM 		SMB_PANIC();
4076600Sas200622 	}
4088934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
4098934SJose.Borrego@Sun.COM 	return (rb);
4108934SJose.Borrego@Sun.COM }
4116600Sas200622 
4128934SJose.Borrego@Sun.COM /*
4139021Samw@Sun.COM  * smb_oplock_broadcast
4148934SJose.Borrego@Sun.COM  *
4158934SJose.Borrego@Sun.COM  * The the calling thread has the pointer to its context stored in ol_thread
4168934SJose.Borrego@Sun.COM  * it resets that field. If any other thread is waiting for that field to
4178934SJose.Borrego@Sun.COM  * turn to NULL it is signaled.
4188934SJose.Borrego@Sun.COM  *
4198934SJose.Borrego@Sun.COM  * Returns:
4208934SJose.Borrego@Sun.COM  *	B_TRUE	Oplock unlocked
4218934SJose.Borrego@Sun.COM  *	B_FALSE	Oplock still locked
4228934SJose.Borrego@Sun.COM  */
4238934SJose.Borrego@Sun.COM boolean_t
4249021Samw@Sun.COM smb_oplock_broadcast(smb_node_t *node)
4258934SJose.Borrego@Sun.COM {
4268934SJose.Borrego@Sun.COM 	smb_oplock_t	*ol;
4278934SJose.Borrego@Sun.COM 	boolean_t	rb;
4286600Sas200622 
4298934SJose.Borrego@Sun.COM 	SMB_NODE_VALID(node);
4308934SJose.Borrego@Sun.COM 	ol = &node->n_oplock;
4318934SJose.Borrego@Sun.COM 	rb = B_FALSE;
4326600Sas200622 
4338934SJose.Borrego@Sun.COM 	mutex_enter(&node->n_mutex);
4348934SJose.Borrego@Sun.COM 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
4358934SJose.Borrego@Sun.COM 		ol->ol_xthread = NULL;
4369021Samw@Sun.COM 		cv_broadcast(&ol->ol_cv);
4378934SJose.Borrego@Sun.COM 		rb = B_TRUE;
4386600Sas200622 	}
4398934SJose.Borrego@Sun.COM 	mutex_exit(&node->n_mutex);
4408934SJose.Borrego@Sun.COM 	return (rb);
4418934SJose.Borrego@Sun.COM }
4426600Sas200622 
4438934SJose.Borrego@Sun.COM /*
4448934SJose.Borrego@Sun.COM  * smb_oplock_wait
4458934SJose.Borrego@Sun.COM  *
4469021Samw@Sun.COM  * The mutex of the node must have been entered before calling this function.
4478934SJose.Borrego@Sun.COM  * If the field ol_xthread is not NULL and doesn't contain the pointer to the
4488934SJose.Borrego@Sun.COM  * context of the calling thread, the caller will sleep until that field is
4498934SJose.Borrego@Sun.COM  * reset (set to NULL).
4508934SJose.Borrego@Sun.COM  */
4518934SJose.Borrego@Sun.COM static void
4529021Samw@Sun.COM smb_oplock_wait(smb_node_t *node)
4538934SJose.Borrego@Sun.COM {
4548934SJose.Borrego@Sun.COM 	smb_oplock_t	*ol = &node->n_oplock;
4558934SJose.Borrego@Sun.COM 
4568934SJose.Borrego@Sun.COM 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
45710483SJose.Borrego@Sun.COM 		ASSERT(!MUTEX_HELD(&ol->ol_ofile->f_mutex));
4588934SJose.Borrego@Sun.COM 		while (ol->ol_xthread != NULL)
4598934SJose.Borrego@Sun.COM 			cv_wait(&ol->ol_cv, &node->n_mutex);
4606600Sas200622 	}
4616600Sas200622 }
462