[SCM] Samba Shared Repository - branch v3-6-test updated

Jeremy Allison jra at samba.org
Fri Dec 10 17:38:39 MST 2010


The branch, v3-6-test has been updated
       via  5dd10a4 Add documentation for "smb2 max credits". (cherry picked from commit 5562a97ece27c26019504f589d4e7992617f1846)
       via  309db0a Add a SMB2 crediting algorithm, by default the same as Windows. Defaults to 128 credits.
      from  7d4e274 s3-vfstest: fixed paths in vfstest

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-6-test


- Log -----------------------------------------------------------------
commit 5dd10a43d45f66b6da9b3273d2c4b044db97006d
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Dec 10 14:40:17 2010 -0800

    Add documentation for "smb2 max credits".
    (cherry picked from commit 5562a97ece27c26019504f589d4e7992617f1846)

commit 309db0a55cea2d504217a8689005b31d41d5542e
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Dec 10 15:46:41 2010 -0800

    Add a SMB2 crediting algorithm, by default the same as Windows. Defaults to 128 credits.
    
    Jeremy.
    (cherry picked from commit 2ac579ca76452c58022e8b9e41d5168dd25fe3b0)

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

Summary of changes:
 docs-xml/smbdotconf/protocol/smb2maxcredits.xml |   15 +++
 source3/include/local.h                         |    5 +
 source3/include/proto.h                         |    1 +
 source3/param/loadparm.c                        |   25 +++-
 source3/smbd/globals.h                          |    5 +-
 source3/smbd/smb2_server.c                      |  155 +++++++++++++++++++----
 6 files changed, 178 insertions(+), 28 deletions(-)
 create mode 100644 docs-xml/smbdotconf/protocol/smb2maxcredits.xml


Changeset truncated at 500 lines:

diff --git a/docs-xml/smbdotconf/protocol/smb2maxcredits.xml b/docs-xml/smbdotconf/protocol/smb2maxcredits.xml
new file mode 100644
index 0000000..69d04f7
--- /dev/null
+++ b/docs-xml/smbdotconf/protocol/smb2maxcredits.xml
@@ -0,0 +1,15 @@
+<samba:parameter name="smb2 max credits"
+		type="integer"
+		context="G"
+		advanced="1" developer="1"
+		xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+<para>This option controls the maximum number of outstanding simultaneous SMB2 operations
+that Samba tells the client it will allow. This is similar to the <smbconfoption name="max mux"/>
+parameter for SMB1. You should never need to set this parameter.
+</para>
+<para>The default is 128 credits, which is the same as a Windows SMB2 server.</para>
+</description>
+
+<value type="default">128</value>
+</samba:parameter>
diff --git a/source3/include/local.h b/source3/include/local.h
index 6c9a8c3..3014f61 100644
--- a/source3/include/local.h
+++ b/source3/include/local.h
@@ -265,4 +265,9 @@
 #define CLIENT_NDR_PADDING_SIZE 8
 #define SERVER_NDR_PADDING_SIZE 8
 
+#define DEFAULT_SMB2_MAX_READ (1024*1024)
+#define DEFAULT_SMB2_MAX_WRITE (1024*1024)
+#define DEFAULT_SMB2_MAX_TRANSACT (1024*1024)
+#define DEFAULT_SMB2_MAX_CREDITS 128
+
 #endif
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 19c693b..402dc3f 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -3349,6 +3349,7 @@ int lp_config_backend(void);
 int lp_smb2_max_read(void);
 int lp_smb2_max_write(void);
 int lp_smb2_max_trans(void);
+int lp_smb2_max_credits(void);
 char *lp_preexec(int );
 char *lp_postexec(int );
 char *lp_rootpreexec(int );
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 0bc27dc..833358d 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -378,6 +378,7 @@ struct global {
 	int ismb2_max_read;
 	int ismb2_max_write;
 	int ismb2_max_trans;
+	int ismb2_max_credits;
 	char *ncalrpc_dir;
 };
 
@@ -2615,6 +2616,15 @@ static struct parm_struct parm_table[] = {
 		.enum_list	= NULL,
 		.flags		= FLAG_ADVANCED,
 	},
+	{
+		.label		= "smb2 max credits",
+		.type		= P_INTEGER,
+		.p_class	= P_GLOBAL,
+		.ptr		= &Globals.ismb2_max_credits,
+		.special	= NULL,
+		.enum_list	= NULL,
+		.flags		= FLAG_ADVANCED,
+	},
 
 	{N_("Printing Options"), P_SEP, P_SEPARATOR},
 
@@ -5384,9 +5394,10 @@ static void init_globals(bool reinit_globals)
 	Globals.bMapUntrustedToDomain = false;
 	Globals.bMulticastDnsRegister = true;
 
-	Globals.ismb2_max_read = 1024*1024;
-	Globals.ismb2_max_write = 1024*1024;
-	Globals.ismb2_max_trans = 1024*1024;
+	Globals.ismb2_max_read = DEFAULT_SMB2_MAX_READ;
+	Globals.ismb2_max_write = DEFAULT_SMB2_MAX_WRITE;
+	Globals.ismb2_max_trans = DEFAULT_SMB2_MAX_TRANSACT;
+	Globals.ismb2_max_credits = DEFAULT_SMB2_MAX_CREDITS;
 
 	string_set(&Globals.ncalrpc_dir, get_dyn_NCALRPCDIR());
 
