[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Fri Apr 23 00:54:23 MDT 2010


The branch, master has been updated
       via  8f67f87... Make deferred opens (NT_STATUS_SHARING_VIOLATION) work over SMB2.
      from  9cd712d... s3: Fix a cut&paste error in a debug message in check_oem_password()

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 8f67f873ace91964da066c421986e260aceba75b
Author: Jeremy Allison <jra at samba.org>
Date:   Thu Apr 22 23:52:19 2010 -0700

    Make deferred opens (NT_STATUS_SHARING_VIOLATION) work over SMB2.
    
    Makes SMB2Create call re-entrant internally.
    Now this infrastructure is in place, oplocks will follow shortly.
    Tested with Win7 client and with W2K8R2.
    
    Jeremy.

-----------------------------------------------------------------------

Summary of changes:
 source3/include/proto.h      |    2 +-
 source3/modules/onefs_open.c |    2 +-
 source3/smbd/globals.h       |   15 ++-
 source3/smbd/open.c          |    2 +-
 source3/smbd/process.c       |    8 +-
 source3/smbd/smb2_create.c   |  364 ++++++++++++++++++++++++++++++++++++++----
 source3/smbd/smb2_glue.c     |   32 ----
 source3/smbd/smb2_server.c   |   17 +-
 8 files changed, 357 insertions(+), 85 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 71962ae..7b279f6 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -6812,7 +6812,7 @@ int srv_set_message(char *buf,
 void remove_deferred_open_message_smb(uint64_t mid);
 void schedule_deferred_open_message_smb(uint64_t mid);
 bool open_was_deferred(uint64_t mid);
-bool get_deferred_open_message_state(uint64_t mid,
+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,
diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c
index b0c88c7..a1412ef 100644
--- a/source3/modules/onefs_open.c
+++ b/source3/modules/onefs_open.c
@@ -544,7 +544,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 
 	if (req) {
 		void *ptr;
-		if (get_deferred_open_message_state(req->mid,
+		if (get_deferred_open_message_state(req,
 				&request_time,
 				&ptr)) {
 			struct deferred_open_record *state = (struct deferred_open_record *)ptr;
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 951d352..a86f0e9 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -318,6 +318,10 @@ NTSTATUS smbd_smb2_request_process_notify(struct smbd_smb2_request *req);
 NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req);
 NTSTATUS smbd_smb2_request_process_setinfo(struct smbd_smb2_request *req);
 NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req);
+NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req);
+void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
+				struct tevent_immediate *im,
+				void *private_data);
 
 /* SMB1 -> SMB2 glue. */
 void send_break_message_smb2(files_struct *fsp, uint8_t level);
@@ -332,13 +336,14 @@ bool push_blocking_lock_request_smb2( struct byte_range_lock *br_lck,
 				uint64_t offset,
 				uint64_t count,
 				uint32_t blocking_pid);
-void remove_deferred_open_message_smb2(uint64_t mid);
-void schedule_deferred_open_message_smb2(uint64_t mid);
-bool open_was_deferred_smb2(uint64_t mid);
-bool get_deferred_open_message_state_smb2(uint64_t mid,
+/* From smbd/smb2_create.c */
+bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req,
 			struct timeval *p_request_time,
 			void **pp_state);
-bool push_deferred_open_message_smb2(struct smb_request *req,
+bool open_was_deferred_smb2(uint64_t mid);
+void remove_deferred_open_message_smb2(uint64_t mid);
+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,
 			char *private_data,
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 0e45c1d..e0c24da 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1546,7 +1546,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
 	if (req) {
 		void *ptr;
-		if (get_deferred_open_message_state(req->mid,
+		if (get_deferred_open_message_state(req,
 				&request_time,
 				&ptr)) {
 
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 8d3c65a..a483898 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -726,19 +726,19 @@ static struct pending_message_list *get_deferred_open_message_smb(uint64_t mid)
  Get the state data queued by this mid.
 ****************************************************************************/
 
-bool get_deferred_open_message_state(uint64_t mid,
+bool get_deferred_open_message_state(struct smb_request *smbreq,
 				struct timeval *p_request_time,
 				void **pp_state)
 {
 	struct pending_message_list *pml;
 
 	if (smbd_server_conn->allow_smb2) {
-		return get_deferred_open_message_state_smb2(mid,
+		return get_deferred_open_message_state_smb2(smbreq->smb2req,
 					p_request_time,
 					pp_state);
 	}
 
-	pml = get_deferred_open_message_smb(mid);
+	pml = get_deferred_open_message_smb(smbreq->mid);
 	if (!pml) {
 		return false;
 	}
@@ -764,7 +764,7 @@ bool push_deferred_open_message_smb(struct smb_request *req,
 	struct timeval end_time;
 
 	if (req->smb2req) {
-		return push_deferred_open_message_smb2(req,
+		return push_deferred_open_message_smb2(req->smb2req,
 						request_time,
 						timeout,
 						private_data,
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index bad0377..7e06914 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -191,6 +191,7 @@ NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *req)
 				       in_name_string,
 				       in_context_blobs);
 	if (subreq == NULL) {
+		req->subreq = NULL;
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
 	}
 	tevent_req_set_callback(subreq, smbd_smb2_request_create_done, req);
@@ -235,7 +236,6 @@ static void smbd_smb2_request_create_done(struct tevent_req *subreq)
 				       &out_file_attributes,
 				       &out_file_id_volatile,
 				       &out_context_blobs);
-	TALLOC_FREE(subreq);
 	if (!NT_STATUS_IS_OK(status)) {
 		error = smbd_smb2_request_error(req, status);
 		if (!NT_STATUS_IS_OK(error)) {
@@ -315,6 +315,10 @@ static void smbd_smb2_request_create_done(struct tevent_req *subreq)
 
 struct smbd_smb2_create_state {
 	struct smbd_smb2_request *smb2req;
+	struct smb_request *smb1req;
+	struct timed_event *te;
+	struct timeval request_time;
+	DATA_BLOB private_data;
 	uint8_t out_oplock_level;
 	uint32_t out_create_action;
 	NTTIME out_creation_time;
@@ -341,33 +345,45 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			const char *in_name,
 			struct smb2_create_blobs in_context_blobs)
 {
-	struct tevent_req *req;
-	struct smbd_smb2_create_state *state;
+	struct tevent_req *req = NULL;
+	struct smbd_smb2_create_state *state = NULL;
 	NTSTATUS status;
-	struct smb_request *smbreq;
-	files_struct *result;
+	struct smb_request *smb1req = NULL;
+	files_struct *result = NULL;
 	int info;
 	struct timespec write_time_ts;
 	struct smb2_create_blobs out_context_blobs;
 
 	ZERO_STRUCT(out_context_blobs);
 
-	req = tevent_req_create(mem_ctx, &state,
+	if (!smb2req->async) {
+		/* New create call. */
+		req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_create_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	state->smb2req = smb2req;
-
-	DEBUG(10,("smbd_smb2_create: name[%s]\n",
-		  in_name));
+		if (req == NULL) {
+			return NULL;
+		}
+		state->smb2req = smb2req;
+		smb2req->subreq = req; /* So we can find this when going async. */
 
-	smbreq = smbd_smb2_fake_smb_request(smb2req);
-	if (tevent_req_nomem(smbreq, req)) {
-		return tevent_req_post(req, ev);
+		smb1req = smbd_smb2_fake_smb_request(smb2req);
+		if (tevent_req_nomem(smb1req, req)) {
+			return tevent_req_post(req, ev);
+		}
+		state->smb1req = smb1req;
+		DEBUG(10,("smbd_smb2_create: name[%s]\n",
+			in_name));
+	} else {
+		/* Re-entrant create call. */
+		req = smb2req->subreq;
+		state = tevent_req_data(req,
+				struct smbd_smb2_create_state);
+		smb1req = state->smb1req;
+		DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
+			in_name ));
 	}
 
-	if (IS_IPC(smbreq->conn)) {
+	if (IS_IPC(smb1req->conn)) {
 		const char *pipe_name = in_name;
 
 		if (!lp_nt_pipe_support()) {
@@ -380,26 +396,26 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			pipe_name++;
 		}
 
-		status = open_np_file(smbreq, pipe_name, &result);
+		status = open_np_file(smb1req, pipe_name, &result);
 		if (!NT_STATUS_IS_OK(status)) {
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
 		info = FILE_WAS_OPENED;
-	} else if (CAN_PRINT(smbreq->conn)) {
-		status = file_new(smbreq, smbreq->conn, &result);
+	} else if (CAN_PRINT(smb1req->conn)) {
+		status = file_new(smb1req, smb1req->conn, &result);
 		if(!NT_STATUS_IS_OK(status)) {
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
 
-		status = print_fsp_open(smbreq,
-					smbreq->conn,
+		status = print_fsp_open(smb1req,
+					smb1req->conn,
 					in_name,
-					smbreq->vuid,
+					smb1req->vuid,
 					result);
 		if (!NT_STATUS_IS_OK(status)) {
-			file_free(smbreq, result);
+			file_free(smb1req, result);
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
@@ -589,8 +605,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 
 		status = filename_convert(req,
-					  smbreq->conn,
-					  smbreq->flags2 & FLAGS2_DFS_PATHNAMES,
+					  smb1req->conn,
+					  smb1req->flags2 & FLAGS2_DFS_PATHNAMES,
 					  fname,
 					  0,
 					  NULL,
@@ -600,8 +616,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			return tevent_req_post(req, ev);
 		}
 
-		status = SMB_VFS_CREATE_FILE(smbreq->conn,
-					     smbreq,
+		status = SMB_VFS_CREATE_FILE(smb1req->conn,
+					     smb1req,
 					     0, /* root_dir_fid */
 					     smb_fname,
 					     in_desired_access,
@@ -617,8 +633,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					     &result,
 					     &info);
 		if (!NT_STATUS_IS_OK(status)) {
+			if (open_was_deferred(smb1req->mid)) {
+				return req;
+			}
 			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
+			req = tevent_req_post(req, ev);
+			return req;
 		}
 
 		if (mxac) {
@@ -631,7 +651,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				uint32_t max_access_granted;
 				DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
-				status = smbd_check_open_rights(smbreq->conn,
+				status = smbd_check_open_rights(smb1req->conn,
 							result->fsp_name,
 							SEC_FLAG_MAXIMUM_ALLOWED,
 							&max_access_granted);
@@ -670,7 +690,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	smb2req->compat_chain_fsp = smbreq->chain_fsp;
+	smb2req->compat_chain_fsp = smb1req->chain_fsp;
 
 	state->out_oplock_level	= 0;
 	if ((in_create_disposition == FILE_SUPERSEDE)
@@ -690,14 +710,14 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	}
 
 	unix_timespec_to_nt_time(&state->out_creation_time,
-			get_create_timespec(smbreq->conn, result,
+			get_create_timespec(smb1req->conn, result,
 					result->fsp_name));
 	unix_timespec_to_nt_time(&state->out_last_access_time,
 			result->fsp_name->st.st_ex_atime);
 	unix_timespec_to_nt_time(&state->out_last_write_time,
 			result->fsp_name->st.st_ex_mtime);
 	unix_timespec_to_nt_time(&state->out_change_time,
-			get_change_timespec(smbreq->conn, result,
+			get_change_timespec(smb1req->conn, result,
 					result->fsp_name));
 	state->out_allocation_size =
 			result->fsp_name->st.st_ex_blksize *
@@ -753,3 +773,281 @@ static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
 	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
+
+/*********************************************************
+ Code for dealing with deferred opens.
+*********************************************************/
+
+bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req,
+			struct timeval *p_request_time,
+			void **pp_state)
+{
+	struct smbd_smb2_create_state *state = NULL;
+	struct tevent_req *req = NULL;
+
+	if (!smb2req) {
+		return false;
+	}
+	if (!smb2req->async) {
+		return false;
+	}
+	req = smb2req->subreq;
+	if (!req) {
+		return false;
+	}
+	state = tevent_req_data(req, struct smbd_smb2_create_state);
+	if (!state) {
+		return false;
+	}
+	if (p_request_time) {
+		*p_request_time = state->request_time;
+	}
+	if (pp_state) {
+		*pp_state = (void *)state->private_data.data;
+	}
+	return true;
+}
+
+/*********************************************************
+ Re-process this call early - requested by message or
+ close.
+*********************************************************/
+
+static struct smbd_smb2_request *find_open_smb2req(uint64_t mid)
+{
+	struct smbd_server_connection *sconn = smbd_server_conn;
+	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);
+		if (message_id == mid) {
+			return smb2req;
+		}
+	}
+	return NULL;
+}
+
+bool open_was_deferred_smb2(uint64_t mid)
+{
+	struct smbd_smb2_create_state *state = NULL;
+	struct smbd_smb2_request *smb2req = find_open_smb2req(mid);
+
+	if (!smb2req) {
+		DEBUG(10,("open_was_deferred_smb2: mid %llu smb2req == NULL\n",
+			(unsigned long long)mid));
+		return false;
+	}
+	if (!smb2req->subreq) {
+		return false;
+	}
+	if (!tevent_req_is_in_progress(smb2req->subreq)) {
+		return false;
+	}
+	state = tevent_req_data(smb2req->subreq,
+			struct smbd_smb2_create_state);
+	if (!state) {
+		return false;
+	}
+	/* It's not in progress if there's no timeout event. */
+	if (!state->te) {
+		return false;
+	}
+
+	DEBUG(10,("open_was_deferred_smb2: mid = %llu\n",
+			(unsigned long long)mid));
+	
+	return true;
+}
+
+void remove_deferred_open_message_smb2(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;
+	}
+	if (!tevent_req_is_in_progress(smb2req->subreq)) {
+		return;
+	}
+	state = tevent_req_data(smb2req->subreq,
+			struct smbd_smb2_create_state);
+	if (!state) {
+		return;
+	}
+
+	DEBUG(10,("remove_deferred_open_message_smb2: "
+		"mid %llu\n",
+		(unsigned long long)mid ));
+
+	/* Ensure we don't have any outstanding timer event. */
+	TALLOC_FREE(state->te);
+}
+
+void schedule_deferred_open_message_smb2(uint64_t mid)
+{
+	struct tevent_immediate *im = NULL;
+	struct smbd_smb2_create_state *state = NULL;
+	struct smbd_smb2_request *smb2req = find_open_smb2req(mid);
+
+	if (!smb2req) {
+		DEBUG(10,("schedule_deferred_open_message_smb2: "
+			"can't find mid %llu\n",
+			(unsigned long long)mid ));
+		return;
+	}
+	if (!smb2req->subreq) {
+		return;
+	}
+	if (!tevent_req_is_in_progress(smb2req->subreq)) {
+		return;
+	}
+	state = tevent_req_data(smb2req->subreq,
+			struct smbd_smb2_create_state);
+	if (!state) {
+		return;
+	}
+	/* Ensure we don't have any outstanding timer event. */
+	TALLOC_FREE(state->te);
+
+	im = tevent_create_immediate(smb2req);
+	if (!im) {
+		smbd_server_connection_terminate(smb2req->sconn,
+			nt_errstr(NT_STATUS_NO_MEMORY));
+	}
+
+	DEBUG(10,("schedule_deferred_open_message_smb2: "
+		"re-processing mid %llu\n",
+		(unsigned long long)mid ));
+
+	tevent_schedule_immediate(im,
+			smb2req->sconn->smb2.event_ctx,
+			smbd_smb2_request_dispatch_immediate,
+			smb2req);
+}
+
+/*********************************************************
+ Re-process this call.
+*********************************************************/
+
+static void smb2_deferred_open_timer(struct event_context *ev,
+					struct timed_event *te,
+					struct timeval _tval,
+					void *private_data)
+{
+	NTSTATUS status;
+	struct smbd_smb2_create_state *state = NULL;
+	struct smbd_smb2_request *smb2req = talloc_get_type(private_data,
+						struct smbd_smb2_request);
+
+	DEBUG(10,("smb2_deferred_open_timer: [idx=%d], %s\n",
+		smb2req->current_idx,
+		tevent_req_default_print(smb2req->subreq, talloc_tos()) ));
+
+	state = tevent_req_data(smb2req->subreq,
+			struct smbd_smb2_create_state);
+	if (!state) {
+		return;
+	}
+	/*
+	 * Null this out, don't talloc_free. It will
+	 * be talloc_free'd by the tevent library when
+	 * this returns.
+	 */


-- 
Samba Shared Repository


More information about the samba-cvs mailing list