mirror of
https://github.com/samba-team/samba.git
synced 2025-02-02 09:47:23 +03:00
r17098: Samba3 now cleanly passes Samba4 RAW-LOCK torture
test. Phew - that was painful :-). But what it means is that we now implement lock cancels and I can add lock cancels into POSIX lock handling which will fix the fast/slow system call issue with cifsfs ! Jeremy. (This used to be commit f1a9cf075b87c76c032d19da0168424c90f6cb3c)
This commit is contained in:
parent
4c713703d0
commit
e1da1fcf12
@ -936,6 +936,7 @@ extern int errno;
|
||||
#include "debugparse.h"
|
||||
#include "version.h"
|
||||
#include "privileges.h"
|
||||
#include "locking.h"
|
||||
#include "smb.h"
|
||||
#include "ads_cldap.h"
|
||||
#include "nameserv.h"
|
||||
|
@ -45,8 +45,10 @@ struct lock_key {
|
||||
SMB_INO_T inode;
|
||||
};
|
||||
|
||||
struct files_struct;
|
||||
|
||||
struct byte_range_lock {
|
||||
files_struct *fsp;
|
||||
struct files_struct *fsp;
|
||||
unsigned int num_locks;
|
||||
BOOL modified;
|
||||
struct lock_key key;
|
||||
|
@ -70,6 +70,7 @@
|
||||
#define MSG_SMB_KERNEL_BREAK 3010
|
||||
#define MSG_SMB_FILE_RENAME 3011
|
||||
#define MSG_SMB_INJECT_FAULT 3012
|
||||
#define MSG_SMB_BLOCKING_LOCK_CANCEL 3013
|
||||
|
||||
/* winbind messages */
|
||||
#define MSG_WINBIND_FINISHED 4001
|
||||
|
@ -440,6 +440,7 @@ typedef struct files_struct {
|
||||
int oplock_type;
|
||||
int sent_oplock_break;
|
||||
struct timed_event *oplock_timeout;
|
||||
struct lock_struct last_lock_failure;
|
||||
|
||||
struct share_mode_entry *pending_break_messages;
|
||||
int num_pending_break_messages;
|
||||
@ -861,8 +862,6 @@ struct parm_struct {
|
||||
#define FLAG_HIDE 0x2000 /* options that should be hidden in SWAT */
|
||||
#define FLAG_DOS_STRING 0x4000 /* convert from UNIX to DOS codepage when reading this string. */
|
||||
|
||||
#include "locking.h"
|
||||
|
||||
struct bitmap {
|
||||
uint32 *b;
|
||||
unsigned int n;
|
||||
|
@ -38,3 +38,7 @@ BOOL conn_snum_used(int snum)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
|
||||
{
|
||||
}
|
||||
|
@ -211,30 +211,34 @@ static BOOL brl_conflict_other(const struct lock_struct *lck1, const struct lock
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Amazingly enough, w2k3 "remembers" whether the last lock failure
|
||||
Amazingly enough, w2k3 "remembers" whether the last lock failure on a fnum
|
||||
is the same as this one and changes its error code. I wonder if any
|
||||
app depends on this ?
|
||||
****************************************************************************/
|
||||
|
||||
static NTSTATUS brl_lock_failed(const struct lock_struct *lock)
|
||||
static NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *lock, int32 lock_timeout)
|
||||
{
|
||||
static struct lock_struct last_lock_failure;
|
||||
|
||||
if (brl_same_context(&lock->context, &last_lock_failure.context) &&
|
||||
lock->fnum == last_lock_failure.fnum &&
|
||||
lock->start == last_lock_failure.start &&
|
||||
lock->size == last_lock_failure.size) {
|
||||
return NT_STATUS_FILE_LOCK_CONFLICT;
|
||||
}
|
||||
last_lock_failure = *lock;
|
||||
if (lock->start >= 0xEF000000 &&
|
||||
(lock->start >> 63) == 0) {
|
||||
if (lock->start >= 0xEF000000 && (lock->start >> 63) == 0) {
|
||||
/* amazing the little things you learn with a test
|
||||
suite. Locks beyond this offset (as a 64 bit
|
||||
number!) always generate the conflict error code,
|
||||
unless the top bit is set */
|
||||
if (lock_timeout == 0) {
|
||||
fsp->last_lock_failure = *lock;
|
||||
}
|
||||
return NT_STATUS_FILE_LOCK_CONFLICT;
|
||||
}
|
||||
|
||||
if (procid_equal(&lock->context.pid, &fsp->last_lock_failure.context.pid) &&
|
||||
lock->context.tid == fsp->last_lock_failure.context.tid &&
|
||||
lock->fnum == fsp->last_lock_failure.fnum &&
|
||||
lock->start == fsp->last_lock_failure.start) {
|
||||
return NT_STATUS_FILE_LOCK_CONFLICT;
|
||||
}
|
||||
|
||||
if (lock_timeout == 0) {
|
||||
fsp->last_lock_failure = *lock;
|
||||
}
|
||||
return NT_STATUS_LOCK_NOT_GRANTED;
|
||||
}
|
||||
|
||||
@ -293,8 +297,7 @@ static int lock_compare(const struct lock_struct *lck1,
|
||||
****************************************************************************/
|
||||
|
||||
static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
|
||||
const struct lock_struct *plock,
|
||||
BOOL *my_lock_ctx)
|
||||
const struct lock_struct *plock, int32 lock_timeout)
|
||||
{
|
||||
unsigned int i;
|
||||
files_struct *fsp = br_lck->fsp;
|
||||
@ -303,12 +306,7 @@ static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
|
||||
for (i=0; i < br_lck->num_locks; i++) {
|
||||
/* Do any Windows or POSIX locks conflict ? */
|
||||
if (brl_conflict(&locks[i], plock)) {
|
||||
NTSTATUS status = brl_lock_failed(plock);;
|
||||
/* Did we block ourselves ? */
|
||||
if (brl_same_context(&locks[i].context, &plock->context)) {
|
||||
*my_lock_ctx = True;
|
||||
}
|
||||
return status;
|
||||
return brl_lock_failed(fsp,plock,lock_timeout);
|
||||
}
|
||||
#if ZERO_ZERO
|
||||
if (plock->start == 0 && plock->size == 0 &&
|
||||
@ -571,8 +569,7 @@ OR
|
||||
****************************************************************************/
|
||||
|
||||
static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
|
||||
const struct lock_struct *plock,
|
||||
BOOL *my_lock_ctx)
|
||||
const struct lock_struct *plock)
|
||||
{
|
||||
unsigned int i, count;
|
||||
struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
|
||||
@ -604,10 +601,6 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
|
||||
if (locks[i].lock_flav == WINDOWS_LOCK) {
|
||||
/* Do any Windows flavour locks conflict ? */
|
||||
if (brl_conflict(&locks[i], plock)) {
|
||||
/* Did we block ourselves ? */
|
||||
if (brl_same_context(&locks[i].context, &plock->context)) {
|
||||
*my_lock_ctx = True;
|
||||
}
|
||||
/* No games with error messages. */
|
||||
SAFE_FREE(tp);
|
||||
return NT_STATUS_FILE_LOCK_CONFLICT;
|
||||
@ -683,13 +676,11 @@ NTSTATUS brl_lock(struct byte_range_lock *br_lck,
|
||||
br_off size,
|
||||
enum brl_type lock_type,
|
||||
enum brl_flavour lock_flav,
|
||||
BOOL *my_lock_ctx)
|
||||
int32 lock_timeout)
|
||||
{
|
||||
NTSTATUS ret;
|
||||
struct lock_struct lock;
|
||||
|
||||
*my_lock_ctx = False;
|
||||
|
||||
#if !ZERO_ZERO
|
||||
if (start == 0 && size == 0) {
|
||||
DEBUG(0,("client sent 0/0 lock - please report this\n"));
|
||||
@ -706,9 +697,9 @@ NTSTATUS brl_lock(struct byte_range_lock *br_lck,
|
||||
lock.lock_flav = lock_flav;
|
||||
|
||||
if (lock_flav == WINDOWS_LOCK) {
|
||||
ret = brl_lock_windows(br_lck, &lock, my_lock_ctx);
|
||||
ret = brl_lock_windows(br_lck, &lock, lock_timeout);
|
||||
} else {
|
||||
ret = brl_lock_posix(br_lck, &lock, my_lock_ctx);
|
||||
ret = brl_lock_posix(br_lck, &lock);
|
||||
}
|
||||
|
||||
#if ZERO_ZERO
|
||||
@ -1165,7 +1156,7 @@ NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
|
||||
Remove a particular pending lock.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL brl_remove_pending_lock(struct byte_range_lock *br_lck,
|
||||
BOOL brl_lock_cancel(struct byte_range_lock *br_lck,
|
||||
uint32 smbpid,
|
||||
struct process_id pid,
|
||||
br_off start,
|
||||
|
@ -185,7 +185,7 @@ NTSTATUS do_lock(files_struct *fsp,
|
||||
SMB_BIG_UINT offset,
|
||||
enum brl_type lock_type,
|
||||
enum brl_flavour lock_flav,
|
||||
BOOL *my_lock_ctx)
|
||||
int32 lock_timeout)
|
||||
{
|
||||
struct byte_range_lock *br_lck = NULL;
|
||||
NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED;
|
||||
@ -216,71 +216,12 @@ NTSTATUS do_lock(files_struct *fsp,
|
||||
count,
|
||||
lock_type,
|
||||
lock_flav,
|
||||
my_lock_ctx);
|
||||
lock_timeout);
|
||||
|
||||
TALLOC_FREE(br_lck);
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Utility function called by locking requests. This is *DISGUSTING*. It also
|
||||
appears to be "What Windows Does" (tm). Andrew, ever wonder why Windows 2000
|
||||
is so slow on the locking tests...... ? This is the reason. Much though I hate
|
||||
it, we need this. JRA.
|
||||
****************************************************************************/
|
||||
|
||||
NTSTATUS do_lock_spin(files_struct *fsp,
|
||||
uint32 lock_pid,
|
||||
SMB_BIG_UINT count,
|
||||
SMB_BIG_UINT offset,
|
||||
enum brl_type lock_type,
|
||||
enum brl_flavour lock_flav,
|
||||
BOOL *my_lock_ctx)
|
||||
{
|
||||
int j, maxj = lp_lock_spin_count();
|
||||
int sleeptime = lp_lock_sleep_time();
|
||||
NTSTATUS status, ret;
|
||||
|
||||
if (maxj <= 0) {
|
||||
maxj = 1;
|
||||
}
|
||||
|
||||
ret = NT_STATUS_OK; /* to keep dumb compilers happy */
|
||||
|
||||
for (j = 0; j < maxj; j++) {
|
||||
status = do_lock(fsp,
|
||||
lock_pid,
|
||||
count,
|
||||
offset,
|
||||
lock_type,
|
||||
lock_flav,
|
||||
my_lock_ctx);
|
||||
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED) &&
|
||||
!NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
|
||||
return status;
|
||||
}
|
||||
/* if we do fail then return the first error code we got */
|
||||
if (j == 0) {
|
||||
ret = status;
|
||||
/* Don't spin if we blocked ourselves. */
|
||||
if (*my_lock_ctx) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Only spin for Windows locks. */
|
||||
if (lock_flav == POSIX_LOCK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (sleeptime) {
|
||||
sys_usleep(sleeptime);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Utility function called by unlocking requests.
|
||||
****************************************************************************/
|
||||
@ -327,6 +268,53 @@ NTSTATUS do_unlock(files_struct *fsp,
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Cancel any pending blocked locks.
|
||||
****************************************************************************/
|
||||
|
||||
NTSTATUS do_lock_cancel(files_struct *fsp,
|
||||
uint32 lock_pid,
|
||||
SMB_BIG_UINT count,
|
||||
SMB_BIG_UINT offset,
|
||||
enum brl_flavour lock_flav)
|
||||
{
|
||||
BOOL ok = False;
|
||||
struct byte_range_lock *br_lck = NULL;
|
||||
|
||||
if (!fsp->can_lock) {
|
||||
return fsp->is_directory ?
|
||||
NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (!lp_locking(SNUM(fsp->conn))) {
|
||||
return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
|
||||
}
|
||||
|
||||
DEBUG(10,("do_lock_cancel: cancel start=%.0f len=%.0f requested for fnum %d file %s\n",
|
||||
(double)offset, (double)count, fsp->fnum, fsp->fsp_name ));
|
||||
|
||||
br_lck = brl_get_locks(NULL, fsp);
|
||||
if (!br_lck) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ok = brl_lock_cancel(br_lck,
|
||||
lock_pid,
|
||||
procid_self(),
|
||||
offset,
|
||||
count,
|
||||
lock_flav);
|
||||
|
||||
TALLOC_FREE(br_lck);
|
||||
|
||||
if (!ok) {
|
||||
DEBUG(10,("do_lock_cancel: returning ERRcancelviolation.\n" ));
|
||||
return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Remove any locks on this fd. Called from file_close().
|
||||
****************************************************************************/
|
||||
@ -340,7 +328,9 @@ void locking_close_file(files_struct *fsp)
|
||||
}
|
||||
|
||||
br_lck = brl_get_locks(NULL,fsp);
|
||||
|
||||
if (br_lck) {
|
||||
cancel_pending_lock_requests_by_fid(fsp, br_lck);
|
||||
brl_close_fnum(br_lck);
|
||||
TALLOC_FREE(br_lck);
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_LOCKING
|
||||
|
||||
/****************************************************************************
|
||||
This is the structure to queue to implement blocking locks.
|
||||
@ -41,15 +43,18 @@ typedef struct _blocking_lock_record {
|
||||
int length;
|
||||
} blocking_lock_record;
|
||||
|
||||
/* dlink list we store pending lock records on. */
|
||||
static blocking_lock_record *blocking_lock_queue;
|
||||
|
||||
/* dlink list we move cancelled lock records onto. */
|
||||
static blocking_lock_record *blocking_lock_cancelled_queue;
|
||||
|
||||
/****************************************************************************
|
||||
Destructor for the above structure.
|
||||
****************************************************************************/
|
||||
|
||||
static void free_blocking_lock_record(blocking_lock_record *blr)
|
||||
{
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
SAFE_FREE(blr->inbuf);
|
||||
SAFE_FREE(blr);
|
||||
}
|
||||
@ -81,7 +86,6 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
|
||||
{
|
||||
static BOOL set_lock_msg;
|
||||
blocking_lock_record *blr, *tmp;
|
||||
BOOL my_lock_ctx = False;
|
||||
struct byte_range_lock *br_lck = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
@ -123,6 +127,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
|
||||
|
||||
br_lck = brl_get_locks(NULL, blr->fsp);
|
||||
if (!br_lck) {
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
free_blocking_lock_record(blr);
|
||||
return False;
|
||||
}
|
||||
@ -135,11 +140,12 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
|
||||
count,
|
||||
PENDING_LOCK,
|
||||
blr->lock_flav,
|
||||
&my_lock_ctx);
|
||||
lock_timeout);
|
||||
TALLOC_FREE(br_lck);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
free_blocking_lock_record(blr);
|
||||
return False;
|
||||
}
|
||||
@ -220,9 +226,24 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS stat
|
||||
status = NT_STATUS_FILE_LOCK_CONFLICT;
|
||||
}
|
||||
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
|
||||
/* Store the last lock error. */
|
||||
files_struct *fsp = blr->fsp;
|
||||
|
||||
fsp->last_lock_failure.context.smbpid = blr->lock_pid;
|
||||
fsp->last_lock_failure.context.tid = fsp->conn->cnum;
|
||||
fsp->last_lock_failure.context.pid = procid_self();
|
||||
fsp->last_lock_failure.start = blr->offset;
|
||||
fsp->last_lock_failure.size = blr->count;
|
||||
fsp->last_lock_failure.fnum = fsp->fnum;
|
||||
fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */
|
||||
fsp->last_lock_failure.lock_flav = blr->lock_flav;
|
||||
}
|
||||
|
||||
ERROR_NT(status);
|
||||
if (!send_smb(smbd_server_fd(),outbuf))
|
||||
if (!send_smb(smbd_server_fd(),outbuf)) {
|
||||
exit_server("generic_blocking_lock_error: send_smb failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -335,7 +356,6 @@ static BOOL process_lockread(blocking_lock_record *blr)
|
||||
size_t numtoread;
|
||||
NTSTATUS status;
|
||||
files_struct *fsp = blr->fsp;
|
||||
BOOL my_lock_ctx = False;
|
||||
|
||||
numtoread = SVAL(inbuf,smb_vwv1);
|
||||
startpos = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv2);
|
||||
@ -343,13 +363,13 @@ static BOOL process_lockread(blocking_lock_record *blr)
|
||||
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
|
||||
data = smb_buf(outbuf) + 3;
|
||||
|
||||
status = do_lock_spin(fsp,
|
||||
(uint32)SVAL(inbuf,smb_pid),
|
||||
(SMB_BIG_UINT)numtoread,
|
||||
startpos,
|
||||
READ_LOCK,
|
||||
WINDOWS_LOCK,
|
||||
&my_lock_ctx);
|
||||
status = do_lock(fsp,
|
||||
(uint32)SVAL(inbuf,smb_pid),
|
||||
(SMB_BIG_UINT)numtoread,
|
||||
startpos,
|
||||
READ_LOCK,
|
||||
WINDOWS_LOCK,
|
||||
(int32)-1);
|
||||
|
||||
if (NT_STATUS_V(status)) {
|
||||
if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
|
||||
@ -410,19 +430,18 @@ static BOOL process_lock(blocking_lock_record *blr)
|
||||
SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
|
||||
NTSTATUS status;
|
||||
files_struct *fsp = blr->fsp;
|
||||
BOOL my_lock_ctx = False;
|
||||
|
||||
count = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
|
||||
offset = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
|
||||
|
||||
errno = 0;
|
||||
status = do_lock_spin(fsp,
|
||||
(uint32)SVAL(inbuf,smb_pid),
|
||||
count,
|
||||
offset,
|
||||
WRITE_LOCK,
|
||||
WINDOWS_LOCK,
|
||||
&my_lock_ctx);
|
||||
status = do_lock(fsp,
|
||||
(uint32)SVAL(inbuf,smb_pid),
|
||||
count,
|
||||
offset,
|
||||
WRITE_LOCK,
|
||||
WINDOWS_LOCK,
|
||||
(int32)-1);
|
||||
|
||||
if (NT_STATUS_IS_ERR(status)) {
|
||||
if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
|
||||
@ -474,7 +493,6 @@ static BOOL process_lockingX(blocking_lock_record *blr)
|
||||
uint32 lock_pid;
|
||||
BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
|
||||
char *data;
|
||||
BOOL my_lock_ctx = False;
|
||||
NTSTATUS status = NT_STATUS_OK;
|
||||
|
||||
data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
|
||||
@ -496,13 +514,14 @@ static BOOL process_lockingX(blocking_lock_record *blr)
|
||||
* request would never have been queued. JRA.
|
||||
*/
|
||||
errno = 0;
|
||||
status = do_lock_spin(fsp,
|
||||
status = do_lock(fsp,
|
||||
lock_pid,
|
||||
count,
|
||||
offset,
|
||||
((locktype & 1) ? READ_LOCK : WRITE_LOCK),
|
||||
((locktype & LOCKING_ANDX_SHARED_LOCK) ?
|
||||
READ_LOCK : WRITE_LOCK),
|
||||
WINDOWS_LOCK,
|
||||
&my_lock_ctx);
|
||||
(int32)-1);
|
||||
|
||||
if (NT_STATUS_IS_ERR(status)) {
|
||||
break;
|
||||
@ -552,7 +571,6 @@ static BOOL process_trans2(blocking_lock_record *blr)
|
||||
extern int max_send;
|
||||
char *inbuf = blr->inbuf;
|
||||
char *outbuf;
|
||||
BOOL my_lock_ctx = False;
|
||||
char params[2];
|
||||
NTSTATUS status;
|
||||
|
||||
@ -562,7 +580,7 @@ static BOOL process_trans2(blocking_lock_record *blr)
|
||||
blr->offset,
|
||||
blr->lock_type,
|
||||
blr->lock_flav,
|
||||
&my_lock_ctx);
|
||||
(int32)-1);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (ERROR_WAS_LOCK_DENIED(status)) {
|
||||
@ -615,33 +633,41 @@ static BOOL blocking_lock_record_process(blocking_lock_record *blr)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Delete entries by fnum from the blocking lock pending queue.
|
||||
Cancel entries by fnum from the blocking lock pending queue.
|
||||
*****************************************************************************/
|
||||
|
||||
void remove_pending_lock_requests_by_fid(files_struct *fsp)
|
||||
void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
|
||||
{
|
||||
blocking_lock_record *blr, *next = NULL;
|
||||
|
||||
for(blr = blocking_lock_queue; blr; blr = next) {
|
||||
next = blr->next;
|
||||
if(blr->fsp->fnum == fsp->fnum) {
|
||||
struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
|
||||
unsigned char locktype = 0;
|
||||
|
||||
if (blr->com_type == SMBlockingX) {
|
||||
locktype = CVAL(blr->inbuf,smb_vwv3);
|
||||
}
|
||||
|
||||
if (br_lck) {
|
||||
DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
|
||||
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
|
||||
|
||||
brl_remove_pending_lock(br_lck,
|
||||
brl_lock_cancel(br_lck,
|
||||
blr->lock_pid,
|
||||
procid_self(),
|
||||
blr->offset,
|
||||
blr->count,
|
||||
blr->lock_flav);
|
||||
TALLOC_FREE(br_lck);
|
||||
|
||||
blocking_lock_cancel(fsp,
|
||||
blr->lock_pid,
|
||||
blr->offset,
|
||||
blr->count,
|
||||
blr->lock_flav,
|
||||
locktype,
|
||||
NT_STATUS_RANGE_NOT_LOCKED);
|
||||
}
|
||||
|
||||
free_blocking_lock_record(blr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -664,7 +690,7 @@ void remove_pending_lock_requests_by_mid(int mid)
|
||||
DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
|
||||
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
|
||||
|
||||
brl_remove_pending_lock(br_lck,
|
||||
brl_lock_cancel(br_lck,
|
||||
blr->lock_pid,
|
||||
procid_self(),
|
||||
blr->offset,
|
||||
@ -674,6 +700,7 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
|
||||
}
|
||||
|
||||
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
free_blocking_lock_record(blr);
|
||||
}
|
||||
}
|
||||
@ -765,7 +792,7 @@ void process_blocking_lock_queue(time_t t)
|
||||
DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
|
||||
fsp->fnum, fsp->fsp_name ));
|
||||
|
||||
brl_remove_pending_lock(br_lck,
|
||||
brl_lock_cancel(br_lck,
|
||||
blr->lock_pid,
|
||||
procid_self(),
|
||||
blr->offset,
|
||||
@ -775,6 +802,7 @@ void process_blocking_lock_queue(time_t t)
|
||||
}
|
||||
|
||||
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
free_blocking_lock_record(blr);
|
||||
continue;
|
||||
}
|
||||
@ -787,7 +815,7 @@ void process_blocking_lock_queue(time_t t)
|
||||
*/
|
||||
|
||||
if (br_lck) {
|
||||
brl_remove_pending_lock(br_lck,
|
||||
brl_lock_cancel(br_lck,
|
||||
blr->lock_pid,
|
||||
procid_self(),
|
||||
blr->offset,
|
||||
@ -799,6 +827,7 @@ void process_blocking_lock_queue(time_t t)
|
||||
DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
|
||||
vuid ));
|
||||
blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
free_blocking_lock_record(blr);
|
||||
continue;
|
||||
}
|
||||
@ -811,7 +840,7 @@ void process_blocking_lock_queue(time_t t)
|
||||
*/
|
||||
|
||||
if (br_lck) {
|
||||
brl_remove_pending_lock(br_lck,
|
||||
brl_lock_cancel(br_lck,
|
||||
blr->lock_pid,
|
||||
procid_self(),
|
||||
blr->offset,
|
||||
@ -822,6 +851,7 @@ void process_blocking_lock_queue(time_t t)
|
||||
|
||||
DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
|
||||
blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
free_blocking_lock_record(blr);
|
||||
change_to_root_user();
|
||||
continue;
|
||||
@ -837,7 +867,7 @@ void process_blocking_lock_queue(time_t t)
|
||||
struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
|
||||
|
||||
if (br_lck) {
|
||||
brl_remove_pending_lock(br_lck,
|
||||
brl_lock_cancel(br_lck,
|
||||
blr->lock_pid,
|
||||
procid_self(),
|
||||
blr->offset,
|
||||
@ -846,8 +876,106 @@ void process_blocking_lock_queue(time_t t)
|
||||
TALLOC_FREE(br_lck);
|
||||
}
|
||||
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
free_blocking_lock_record(blr);
|
||||
}
|
||||
change_to_root_user();
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Handle a cancel message. Lock already moved onto the cancel queue.
|
||||
*****************************************************************************/
|
||||
|
||||
#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS))
|
||||
|
||||
static void process_blocking_lock_cancel_message(int msg_type, struct process_id src,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
NTSTATUS err;
|
||||
const char *msg = (const char *)buf;
|
||||
blocking_lock_record *blr;
|
||||
|
||||
if (buf == NULL) {
|
||||
smb_panic("process_blocking_lock_cancel_message: null msg\n");
|
||||
}
|
||||
|
||||
if (len != MSG_BLOCKING_LOCK_CANCEL_SIZE) {
|
||||
DEBUG(0, ("process_blocking_lock_cancel_message: "
|
||||
"Got invalid msg len %d\n", (int)len));
|
||||
smb_panic("process_blocking_lock_cancel_message: bad msg\n");
|
||||
}
|
||||
|
||||
memcpy(&blr, msg, sizeof(blr));
|
||||
memcpy(&err, &msg[sizeof(blr)], sizeof(NTSTATUS));
|
||||
|
||||
DEBUG(10,("process_blocking_lock_cancel_message: returning error %s\n",
|
||||
nt_errstr(err) ));
|
||||
|
||||
blocking_lock_reply_error(blr, err);
|
||||
DLIST_REMOVE(blocking_lock_cancelled_queue, blr);
|
||||
free_blocking_lock_record(blr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Send ourselves a blocking lock cancelled message. Handled asynchronously above.
|
||||
*****************************************************************************/
|
||||
|
||||
BOOL blocking_lock_cancel(files_struct *fsp,
|
||||
uint32 lock_pid,
|
||||
SMB_BIG_UINT offset,
|
||||
SMB_BIG_UINT count,
|
||||
enum brl_flavour lock_flav,
|
||||
unsigned char locktype,
|
||||
NTSTATUS err)
|
||||
{
|
||||
static BOOL initialized;
|
||||
char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE];
|
||||
blocking_lock_record *blr;
|
||||
|
||||
if (!initialized) {
|
||||
/* Register our message. */
|
||||
message_register(MSG_SMB_BLOCKING_LOCK_CANCEL,
|
||||
process_blocking_lock_cancel_message);
|
||||
|
||||
initialized = True;
|
||||
}
|
||||
|
||||
for (blr = blocking_lock_queue; blr; blr = blr->next) {
|
||||
if (fsp == blr->fsp &&
|
||||
lock_pid == blr->lock_pid &&
|
||||
offset == blr->offset &&
|
||||
count == blr->count &&
|
||||
lock_flav == blr->lock_flav) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!blr) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Check the flags are right. */
|
||||
if (blr->com_type == SMBlockingX &&
|
||||
(locktype & LOCKING_ANDX_LARGE_FILES) !=
|
||||
(CVAL(blr->inbuf,smb_vwv3) & LOCKING_ANDX_LARGE_FILES)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Move to cancelled queue. */
|
||||
DLIST_REMOVE(blocking_lock_queue, blr);
|
||||
DLIST_ADD(blocking_lock_cancelled_queue, blr);
|
||||
|
||||
/* Create the message. */
|
||||
memcpy(msg, &blr, sizeof(blr));
|
||||
memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS));
|
||||
|
||||
/* Don't need to be root here as we're only ever
|
||||
sending to ourselves. */
|
||||
|
||||
message_send_pid(pid_to_procid(sys_getpid()),
|
||||
MSG_SMB_BLOCKING_LOCK_CANCEL,
|
||||
&msg, sizeof(msg), True);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
@ -268,8 +268,6 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
|
||||
int err = 0;
|
||||
int err1 = 0;
|
||||
|
||||
remove_pending_lock_requests_by_fid(fsp);
|
||||
|
||||
if (fsp->aio_write_behind) {
|
||||
/*
|
||||
* If we're finishing write behind on a close we can get a write
|
||||
|
@ -2371,7 +2371,6 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
|
||||
size_t numtoread;
|
||||
NTSTATUS status;
|
||||
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
|
||||
BOOL my_lock_ctx = False;
|
||||
START_PROFILE(SMBlockread);
|
||||
|
||||
CHECK_FSP(fsp,conn);
|
||||
@ -2396,13 +2395,13 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
|
||||
* Note that the requested lock size is unaffected by max_recv.
|
||||
*/
|
||||
|
||||
status = do_lock_spin(fsp,
|
||||
(uint32)SVAL(inbuf,smb_pid),
|
||||
(SMB_BIG_UINT)numtoread,
|
||||
(SMB_BIG_UINT)startpos,
|
||||
WRITE_LOCK,
|
||||
WINDOWS_LOCK,
|
||||
&my_lock_ctx);
|
||||
status = do_lock(fsp,
|
||||
(uint32)SVAL(inbuf,smb_pid),
|
||||
(SMB_BIG_UINT)numtoread,
|
||||
(SMB_BIG_UINT)startpos,
|
||||
WRITE_LOCK,
|
||||
WINDOWS_LOCK,
|
||||
0 /* zero timeout. */);
|
||||
|
||||
if (NT_STATUS_V(status)) {
|
||||
#if 0
|
||||
@ -2412,7 +2411,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
|
||||
* tester. JRA.
|
||||
*/
|
||||
|
||||
if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
|
||||
if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
|
||||
/*
|
||||
* A blocking lock was requested. Package up
|
||||
* this smb into a queued request and push it
|
||||
@ -3418,7 +3417,6 @@ int reply_lock(connection_struct *conn,
|
||||
SMB_BIG_UINT count,offset;
|
||||
NTSTATUS status;
|
||||
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
|
||||
BOOL my_lock_ctx = False;
|
||||
|
||||
START_PROFILE(SMBlock);
|
||||
|
||||
@ -3432,17 +3430,18 @@ int reply_lock(connection_struct *conn,
|
||||
DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
|
||||
fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
|
||||
|
||||
status = do_lock_spin(fsp,
|
||||
(uint32)SVAL(inbuf,smb_pid),
|
||||
count,
|
||||
offset,
|
||||
WRITE_LOCK,
|
||||
WINDOWS_LOCK,
|
||||
&my_lock_ctx);
|
||||
status = do_lock(fsp,
|
||||
(uint32)SVAL(inbuf,smb_pid),
|
||||
count,
|
||||
offset,
|
||||
WRITE_LOCK,
|
||||
WINDOWS_LOCK,
|
||||
0 /* zero timeout. */);
|
||||
|
||||
if (NT_STATUS_V(status)) {
|
||||
#if 0
|
||||
/* Tests using Samba4 against W2K show this call never creates a blocking lock. */
|
||||
if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
|
||||
if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
|
||||
/*
|
||||
* A blocking lock was requested. Package up
|
||||
* this smb into a queued request and push it
|
||||
@ -5228,7 +5227,6 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
|
||||
BOOL large_file_format =
|
||||
(locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
|
||||
BOOL err;
|
||||
BOOL my_lock_ctx = False;
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
|
||||
START_PROFILE(SMBlockingX);
|
||||
@ -5244,11 +5242,6 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
|
||||
return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
|
||||
}
|
||||
|
||||
if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
|
||||
/* Need to make this like a cancel.... JRA. */
|
||||
return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
/* Check if this is an oplock break on a file
|
||||
we have granted an oplock on.
|
||||
*/
|
||||
@ -5360,7 +5353,11 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
|
||||
|
||||
/* Setup the timeout in seconds. */
|
||||
|
||||
lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
|
||||
if (lp_blocking_locks(SNUM(conn))) {
|
||||
lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
|
||||
} else {
|
||||
lock_timeout = 0;
|
||||
}
|
||||
|
||||
/* Now do any requested locks */
|
||||
data += ((large_file_format ? 20 : 10)*num_ulocks);
|
||||
@ -5369,7 +5366,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
|
||||
of smb_lkrng structs */
|
||||
|
||||
for(i = 0; i < (int)num_locks; i++) {
|
||||
enum brl_type lock_type = ((locktype & 1) ? READ_LOCK:WRITE_LOCK);
|
||||
enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
|
||||
READ_LOCK:WRITE_LOCK);
|
||||
lock_pid = get_lock_pid( data, i, large_file_format);
|
||||
count = get_lock_count( data, i, large_file_format);
|
||||
offset = get_lock_offset( data, i, large_file_format, &err);
|
||||
@ -5387,31 +5385,54 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
|
||||
(double)count, (unsigned int)lock_pid,
|
||||
fsp->fsp_name, (int)lock_timeout ));
|
||||
|
||||
status = do_lock_spin(fsp,
|
||||
if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
|
||||
if (lp_blocking_locks(SNUM(conn))) {
|
||||
|
||||
/* Schedule a message to ourselves to
|
||||
remove the blocking lock record and
|
||||
return the right error. */
|
||||
|
||||
if (!blocking_lock_cancel(fsp,
|
||||
lock_pid,
|
||||
offset,
|
||||
count,
|
||||
WINDOWS_LOCK,
|
||||
locktype,
|
||||
NT_STATUS_FILE_LOCK_CONFLICT)) {
|
||||
END_PROFILE(SMBlockingX);
|
||||
return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
|
||||
}
|
||||
}
|
||||
/* Remove a matching pending lock. */
|
||||
status = do_lock_cancel(fsp,
|
||||
lock_pid,
|
||||
count,
|
||||
offset,
|
||||
WINDOWS_LOCK);
|
||||
} else {
|
||||
status = do_lock(fsp,
|
||||
lock_pid,
|
||||
count,
|
||||
offset,
|
||||
lock_type,
|
||||
WINDOWS_LOCK,
|
||||
&my_lock_ctx);
|
||||
lock_timeout);
|
||||
|
||||
if (NT_STATUS_V(status)) {
|
||||
/*
|
||||
* Interesting fact found by IFSTEST /t
|
||||
* LockOverlappedTest... Even if it's our own lock
|
||||
* context, we need to wait here as there may be an
|
||||
* unlock on the way. So I removed a "&&
|
||||
* !my_lock_ctx" from the following if statement. JRA.
|
||||
*/
|
||||
if ((lock_timeout != 0) &&
|
||||
lp_blocking_locks(SNUM(conn)) &&
|
||||
ERROR_WAS_LOCK_DENIED(status)) {
|
||||
if (NT_STATUS_V(status)) {
|
||||
/*
|
||||
* A blocking lock was requested. Package up
|
||||
* this smb into a queued request and push it
|
||||
* onto the blocking lock queue.
|
||||
* Interesting fact found by IFSTEST /t
|
||||
* LockOverlappedTest... Even if it's our own lock
|
||||
* context, we need to wait here as there may be an
|
||||
* unlock on the way. JRA.
|
||||
*/
|
||||
if(push_blocking_lock_request(inbuf, length,
|
||||
if ((lock_timeout != 0) &&
|
||||
ERROR_WAS_LOCK_DENIED(status)) {
|
||||
/*
|
||||
* A blocking lock was requested. Package up
|
||||
* this smb into a queued request and push it
|
||||
* onto the blocking lock queue.
|
||||
*/
|
||||
if(push_blocking_lock_request(inbuf, length,
|
||||
fsp,
|
||||
lock_timeout,
|
||||
i,
|
||||
@ -5420,17 +5441,25 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
|
||||
WINDOWS_LOCK,
|
||||
offset,
|
||||
count)) {
|
||||
END_PROFILE(SMBlockingX);
|
||||
return -1;
|
||||
END_PROFILE(SMBlockingX);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (NT_STATUS_V(status)) {
|
||||
END_PROFILE(SMBlockingX);
|
||||
return ERROR_NT(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* If any of the above locks failed, then we must unlock
|
||||
all of the previous locks (X/Open spec). */
|
||||
if (i != num_locks && num_locks != 0) {
|
||||
|
||||
if (!(locktype & LOCKING_ANDX_CANCEL_LOCK) &&
|
||||
(i != num_locks) &&
|
||||
(num_locks != 0)) {
|
||||
/*
|
||||
* Ensure we don't do a remove on the lock that just failed,
|
||||
* as under POSIX rules, if we have a lock already there, we
|
||||
|
@ -4505,7 +4505,6 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
|
||||
uint32 lock_pid;
|
||||
BOOL lock_blocking;
|
||||
enum brl_type lock_type;
|
||||
BOOL my_lock_ctx;
|
||||
|
||||
if (fsp == NULL || fsp->fh->fd == -1) {
|
||||
return ERROR_NT(NT_STATUS_INVALID_HANDLE);
|
||||
@ -4564,8 +4563,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
|
||||
count,
|
||||
offset,
|
||||
lock_type,
|
||||
POSIX_LOCK,
|
||||
&my_lock_ctx);
|
||||
POSIX_LOCK);
|
||||
|
||||
if (lock_blocking && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user