@@ -5755,7 +5766,13 @@ FN_GLOBAL_INTEGER(lp_config_backend, &Globals.ConfigBackend)
 FN_GLOBAL_INTEGER(lp_smb2_max_read, &Globals.ismb2_max_read)
 FN_GLOBAL_INTEGER(lp_smb2_max_write, &Globals.ismb2_max_write)
 FN_GLOBAL_INTEGER(lp_smb2_max_trans, &Globals.ismb2_max_trans)
-
+int lp_smb2_max_credits(void)
+{
+	if (Globals.ismb2_max_credits == 0) {
+		Globals.ismb2_max_credits = DEFAULT_SMB2_MAX_CREDITS;
+	}
+	return Globals.ismb2_max_credits;
+}
 FN_LOCAL_STRING(lp_preexec, szPreExec)
 FN_LOCAL_STRING(lp_postexec, szPostExec)
 FN_LOCAL_STRING(lp_rootpreexec, szRootPreExec)
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 5037b6d..cb97cb5 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -581,7 +581,10 @@ struct smbd_server_connection {
 			bool blocking_lock_unlock_state;
 		} locks;
 		struct smbd_smb2_request *requests;
-		uint64_t credits_granted;
+		uint64_t seqnum_low;
+		uint32_t credits_granted;
+		uint32_t max_credits;
+		struct bitmap *credits_bitmap;
 	} smb2;
 };
 
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index eb19d67..9ed74fc 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -110,6 +110,13 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
 	}
 	sconn->smb2.sessions.limit = 0x0000FFFE;
 	sconn->smb2.sessions.list = NULL;
