SMB3: Add mount parameter to allow user to override max credits
authorSteve French <smfrench@gmail.com>
Fri, 23 Sep 2016 05:44:16 +0000 (00:44 -0500)
committerSteve French <smfrench@gmail.com>
Wed, 12 Oct 2016 17:08:33 +0000 (12:08 -0500)
Add mount option "max_credits" to allow setting maximum SMB3
credits to any value from 10 to 64000 (default is 32000).
This can be useful to workaround servers with problems allocating
credits, or to throttle the client to use smaller amount of
simultaneous i/o or to workaround server performance issues.

Also adds a cap, so that even if the server granted us more than
65000 credits due to a server bug, we would not use that many.

Signed-off-by: Steve French <steve.french@primarydata.com>
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/smb2glob.h
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c

index 65f78b7a90620a02c82d19f020f2c087b3fad8e9..cd80594f14d0e7e5ac117dfac2fd0130017fbbdb 100644 (file)
 #define SMB_ECHO_INTERVAL_MAX 600
 #define SMB_ECHO_INTERVAL_DEFAULT 60
 
+/*
+ * Default number of credits to keep available for SMB3.
+ * This value is chosen somewhat arbitrarily. The Windows client
+ * defaults to 128 credits, the Windows server allows clients up to
+ * 512 credits (or 8K for later versions), and the NetApp server
+ * does not limit clients at all.  Choose a high enough default value
+ * such that the client shouldn't limit performance, but allow mount
+ * to override (until you approach 64K, where we limit credits to 65000
+ * to reduce possibility of seeing more server credit overflow bugs.
+ */
+#define SMB2_MAX_CREDITS_AVAILABLE 32000
+
 #include "cifspdu.h"
 
 #ifndef XATTR_DOS_ATTRIB
@@ -510,6 +522,7 @@ struct smb_vol {
        struct sockaddr_storage srcaddr; /* allow binding to a local IP */
        struct nls_table *local_nls;
        unsigned int echo_interval; /* echo interval in secs */
+       unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
 };
 
 #define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
@@ -567,7 +580,8 @@ struct TCP_Server_Info {
        bool noblocksnd;                /* use blocking sendmsg */
        bool noautotune;                /* do not autotune send buf sizes */
        bool tcp_nodelay;
-       int credits;  /* send no more requests at once */
+       unsigned int credits;  /* send no more requests at once */
+       unsigned int max_credits; /* can override large 32000 default at mnt */
        unsigned int in_flight;  /* number of requests on the wire to server */
        spinlock_t req_lock;  /* protect the two values above */
        struct mutex srv_mutex;
index 7b67179521cfcfaa84f59a4605078ac4dc43b644..657369db76dfe555824e7b7bc73e9c89370ac5b2 100644 (file)
@@ -63,7 +63,6 @@ extern mempool_t *cifs_req_poolp;
 #define TLINK_IDLE_EXPIRE      (600 * HZ)
 
 enum {
-
        /* Mount options that take no arguments */
        Opt_user_xattr, Opt_nouser_xattr,
        Opt_forceuid, Opt_noforceuid,
@@ -95,7 +94,7 @@ enum {
        Opt_cruid, Opt_gid, Opt_file_mode,
        Opt_dirmode, Opt_port,
        Opt_rsize, Opt_wsize, Opt_actimeo,
-       Opt_echo_interval,
+       Opt_echo_interval, Opt_max_credits,
 
        /* Mount options which take string value */
        Opt_user, Opt_pass, Opt_ip,
@@ -190,6 +189,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_wsize, "wsize=%s" },
        { Opt_actimeo, "actimeo=%s" },
        { Opt_echo_interval, "echo_interval=%s" },
+       { Opt_max_credits, "max_credits=%s" },
 
        { Opt_blank_user, "user=" },
        { Opt_blank_user, "username=" },
@@ -1586,6 +1586,15 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        }
                        vol->echo_interval = option;
                        break;
+               case Opt_max_credits:
+                       if (get_option_ul(args, &option) || (option < 20) ||
+                           (option > 60000)) {
+                               cifs_dbg(VFS, "%s: Invalid max_credits value\n",
+                                        __func__);
+                               goto cifs_parse_mount_err;
+                       }
+                       vol->max_credits = option;
+                       break;
 
                /* String Arguments */
 
@@ -3598,7 +3607,11 @@ try_mount_again:
                bdi_destroy(&cifs_sb->bdi);
                goto out;
        }
-
+       if ((volume_info->max_credits < 20) ||
+            (volume_info->max_credits > 60000))
+               server->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
+       else
+               server->max_credits = volume_info->max_credits;
        /* get a reference to a SMB session */
        ses = cifs_get_smb_ses(server, volume_info);
        if (IS_ERR(ses)) {
index 238759c146badd9eddc372e31c558ec948647343..0ffa180943357c5514b5ae025f61e4b19f574f38 100644 (file)
 /* Maximum buffer size value we can send with 1 credit */
 #define SMB2_MAX_BUFFER_SIZE 65536
 
-/*
- * Maximum number of credits to keep available.
- * This value is chosen somewhat arbitrarily. The Windows client
- * defaults to 128 credits, the Windows server allows clients up to
- * 512 credits, and the NetApp server does not limit clients at all.
- * Choose a high enough value such that the client shouldn't limit
- * performance.
- */
-#define SMB2_MAX_CREDITS_AVAILABLE 32000
-
 #endif /* _SMB2_GLOB_H */
index 91e53df4e420e90c6b02d5aa58779c6220958c0b..378260cd25a6216fd26bccd026eeac8fc7b5bf8e 100644 (file)
@@ -70,6 +70,10 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
        spin_lock(&server->req_lock);
        val = server->ops->get_credits_field(server, optype);
        *val += add;
+       if (*val > 65000) {
+               *val = 65000; /* Don't get near 64K credits, avoid srv bugs */
+               printk_once(KERN_WARNING "server overflowed SMB3 credits\n");
+       }
        server->in_flight--;
        if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP)
                rc = change_conf(server);
index 4d944c4c55a825241118756c9c0776b42378d196..d6a0456902660cb492c671d7f0d9db7ef6565c75 100644 (file)
@@ -105,11 +105,11 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
 
                spin_lock(&server->req_lock);
                /* Request up to 2 credits but don't go over the limit. */
-               if (server->credits >= SMB2_MAX_CREDITS_AVAILABLE)
+               if (server->credits >= server->max_credits)
                        hdr->CreditRequest = cpu_to_le16(0);
                else
                        hdr->CreditRequest = cpu_to_le16(
-                               min_t(int, SMB2_MAX_CREDITS_AVAILABLE -
+                               min_t(int, server->max_credits -
                                                server->credits, 2));
                spin_unlock(&server->req_lock);
        } else {