aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-05-23 08:18:00 -0400
committerSteve French <smfrench@gmail.com>2012-07-24 11:25:23 -0400
commit28ea5290d78a7fc87a4b4f7cedcaa662f5b8d977 (patch)
tree25f091cdd90fa160d0a10ce2798c7960bdfd051c /fs/cifs
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')
-rw-r--r--fs/cifs/cifsglob.h5
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/connect.c2
-rw-r--r--fs/cifs/smb2ops.c79
4 files changed, 86 insertions, 1 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3575f0f832b1..480b6385a9b6 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -343,6 +343,11 @@ struct TCP_Server_Info {
343 char server_GUID[16]; 343 char server_GUID[16];
344 __u16 sec_mode; 344 __u16 sec_mode;
345 bool session_estab; /* mark when very first sess is established */ 345 bool session_estab; /* mark when very first sess is established */
346#ifdef CONFIG_CIFS_SMB2
347 int echo_credits; /* echo reserved slots */
348 int oplock_credits; /* oplock break reserved slots */
349 bool echoes:1; /* enable echoes */
350#endif
346 u16 dialect; /* dialect index that server chose */ 351 u16 dialect; /* dialect index that server chose */
347 enum securityEnum secType; 352 enum securityEnum secType;
348 bool oplocks:1; /* enable oplocks */ 353 bool oplocks:1; /* enable oplocks */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 88967d0885bf..3b4d41f9ceeb 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -91,6 +91,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
91 struct smb_hdr *in_buf , 91 struct smb_hdr *in_buf ,
92 struct smb_hdr *out_buf, 92 struct smb_hdr *out_buf,
93 int *bytes_returned); 93 int *bytes_returned);
94extern int cifs_reconnect(struct TCP_Server_Info *server);
94extern int checkSMB(char *buf, unsigned int length); 95extern int checkSMB(char *buf, unsigned int length);
95extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *); 96extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
96extern bool backup_cred(struct cifs_sb_info *); 97extern bool backup_cred(struct cifs_sb_info *);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index cfb7e7797642..a6197224b102 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -297,7 +297,7 @@ static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
297 * reconnect tcp session 297 * reconnect tcp session
298 * wake up waiters on reconnection? - (not needed currently) 298 * wake up waiters on reconnection? - (not needed currently)
299 */ 299 */
300static int 300int
301cifs_reconnect(struct TCP_Server_Info *server) 301cifs_reconnect(struct TCP_Server_Info *server)
302{ 302{
303 int rc = 0; 303 int rc = 0;
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 @@
20#include "cifsglob.h" 20#include "cifsglob.h"
21#include "smb2pdu.h" 21#include "smb2pdu.h"
22#include "smb2proto.h" 22#include "smb2proto.h"
23#include "cifsproto.h"
24#include "cifs_debug.h"
25
26static int
27change_conf(struct TCP_Server_Info *server)
28{
29 server->credits += server->echo_credits + server->oplock_credits;
30 server->oplock_credits = server->echo_credits = 0;
31 switch (server->credits) {
32 case 0:
33 return -1;
34 case 1:
35 server->echoes = false;
36 server->oplocks = false;
37 cERROR(1, "disabling echoes and oplocks");
38 break;
39 case 2:
40 server->echoes = true;
41 server->oplocks = false;
42 server->echo_credits = 1;
43 cFYI(1, "disabling oplocks");
44 break;
45 default:
46 server->echoes = true;
47 server->oplocks = true;
48 server->echo_credits = 1;
49 server->oplock_credits = 1;
50 }
51 server->credits -= server->echo_credits + server->oplock_credits;
52 return 0;
53}
54
55static void
56smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
57 const int optype)
58{
59 int *val, rc = 0;
60 spin_lock(&server->req_lock);
61 val = server->ops->get_credits_field(server, optype);
62 *val += add;
63 server->in_flight--;
64 if (server->in_flight == 0)
65 rc = change_conf(server);
66 spin_unlock(&server->req_lock);
67 wake_up(&server->request_q);
68 if (rc)
69 cifs_reconnect(server);
70}
71
72static void
73smb2_set_credits(struct TCP_Server_Info *server, const int val)
74{
75 spin_lock(&server->req_lock);
76 server->credits = val;
77 spin_unlock(&server->req_lock);
78}
79
80static int *
81smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
82{
83 switch (optype) {
84 case CIFS_ECHO_OP:
85 return &server->echo_credits;
86 case CIFS_OBREAK_OP:
87 return &server->oplock_credits;
88 default:
89 return &server->credits;
90 }
91}
92
93static unsigned int
94smb2_get_credits(struct mid_q_entry *mid)
95{
96 return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
97}
23 98
24static __u64 99static __u64
25smb2_get_next_mid(struct TCP_Server_Info *server) 100smb2_get_next_mid(struct TCP_Server_Info *server)
@@ -35,6 +110,10 @@ smb2_get_next_mid(struct TCP_Server_Info *server)
35struct smb_version_operations smb21_operations = { 110struct smb_version_operations smb21_operations = {
36 .setup_request = smb2_setup_request, 111 .setup_request = smb2_setup_request,
37 .check_receive = smb2_check_receive, 112 .check_receive = smb2_check_receive,
113 .add_credits = smb2_add_credits,
114 .set_credits = smb2_set_credits,
115 .get_credits_field = smb2_get_credits_field,
116 .get_credits = smb2_get_credits,
38 .get_next_mid = smb2_get_next_mid, 117 .get_next_mid = smb2_get_next_mid,
39}; 118};
40 119