Add pending break list
authorSachin Prabhu <sprabhu@redhat.com>
Fri, 20 Sep 2019 17:07:07 +0000 (18:07 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 28 Jan 2020 12:26:51 +0000 (13:26 +0100)
This is in preparation to enable channel retries.

Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
source3/librpc/idl/smbXsrv.idl
source3/smbd/globals.h
source3/smbd/smb2_break.c
source3/smbd/smb2_server.c

index 89d5287a1095f0a2666adf32b2543e72d6df75a1..a47d1e2a312e5c9f2dee39b0a62cac36d387dc87 100644 (file)
@@ -140,6 +140,8 @@ interface smbXsrv
                 * one in future.
                 */
                [ignore] struct smbXsrv_connection      *connections;
+               /* List of oplock breaks awaiting a response from clients */
+               [ignore] struct smbXsrv_pending_breaks  *pending_breaks;
                boolean8                server_multi_channel_enabled;
        } smbXsrv_client;
 
index c6f27bf511f851f0af6e33bb75531b27730df2bb..32a403ff15e69f8ac3fe87cc78ac0f844a9b209b 100644 (file)
@@ -343,6 +343,13 @@ struct smbXsrv_preauth {
        uint8_t sha512_value[64];
 };
 
+struct smbXsrv_pending_breaks {
+       struct smbXsrv_pending_breaks *prev, *next;
+       bool is_lease;
+       uint64_t data[2];
+       struct tevent_req *req;
+};
+
 struct smbXsrv_connection {
        struct smbXsrv_connection *prev, *next;
 
index ae6b9214b229c46e8091973a5c82ae5f071828f3..b79c18313c08f90d4ba2e3b64683a13372ad0257 100644 (file)
@@ -25,6 +25,7 @@
 #include "../libcli/smb/smb_common.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "locking/leases_db.h"
+#include "lib/tevent_wait.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_SMB2
@@ -41,6 +42,8 @@ static NTSTATUS smbd_smb2_oplock_break_recv(struct tevent_req *req,
                                            uint8_t *out_oplock_level);
 
 static void smbd_smb2_request_oplock_break_done(struct tevent_req *subreq);
+static void smbd_smb2_request_break_done(struct smbXsrv_connection *xconn, uint64_t data0,
+                                        uint64_t data1, int is_lease);
 NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req)
 {
        NTSTATUS status;
@@ -81,6 +84,9 @@ NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req)
                        req, NT_STATUS_INVALID_OPLOCK_PROTOCOL);
        }
 
+       smbd_smb2_request_break_done(req->xconn, in_file_id_persistent,
+                                    in_file_id_volatile, 0);
+
        if (in_oplock_level != SMB2_OPLOCK_LEVEL_NONE &&
            in_oplock_level != SMB2_OPLOCK_LEVEL_II) {
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
@@ -96,6 +102,28 @@ NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req)
        return smbd_smb2_request_pending_queue(req, subreq, 500);
 }
 
