diff options
author | Jeremy Allison <jra@samba.org> | 2003-02-27 01:04:34 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2003-02-27 01:04:34 +0000 |
commit | fb3e4b87973e9ad0c818e8d9dd60329c47f22afe (patch) | |
tree | 98365addb079aa17a6aa8d05a61affcfe54f0dac /source3/locking | |
parent | 1502667e923620cddd0137e94dc8d892ce2e95a8 (diff) | |
download | samba-fb3e4b87973e9ad0c818e8d9dd60329c47f22afe.tar.gz samba-fb3e4b87973e9ad0c818e8d9dd60329c47f22afe.tar.xz samba-fb3e4b87973e9ad0c818e8d9dd60329c47f22afe.zip |
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 766928bbba1e597c9c2b12458dd8d37e6080593e)
Diffstat (limited to 'source3/locking')
-rw-r--r-- | source3/locking/brlock.c | 82 | ||||
-rw-r--r-- | source3/locking/locking.c | 4 |
2 files changed, 78 insertions, 8 deletions
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index 9902c7bbd7b..4cd885f1a65 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -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; @@ -386,15 +395,29 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, } /**************************************************************************** + 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], diff --git a/source3/locking/locking.c b/source3/locking/locking.c index fdfd4d661c6..651f905e15d 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -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" )); |