mirror of
https://github.com/samba-team/samba.git
synced 2025-01-15 23:24:37 +03:00
Fix to allow blocking lock notification to be done rapidly (no wait
for smb -> smb lock release). Adds new PENDING_LOCK type to lockdb (does not interfere with existing locks). Jeremy. (This used to be commit 22fc0d48ff2052b4274c65f85050c58b235bf4e4)
This commit is contained in:
parent
20d0bb2310
commit
f6f76ad5ed
@ -62,6 +62,7 @@
|
||||
#define MSG_SMB_FORCE_TDIS 3002
|
||||
#define MSG_SMB_SAM_SYNC 3003
|
||||
#define MSG_SMB_SAM_REPL 3004
|
||||
#define MSG_SMB_UNLOCK 3005
|
||||
|
||||
/* Flags to classify messages - used in message_send_all() */
|
||||
/* Sender will filter by flag. */
|
||||
|
@ -772,7 +772,7 @@ typedef enum
|
||||
} parm_class;
|
||||
|
||||
/* passed to br lock code */
|
||||
enum brl_type {READ_LOCK, WRITE_LOCK};
|
||||
enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_LOCK};
|
||||
|
||||
struct enum_list {
|
||||
int value;
|
||||
|
@ -98,6 +98,9 @@ static BOOL brl_same_context(struct lock_context *ctx1,
|
||||
static BOOL brl_conflict(struct lock_struct *lck1,
|
||||
struct lock_struct *lck2)
|
||||
{
|
||||
if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
|
||||
return False;
|
||||
|
||||
if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
|
||||
return False;
|
||||
}
|
||||
@ -119,6 +122,9 @@ static BOOL brl_conflict(struct lock_struct *lck1,
|
||||
static BOOL brl_conflict1(struct lock_struct *lck1,
|
||||
struct lock_struct *lck2)
|
||||
{
|
||||
if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
|
||||
return False;
|
||||
|
||||
if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
|
||||
return False;
|
||||
}
|
||||
@ -148,6 +154,9 @@ static BOOL brl_conflict1(struct lock_struct *lck1,
|
||||
|
||||
static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
|
||||
{
|
||||
if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
|
||||
return False;
|
||||
|
||||
if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
|
||||
return False;
|
||||
|
||||
@ -385,16 +394,30 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Check if an unlock overlaps a pending lock.
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL brl_pending_overlap(struct lock_struct *lock, struct lock_struct *pend_lock)
|
||||
{
|
||||
if ((lock->start <= pend_lock->start) && (lock->start + lock->size > pend_lock->start))
|
||||
return True;
|
||||
if ((lock->start >= pend_lock->start) && (lock->start <= pend_lock->start + pend_lock->size))
|
||||
return True;
|
||||
return False;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Unlock a range of bytes.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
|
||||
uint16 smbpid, pid_t pid, uint16 tid,
|
||||
br_off start, br_off size)
|
||||
br_off start, br_off size,
|
||||
BOOL remove_pending_locks_only)
|
||||
{
|
||||
TDB_DATA kbuf, dbuf;
|
||||
int count, i;
|
||||
int count, i, j;
|
||||
struct lock_struct *locks;
|
||||
struct lock_context context;
|
||||
|
||||
@ -452,9 +475,34 @@ BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
|
||||
struct lock_struct *lock = &locks[i];
|
||||
|
||||
if (brl_same_context(&lock->context, &context) &&
|
||||
lock->fnum == fnum &&
|
||||
lock->start == start &&
|
||||
lock->size == size) {
|
||||
lock->fnum == fnum &&
|
||||
lock->start == start &&
|
||||
lock->size == size) {
|
||||
|
||||
if (remove_pending_locks_only && lock->lock_type != PENDING_LOCK)
|
||||
continue;
|
||||
|
||||
if (lock->lock_type != PENDING_LOCK) {
|
||||
/* Send unlock messages to any pending waiters that overlap. */
|
||||
for (j=0; j<count; j++) {
|
||||
struct lock_struct *pend_lock = &locks[j];
|
||||
|
||||
/* Ignore non-pending locks. */
|
||||
if (pend_lock->lock_type != PENDING_LOCK)
|
||||
continue;
|
||||
|
||||
/* We could send specific lock info here... */
|
||||
if (brl_pending_overlap(lock, pend_lock)) {
|
||||
DEBUG(10,("brl_unlock: sending unlock message to pid %u\n",
|
||||
(unsigned int)pend_lock->context.pid ));
|
||||
|
||||
message_send_pid(pend_lock->context.pid,
|
||||
MSG_SMB_UNLOCK,
|
||||
NULL, 0, True);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* found it - delete it */
|
||||
if (count == 1) {
|
||||
tdb_delete(tdb, kbuf);
|
||||
@ -546,7 +594,7 @@ BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
|
||||
void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
|
||||
{
|
||||
TDB_DATA kbuf, dbuf;
|
||||
int count, i, dcount=0;
|
||||
int count, i, j, dcount=0;
|
||||
struct lock_struct *locks;
|
||||
|
||||
kbuf = locking_key(dev,ino);
|
||||
@ -561,12 +609,34 @@ void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
|
||||
/* there are existing locks - remove any for this fnum */
|
||||
locks = (struct lock_struct *)dbuf.dptr;
|
||||
count = dbuf.dsize / sizeof(*locks);
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
struct lock_struct *lock = &locks[i];
|
||||
|
||||
if (lock->context.tid == tid &&
|
||||
lock->context.pid == pid &&
|
||||
lock->fnum == fnum) {
|
||||
|
||||
/* Send unlock messages to any pending waiters that overlap. */
|
||||
for (j=0; j<count; j++) {
|
||||
struct lock_struct *pend_lock = &locks[j];
|
||||
|
||||
/* Ignore our own or non-pending locks. */
|
||||
if (pend_lock->lock_type != PENDING_LOCK)
|
||||
continue;
|
||||
|
||||
if (pend_lock->context.tid == tid &&
|
||||
pend_lock->context.pid == pid &&
|
||||
pend_lock->fnum == fnum)
|
||||
continue;
|
||||
|
||||
/* We could send specific lock info here... */
|
||||
if (brl_pending_overlap(lock, pend_lock))
|
||||
message_send_pid(pend_lock->context.pid,
|
||||
MSG_SMB_UNLOCK,
|
||||
NULL, 0, True);
|
||||
}
|
||||
|
||||
/* found it - delete it */
|
||||
if (count > 1 && i < count-1) {
|
||||
memmove(&locks[i], &locks[i+1],
|
||||
|
@ -132,7 +132,7 @@ static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_p
|
||||
*/
|
||||
(void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
|
||||
lock_pid, sys_getpid(), conn->cnum,
|
||||
offset, count);
|
||||
offset, count, False);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,7 +201,7 @@ NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
|
||||
*/
|
||||
|
||||
ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
|
||||
lock_pid, sys_getpid(), conn->cnum, offset, count);
|
||||
lock_pid, sys_getpid(), conn->cnum, offset, count, False);
|
||||
|
||||
if (!ok) {
|
||||
DEBUG(10,("do_unlock: returning ERRlock.\n" ));
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Blocking Locking functions
|
||||
Copyright (C) Jeremy Allison 1998
|
||||
Copyright (C) Jeremy Allison 1998-2003
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -33,6 +33,9 @@ typedef struct {
|
||||
files_struct *fsp;
|
||||
time_t expire_time;
|
||||
int lock_num;
|
||||
SMB_BIG_UINT offset;
|
||||
SMB_BIG_UINT count;
|
||||
uint16 lock_pid;
|
||||
char *inbuf;
|
||||
int length;
|
||||
} blocking_lock_record;
|
||||
@ -77,13 +80,18 @@ static BOOL in_chained_smb(void)
|
||||
return (chain_size != 0);
|
||||
}
|
||||
|
||||
static void received_unlock_msg(int msg_type, pid_t src, void *buf, size_t len);
|
||||
|
||||
/****************************************************************************
|
||||
Function to push a blocking lock request onto the lock queue.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int lock_num)
|
||||
BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
|
||||
int lock_num, uint16 lock_pid, SMB_BIG_UINT offset, SMB_BIG_UINT count)
|
||||
{
|
||||
static BOOL set_lock_msg;
|
||||
blocking_lock_record *blr;
|
||||
NTSTATUS status;
|
||||
|
||||
if(in_chained_smb() ) {
|
||||
DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
|
||||
@ -110,11 +118,31 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int
|
||||
blr->fsp = get_fsp_from_pkt(inbuf);
|
||||
blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout;
|
||||
blr->lock_num = lock_num;
|
||||
blr->lock_pid = lock_pid;
|
||||
blr->offset = offset;
|
||||
blr->count = count;
|
||||
memcpy(blr->inbuf, inbuf, length);
|
||||
blr->length = length;
|
||||
|
||||
/* Add a pending lock record for this. */
|
||||
status = brl_lock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
|
||||
lock_pid, sys_getpid(), blr->fsp->conn->cnum,
|
||||
offset, count,
|
||||
PENDING_LOCK);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
|
||||
free_blocking_lock_record(blr);
|
||||
return False;
|
||||
}
|
||||
|
||||
ubi_slAddTail(&blocking_lock_queue, blr);
|
||||
|
||||
/* Ensure we'll receive messages when this is unlocked. */
|
||||
if (!set_lock_msg) {
|
||||
message_register(MSG_SMB_UNLOCK, received_unlock_msg);
|
||||
set_lock_msg = True;
|
||||
}
|
||||
|
||||
DEBUG(3,("push_blocking_lock_request: lock request length=%d blocked with expiry time %d (+%d) \
|
||||
for fnum = %d, name = %s\n", length, (int)blr->expire_time, lock_timeout,
|
||||
@ -493,6 +521,10 @@ void remove_pending_lock_requests_by_fid(files_struct *fsp)
|
||||
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_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
|
||||
blr->lock_pid, sys_getpid(), blr->fsp->conn->cnum,
|
||||
blr->offset, blr->count, True);
|
||||
|
||||
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
|
||||
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
|
||||
continue;
|
||||
@ -520,6 +552,9 @@ void remove_pending_lock_requests_by_mid(int mid)
|
||||
file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
|
||||
|
||||
blocking_lock_reply_error(blr,NT_STATUS_CANCELLED);
|
||||
brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
|
||||
blr->lock_pid, sys_getpid(), blr->fsp->conn->cnum,
|
||||
blr->offset, blr->count, True);
|
||||
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
|
||||
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
|
||||
continue;
|
||||
@ -530,9 +565,20 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Set a flag as an unlock request affects one of our pending locks.
|
||||
*****************************************************************************/
|
||||
|
||||
static void received_unlock_msg(int msg_type, pid_t src, void *buf, size_t len)
|
||||
{
|
||||
DEBUG(10,("received_unlock_msg\n"));
|
||||
process_blocking_lock_queue(time(NULL));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Return the number of seconds to the next blocking locks timeout, or default_timeout
|
||||
*****************************************************************************/
|
||||
|
||||
unsigned blocking_locks_timeout(unsigned default_timeout)
|
||||
{
|
||||
unsigned timeout = default_timeout;
|
||||
@ -540,22 +586,21 @@ unsigned blocking_locks_timeout(unsigned default_timeout)
|
||||
blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst(&blocking_lock_queue);
|
||||
|
||||
/* note that we avoid the time() syscall if there are no blocking locks */
|
||||
if (!blr) {
|
||||
if (!blr)
|
||||
return timeout;
|
||||
}
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
while (blr) {
|
||||
if (timeout > (blr->expire_time - t)) {
|
||||
if ((blr->expire_time != (time_t)-1) &&
|
||||
(timeout > (blr->expire_time - t))) {
|
||||
timeout = blr->expire_time - t;
|
||||
}
|
||||
blr = (blocking_lock_record *)ubi_slNext(blr);
|
||||
}
|
||||
|
||||
if (timeout < 1) {
|
||||
if (timeout < 1)
|
||||
timeout = 1;
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
@ -604,6 +649,10 @@ 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_unlock(fsp->dev, fsp->inode, fsp->fnum,
|
||||
blr->lock_pid, sys_getpid(), conn->cnum,
|
||||
blr->offset, blr->count, True);
|
||||
|
||||
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
|
||||
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
|
||||
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
|
||||
@ -617,6 +666,11 @@ void process_blocking_lock_queue(time_t t)
|
||||
* Remove the entry and return an error to the client.
|
||||
*/
|
||||
blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
|
||||
|
||||
brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
|
||||
blr->lock_pid, sys_getpid(), conn->cnum,
|
||||
blr->offset, blr->count, True);
|
||||
|
||||
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
|
||||
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
|
||||
continue;
|
||||
@ -628,6 +682,11 @@ void process_blocking_lock_queue(time_t t)
|
||||
* Remove the entry and return an error to the client.
|
||||
*/
|
||||
blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
|
||||
|
||||
brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
|
||||
blr->lock_pid, sys_getpid(), conn->cnum,
|
||||
blr->offset, blr->count, True);
|
||||
|
||||
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
|
||||
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
|
||||
change_to_root_user();
|
||||
@ -641,6 +700,11 @@ void process_blocking_lock_queue(time_t t)
|
||||
*/
|
||||
|
||||
if(blocking_lock_record_process(blr)) {
|
||||
|
||||
brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
|
||||
blr->lock_pid, sys_getpid(), conn->cnum,
|
||||
blr->offset, blr->count, True);
|
||||
|
||||
free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
|
||||
blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
|
||||
change_to_root_user();
|
||||
|
@ -1271,6 +1271,13 @@ void smbd_process(void)
|
||||
lp_talloc_free();
|
||||
main_loop_talloc_free();
|
||||
|
||||
/* Did someone ask for immediate checks on things like blocking locks ? */
|
||||
if (select_timeout == 0) {
|
||||
if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
|
||||
return;
|
||||
num_smbs = 0; /* Reset smb counter. */
|
||||
}
|
||||
|
||||
while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) {
|
||||
if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
|
||||
return;
|
||||
|
@ -1609,7 +1609,8 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
|
||||
* this smb into a queued request and push it
|
||||
* onto the blocking lock queue.
|
||||
*/
|
||||
if(push_blocking_lock_request(inbuf, length, -1, 0)) {
|
||||
if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)startpos,
|
||||
(SMB_BIG_UINT)numtoread)) {
|
||||
END_PROFILE(SMBlockread);
|
||||
return -1;
|
||||
}
|
||||
@ -2514,7 +2515,7 @@ int reply_lock(connection_struct *conn,
|
||||
* this smb into a queued request and push it
|
||||
* onto the blocking lock queue.
|
||||
*/
|
||||
if(push_blocking_lock_request(inbuf, length, -1, 0)) {
|
||||
if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), offset, count)) {
|
||||
END_PROFILE(SMBlock);
|
||||
return -1;
|
||||
}
|
||||
@ -3955,7 +3956,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
|
||||
* this smb into a queued request and push it
|
||||
* onto the blocking lock queue.
|
||||
*/
|
||||
if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) {
|
||||
if(push_blocking_lock_request(inbuf, length, lock_timeout, i, lock_pid, offset, count)) {
|
||||
END_PROFILE(SMBlockingX);
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user