+static void smbd_smb2_request_break_done(struct smbXsrv_connection *xconn,
+                                        uint64_t data0, uint64_t data1,
+                                        int is_lease)
+{
+       struct smbXsrv_pending_breaks *cur = NULL;
+       struct smbXsrv_pending_breaks *next = NULL;
+
+       for (cur = xconn->client->pending_breaks; cur != NULL; cur = next) {
+               next = cur->next;
+
+               if ((cur->is_lease == is_lease) &&
+                   (cur->data[0] == data0) &&
+                   (cur->data[1] == data1)) {
+                       DLIST_REMOVE(xconn->client->pending_breaks, cur);
+                       tevent_wait_done(cur->req);
+               }
+
+       }
+
+       return;
+}
+
 static void smbd_smb2_request_oplock_break_done(struct tevent_req *subreq)
 {
        struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
@@ -265,6 +293,9 @@ static NTSTATUS smbd_smb2_request_process_lease_break(
        in_lease_key.data[1] = BVAL(inbody, 16);
        in_lease_state = IVAL(inbody, 24);
 
+       smbd_smb2_request_break_done(req->xconn, in_lease_key.data[0],
+                                    in_lease_key.data[1], 1);
+
        subreq = smbd_smb2_lease_break_send(req, req->sconn->ev_ctx, req,
                                            in_lease_key, in_lease_state);
        if (subreq == NULL) {
index e69e11d752e0c53800c21ba00f4a50c56914798d..b2748400993f4a78e24d42dfacfd78487b84a7c8 100644 (file)
@@ -3541,6 +3541,7 @@ struct smbXsrv_connection
 
 struct smbd_smb2_send_break_state {
        struct smbd_smb2_send_queue queue_entry;
+       struct smbXsrv_pending_breaks break_queue_entry;
        TALLOC_CTX *mem_ctx;
        struct tevent_context *ev_ctx;
        struct smbXsrv_connection *xconn;
@@ -3715,8 +3716,8 @@ error:
 static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
                                     struct smbXsrv_session *session,
                                     struct smbXsrv_tcon *tcon,
-                                    const uint8_t *body,
-                                    size_t body_len)
+                                    const uint8_t *body, size_t body_len,
+                                    bool is_lease, bool ack_needed)
 {
        NTSTATUS status;
        struct smbd_smb2_send_break_state *state;
@@ -3728,6 +3729,22 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
                return status;
        }
 
+       if (ack_needed) {
+               tevent_req_set_endtime(state->queue_entry.req,
+                               state->ev_ctx,
+                               timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0));
+               /* Build smbXsrv_pending_breaks */
+               state->break_queue_entry.req = state->queue_entry.req;
+               /* FileId for oplock breaks, LeaseKey for lease breaks */
+               memcpy(&state->break_queue_entry.data[0], &body[0x8],
+               sizeof(uint64_t));
+               memcpy(&state->break_queue_entry.data[1], &body[0x10],
+               sizeof(uint64_t));
+               state->break_queue_entry.is_lease = is_lease;
+               DLIST_ADD_END(xconn->client->pending_breaks,
+                             &state->break_queue_entry);
+       }
+
        tevent_req_set_callback(state->queue_entry.req, smbd_smb2_send_break_done,
                                state);
 
@@ -3739,7 +3756,11 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
                TALLOC_FREE(state);
                return status;
        }
-       tevent_wait_done(state->queue_entry.req);
+
+       /* No acks being received. */
+       if (!ack_needed) {
+               tevent_wait_done(state->queue_entry.req);
+       }
 
        return NT_STATUS_OK;
 }
@@ -3757,6 +3778,10 @@ static void smbd_smb2_send_break_done(struct tevent_req *ack_req)
        TALLOC_FREE(ack_req);
        xconn = state->xconn;
 
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               DLIST_REMOVE(xconn->client->pending_breaks,
+                               &state->break_queue_entry);
+       }
        TALLOC_FREE(state);
 }
 
@@ -3775,7 +3800,9 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbXsrv_connection *xconn,
        SBVAL(body, 0x08, op->global->open_persistent_id);
        SBVAL(body, 0x10, op->global->open_volatile_id);
 
-       return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body));
+       return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body),
+                                   false, /* Not lease */
+                                   0);
 }
 
 NTSTATUS smbd_smb2_send_lease_break(struct smbXsrv_connection *xconn,
@@ -3798,7 +3825,9 @@ NTSTATUS smbd_smb2_send_lease_break(struct smbXsrv_connection *xconn,
        SIVAL(body, 0x24, 0);           /* AccessMaskHint, MUST be 0 */
        SIVAL(body, 0x28, 0);           /* ShareMaskHint, MUST be 0 */
 
-       return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body));
+       return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body),
+                                   true, /* Is Lease */
+                                   0);
 }
 
 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)