Author: jra
Date: 2006-04-19 18:48:14 +0000 (Wed, 19 Apr 2006)
New Revision: 15138

WebSVN: 
http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=15138

Log:
Teach Samba the difference between exclusive and batch oplocks.
Pass Samba4 oplock test (with kernel oplocks off).
Jeremy.

Modified:
   branches/SAMBA_3_0/source/smbd/open.c


Changeset:
Modified: branches/SAMBA_3_0/source/smbd/open.c
===================================================================
--- branches/SAMBA_3_0/source/smbd/open.c       2006-04-19 15:43:48 UTC (rev 
15137)
+++ branches/SAMBA_3_0/source/smbd/open.c       2006-04-19 18:48:14 UTC (rev 
15138)
@@ -608,7 +608,7 @@
  * 3) Only level2 around: Grant level2 and do nothing else.
  */
 
-static BOOL delay_for_oplocks(struct share_mode_lock *lck, files_struct *fsp)
+static BOOL delay_for_oplocks(struct share_mode_lock *lck, files_struct *fsp, 
int pass_number)
 {
        int i;
        struct share_mode_entry *exclusive = NULL;
@@ -630,9 +630,16 @@
                /* At least one entry is not an invalid or deferred entry. */
                valid_entry = True;
 
-               if (EXCLUSIVE_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
-                       SMB_ASSERT(exclusive == NULL);                  
-                       exclusive = &lck->share_modes[i];
+               if (pass_number == 1) {
+                       if (BATCH_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
+                               SMB_ASSERT(exclusive == NULL);                  
+                               exclusive = &lck->share_modes[i];
+                       }
+               } else {
+                       if (EXCLUSIVE_OPLOCK_TYPE(lck->share_modes[i].op_type)) 
{
+                               SMB_ASSERT(exclusive == NULL);                  
+                               exclusive = &lck->share_modes[i];
+                       }
                }
 
                if (lck->share_modes[i].op_type == LEVEL_II_OPLOCK) {
@@ -1024,6 +1031,42 @@
 
 }
 
+static void schedule_defer_open(struct share_mode_lock *lck, struct timeval 
request_time)
+{
+       struct deferred_open_record state;
+
+       /* This is a relative time, added to the absolute
+          request_time value to get the absolute timeout time.
+          Note that if this is the second or greater time we enter
+          this codepath for this particular request mid then
+          request_time is left as the absolute time of the *first*
+          time this request mid was processed. This is what allows
+          the request to eventually time out. */
+
+       struct timeval timeout;
+
+       /* Normally the smbd we asked should respond within
+        * OPLOCK_BREAK_TIMEOUT seconds regardless of whether
+        * the client did, give twice the timeout as a safety
+        * measure here in case the other smbd is stuck
+        * somewhere else. */
+
+       timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
+
+       /* Nothing actually uses state.delayed_for_oplocks
+          but it's handy to differentiate in debug messages
+          between a 30 second delay due to oplock break, and
+          a 1 second delay for share mode conflicts. */
+
+       state.delayed_for_oplocks = True;
+       state.dev = lck->dev;
+       state.inode = lck->ino;
+
+       if (!request_timed_out(request_time, timeout)) {
+               defer_open(lck, request_time, timeout, &state);
+       }
+}
+
 /****************************************************************************
  Open a file with a share mode.
 ****************************************************************************/
@@ -1310,7 +1353,6 @@
        }
 
        if (file_existed) {
-
                dev = psbuf->st_dev;
                inode = psbuf->st_ino;
 
@@ -1324,41 +1366,9 @@
                        return NULL;
                }
 
-               if (delay_for_oplocks(lck, fsp)) {
-                       struct deferred_open_record state;
-
-                       /* This is a relative time, added to the absolute
-                          request_time value to get the absolute timeout time.
-                          Note that if this is the second or greater time we 
enter
-                          this codepath for this particular request mid then
-                          request_time is left as the absolute time of the 
*first*
-                          time this request mid was processed. This is what 
allows
-                          the request to eventually time out. */
-
-                       struct timeval timeout;
-
-                       /* Normally the smbd we asked should respond within
-                        * OPLOCK_BREAK_TIMEOUT seconds regardless of whether
-                        * the client did, give twice the timeout as a safety
-                        * measure here in case the other smbd is stuck
-                        * somewhere else. */
-
-                       timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
-
-                       /* Nothing actually uses state.delayed_for_oplocks
-                          but it's handy to differentiate in debug messages
-                          between a 30 second delay due to oplock break, and
-                          a 1 second delay for share mode conflicts. */
-
-                       state.delayed_for_oplocks = True;
-                       state.dev = dev;
-                       state.inode = inode;
-
-                       if (!request_timed_out(request_time, timeout)) {
-                               defer_open(lck, request_time, timeout,
-                                          &state);
-                       }
-
+               /* First pass - send break only on batch oplocks. */
+               if (delay_for_oplocks(lck, fsp, 1)) {
+                       schedule_defer_open(lck, request_time);
                        TALLOC_FREE(lck);
                        return NULL;
                }
@@ -1367,6 +1377,16 @@
                                         access_mask, share_access,
                                         create_options, &file_existed);
 
+               if (NT_STATUS_IS_OK(status)) {
+                       /* We might be going to allow this open. Check oplock 
status again. */
+                       /* Second pass - send break for both batch or exclusive 
oplocks. */
+                       if (delay_for_oplocks(lck, fsp, 2)) {
+                               schedule_defer_open(lck, request_time);
+                               TALLOC_FREE(lck);
+                               return NULL;
+                       }
+               }
+
                if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
                        /* DELETE_PENDING is not deferred for a second */
                        set_saved_ntstatus(status);

Reply via email to