r3031: added support for lock cancelation, which effectively just triggers an early...
authorAndrew Tridgell <tridge@samba.org>
Mon, 18 Oct 2004 09:16:55 +0000 (09:16 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:00:00 +0000 (13:00 -0500)
added support for more of the bizarre special lock offset semantics of w2k3

source/ntvfs/common/brlock.c
source/ntvfs/posix/pvfs_lock.c
source/ntvfs/posix/pvfs_open.c
source/ntvfs/posix/vfs_posix.h

index 792ee52ad58b07f771566b06c277b57b5009567e..2da32891fbad3c746456b924ea4433ef96dcc391 100644 (file)
@@ -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;
index 548c5bd82ce0db93180d75e39debafde907a05fe..100fc50e55609932ec7b4115268e2b00e68644ec 100644 (file)
@@ -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;
                        }
@@ -191,6 +197,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
 */
@@ -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 */
index 5798aa782fc05b7aaa8bf10e4582d1ff3506e3e6..05c2bdda28b9876f7be78784b33e76580ee3372f 100644 (file)
@@ -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);
index e83f0479a9164de254e77dbd565149536216fd34..6aaa43a2134b53181b43cc5acd2eb7523cafd135 100644 (file)
@@ -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];
        /*