summaryrefslogtreecommitdiff
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-05-23 16:18:00 +0400
committerSteve French <smfrench@gmail.com>2012-07-24 10:25:23 -0500
commit28ea5290d78a7fc87a4b4f7cedcaa662f5b8d977 (patch)
tree25f091cdd90fa160d0a10ce2798c7960bdfd051c /fs/cifs/smb2ops.c
parent2dc7e1c03316940dec899fa3206a595de000e99b (diff)
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: Jeff Layton <jlayton@redhat.com> Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r--fs/cifs/smb2ops.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 09530f416123..67a05984cd41 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -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,
};