summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2010-04-23 13:10:15 -0700
committerJeremy Allison <jra@samba.org>2010-04-23 13:10:15 -0700
commit2bbb8c917e372ceeb1e144259d9d2b0eab7cc212 (patch)
treef9cbf789caf28cf2cbd3506e82b575f9ac4af2d8
parentdd2025947136f28b22b70de59309e149a1f45f3d (diff)
downloadsamba-2bbb8c917e372ceeb1e144259d9d2b0eab7cc212.tar.gz
samba-2bbb8c917e372ceeb1e144259d9d2b0eab7cc212.tar.bz2
samba-2bbb8c917e372ceeb1e144259d9d2b0eab7cc212.zip
Allow smb2 create requests to be cancelled.
Jeremy.
-rw-r--r--source3/include/proto.h9
-rw-r--r--source3/modules/onefs_open.c11
-rw-r--r--source3/smbd/globals.h1
-rw-r--r--source3/smbd/open.c27
-rw-r--r--source3/smbd/process.c2
-rw-r--r--source3/smbd/smb2_create.c80
6 files changed, 98 insertions, 32 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 073a0dc989..d4e7f39026 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -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,
diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c
index a1412ef3e8..e97fe9e38a 100644
--- a/source3/modules/onefs_open.c
+++ b/source3/modules/onefs_open.c
@@ -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);
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index a86f0e9bc2..4d1a13d3b1 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -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);
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index e0c24dab8d..f49aca8429 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -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);
@@ -1449,6 +1449,22 @@ static NTSTATUS calculate_access_mask(connection_struct *conn,
}
/****************************************************************************
+ 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);
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index a4838987a3..bbfa052de4 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -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);
}
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index ec20b7c365..d97d4af63a 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -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;
}