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;
}
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;
}
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;
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;
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);
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);
/* 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],
/*
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
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;
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"));
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,
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;
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;
}
}
+/****************************************************************************
+ 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;
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;
}
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));
* 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;
* 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();
*/
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();