summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/ntvfs/common/brlock.c19
-rw-r--r--source4/ntvfs/posix/pvfs_lock.c59
-rw-r--r--source4/ntvfs/posix/pvfs_open.c1
-rw-r--r--source4/ntvfs/posix/vfs_posix.h4
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];
/*