[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Sat Apr 24 01:31:29 MDT 2010


The branch, master has been updated
       via  a796542... Implement oplocks within SMB2. Plumb into the existing SMB1 oplock system.
      from  2472731... When sending the initial async response, this is never part of a chain.

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


- Log -----------------------------------------------------------------
commit a796542a930dec93c2a747c4b015d8d650a081fd
Author: Jeremy Allison <jra at samba.org>
Date:   Sat Apr 24 00:29:41 2010 -0700

    Implement oplocks within SMB2. Plumb into the existing SMB1 oplock system.
    
    Seems to work but needs more tests (to be added).
    
    Jeremy.

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

Summary of changes:
 source3/smbd/globals.h     |    5 ++-
 source3/smbd/oplock.c      |    6 ++--
 source3/smbd/smb2_break.c  |   70 +++++++++++++++++++++++++++++++++++++++----
 source3/smbd/smb2_create.c |   43 +++++++++++++++++++++++++-
 source3/smbd/smb2_server.c |    5 +--
 5 files changed, 112 insertions(+), 17 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 4d1a13d..aa0018f 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -288,7 +288,6 @@ NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
 	smbd_smb2_request_done_ex(req, NT_STATUS_OK, body, dyn, __location__)
 
 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
-				     uint64_t file_id_persistent,
 				     uint64_t file_id_volatile,
 				     uint8_t oplock_level);
 
@@ -324,7 +323,7 @@ void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
 				void *private_data);
 
 /* SMB1 -> SMB2 glue. */
-void send_break_message_smb2(files_struct *fsp, uint8_t level);
+void send_break_message_smb2(files_struct *fsp, int level);
 bool push_blocking_lock_request_smb2( struct byte_range_lock *br_lck,
 				struct smb_request *req,
 				files_struct *fsp,
@@ -337,6 +336,8 @@ bool push_blocking_lock_request_smb2( struct byte_range_lock *br_lck,
 				uint64_t count,
 				uint32_t blocking_pid);
 /* From smbd/smb2_create.c */
+int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level);
+uint8_t map_samba_oplock_levels_to_smb2(int oplock_type);
 bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req,
 			struct timeval *p_request_time,
 			void **pp_state);
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 2289787..c22a589 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -215,7 +215,7 @@ bool should_notify_deferred_opens()
 ****************************************************************************/
 
 static char *new_break_message_smb1(TALLOC_CTX *mem_ctx,
-				   files_struct *fsp, uint8 cmd)
+				   files_struct *fsp, int cmd)
 {
 	char *result = TALLOC_ARRAY(mem_ctx, char, smb_size + 8*2 + 0);
 
@@ -345,7 +345,7 @@ static void add_oplock_timeout_handler(files_struct *fsp)
 	}
 
 	fsp->oplock_timeout =
-		event_add_timed(smbd_event_context(), NULL,
+		event_add_timed(smbd_event_context(), fsp,
 				timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
 				oplock_timeout_handler, fsp);
 
@@ -354,7 +354,7 @@ static void add_oplock_timeout_handler(files_struct *fsp)
 	}
 }
 
-static void send_break_message_smb1(files_struct *fsp, uint8_t level)
+static void send_break_message_smb1(files_struct *fsp, int level)
 {
 	char *break_msg = new_break_message_smb1(talloc_tos(),
 					fsp,
diff --git a/source3/smbd/smb2_break.c b/source3/smbd/smb2_break.c
index 8bb1bfc..d28bbf5 100644
--- a/source3/smbd/smb2_break.c
+++ b/source3/smbd/smb2_break.c
@@ -56,6 +56,12 @@ NTSTATUS smbd_smb2_request_process_break(struct smbd_smb2_request *req)
 	}
 
 	in_oplock_level		= CVAL(inbody, 0x02);
+
+	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);
+	}
+
 	/* 0x03 1 bytes reserved */
 	/* 0x04 4 bytes reserved */
 	in_file_id_persistent		= BVAL(inbody, 0x08);
