smbd: Fix raw.batch.exclusive[59]
authorVolker Lendecke <vl@samba.org>
Thu, 26 Sep 2013 23:15:31 +0000 (16:15 -0700)
committerStefan Metzmacher <metze@samba.org>
Wed, 23 Oct 2013 09:58:56 +0000 (11:58 +0200)
The level we have to break to depend on the breakers create_disposition:
If we overwrite, we have to break to none.

This patch overloads the "op_type" field in the break message we send
across to the smbd holding the oplock with the oplock level we want to
break to. Because it depends on the create_disposition in the breaking
open, only the breaker can make that decision. We might want to use
a different mechanism for this in the future, but for now using the
op_type field seems acceptable to me.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
selftest/knownfail
source3/smbd/open.c
source3/smbd/oplock.c

index b364e9c0b16c76c563bda7da62afee2f6fa05775..cfa8b4b2736f1eb34ee9a9edf38107915472bcdf 100644 (file)
@@ -61,8 +61,6 @@
 ^samba3.raw.acls nfs4acl_xattr-special.inheritance\(s3dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.inherit_creator_owner\(s3dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.inherit_creator_group\(s3dc\)
-^samba3.raw.oplock.exclusive5
-^samba3.raw.oplock.exclusive9
 ^samba3.base.delete.deltest16a
 ^samba3.base.delete.deltest17a
 ^samba3.unix.whoami anonymous connection.whoami\(plugin_s4_dc\) # We need to resolve if we should be including SID_NT_WORLD and SID_NT_NETWORK in this token
 ^samba3.smb2.lease.multibreak
 ^samba3.smb2.lease.v2_request
 ^samba3.smb2.oplock.batch20
-^samba3.smb2.oplock.exclusive9
 ^samba3.smb2.oplock.stream1
 ^samba3.smb2.streams.rename
 ^samba3.smb2.streams.rename2
index a9147f80b82e75435b9ec76a8230848c6b66e022..494145397d37c370741be773727c6ec97bbe9bb1 100644 (file)
@@ -1168,7 +1168,8 @@ static NTSTATUS open_mode_check(connection_struct *conn,
  */
 
 static NTSTATUS send_break_message(struct messaging_context *msg_ctx,
-                                  const struct share_mode_entry *exclusive)
+                                  const struct share_mode_entry *exclusive,
+                                  uint16_t break_to)
 {
        NTSTATUS status;
        char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
@@ -1179,6 +1180,9 @@ static NTSTATUS send_break_message(struct messaging_context *msg_ctx,
        /* Create the message. */
        share_mode_entry_to_message(msg, exclusive);
 
+       /* Overload entry->op_type */
+       SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET, break_to);
+
        status = messaging_send_buf(msg_ctx, exclusive->pid,
                                    MSG_SMB_BREAK_REQUEST,
                                    (uint8 *)msg, sizeof(msg));
@@ -1292,12 +1296,14 @@ static bool validate_oplock_types(struct share_mode_lock *lck)
 static bool delay_for_oplock(files_struct *fsp,
                             int oplock_request,
                             struct share_mode_lock *lck,
-                            bool have_sharing_violation)
+                            bool have_sharing_violation,
+                            uint32_t create_disposition)
 {
        struct share_mode_data *d = lck->data;
        struct share_mode_entry *entry;
        uint32_t num_non_stat_opens = 0;
        uint32_t i;
+       uint16_t break_to;
 
        if ((oplock_request & INTERNAL_OPEN_ONLY) || is_stat_open(fsp->access_mask)) {
                return false;
@@ -1342,11 +1348,21 @@ static bool delay_for_oplock(files_struct *fsp,
                return false;
        }
 
+       switch (create_disposition) {
+       case FILE_SUPERSEDE:
+       case FILE_OVERWRITE_IF:
+               break_to = NO_OPLOCK;
+               break;
+       default:
+               break_to = LEVEL_II_OPLOCK;
+               break;
+       }
+
        if (have_sharing_violation && (entry->op_type & BATCH_OPLOCK)) {
                if (share_mode_stale_pid(d, 0)) {
                        return false;
                }
-               send_break_message(fsp->conn->sconn->msg_ctx, entry);
+               send_break_message(fsp->conn->sconn->msg_ctx, entry, break_to);
                return true;
        }
        if (have_sharing_violation) {
@@ -1366,7 +1382,7 @@ static bool delay_for_oplock(files_struct *fsp,
                return false;
        }
 
-       send_break_message(fsp->conn->sconn->msg_ctx, entry);
+       send_break_message(fsp->conn->sconn->msg_ctx, entry, break_to);
        return true;
 }
 
@@ -2343,7 +2359,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                        smb_panic("validate_oplock_types failed");
                }
 
-               if (delay_for_oplock(fsp, 0, lck, false)) {
+               if (delay_for_oplock(fsp, 0, lck, false, create_disposition)) {
                        schedule_defer_open(lck, request_time, req);
                        TALLOC_FREE(lck);
                        DEBUG(10, ("Sent oplock break request to kernel "
@@ -2455,7 +2471,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        if ((req != NULL) &&
            delay_for_oplock(
                    fsp, oplock_request, lck,
-                   NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION))) {
+                   NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION),
+                   create_disposition)) {
                schedule_defer_open(lck, request_time, req);
                TALLOC_FREE(lck);
                fd_close(fsp);
index e2880c5de97342ef3619e3b7a86f29e64cbec9e3..f1b89b4650bf7802d9898c42f9a8aa3b5ed4b34c 100644 (file)
@@ -510,6 +510,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
                struct smbd_server_connection);
        struct server_id self = messaging_server_id(sconn->msg_ctx);
        struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
+       uint16_t break_to;
 
        if (data->data == NULL) {
                DEBUG(0, ("Got NULL buffer\n"));
@@ -523,9 +524,10 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
 
        /* De-linearize incoming message. */
        message_to_share_mode_entry(&msg, (char *)data->data);
+       break_to = msg.op_type;
 
-       DEBUG(10, ("Got oplock break message from pid %s: %s/%llu\n",
-                  server_id_str(talloc_tos(), &src),
+       DEBUG(10, ("Got oplock break to %u message from pid %s: %s/%llu\n",
+                  (unsigned)break_to, server_id_str(talloc_tos(), &src),
                   file_id_string_tos(&msg.id),
                   (unsigned long long)msg.share_file_id));
 
@@ -545,8 +547,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
                return;
        }
 
-       if (EXCLUSIVE_OPLOCK_TYPE(msg.op_type) &&
-           !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+       if (break_to == fsp->oplock_type) {
                DEBUG(3, ("Already downgraded oplock on %s: %s\n",
                          file_id_string_tos(&fsp->file_id),
                          fsp_str_dbg(fsp)));
@@ -556,6 +557,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
        use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks;
 
        if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
+           (break_to != NO_OPLOCK) &&
            !(use_kernel && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) &&
            lp_level2_oplocks(SNUM(fsp->conn))) {
                break_to_level2 = True;