smb_common_lock.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* SMB Locking library functions.
*/
#include <smbsrv/smb_incl.h>
/*
* Oplock timeout configuration.
*/
#define OPLOCK_RETRIES 2
/*
*/
/*
* 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_acquire_oplock
*
* Attempt to acquire an oplock. Note that the oplock granted may be
* none, i.e. the oplock was not granted.
*
* We may have to break an oplock in order to acquire one, and depending
* on what action is taken by the other client (unlock or close), we may
* or may not end up with an oplock. The type of oplock being requested
* is passed in level_requested, the result is returned in level_granted
* and is only valid if the status is NT_STATUS_SUCCESS.
*
* The Returns NT status codes:
* NT_STATUS_SUCCESS
* NT_STATUS_CONNECTION_DISCONNECTED
*/
struct smb_request *sr,
unsigned int level_requested,
unsigned int *level_granted)
{
unsigned int level;
int oplock_owner;
return (NT_STATUS_SUCCESS);
return (NT_STATUS_SUCCESS);
oplock_owner = 0;
/*
* I'm not convinced the client redirector will send multiple
* opens requesting a batch oplock for the same file. I think
* the client redirector will handle the multiple instances
* and only send a single open to the server. The the original
* implementation supported it, however, so I'll leave it here
* for now.
*
* Grant an oplock to the requester 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. We grant
* any oplock requested to the owner.
*/
if (MYF_IS_EXCLUSIVE_OPLOCK(level)) {
} else if (MYF_IS_BATCH_OPLOCK(level)) {
} else {
level &= ~MYF_OPLOCK_MASK;
}
*level_granted = level;
return (NT_STATUS_SUCCESS);
}
/*
* Other clients have this file open but they do not have any
* oplocks in force, so we must reject this oplock request.
*/
return (NT_STATUS_SUCCESS);
}
/*
* Someone has an oplock, we need to break it.
*/
goto restart;
return (status);
}
/*
* smb_break_oplock
*
* The oplock break may succeed for multiple reasons: file close, oplock
* release, holder connection dropped, requesting client disconnect etc.
* Whatever the reason, the oplock should be broken when this function
* returns. The exceptions are when the client making this request gets
* disconnected or when another client is handling the break and it gets
* disconnected.
*
* Returns NT status codes:
* NT_STATUS_SUCCESS No oplock in force, i.e. the
* oplock has been broken.
* NT_STATUS_CONNECTION_DISCONNECTED Requesting client disconnected.
* NT_STATUS_INTERNAL_ERROR
*/
{
struct smb_session *sent_session;
struct smb_ofile *sent_ofile;
struct mbuf_chain mbc;
int retries = 0;
int tid;
unsigned short fid;
elapsed_time = 0;
/*
* Another client is already attempting to break the oplock.
* We wait for it to finish. If the caller was trying to
* acquire an oplock, he should retry in case the client's
* connection was dropped while trying to break the oplock.
*
* If the holder's connection has been dropped, we yield to
* allow the thread handling the break to detect it and set
* the flags.
*/
(elapsed_time < max_time)) {
if (timeleft == -1) {
} else {
}
}
/*
* If there are no oplocks in force we're done.
* Otherwise fall through and break the oplock.
*/
if (OPLOCKS_IN_FORCE(node) == 0) {
return (NT_STATUS_SUCCESS);
} else {
/*
* Should we clear the
* LOCK_BREAKING_OPLOCK flag?
*/
return (NT_STATUS_INTERNAL_ERROR);
}
}
/*
* No oplock break is in progress so we start one.
*/
/*
* If a client has an OPLOCK on a file it would not break it because
* another of its processes wants to open the same file. However, if
* a client were to behave like that it would create a deadlock in the
* code that follows. For now we leave the ASSERT(). Eventually the
* code will have to be more defensive.
*/
/*
* IR #104382
* What we could find from this panic was that the tree field
* of sent_ofile structure points to an invalid memory page,
* but we couldn't find why exactly this happened. So, this is
* a work around till we can find the real problem.
*/
do {
SMB_COM_LOCKING_ANDX, /* Command */
tid, /* TID */
0xffff, /* PID */
0, /* UID */
0xffff, /* MID oplock break */
8, /* parameter words=8 */
0xff, /* 0xFF=none */
fid, /* File handle */
while (flag) {
switch (sent_session->s_state) {
return (NT_STATUS_SUCCESS);
break;
break;
default:
-1);
break;
}
}
elapsed_time = 0;
(elapsed_time < max_time)) {
if (timeleft == -1) {
} else {
}
}
if (OPLOCKS_IN_FORCE(node) == 0) {
return (NT_STATUS_SUCCESS);
}
} while (++retries < OPLOCK_RETRIES);
/*
* Retries exhausted and timed out.
* Cancel the oplock and continue.
*/
return (NT_STATUS_SUCCESS);
}
/*
* smb_release_oplock
*
* The original code supported batch oplock inheritance but I'm not
* convinced the client redirector will open multiple instances of a
* file with batch oplocks on the server (see smb_acquire_oplock).
*/
void /*ARGSUSED*/
{
return;
}
}
}