diff options
author | Andrew Tridgell <tridge@samba.org> | 2004-10-18 09:16:55 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:00:00 -0500 |
commit | 43a80e1d83dad9450014b2a7e0ad5a5e495f69ce (patch) | |
tree | 64f0abd7998874cd067bd20c15504b93324d6906 /source4 | |
parent | 0ca4a7700509b399e04ac93105962b1739c7a13c (diff) | |
download | samba-43a80e1d83dad9450014b2a7e0ad5a5e495f69ce.tar.gz samba-43a80e1d83dad9450014b2a7e0ad5a5e495f69ce.tar.bz2 samba-43a80e1d83dad9450014b2a7e0ad5a5e495f69ce.zip |
r3031: added support for lock cancelation, which effectively just triggers an early lock timeout
added support for more of the bizarre special lock offset semantics of w2k3
(This used to be commit d5bfc910b1200fb283e26572dc57fcf93652fd32)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/ntvfs/common/brlock.c | 19 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_lock.c | 59 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 1 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 4 |
4 files changed, 72 insertions, 11 deletions
diff --git a/source4/ntvfs/common/brlock.c b/source4/ntvfs/common/brlock.c index 792ee52ad5..2da32891fb 100644 --- a/source4/ntvfs/common/brlock.c +++ b/source4/ntvfs/common/brlock.c @@ -117,8 +117,16 @@ static BOOL brl_same_context(struct lock_context *ctx1, struct lock_context *ctx static BOOL brl_overlap(struct lock_struct *lck1, struct lock_struct *lck2) { - if (lck1->start >= (lck2->start + lck2->size) || - lck2->start >= (lck1->start + lck1->size)) { + /* this extra check is not redundent - it copes with locks + that go beyond the end of 64 bit file space */ + if (lck1->size != 0 && + lck1->start == lck2->start && + lck1->size == lck2->size) { + return True; + } + + if (lck1->start >= (lck2->start+lck2->size) || + lck2->start >= (lck1->start+lck1->size)) { return False; } return True; @@ -193,11 +201,12 @@ static NTSTATUS brl_lock_failed(struct brl_context *brl, struct lock_struct *loc return NT_STATUS_FILE_LOCK_CONFLICT; } brl->last_lock_failure = *lock; - if (lock->start >= 0xEF000000) { + 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. */ + number!) always generate the conflict error code, + unless the top bit is set */ return NT_STATUS_FILE_LOCK_CONFLICT; } return NT_STATUS_LOCK_NOT_GRANTED; diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c index 548c5bd82c..100fc50e55 100644 --- a/source4/ntvfs/posix/pvfs_lock.c +++ b/source4/ntvfs/posix/pvfs_lock.c @@ -45,7 +45,8 @@ NTSTATUS pvfs_check_lock(struct pvfs_state *pvfs, } /* this state structure holds information about a lock we are waiting on */ -struct pending_state { +struct pvfs_pending_lock { + struct pvfs_pending_lock *next, *prev; struct pvfs_state *pvfs; union smb_lock *lck; struct pvfs_file *f; @@ -55,7 +56,6 @@ struct pending_state { time_t end_time; }; - /* a secondary attempt to setup a lock has failed - back out the locks we did get and send an error @@ -89,7 +89,7 @@ static void pvfs_lock_async_failed(struct pvfs_state *pvfs, */ static void pvfs_pending_lock_continue(void *private, BOOL timed_out) { - struct pending_state *pending = private; + struct pvfs_pending_lock *pending = private; struct pvfs_state *pvfs = pending->pvfs; struct pvfs_file *f = pending->f; struct smbsrv_request *req = pending->req; @@ -107,6 +107,8 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out) rw = WRITE_LOCK; } + DLIST_REMOVE(f->pending_list, pending); + status = brl_lock(pvfs->brl_context, &f->locking_key, req->smbpid, @@ -130,8 +132,10 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out) if (timed_out) { /* no more chances */ pvfs_lock_async_failed(pvfs, req, f, locks, pending->pending_lock, status); + } else { + /* we can try again */ + DLIST_ADD(f->pending_list, pending); } - /* we can try again */ return; } @@ -170,6 +174,8 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out) pending); if (pending->wait_handle == NULL) { pvfs_lock_async_failed(pvfs, req, f, locks, i, NT_STATUS_NO_MEMORY); + } else { + DLIST_ADD(f->pending_list, pending); } return; } @@ -192,6 +198,42 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out) /* + cancel a set of locks +*/ +static NTSTATUS pvfs_lock_cancel(struct pvfs_state *pvfs, struct smbsrv_request *req, union smb_lock *lck, + struct pvfs_file *f) +{ + struct pvfs_pending_lock *p; + + for (p=f->pending_list;p;p=p->next) { + /* check if the lock request matches exactly - you can only cancel with exact matches */ + if (p->lck->lockx.in.ulock_cnt == lck->lockx.in.ulock_cnt && + p->lck->lockx.in.lock_cnt == lck->lockx.in.lock_cnt && + p->lck->lockx.in.fnum == lck->lockx.in.fnum && + p->lck->lockx.in.mode == (lck->lockx.in.mode & ~LOCKING_ANDX_CANCEL_LOCK)) { + int i; + + for (i=0;i<lck->lockx.in.ulock_cnt + lck->lockx.in.lock_cnt;i++) { + if (p->lck->lockx.in.locks[i].pid != lck->lockx.in.locks[i].pid || + p->lck->lockx.in.locks[i].offset != lck->lockx.in.locks[i].offset || + p->lck->lockx.in.locks[i].count != lck->lockx.in.locks[i].count) { + break; + } + } + if (i < lck->lockx.in.ulock_cnt) continue; + + /* an exact match! we can cancel it, which is equivalent + to triggering the timeout early */ + pvfs_pending_lock_continue(p ,True); + return NT_STATUS_OK; + } + } + + return NT_STATUS_UNSUCCESSFUL; +} + + +/* lock or unlock a byte range */ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, @@ -202,7 +244,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, struct smb_lock_entry *locks; int i; enum brl_type rw; - struct pending_state *pending = NULL; + struct pvfs_pending_lock *pending = NULL; f = pvfs_find_fd(pvfs, req, lck->generic.in.fnum); if (!f) { @@ -237,7 +279,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, /* now the lockingX case, most common and also most complex */ if (lck->lockx.in.timeout != 0) { - pending = talloc_p(req, struct pending_state); + pending = talloc_p(req, struct pvfs_pending_lock); if (pending == NULL) { return NT_STATUS_NO_MEMORY; } @@ -257,6 +299,10 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, rw = pending? PENDING_WRITE_LOCK : WRITE_LOCK; } + if (lck->lockx.in.mode & LOCKING_ANDX_CANCEL_LOCK) { + return pvfs_lock_cancel(pvfs, req, lck, f); + } + if (lck->lockx.in.mode & (LOCKING_ANDX_OPLOCK_RELEASE | LOCKING_ANDX_CHANGE_LOCKTYPE | @@ -309,6 +355,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, if (pending->wait_handle == NULL) { return NT_STATUS_NO_MEMORY; } + DLIST_ADD(f->pending_list, pending); return NT_STATUS_OK; } /* undo the locks we just did */ diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 5798aa782f..05c2bdda28 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -171,6 +171,7 @@ do_open: f->session = req->session; f->smbpid = req->smbpid; f->pvfs = pvfs; + f->pending_list = NULL; /* we must zero here to take account of padding */ ZERO_STRUCT(lock_context); diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index e83f0479a9..6aaa43a213 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -123,8 +123,12 @@ struct pvfs_file { /* we need this hook back to our parent for lock destruction */ struct pvfs_state *pvfs; + + /* a list of pending locks - used for locking cancel operations */ + struct pvfs_pending_lock *pending_list; }; + struct pvfs_mangle_context { uint8_t char_flags[256]; /* |