@@ -123,7 +129,7 @@ static void smbd_smb2_request_oplock_break_done(struct tevent_req *subreq)
 
 	SSVAL(outbody.data, 0x00, 0x18);	/* struct size */
 	SCVAL(outbody.data, 0x02,
-	      out_oplock_level);		/* oplock level */
+	      out_oplock_level);		/* SMB2 oplock level */
 	SCVAL(outbody.data, 0x03, 0);		/* reserved */
 	SIVAL(outbody.data, 0x04, 0);		/* reserved */
 	SBVAL(outbody.data, 0x08,
@@ -141,7 +147,7 @@ static void smbd_smb2_request_oplock_break_done(struct tevent_req *subreq)
 
 struct smbd_smb2_oplock_break_state {
 	struct smbd_smb2_request *smb2req;
-	uint8_t out_oplock_level;
+	uint8_t out_oplock_level; /* SMB2 oplock level. */
 };
 
 static struct tevent_req *smbd_smb2_oplock_break_send(TALLOC_CTX *mem_ctx,
@@ -154,7 +160,10 @@ static struct tevent_req *smbd_smb2_oplock_break_send(TALLOC_CTX *mem_ctx,
 	struct smbd_smb2_oplock_break_state *state;
 	struct smb_request *smbreq;
 	connection_struct *conn = smb2req->tcon->compat_conn;
-	files_struct *fsp;
+	files_struct *fsp = NULL;
+	int oplocklevel = map_smb2_oplock_levels_to_samba(in_oplock_level);
+	bool break_to_none = (oplocklevel == NO_OPLOCK);
+	bool result;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_oplock_break_state);
@@ -164,8 +173,10 @@ static struct tevent_req *smbd_smb2_oplock_break_send(TALLOC_CTX *mem_ctx,
 	state->smb2req = smb2req;
 	state->out_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 
-	DEBUG(10,("smbd_smb2_oplock_break_send: file_id[0x%016llX]\n",
-		  (unsigned long long)in_file_id_volatile));
+	DEBUG(10,("smbd_smb2_oplock_break_send: file_id[0x%016llX] "
+		"samba level %d\n",
+		(unsigned long long)in_file_id_volatile,
+		oplocklevel));
 
 	smbreq = smbd_smb2_fake_smb_request(smb2req);
 	if (tevent_req_nomem(smbreq, req)) {
@@ -186,7 +197,31 @@ static struct tevent_req *smbd_smb2_oplock_break_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
+	DEBUG(5,("smbd_smb2_oplock_break_send: got SMB2 oplock break (%u) from client "
+		"for file %s fnum = %d\n",
+		(unsigned int)in_oplock_level,
+		fsp_str_dbg(fsp),
+		fsp->fnum ));
+
+	if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
+			(break_to_none)) {
+		result = remove_oplock(fsp);
+		state->out_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+	} else {
+		result = downgrade_oplock(fsp);
+		state->out_oplock_level = SMB2_OPLOCK_LEVEL_II;
+	}
+
+	if (!result) {
+		DEBUG(0, ("smbd_smb2_oplock_break_send: error in removing "
+			"oplock on file %s\n", fsp_str_dbg(fsp)));
+		/* Hmmm. Is this panic justified? */
+		smb_panic("internal tdb error");
+	}
+
+	reply_to_oplock_break_requests(fsp);
+
+	tevent_req_done(req);
 	return tevent_req_post(req, ev);
 }
 
@@ -209,6 +244,27 @@ static NTSTATUS smbd_smb2_oplock_break_recv(struct tevent_req *req,
 	return NT_STATUS_OK;
 }
 
-void send_break_message_smb2(files_struct *fsp, uint8_t level)
+/*********************************************************
+ Create and send an asynchronous
+ SMB2 OPLOCK_BREAK_NOTIFICATION.
+*********************************************************/
+
+void send_break_message_smb2(files_struct *fsp, int level)
 {
+	uint8_t smb2_oplock_level = map_samba_oplock_levels_to_smb2(level);
+	NTSTATUS status;
+
+	DEBUG(10,("send_break_message_smb2: sending oplock break "
+		"for file %s, fnum = %d, smb2 level %u\n",
+		fsp_str_dbg(fsp),
+		fsp->fnum,
+		(unsigned int)smb2_oplock_level ));
+		
+	status = smbd_smb2_send_oplock_break(fsp->conn->sconn,
+					(uint64_t)fsp->fnum,
+					smb2_oplock_level);
+	if (!NT_STATUS_IS_OK(status)) {
+		smbd_server_connection_terminate(fsp->conn->sconn,
+				 nt_errstr(status));
+	}
 }
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index d97d4af..6a118c3 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -22,6 +22,42 @@
 #include "smbd/globals.h"
 #include "../libcli/smb/smb_common.h"
 
+int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
+{
+	switch(in_oplock_level) {
+	case SMB2_OPLOCK_LEVEL_NONE:
+		return NO_OPLOCK;
+	case SMB2_OPLOCK_LEVEL_II:
+		return LEVEL_II_OPLOCK;
+	case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
+		return EXCLUSIVE_OPLOCK;
+	case SMB2_OPLOCK_LEVEL_BATCH:
+		return BATCH_OPLOCK;
+	case SMB2_OPLOCK_LEVEL_LEASE:
+		DEBUG(2,("map_smb2_oplock_levels_to_samba: "
+			"LEASE_OPLOCK_REQUESTED\n"));
+		return NO_OPLOCK;
+	default:
+		DEBUG(2,("map_smb2_oplock_levels_to_samba: "
+			"unknown level %u\n",
+			(unsigned int)in_oplock_level));
+		return NO_OPLOCK;
+	}
+}
+
+uint8_t map_samba_oplock_levels_to_smb2(int oplock_type)
+{
+	if (BATCH_OPLOCK_TYPE(oplock_type)) {
+		return SMB2_OPLOCK_LEVEL_BATCH;
+	} else if (EXCLUSIVE_OPLOCK_TYPE(oplock_type)) {
+		return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+	} else if (LEVEL_II_OPLOCK_TYPE(oplock_type)) {
+		return SMB2_OPLOCK_LEVEL_II;
+	} else {
+		return SMB2_OPLOCK_LEVEL_NONE;
+	}
+}
+
 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			struct tevent_context *ev,
 			struct smbd_smb2_request *smb2req,
@@ -636,6 +672,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			return tevent_req_post(req, ev);
 		}
 
+		in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+
 		status = SMB_VFS_CREATE_FILE(smb1req->conn,
 					     smb1req,
 					     0, /* root_dir_fid */
@@ -645,7 +683,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					     in_create_disposition,
 					     in_create_options,
 					     in_file_attributes,
-					     0, /* oplock_request */
+					     map_smb2_oplock_levels_to_samba(in_oplock_level),
 					     allocation_size,
 					     0, /* private_flags */
 					     sec_desc,
@@ -711,7 +749,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 	smb2req->compat_chain_fsp = smb1req->chain_fsp;
 
-	state->out_oplock_level	= 0;
+	state->out_oplock_level	= map_samba_oplock_levels_to_smb2(result->oplock_type);
+
 	if ((in_create_disposition == FILE_SUPERSEDE)
 	    && (info == FILE_WAS_OVERWRITTEN)) {
 		state->out_create_action = FILE_WAS_SUPERSEDED;
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 04cace8..8940427 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -49,7 +49,7 @@ static const char *smb2_names[] = {
 
 const char *smb2_opcode_name(uint16_t opcode)
 {
-	if (opcode >= 0x12) {
+	if (opcode > 0x12) {
 		return "Bad SMB2 opcode";
 	}
 	return smb2_names[opcode];
@@ -1427,7 +1427,6 @@ struct smbd_smb2_send_oplock_break_state {
 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
 
 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
-				     uint64_t file_id_persistent,
 				     uint64_t file_id_volatile,
 				     uint8_t oplock_level)
 {
@@ -1468,7 +1467,7 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
 	SCVAL(body, 0x02, oplock_level);
 	SCVAL(body, 0x03, 0);		/* reserved */
 	SIVAL(body, 0x04, 0);		/* reserved */
-	SBVAL(body, 0x08, file_id_persistent);
+	SBVAL(body, 0x08, 0);		/* file_id_persistent */
 	SBVAL(body, 0x10, file_id_volatile);
 
 	subreq = tstream_writev_queue_send(state,


-- 
Samba Shared Repository


More information about the samba-cvs mailing list