pvfs_unlink: retry unlink after oplock not granted
authorStefan Metzmacher <metze@samba.org>
Fri, 22 Feb 2008 10:52:17 +0000 (11:52 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 26 Feb 2008 08:32:59 +0000 (09:32 +0100)
metze

source/ntvfs/posix/pvfs_open.c
source/ntvfs/posix/pvfs_unlink.c

index 8429c14d1ba6f9693097cefb6e2af5b1d9eec75c..4110df292d26fe4e5eb0ce2fb08dde60cb443d1a 100644 (file)
@@ -1008,7 +1008,8 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
                                      struct ntvfs_request *req, 
                                      union smb_open *io,
                                      struct pvfs_file *f,
-                                     struct odb_lock *lck)
+                                     struct odb_lock *lck,
+                                     NTSTATUS parent_status)
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
        NTSTATUS status;
@@ -1027,7 +1028,15 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
        /* the retry should allocate a new file handle */
        talloc_free(f);
 
-       end_time = timeval_add(&req->statistics.request_time, 0, pvfs->sharing_violation_delay);
+       if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      0, pvfs->sharing_violation_delay);
+       } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      pvfs->oplock_break_timeout, 0);
+       } else {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
 
        return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
                                    pvfs_retry_open_sharing);
@@ -1253,11 +1262,16 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                               io->generic.in.open_disposition,
                               false, oplock_level, &oplock_granted);
 
-       /* on a sharing violation we need to retry when the file is closed by 
-          the other user, or after 1 second */
-       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
+       /*
+        * on a sharing violation we need to retry when the file is closed by
+        * the other user, or after 1 second
+        * on a non granted oplock we need to retry when the file is closed by
+        * the other user, or after 30 seconds
+       */
+       if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+            NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
            (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
-               return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
+               return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
        }
 
        if (!NT_STATUS_IS_OK(status)) {
index bda4014beec16c8a701347d0e6d8a36188350627..7a2d964b9dd82d82a90f504c19b88d538458909b 100644 (file)
 #include "vfs_posix.h"
 #include "system/dir.h"
 
+/*
+  retry an open after a sharing violation
+*/
+static void pvfs_retry_unlink(struct pvfs_odb_retry *r,
+                             struct ntvfs_module_context *ntvfs,
+                             struct ntvfs_request *req,
+                             void *_io,
+                             void *private_data,
+                             enum pvfs_wait_notice reason)
+{
+       union smb_unlink *io = talloc_get_type(_io, union smb_unlink);
+       NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+
+       talloc_free(r);
+
+       switch (reason) {
+       case PVFS_WAIT_CANCEL:
+/*TODO*/
+               status = NT_STATUS_CANCELLED;
+               break;
+       case PVFS_WAIT_TIMEOUT:
+               /* if it timed out, then give the failure
+                  immediately */
+/*TODO*/
+               status = NT_STATUS_SHARING_VIOLATION;
+               break;
+       case PVFS_WAIT_EVENT:
+
+               /* try the open again, which could trigger another retry setup
+                  if it wants to, so we have to unmark the async flag so we
+                  will know if it does a second async reply */
+               req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
+
+               status = pvfs_unlink(ntvfs, req, io);
+               if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
+                       /* the 2nd try also replied async, so we don't send
+                          the reply yet */
+                       return;
+               }
+
+               /* re-mark it async, just in case someone up the chain does
+                  paranoid checking */
+               req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+               break;
+       }
+
+       /* send the reply up the chain */
+       req->async_states->status = status;
+       req->async_states->send_fn(req);
+}
+
+/*
+  setup for a unlink retry after a sharing violation
+  or a non granted oplock
+*/
+static NTSTATUS pvfs_unlink_setup_retry(struct ntvfs_module_context *ntvfs,
+                                       struct ntvfs_request *req,
+                                       union smb_unlink *io,
+                                       struct odb_lock *lck,
+                                       NTSTATUS status)
+{
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct timeval end_time;
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      0, pvfs->sharing_violation_delay);
+       } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      pvfs->oplock_break_timeout, 0);
+       } else {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
+                                   pvfs_retry_unlink);
+}
+
 
 /*
   unlink a file
@@ -67,6 +145,7 @@ static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
                                struct pvfs_filename *name)
 {
        NTSTATUS status;
+       struct odb_lock *lck = NULL;
 
        /* make sure its matches the given attributes */
        status = pvfs_match_attrib(pvfs, name,
@@ -75,7 +154,20 @@ static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
                return status;
        }
 
-       status = pvfs_can_delete(pvfs, req, name, NULL);
+       status = pvfs_can_delete(pvfs, req, name, &lck);
+
+       /*
+        * on a sharing violation we need to retry when the file is closed by
+        * the other user, or after 1 second
+        * on a non granted oplock we need to retry when the file is closed by
+        * the other user, or after 30 seconds
+        */
+       if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+            NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
+           (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
+               return pvfs_unlink_setup_retry(pvfs->ntvfs, req, unl, lck, status);
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }