Allow smb2 create requests to be cancelled.
authorJeremy Allison <jra@samba.org>
Fri, 23 Apr 2010 20:10:15 +0000 (13:10 -0700)
committerJeremy Allison <jra@samba.org>
Fri, 23 Apr 2010 20:10:15 +0000 (13:10 -0700)
Jeremy.

source3/include/proto.h
source3/modules/onefs_open.c
source3/smbd/globals.h
source3/smbd/open.c
source3/smbd/process.c
source3/smbd/smb2_create.c

index 073a0dc989243ea0676201a319641606eef6828f..d4e7f3902628627067b14affa5980de6675df703 100644 (file)
@@ -6658,6 +6658,7 @@ bool map_open_params_to_ntcreate(const struct smb_filename *smb_fname,
                                 uint32 *pcreate_disposition,
                                 uint32 *pcreate_options,
                                 uint32_t *pprivate_flags);
+void remove_deferred_open_entry(struct file_id id, uint64_t mid);
 NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn,
                          struct smb_filename *smb_fname,
                          files_struct **result);
@@ -6819,9 +6820,11 @@ bool get_deferred_open_message_state(struct smb_request *smbreq,
                                struct timeval *p_request_time,
                                void **pp_state);
 bool push_deferred_open_message_smb(struct smb_request *req,
-                              struct timeval request_time,
-                              struct timeval timeout,
-                              char *private_data, size_t priv_len);
+                               struct timeval request_time,
+                               struct timeval timeout,
+                               struct file_id id,
+                               char *private_data,
+                               size_t priv_len);
 struct idle_event *event_add_idle(struct event_context *event_ctx,
                                  TALLOC_CTX *mem_ctx,
                                  struct timeval interval,
index a1412ef3e84a402cf1d201d125dc801a702d332d..e97fe9e38a13209b3b8829d9b00b1d6b878148da 100644 (file)
@@ -373,7 +373,7 @@ static void defer_open(struct share_mode_lock *lck,
                  (unsigned long long)req->mid));
 
        if (!push_deferred_open_message_smb(req, request_time, timeout,
-                                      (char *)state, sizeof(*state))) {
+                                      state->id, (char *)state, sizeof(*state))) {
                exit_server("push_deferred_open_message_smb failed");
        }
        add_deferred_open(lck, req->mid, request_time, state->id);
@@ -554,14 +554,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
                           see if this has timed out. */
 
                        /* Remove the deferred open entry under lock. */
-                       lck = get_share_mode_lock(talloc_tos(), state->id,
-                                       NULL, NULL, NULL);
-                       if (lck == NULL) {
-                               DEBUG(0, ("could not get share mode lock\n"));
-                       } else {
-                               del_deferred_open_entry(lck, req->mid);
-                               TALLOC_FREE(lck);
-                       }
+                       remove_deferred_open_entry(state->id, req->mid);
 
                        /* Ensure we don't reprocess this message. */
                        remove_deferred_open_message_smb(req->mid);
index a86f0e9bc203339002591e12039887facb9811cc..4d1a13d3b10397b4b24fcce1b3fb3ce3e5d3fb6b 100644 (file)
@@ -346,6 +346,7 @@ void schedule_deferred_open_message_smb2(uint64_t mid);
 bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
                        struct timeval request_time,
                        struct timeval timeout,
+                       struct file_id id,
                        char *private_data,
                        size_t priv_len);
 
index e0c24dab8d7fbf8ea595ebd2ba4f7f9651479460..f49aca84294b7fc1da20abb3cacf74782b05a30c 100644 (file)
@@ -1085,7 +1085,7 @@ static void defer_open(struct share_mode_lock *lck,
                  (unsigned long long)req->mid));
 
        if (!push_deferred_open_message_smb(req, request_time, timeout,
-                                      (char *)state, sizeof(*state))) {
+                                      state->id, (char *)state, sizeof(*state))) {
                exit_server("push_deferred_open_message_smb failed");
        }
        add_deferred_open(lck, req->mid, request_time, state->id);
@@ -1448,6 +1448,22 @@ static NTSTATUS calculate_access_mask(connection_struct *conn,
        return NT_STATUS_OK;
 }
 
+/****************************************************************************
+ Remove the deferred open entry under lock.
+****************************************************************************/
+
+void remove_deferred_open_entry(struct file_id id, uint64_t mid)
+{
+       struct share_mode_lock *lck = get_share_mode_lock(talloc_tos(), id,
+                       NULL, NULL, NULL);
+       if (lck == NULL) {
+               DEBUG(0, ("could not get share mode lock\n"));
+       } else {
+               del_deferred_open_entry(lck, mid);
+               TALLOC_FREE(lck);
+       }
+}
+
 /****************************************************************************
  Open a file with a share mode. Passed in an already created files_struct *.
 ****************************************************************************/
@@ -1556,14 +1572,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                           see if this has timed out. */
 
                        /* Remove the deferred open entry under lock. */
-                       lck = get_share_mode_lock(talloc_tos(), state->id,
-                                       NULL, NULL, NULL);
-                       if (lck == NULL) {
-                               DEBUG(0, ("could not get share mode lock\n"));
-                       } else {
-                               del_deferred_open_entry(lck, req->mid);
-                               TALLOC_FREE(lck);
-                       }
+                       remove_deferred_open_entry(state->id, req->mid);
 
                        /* Ensure we don't reprocess this message. */
                        remove_deferred_open_message_smb(req->mid);
index a4838987a3ce39b88a74342e7c2f9ef6f42cb509..bbfa052de4ead9946ad61c4c9dfab398943400ad 100644 (file)
@@ -759,6 +759,7 @@ bool get_deferred_open_message_state(struct smb_request *smbreq,
 bool push_deferred_open_message_smb(struct smb_request *req,
                               struct timeval request_time,
                               struct timeval timeout,
+                              struct file_id id,
                               char *private_data, size_t priv_len)
 {
        struct timeval end_time;
@@ -767,6 +768,7 @@ bool push_deferred_open_message_smb(struct smb_request *req,
                return push_deferred_open_message_smb2(req->smb2req,
                                                request_time,
                                                timeout,
+                                               id,
                                                private_data,
                                                priv_len);
        }
index ec20b7c365c84d40c7b083ae3a573313f57ec6e5..d97d4af63a906bf5b74f71c483767c2ef005636e 100644 (file)
@@ -199,6 +199,12 @@ NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
        return smbd_smb2_request_pending_queue(smb2req, tsubreq);
 }
 
+static uint64_t get_mid_from_smb2req(struct smbd_smb2_request *smb2req)
+{
+       uint8_t *reqhdr = (uint8_t *)smb2req->out.vector[smb2req->current_idx].iov_base;
+       return BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
+}
+
 static void smbd_smb2_request_create_done(struct tevent_req *tsubreq)
 {
        struct smbd_smb2_request *smb2req = tevent_req_callback_data(tsubreq,
@@ -223,6 +229,19 @@ static void smbd_smb2_request_create_done(struct tevent_req *tsubreq)
        NTSTATUS status;
        NTSTATUS error; /* transport error */
 
+       if (smb2req->cancelled) {
+               uint64_t mid = get_mid_from_smb2req(smb2req);
+               DEBUG(10,("smbd_smb2_request_create_done: cancelled mid %llu\n",
+                       (unsigned long long)mid ));
+               error = smbd_smb2_request_error(smb2req, NT_STATUS_CANCELLED);
+               if (!NT_STATUS_IS_OK(error)) {
+                       smbd_server_connection_terminate(smb2req->sconn,
+                               nt_errstr(error));
+                       return;
+               }
+               return;
+       }
+
        status = smbd_smb2_create_recv(tsubreq,
                                       smb2req,
                                       &out_oplock_level,
@@ -318,6 +337,7 @@ struct smbd_smb2_create_state {
        struct smb_request *smb1req;
        struct timed_event *te;
        struct timeval request_time;
+       struct file_id id;
        DATA_BLOB private_data;
        uint8_t out_oplock_level;
        uint32_t out_create_action;
@@ -818,8 +838,7 @@ static struct smbd_smb2_request *find_open_smb2req(uint64_t mid)
        struct smbd_smb2_request *smb2req;
 
        for (smb2req = sconn->smb2.requests; smb2req; smb2req = smb2req->next) {
-               uint8_t *reqhdr = (uint8_t *)smb2req->out.vector[smb2req->current_idx].iov_base;
-               uint64_t message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
+               uint64_t message_id = get_mid_from_smb2req(smb2req);
                if (message_id == mid) {
                        return smb2req;
                }
@@ -859,17 +878,11 @@ bool open_was_deferred_smb2(uint64_t mid)
        return true;
 }
 
-void remove_deferred_open_message_smb2(uint64_t mid)
+static void remove_deferred_open_message_smb2_internal(struct smbd_smb2_request *smb2req,
+                                                       uint64_t mid)
 {
        struct smbd_smb2_create_state *state = NULL;
-       struct smbd_smb2_request *smb2req = find_open_smb2req(mid);
 
-       if (!smb2req) {
-               DEBUG(10,("remove_deferred_open_message_smb2: "
-                       "can't find mid %llu\n",
-                       (unsigned long long)mid ));
-               return;
-       }
        if (!smb2req->subreq) {
                return;
        }
@@ -882,7 +895,7 @@ void remove_deferred_open_message_smb2(uint64_t mid)
                return;
        }
 
-       DEBUG(10,("remove_deferred_open_message_smb2: "
+       DEBUG(10,("remove_deferred_open_message_smb2_internal: "
                "mid %llu\n",
                (unsigned long long)mid ));
 
@@ -890,6 +903,19 @@ void remove_deferred_open_message_smb2(uint64_t mid)
        TALLOC_FREE(state->te);
 }
 
+void remove_deferred_open_message_smb2(uint64_t mid)
+{
+       struct smbd_smb2_request *smb2req = find_open_smb2req(mid);
+
+       if (!smb2req) {
+               DEBUG(10,("remove_deferred_open_message_smb2: "
+                       "can't find mid %llu\n",
+                       (unsigned long long)mid ));
+               return;
+       }
+       remove_deferred_open_message_smb2_internal(smb2req, mid);
+}
+
 void schedule_deferred_open_message_smb2(uint64_t mid)
 {
        struct tevent_immediate *im = NULL;
@@ -979,9 +1005,36 @@ static void smb2_deferred_open_timer(struct event_context *ev,
        }
 }
 
+static bool smbd_smb2_create_cancel(struct tevent_req *req)
+{
+       struct smbd_smb2_request *smb2req = NULL;
+       struct smbd_smb2_create_state *state = tevent_req_data(req,
+                               struct smbd_smb2_create_state);
+       uint64_t mid;
+
+       if (!state) {
+               return false;
+       }
+
+       if (!state->smb2req) {
+               return false;
+       }
+
+       smb2req = state->smb2req;
+       mid = get_mid_from_smb2req(smb2req);
+
+       remove_deferred_open_entry(state->id, mid);
+       remove_deferred_open_message_smb2_internal(smb2req, mid);
+       smb2req->cancelled = true;
+
+       tevent_req_done(req);
+       return true;
+}
+
 bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
                                 struct timeval request_time,
                                 struct timeval timeout,
+                               struct file_id id,
                                 char *private_data,
                                 size_t priv_len)
 {
@@ -1000,6 +1053,7 @@ bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
        if (!state) {
                return false;
        }
+       state->id = id;
        state->request_time = request_time;
        state->private_data = data_blob_talloc(state, private_data,
                                                priv_len);
@@ -1048,5 +1102,9 @@ bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
         if (!state->te) {
                return false;
        }
+
+       /* allow this request to be canceled */
+       tevent_req_set_cancel_fn(req, smbd_smb2_create_cancel);
+
        return true;
 }