smbd: Base smb2_lock.c on tevent_req
authorVolker Lendecke <vl@samba.org>
Sat, 15 Jun 2019 22:23:50 +0000 (15:23 -0700)
committerJeremy Allison <jra@samba.org>
Thu, 20 Jun 2019 17:18:19 +0000 (17:18 +0000)
smb2 locking is a lot more regular than reply_lockingX. So this is a
much smaller change.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/include/vfs.h
source3/smbd/smb2_close.c
source3/smbd/smb2_lock.c

index 059b01135c2630c4f8cc25d3cddc158e1c103a7d..6f6bdbf28ad0c53e637a33ffbfc9316376517891 100644 (file)
@@ -384,6 +384,7 @@ typedef struct files_struct {
         */
        unsigned num_aio_requests;
        struct tevent_req **aio_requests;
+       bool closing;
 
        /*
         * Requests waiting for smb1 byte range locks. They are
index dea9512dfc6e7a9f2274d7326a548359782098c0..93539d4884587bff00872b44b81e564a3e03d600 100644 (file)
@@ -313,6 +313,7 @@ static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
 {
        struct tevent_req *req;
        struct smbd_smb2_close_state *state;
+       unsigned i;
        NTSTATUS status;
 
        req = tevent_req_create(mem_ctx, &state,
@@ -324,6 +325,17 @@ static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
        state->in_fsp = in_fsp;
        state->in_flags = in_flags;
 
+       in_fsp->closing = true;
+
+       i = 0;
+       while (i < in_fsp->num_aio_requests) {
+               bool ok = tevent_req_cancel(in_fsp->aio_requests[i]);
+               if (ok) {
+                       continue;
+               }
+               i += 1;
+       }
+
        if (in_fsp->num_aio_requests != 0) {
                in_fsp->deferred_close = tevent_wait_send(in_fsp, ev);
                if (tevent_req_nomem(in_fsp->deferred_close, req)) {
index d2d8f0adf340c0b704b4b35cdc7d761504509593..856a22eb077e2324555b9daabbe0fb43a2d5318f 100644 (file)
@@ -24,6 +24,8 @@
 #include "smbd/globals.h"
 #include "../libcli/smb/smb_common.h"
 #include "../lib/util/tevent_ntstatus.h"
+#include "lib/dbwrap/dbwrap_watch.h"
+#include "librpc/gen_ndr/open_files.h"
 #include "messages.h"
 
 #undef DBGC_CLASS
@@ -36,8 +38,10 @@ struct smbd_smb2_lock_element {
 };
 
 struct smbd_smb2_lock_state {
+       struct tevent_context *ev;
        struct smbd_smb2_request *smb2req;
        struct smb_request *smb1req;
+       struct files_struct *fsp;
        struct blocking_lock_record *blr;
        uint16_t lock_count;
        struct smbd_lock_element *locks;
@@ -188,6 +192,9 @@ static void smbd_smb2_request_lock_done(struct tevent_req *subreq)
        }
 }
 
+static void smbd_smb2_lock_retry(struct tevent_req *subreq);
+static bool smbd_smb2_lock_cancel(struct tevent_req *req);
+
 static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
                                                 struct tevent_context *ev,
                                                 struct smbd_smb2_request *smb2req,
@@ -197,27 +204,30 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
 {
        struct tevent_req *req;
        struct smbd_smb2_lock_state *state;
-       struct smb_request *smb1req;
-       int32_t timeout = -1;
+       bool blocking = false;
        bool isunlock = false;
        uint16_t i;
        struct smbd_lock_element *locks;
+       struct share_mode_lock *lck = NULL;
+       uint16_t blocker_idx;
+       struct server_id blocking_pid = { 0 };
+       uint64_t blocking_smblctx;
        NTSTATUS status;
-       bool async = false;
 
        req = tevent_req_create(mem_ctx, &state,
                        struct smbd_smb2_lock_state);
        if (req == NULL) {
                return NULL;
        }
+       state->ev = ev;
+       state->fsp = fsp;
        state->smb2req = smb2req;
        smb2req->subreq = req; /* So we can find this when going async. */
 
-       smb1req = smbd_smb2_fake_smb_request(smb2req);
-       if (tevent_req_nomem(smb1req, req)) {
+       state->smb1req = smbd_smb2_fake_smb_request(smb2req);
+       if (tevent_req_nomem(state->smb1req, req)) {
                return tevent_req_post(req, ev);
        }
-       state->smb1req = smb1req;
 
        DEBUG(10,("smbd_smb2_lock_send: %s - %s\n",
                  fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
@@ -235,19 +245,17 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
                        tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
                        return tevent_req_post(req, ev);
                }
-               timeout = -1;
+               blocking = true;
                break;
 
        case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY:
        case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY:
-               timeout = 0;
                break;
 
        case SMB2_LOCK_FLAG_UNLOCK:
                /* only the first lock gives the UNLOCK bit - see
                   MS-SMB2 3.3.5.14 */
                isunlock = true;
-               timeout = 0;
                break;
 
        default:
@@ -349,7 +357,7 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
 
        if (isunlock) {
                status = smbd_do_unlocking(
-                       smb1req, fsp, in_lock_count, locks, WINDOWS_LOCK);
+                       state->smb1req, fsp, in_lock_count, locks, WINDOWS_LOCK);
 
                if (tevent_req_nterror(req, status)) {
                        return tevent_req_post(req, ev);
@@ -358,27 +366,103 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       status = smbd_do_locking(
-               smb1req, fsp, timeout, in_lock_count, locks, &async);
+       lck = get_existing_share_mode_lock(
+               talloc_tos(), state->fsp->file_id);
+       if (tevent_req_nomem(lck, req)) {
+               return tevent_req_post(req, ev);
+       }
 
-       if (!NT_STATUS_IS_OK(status)) {
-               if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
-                      status = NT_STATUS_LOCK_NOT_GRANTED;
-               }
-               tevent_req_nterror(req, status);
+       status = smbd_do_locks_try(
+               state->smb1req->sconn->msg_ctx,
+               state->fsp,
+               WINDOWS_LOCK,
+               state->lock_count,
+               state->locks,
+               &blocker_idx,
+               &blocking_pid,
+               &blocking_smblctx);
+
+       if (NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(lck);
+               tevent_req_done(req);
                return tevent_req_post(req, ev);
        }
 
-       if (async) {
+       if (blocking &&
+           (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED) ||
+            NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT))) {
+               struct tevent_req *subreq;
+
+               DBG_DEBUG("Watching share mode lock\n");
+
+               subreq = dbwrap_watched_watch_send(
+                       state, state->ev, lck->data->record, blocking_pid);
+               TALLOC_FREE(lck);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, smbd_smb2_lock_retry, req);
+
                tevent_req_defer_callback(req, smb2req->sconn->ev_ctx);
-               SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
+               aio_add_req_to_fsp(state->fsp, req);
+               tevent_req_set_cancel_fn(req, smbd_smb2_lock_cancel);
+
                return req;
        }
 
-       tevent_req_done(req);
+       TALLOC_FREE(lck);
+       tevent_req_nterror(req, status);
        return tevent_req_post(req, ev);
 }
 
+static void smbd_smb2_lock_retry(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct smbd_smb2_lock_state *state = tevent_req_data(
+               req, struct smbd_smb2_lock_state);
+       struct share_mode_lock *lck = NULL;
+       uint16_t blocker_idx;
+       struct server_id blocking_pid = { 0 };
+       uint64_t blocking_smblctx;
+       NTSTATUS status;
+
+       status = dbwrap_watched_watch_recv(subreq, NULL, NULL);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       lck = get_existing_share_mode_lock(
+               talloc_tos(), state->fsp->file_id);
+       if (tevent_req_nomem(lck, req)) {
+               return;
+       }
+
+       status = smbd_do_locks_try(
+               state->smb1req->sconn->msg_ctx,
+               state->fsp,
+               WINDOWS_LOCK,
+               state->lock_count,
+               state->locks,
+               &blocker_idx,
+               &blocking_pid,
+               &blocking_smblctx);
+       if (NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(lck);
+               tevent_req_done(req);
+               return;
+       }
+
+       subreq = dbwrap_watched_watch_send(
+               state, state->ev, lck->data->record, blocking_pid);
+       TALLOC_FREE(lck);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, smbd_smb2_lock_retry, req);
+}
+
 static NTSTATUS smbd_smb2_lock_recv(struct tevent_req *req)
 {
        return tevent_req_simple_recv_ntstatus(req);
@@ -403,23 +487,14 @@ static bool smbd_smb2_lock_cancel(struct tevent_req *req)
 
        smb2req = state->smb2req;
 
-       remove_pending_lock(state, state->blr);
-
        /*
-        * If the request is canceled because of logoff, tdis or close
+        * If the request is canceled because of close, logoff or tdis
         * the status is NT_STATUS_RANGE_NOT_LOCKED instead of
         * NT_STATUS_CANCELLED.
-        *
-        * Note that the close case is handled in
-        * cancel_pending_lock_requests_by_fid_smb2(SHUTDOWN_CLOSE)
-        * for now.
         */
-       if (!NT_STATUS_IS_OK(smb2req->session->status)) {
-               tevent_req_nterror(req, NT_STATUS_RANGE_NOT_LOCKED);
-               return true;
-       }
-
-       if (!NT_STATUS_IS_OK(smb2req->tcon->status)) {
+       if (state->fsp->closing ||
+           !NT_STATUS_IS_OK(smb2req->session->status) ||
+           !NT_STATUS_IS_OK(smb2req->tcon->status)) {
                tevent_req_nterror(req, NT_STATUS_RANGE_NOT_LOCKED);
                return true;
        }