Fix the SMB2 showstopper, found by an extended torture test from Volker.
authorJeremy Allison <jra@samba.org>
Mon, 16 May 2011 19:20:14 +0000 (12:20 -0700)
committerJeremy Allison <jra@samba.org>
Mon, 16 May 2011 20:38:20 +0000 (22:38 +0200)
In the oplock refactoring, the algorithm underwent an unnoticed change.
In 3.5.x stat_opens were silently (i.e. no explicit code had comments
explaining this) ignored when looking for oplock breaks and share mode
violations. After the refactoring, the function find_oplock_types()
no longer ignored stat_open entries in the share mode table when looking
for batch and exclusive oplocks. This patch adds two changes to find_oplock_types()
to ignore the case where the incoming open request is a stat open being
tested against existing opens, and also when the incoming open request
is a non-stat open being tested against existing stat opens. Neither
of these cause an oplock break or share mode violation. Thanks a *lot*
to Volker, who persevered in reproducing this problem.

Autobuild-User: Jeremy Allison <jra@samba.org>
Autobuild-Date: Mon May 16 22:38:20 CEST 2011 on sn-devel-104

source3/smbd/open.c

index 5d9621748fe46790c28dd7480c318d0f0790f654..bb7e6c29dfa495b189609f0aad5fc1553deacab2 100644 (file)
@@ -949,7 +949,9 @@ static NTSTATUS send_break_message(files_struct *fsp,
  * Do internal consistency checks on the share mode for a file.
  */
 
-static void find_oplock_types(struct share_mode_lock *lck,
+static void find_oplock_types(files_struct *fsp,
+                               int oplock_request,
+                               struct share_mode_lock *lck,
                                struct share_mode_entry **pp_batch,
                                struct share_mode_entry **pp_ex_or_batch,
                                bool *got_level2,
@@ -962,11 +964,27 @@ static void find_oplock_types(struct share_mode_lock *lck,
        *got_level2 = false;
        *got_no_oplock = false;
 
+       /* Ignore stat or internal opens, as is done in
+               delay_for_batch_oplocks() and
+               delay_for_exclusive_oplocks().
+        */
+       if ((oplock_request & INTERNAL_OPEN_ONLY) || is_stat_open(fsp->access_mask)) {
+               return;
+       }
+
        for (i=0; i<lck->num_share_modes; i++) {
                if (!is_valid_share_mode_entry(&lck->share_modes[i])) {
                        continue;
                }
 
+               if (lck->share_modes[i].op_type == NO_OPLOCK &&
+                               is_stat_open(lck->share_modes[i].access_mask)) {
+                       /* We ignore stat opens in the table - they
+                          always have NO_OPLOCK and never get or
+                          cause breaks. JRA. */
+                       continue;
+               }
+
                if (BATCH_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
                        /* batch - can only be one. */
                        if (*pp_ex_or_batch || *pp_batch || *got_level2 || *got_no_oplock) {
@@ -1906,7 +1924,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                }
 
                /* Get the types we need to examine. */
-               find_oplock_types(lck,
+               find_oplock_types(fsp,
+                               oplock_request,
+                               lck,
                                &batch_entry,
                                &exclusive_entry,
                                &got_level2_oplock,
@@ -2151,7 +2171,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                }
 
                /* Get the types we need to examine. */
-               find_oplock_types(lck,
+               find_oplock_types(fsp,
+                               oplock_request,
+                               lck,
                                &batch_entry,
                                &exclusive_entry,
                                &got_level2_oplock,