smb_oplock.c revision 2c2961f8403049d948b9f3e6c35d6488b6b7e1aa
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* SMB Locking library functions.
*/
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
static void smb_oplock_enter(smb_node_t *);
/*
* Magic 0xFF 'S' 'M' 'B'
* smb_com a byte, the "first" command
* Error a 4-byte union, ignored in a request
* smb_flg a one byte set of eight flags
* smb_flg2 a two byte set of 16 flags
* . twelve reserved bytes, have a role
* in connectionless transports (IPX, UDP?)
* smb_tid a 16-bit tree ID, a mount point sorta,
* 0xFFFF is this command does not have
* or require a tree context
* smb_pid a 16-bit process ID
* smb_uid a 16-bit user ID, specific to this "session"
* and mapped to a system (bona-fide) UID
* smb_mid a 16-bit multiplex ID, used to differentiate
* multiple simultaneous requests from the same
* process (pid) (ref RPC "xid")
*
*
* Client Request Description
* ================================== =================================
*
* UCHAR WordCount; Count of parameter words = 8
* UCHAR AndXCommand; Secondary (X) command; 0xFF = none
* UCHAR AndXReserved; Reserved (must be 0)
* USHORT AndXOffset; Offset to next command WordCount
* USHORT Fid; File handle
* UCHAR LockType; See LockType table below
* UCHAR OplockLevel; The new oplock level
* ULONG Timeout; Milliseconds to wait for unlock
* USHORT NumberOfUnlocks; Num. unlock range structs following
* USHORT NumberOfLocks; Num. lock range structs following
* USHORT ByteCount; Count of data bytes
* LOCKING_ANDX_RANGE Unlocks[]; Unlock ranges
* LOCKING_ANDX_RANGE Locks[]; Lock ranges
*
* LockType Flag Name Value Description
* ============================ ===== ================================
*
* LOCKING_ANDX_SHARED_LOCK 0x01 Read-only lock
* LOCKING_ANDX_OPLOCK_RELEASE 0x02 Oplock break notification
* LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 Change lock type
* LOCKING_ANDX_CANCEL_LOCK 0x08 Cancel outstanding request
* LOCKING_ANDX_LARGE_FILES 0x10 Large file locking format
*
* LOCKING_ANDX_RANGE Format
* =====================================================================
*
* USHORT Pid; PID of process "owning" lock
* ULONG Offset; Offset to bytes to [un]lock
* ULONG Length; Number of bytes to [un]lock
*
* Large File LOCKING_ANDX_RANGE Format
* =====================================================================
*
* USHORT Pid; PID of process "owning" lock
* USHORT Pad; Pad to DWORD align (mbz)
* ULONG OffsetHigh; Offset to bytes to [un]lock
* (high)
* ULONG OffsetLow; Offset to bytes to [un]lock (low)
* ULONG LengthHigh; Number of bytes to [un]lock
* (high)
* ULONG LengthLow; Number of bytes to [un]lock (low)
*
* Server Response Description
* ================================== =================================
*
* UCHAR WordCount; Count of parameter words = 2
* UCHAR AndXCommand; Secondary (X) command; 0xFF =
* none
* UCHAR AndXReserved; Reserved (must be 0)
* USHORT AndXOffset; Offset to next command WordCount
* USHORT ByteCount; Count of data bytes = 0
*
*/
/*
* smb_oplock_acquire
*
* Attempt to acquire an oplock. Note that the oplock granted may be
* none, i.e. the oplock was not granted. The result of the acquisition is
* provided in ol->ol_level.
*
* Grant an oplock to the requestor if this session is the only one
* that has the file open, regardless of the number of instances of
* the file opened by this session.
*
* However, if there is no oplock on this file and there is already
* at least one open, we will not grant an oplock, even if the only
* existing opens are from the same client. This is "server discretion."
*
* An oplock may need to be broken in order for one to be granted, and
* depending on what action is taken by the other client (unlock or close),
* an oplock may or may not be granted. (The breaking of an oplock is
* done earlier in the calling path.)
*/
void
{
if (!smb_session_oplocks_enable(session) ||
/* This implies that trees cannot overlap. */
return;
}
for (;;) {
int rc;
return;
}
return;
}
if (ol->ol_waiters_count != 0)
break;
}
break;
}
ol->ol_waiters_count++;
ol->ol_waiters_count--;
if (rc == -1) {
/*
* Oplock release timed out.
*/
if (ol->ol_waiters_count != 0)
}
}
}
}
/*
* smb_oplock_break
*
* The oplock break may succeed for multiple reasons: file close, oplock
* release, holder connection dropped, requesting client disconnect etc.
*
* Returns:
*
* B_TRUE The oplock is broken.
* B_FALSE The oplock is being broken. This is returned if nowait is set
* to B_TRUE;
*/
{
return (B_TRUE);
}
for (;;) {
int rc;
return (B_TRUE);
}
}
if (nowait) {
return (B_FALSE);
}
ol->ol_waiters_count++;
ol->ol_waiters_count--;
if (rc == -1) {
/*
* Oplock release timed out.
*/
if (ol->ol_waiters_count != 0)
break;
}
}
}
return (B_TRUE);
}
/*
* smb_oplock_release
*
* This function releases the oplock on the node passed in. If other threads
* were waiting for the oplock to be released they are signaled.
*/
void
{
case SMB_NODE_STATE_AVAILABLE:
break;
if (ol->ol_waiters_count != 0)
}
break;
default:
SMB_PANIC();
}
}
/*
* smb_oplock_conflict
*
* The two checks on "session" and "op" are primarily for the open path.
* Other CIFS functions may call smb_oplock_conflict() with a session
* pointer so as to do the session check.
*/
{
case SMB_NODE_STATE_AVAILABLE:
break;
break;
}
FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) &&
/* Attributs only */
break;
}
}
break;
default:
SMB_PANIC();
}
return (rb);
}
/*
* smb_oplock_exit
*
* The the calling thread has the pointer to its context stored in ol_thread
* it resets that field. If any other thread is waiting for that field to
* turn to NULL it is signaled.
*
* Returns:
* B_TRUE Oplock unlocked
* B_FALSE Oplock still locked
*/
{
if (ol->ol_waiters_count != 0)
}
return (rb);
}
/*
* smb_oplock_wait
*
* The mutex of the node must have benn entered before calling this function.
* If the field ol_xthread is not NULL and doesn't contain the pointer to the
* context of the calling thread, the caller will sleep until that field is
* reset (set to NULL).
*/
static void
{
ol->ol_waiters_count++;
ol->ol_waiters_count--;
}
}