Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28ea5290 authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French
Browse files

CIFS: Add SMB2 credits support



For SMB2 protocol we can add more than one credit for one received
request: it depends on CreditRequest field in SMB2 response header.
Also we divide all requests by type: echoes, oplocks and others.
Each type uses its own slot pull.

Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarPavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 2dc7e1c0
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -343,6 +343,11 @@ struct TCP_Server_Info {
	char server_GUID[16];
	__u16 sec_mode;
	bool session_estab; /* mark when very first sess is established */
#ifdef CONFIG_CIFS_SMB2
	int echo_credits;  /* echo reserved slots */
	int oplock_credits;  /* oplock break reserved slots */
	bool echoes:1; /* enable echoes */
#endif
	u16 dialect; /* dialect index that server chose */
	enum securityEnum secType;
	bool oplocks:1; /* enable oplocks */
+1 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
			struct smb_hdr *in_buf ,
			struct smb_hdr *out_buf,
			int *bytes_returned);
extern int cifs_reconnect(struct TCP_Server_Info *server);
extern int checkSMB(char *buf, unsigned int length);
extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
extern bool backup_cred(struct cifs_sb_info *);
+1 −1
Original line number Diff line number Diff line
@@ -297,7 +297,7 @@ static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
 * reconnect tcp session
 * wake up waiters on reconnection? - (not needed currently)
 */
static int
int
cifs_reconnect(struct TCP_Server_Info *server)
{
	int rc = 0;
+79 −0
Original line number Diff line number Diff line
@@ -20,6 +20,81 @@
#include "cifsglob.h"
#include "smb2pdu.h"
#include "smb2proto.h"
#include "cifsproto.h"
#include "cifs_debug.h"

static int
change_conf(struct TCP_Server_Info *server)
{
	server->credits += server->echo_credits + server->oplock_credits;
	server->oplock_credits = server->echo_credits = 0;
	switch (server->credits) {
	case 0:
		return -1;
	case 1:
		server->echoes = false;
		server->oplocks = false;
		cERROR(1, "disabling echoes and oplocks");
		break;
	case 2:
		server->echoes = true;
		server->oplocks = false;
		server->echo_credits = 1;
		cFYI(1, "disabling oplocks");
		break;
	default:
		server->echoes = true;
		server->oplocks = true;
		server->echo_credits = 1;
		server->oplock_credits = 1;
	}
	server->credits -= server->echo_credits + server->oplock_credits;
	return 0;
}

static void
smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
		 const int optype)
{
	int *val, rc = 0;
	spin_lock(&server->req_lock);
	val = server->ops->get_credits_field(server, optype);
	*val += add;
	server->in_flight--;
	if (server->in_flight == 0)
		rc = change_conf(server);
	spin_unlock(&server->req_lock);
	wake_up(&server->request_q);
	if (rc)
		cifs_reconnect(server);
}

static void
smb2_set_credits(struct TCP_Server_Info *server, const int val)
{
	spin_lock(&server->req_lock);
	server->credits = val;
	spin_unlock(&server->req_lock);
}

static int *
smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
{
	switch (optype) {
	case CIFS_ECHO_OP:
		return &server->echo_credits;
	case CIFS_OBREAK_OP:
		return &server->oplock_credits;
	default:
		return &server->credits;
	}
}

static unsigned int
smb2_get_credits(struct mid_q_entry *mid)
{
	return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
}

static __u64
smb2_get_next_mid(struct TCP_Server_Info *server)
@@ -35,6 +110,10 @@ smb2_get_next_mid(struct TCP_Server_Info *server)
struct smb_version_operations smb21_operations = {
	.setup_request = smb2_setup_request,
	.check_receive = smb2_check_receive,
	.add_credits = smb2_add_credits,
	.set_credits = smb2_set_credits,
	.get_credits_field = smb2_get_credits_field,
	.get_credits = smb2_get_credits,
	.get_next_mid = smb2_get_next_mid,
};