r6579: improved the handling of lock timeouts and cancels in the pvfs locking
[samba.git] / source / ntvfs / posix / pvfs_lock.c
index 2668eec00484c435462e980bbf24707606fd3582..8015fc46c4c421f30807e8ea72f99b237bdd01a5 100644 (file)
@@ -20,7 +20,7 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "include/includes.h"
+#include "includes.h"
 #include "vfs_posix.h"
 #include "system/time.h"
 #include "dlinklist.h"
@@ -41,7 +41,7 @@ NTSTATUS pvfs_check_lock(struct pvfs_state *pvfs,
        }
 
        return brl_locktest(pvfs->brl_context,
-                           &f->locking_key,
+                           &f->handle->brl_locking_key,
                            f->fnum,
                            smbpid,
                            offset, count, rw);
@@ -56,7 +56,7 @@ struct pvfs_pending_lock {
        struct smbsrv_request *req;
        int pending_lock;
        void *wait_handle;
-       time_t end_time;
+       struct timeval end_time;
 };
 
 /*
@@ -73,7 +73,7 @@ static void pvfs_lock_async_failed(struct pvfs_state *pvfs,
        /* undo the locks we just did */
        for (i=i-1;i>=0;i--) {
                brl_unlock(pvfs->brl_context,
-                          &f->locking_key,
+                          &f->handle->brl_locking_key,
                           locks[i].pid,
                           f->fnum,
                           locks[i].offset,
@@ -91,7 +91,7 @@ static void pvfs_lock_async_failed(struct pvfs_state *pvfs,
   range, so we should try the lock again. Note that on timeout we
   do retry the lock, giving it a last chance.
 */
-static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
+static void pvfs_pending_lock_continue(void *private, enum pvfs_wait_notice reason)
 {
        struct pvfs_pending_lock *pending = private;
        struct pvfs_state *pvfs = pending->pvfs;
@@ -102,6 +102,9 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
        enum brl_type rw;
        NTSTATUS status;
        int i;
+       BOOL timed_out;
+
+       timed_out = (reason != PVFS_WAIT_EVENT);
 
        locks = lck->lockx.in.locks + lck->lockx.in.ulock_cnt;
 
@@ -113,23 +116,29 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
 
        DLIST_REMOVE(f->pending_list, pending);
 
-       status = brl_lock(pvfs->brl_context,
-                         &f->locking_key,
-                         req->smbpid,
-                         f->fnum,
-                         locks[pending->pending_lock].offset,
-                         locks[pending->pending_lock].count,
-                         rw, NULL);
-
+       /* we don't retry on a cancel */
+       if (reason == PVFS_WAIT_CANCEL) {
+               status = NT_STATUS_CANCELLED;
+       } else {
+               status = brl_lock(pvfs->brl_context,
+                                 &f->handle->brl_locking_key,
+                                 req->smbpid,
+                                 f->fnum,
+                                 locks[pending->pending_lock].offset,
+                                 locks[pending->pending_lock].count,
+                                 rw, NULL);
+       }
        if (NT_STATUS_IS_OK(status)) {
                f->lock_count++;
+               timed_out = False;
        }
 
        /* if we have failed and timed out, or succeeded, then we
           don't need the pending lock any more */
        if (NT_STATUS_IS_OK(status) || timed_out) {
                NTSTATUS status2;
-               status2 = brl_remove_pending(pvfs->brl_context, &f->locking_key, pending);
+               status2 = brl_remove_pending(pvfs->brl_context, 
+                                            &f->handle->brl_locking_key, pending);
                if (!NT_STATUS_IS_OK(status2)) {
                        DEBUG(0,("pvfs_lock: failed to remove pending lock - %s\n", nt_errstr(status2)));
                }
@@ -148,14 +157,10 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
        }
 
        /* if we haven't timed out yet, then we can do more pending locks */
-       if (timed_out) {
-               pending = NULL;
+       if (rw == READ_LOCK) {
+               rw = PENDING_READ_LOCK;
        } else {
-               if (rw == READ_LOCK) {
-                       rw = PENDING_READ_LOCK;
-               } else {
-                       rw = PENDING_WRITE_LOCK;
-               }
+               rw = PENDING_WRITE_LOCK;
        }
 
        /* we've now got the pending lock. try and get the rest, which might
@@ -166,7 +171,7 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
                }
 
                status = brl_lock(pvfs->brl_context,
-                                 &f->locking_key,
+                                 &f->handle->brl_locking_key,
                                  req->smbpid,
                                  f->fnum,
                                  locks[i].offset,
@@ -183,6 +188,7 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
                                if (pending->wait_handle == NULL) {
                                        pvfs_lock_async_failed(pvfs, req, f, locks, i, NT_STATUS_NO_MEMORY);
                                } else {
+                                       talloc_steal(pending, pending->wait_handle);
                                        DLIST_ADD(f->pending_list, pending);
                                }
                                return;
@@ -210,7 +216,7 @@ void pvfs_lock_close(struct pvfs_state *pvfs, struct pvfs_file *f)
        if (f->lock_count || f->pending_list) {
                DEBUG(5,("pvfs_lock: removing %.0f locks on close\n", 
                         (double)f->lock_count));
-               brl_close(f->pvfs->brl_context, &f->locking_key, f->fnum);
+               brl_close(f->pvfs->brl_context, &f->handle->brl_locking_key, f->fnum);
                f->lock_count = 0;
        }
 
@@ -219,7 +225,6 @@ void pvfs_lock_close(struct pvfs_state *pvfs, struct pvfs_file *f)
        for (p=f->pending_list;p;p=next) {
                next = p->next;
                DLIST_REMOVE(f->pending_list, p);
-               talloc_free(p->wait_handle);
                p->req->async_states->status = NT_STATUS_RANGE_NOT_LOCKED;
                p->req->async_states->send_fn(p->req);
        }
@@ -285,13 +290,13 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_HANDLE;
        }
 
-       if (f->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
+       if (f->handle->fd == -1) {
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
 
        if (lck->lockx.in.timeout != 0 && 
            (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
-               pending = talloc_p(req, struct pvfs_pending_lock);
+               pending = talloc(f, struct pvfs_pending_lock);
                if (pending == NULL) {
                        return NT_STATUS_NO_MEMORY;
                }
@@ -301,8 +306,9 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
                pending->f = f;
                pending->req = req;
 
-               /* round up to the nearest second */
-               pending->end_time = time(NULL) + ((lck->lockx.in.timeout+999)/1000);
+               pending->end_time = 
+                       timeval_current_ofs(lck->lockx.in.timeout/1000,
+                                           1000*(lck->lockx.in.timeout%1000));
        }
 
        if (lck->lockx.in.mode & LOCKING_ANDX_SHARED_LOCK) {
@@ -332,7 +338,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
 
        for (i=0;i<lck->lockx.in.ulock_cnt;i++) {
                status = brl_unlock(pvfs->brl_context,
-                                   &f->locking_key,
+                                   &f->handle->brl_locking_key,
                                    locks[i].pid,
                                    f->fnum,
                                    locks[i].offset,
@@ -351,7 +357,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
                }
 
                status = brl_lock(pvfs->brl_context,
-                                 &f->locking_key,
+                                 &f->handle->brl_locking_key,
                                  locks[i].pid,
                                  f->fnum,
                                  locks[i].offset,
@@ -368,13 +374,14 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
                                if (pending->wait_handle == NULL) {
                                        return NT_STATUS_NO_MEMORY;
                                }
+                               talloc_steal(pending, pending->wait_handle);
                                DLIST_ADD(f->pending_list, pending);
                                return NT_STATUS_OK;
                        }
                        /* undo the locks we just did */
                        for (i=i-1;i>=0;i--) {
                                brl_unlock(pvfs->brl_context,
-                                          &f->locking_key,
+                                          &f->handle->brl_locking_key,
                                           locks[i].pid,
                                           f->fnum,
                                           locks[i].offset,