+	sconn->smb2.seqnum_low = 0;
+	sconn->smb2.credits_granted = 1;
+	sconn->smb2.max_credits = lp_smb2_max_credits();
+	sconn->smb2.credits_bitmap = bitmap_talloc(sconn, 2*sconn->smb2.max_credits);
+	if (sconn->smb2.credits_bitmap == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	ret = tstream_bsd_existing_socket(sconn, sconn->sock,
 					  &sconn->smb2.stream);
@@ -284,14 +291,70 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req,
-				uint16_t *p_creds_requested)
+static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
+				const uint8_t *inhdr)
+{
+	uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
+	struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
+	uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
+	unsigned int bitmap_offset;
+
+	if (opcode == SMB2_OP_CANCEL) {
+		/* SMB2_CANCEL requests by definition resend messageids. */
+		return true;
+	}
+
+	if (message_id < sconn->smb2.seqnum_low ||
+			message_id > (sconn->smb2.seqnum_low +
+			(2*sconn->smb2.credits_granted))) {
+		DEBUG(0,("smb2_validate_message_id: bad message_id "
+			"%llu (low = %llu, granted = %lu)\n",
+			(unsigned long long)message_id,
+			(unsigned long long)sconn->smb2.seqnum_low,
+			(unsigned long)sconn->smb2.credits_granted ));
+		return false;
+	}
+
+	/* client just used a credit. */
+	SMB_ASSERT(sconn->smb2.credits_granted > 0);
+	sconn->smb2.credits_granted -= 1;
+
+	/* Mark the message_id as seen in the bitmap. */
+	bitmap_offset = (unsigned int)(message_id %
+			(uint64_t)(sconn->smb2.max_credits * 2));
+	if (bitmap_query(credits_bm, bitmap_offset)) {
+		DEBUG(0,("smb2_validate_message_id: duplicate message_id "
+			"%llu (bm offset %u)\n",
+			(unsigned long long)message_id,
+			bitmap_offset));
+		return false;
+	}
+	bitmap_set(credits_bm, bitmap_offset);
+
+	if (message_id == sconn->smb2.seqnum_low + 1) {
+		/* Move the window forward by all the message_id's
+		   already seen. */
+		while (bitmap_query(credits_bm, bitmap_offset)) {
+			DEBUG(10,("smb2_validate_message_id: clearing "
+				"id %llu (position %u) from bitmap\n",
+				(unsigned long long)(sconn->smb2.seqnum_low + 1),
+				bitmap_offset ));
+			bitmap_clear(credits_bm, bitmap_offset);
+			sconn->smb2.seqnum_low += 1;
+			bitmap_offset = (bitmap_offset + 1) %
+				(sconn->smb2.max_credits * 2);
+		}
+	}
+
+	return true;
+}
+
+static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
 {
 	int count;
 	int idx;
 	bool compound_related = false;
 
-	*p_creds_requested = 0;
 	count = req->in.vector_count;
 
 	if (count < 4) {
@@ -300,7 +363,6 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req,
 	}
 
 	for (idx=1; idx < count; idx += 3) {
-		uint16_t creds_requested = 0;
 		const uint8_t *inhdr = NULL;
 		uint32_t flags;
 
@@ -314,16 +376,13 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req,
 
 		inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
 
-		/* setup the SMB2 header */
+		/* Check the SMB2 header */
 		if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
 			return NT_STATUS_INVALID_PARAMETER;
 		}
 
-		creds_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
-		if (*p_creds_requested + creds_requested < creds_requested) {
-			*p_creds_requested = 65535;
-		} else {
-			*p_creds_requested += creds_requested;
+		if (!smb2_validate_message_id(req->sconn, inhdr)) {
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 
 		flags = IVAL(inhdr, SMB2_HDR_FLAGS);
@@ -374,6 +433,54 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req,
 	return NT_STATUS_OK;
 }
 
+static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
+			const struct iovec *in_vector,
+			struct iovec *out_vector)
+{
+	uint8_t *outhdr = out_vector->iov_base;
+	uint16_t credits_requested = 0;
+	uint16_t credits_granted = 0;
+
+	if (in_vector != NULL) {
+		const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
+		credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
+	}
+
+	SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
+
+	/* Remember what we gave out. */
+	credits_granted = MIN(credits_requested, (sconn->smb2.max_credits -
+		sconn->smb2.credits_granted));
+
+	if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
+		/* Ensure the client credits can never drop to zero. */
+		credits_granted = 1;
+	}
+
+	SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
+	sconn->smb2.credits_granted += credits_granted;
+
+	DEBUG(10,("smb2_set_operation_credit: requested %u, "
+		"granted %u, total granted %u\n",
+		(unsigned int)credits_requested,
+		(unsigned int)credits_granted,
+		(unsigned int)sconn->smb2.credits_granted ));
+}
+
+static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
+				struct smbd_smb2_request *outreq)
+{
+	int count, idx;
+
+	count = outreq->out.vector_count;
+
+	for (idx=1; idx < count; idx += 3) {
+		smb2_set_operation_credit(outreq->sconn,
+			&inreq->in.vector[idx],
+			&outreq->out.vector[idx]);
+	}
+}
+
 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req, uint16_t creds)
 {
 	struct iovec *vector;
@@ -432,11 +539,6 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req, uint1
 		      NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
 		SSVAL(outhdr, SMB2_HDR_OPCODE,
 		      SVAL(inhdr, SMB2_HDR_OPCODE));
-		SSVAL(outhdr, SMB2_HDR_CREDIT,		creds);
-
-		/* Remember what we gave out. */
-		req->sconn->smb2.credits_granted += creds;
-
 		SIVAL(outhdr, SMB2_HDR_FLAGS,
 		      IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
 		SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND,	next_command_ofs);
@@ -623,6 +725,9 @@ static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request
 	/* And end the chain. */
 	SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
 
+	/* Calculate outgoing credits */
+	smb2_calculate_credits(req, nreq);
+
 	/* Re-sign if needed. */
 	if (nreq->do_signing) {
 		NTSTATUS status;
@@ -779,9 +884,6 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
 	SSVAL(hdr, SMB2_HDR_EPOCH, 0);
 	SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
 	SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
-	SSVAL(hdr, SMB2_HDR_CREDIT, 5);
-
-	req->sconn->smb2.credits_granted += 5;
 
 	SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
 	SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
@@ -799,6 +901,11 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
 	/* Match W2K8R2... */
 	SCVAL(body, 0x08, 0x21);
 
+	/* Ensure we correctly go through crediting. */
+	smb2_set_operation_credit(req->sconn,
+			NULL,
+			&state->vector[1]);
+
 	if (req->do_signing) {
 		status = smb2_signing_sign_pdu(req->session->session_key,
 					state->vector, 3);
@@ -876,8 +983,6 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
 	reqhdr = (uint8_t *)req->out.vector[1].iov_base;
 	SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
 	SBVAL(reqhdr, SMB2_HDR_PID, async_id);
-	/* Only return credits on the interim response. */
-	SSVAL(reqhdr, SMB2_HDR_CREDIT, 0);
 
 	{
 		const uint8_t *inhdr =
@@ -1331,13 +1436,18 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
 {
 	struct tevent_req *subreq;
+	int i = req->current_idx;
 
 	req->subreq = NULL;
 
 	smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
 
+	/* Set credit for this operation. */
+	smb2_set_operation_credit(req->sconn,
+			&req->in.vector[i],
+			&req->out.vector[i]);
+
 	if (req->do_signing) {
-		int i = req->current_idx;
 		NTSTATUS status;
 		status = smb2_signing_sign_pdu(req->session->session_key,
 					       &req->out.vector[i], 3);
@@ -2091,7 +2201,6 @@ void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
 
 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
 {
-	uint16_t creds_requested = 0;
 	struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
 					       struct smbd_server_connection);
 	NTSTATUS status;
@@ -2118,7 +2227,7 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq)
 	DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
 		 req->current_idx, req->in.vector_count));
 
-	status = smbd_smb2_request_validate(req, &creds_requested);
+	status = smbd_smb2_request_validate(req);
 	if (!NT_STATUS_IS_OK(status)) {
 		smbd_server_connection_terminate(sconn, nt_errstr(status));
 		return;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list