smb3: make default i/o size for smb3 mounts larger
authorSteve French <stfrench@microsoft.com>
Fri, 1 Mar 2019 03:32:15 +0000 (21:32 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Mar 2019 19:11:17 +0000 (20:11 +0100)
commit e8506d25f740fd058791cc12a6dfa9386ada6b96 upstream.

We negotiate rsize mounts (and it can be overridden by user) to
typically 4MB, so using larger default I/O sizes from userspace
(changing to 1MB default i/o size returned by stat) the
performance is much better (and not just for long latency
network connections) in most use cases for SMB3 than the default I/O
size (which ends up being 128K for cp and can be even smaller for cp).
This can be 4x slower or worse depending on network latency.

By changing inode->blocksize from 32K (which was perhaps ok
for very old SMB1/CIFS) to a larger value, 1MB (but still less than
max size negotiated with the server which is 4MB, in order to minimize
risk) it significantly increases performance for the
noncached case, and slightly increases it for the cached case.
This can be changed by the user on mount (specifying bsize=
values from 16K to 16MB) to tune better for performance
for applications that depend on blocksize.

Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/inode.c

index 42f0d67f10546a4773a1984bb98e31d8ef69f69c..ed49222abecb467f9b4a7a8b7e68e06aa6fa46ac 100644 (file)
@@ -58,6 +58,7 @@ struct cifs_sb_info {
        spinlock_t tlink_tree_lock;
        struct tcon_link *master_tlink;
        struct nls_table *local_nls;
+       unsigned int bsize;
        unsigned int rsize;
        unsigned int wsize;
        unsigned long actimeo; /* attribute cache timeout (jiffies) */
index 62d48d486d8f8278aa58413501b1f56dc7fb1bfa..f2c0d863fb521f39a448224ea85be38cad0c9259 100644 (file)
@@ -554,6 +554,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
 
        seq_printf(s, ",rsize=%u", cifs_sb->rsize);
        seq_printf(s, ",wsize=%u", cifs_sb->wsize);
+       seq_printf(s, ",bsize=%u", cifs_sb->bsize);
        seq_printf(s, ",echo_interval=%lu",
                        tcon->ses->server->echo_interval / HZ);
        if (tcon->snapshot_time)
index 30f49706b02f0eb615ee2d77c28457ac2de90e6b..1b25e6e95d45f8fe9ec2f39420de960c5fe0202b 100644 (file)
@@ -559,6 +559,7 @@ struct smb_vol {
        bool resilient:1; /* noresilient not required since not fored for CA */
        bool domainauto:1;
        bool rdma:1;
+       unsigned int bsize;
        unsigned int rsize;
        unsigned int wsize;
        bool sockopt_tcp_nodelay:1;
index 8463c940e0e59779390b210fa3ebba45df86f80b..e61cd2938c9e597c1f0db9aa506b37a426e6ae62 100644 (file)
@@ -102,7 +102,7 @@ enum {
        Opt_backupuid, Opt_backupgid, Opt_uid,
        Opt_cruid, Opt_gid, Opt_file_mode,
        Opt_dirmode, Opt_port,
-       Opt_rsize, Opt_wsize, Opt_actimeo,
+       Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
        Opt_echo_interval, Opt_max_credits,
        Opt_snapshot,
 
@@ -204,6 +204,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_dirmode, "dirmode=%s" },
        { Opt_dirmode, "dir_mode=%s" },
        { Opt_port, "port=%s" },
+       { Opt_blocksize, "bsize=%s" },
        { Opt_rsize, "rsize=%s" },
        { Opt_wsize, "wsize=%s" },
        { Opt_actimeo, "actimeo=%s" },
@@ -1571,7 +1572,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
        vol->cred_uid = current_uid();
        vol->linux_uid = current_uid();
        vol->linux_gid = current_gid();
-
+       vol->bsize = 1024 * 1024; /* can improve cp performance significantly */
        /*
         * default to SFM style remapping of seven reserved characters
         * unless user overrides it or we negotiate CIFS POSIX where
@@ -1944,6 +1945,26 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        }
                        port = (unsigned short)option;
                        break;
+               case Opt_blocksize:
+                       if (get_option_ul(args, &option)) {
+                               cifs_dbg(VFS, "%s: Invalid blocksize value\n",
+                                       __func__);
+                               goto cifs_parse_mount_err;
+                       }
+                       /*
+                        * inode blocksize realistically should never need to be
+                        * less than 16K or greater than 16M and default is 1MB.
+                        * Note that small inode block sizes (e.g. 64K) can lead
+                        * to very poor performance of common tools like cp and scp
+                        */
+                       if ((option < CIFS_MAX_MSGSIZE) ||
+                          (option > (4 * SMB3_DEFAULT_IOSIZE))) {
+                               cifs_dbg(VFS, "%s: Invalid blocksize\n",
+                                       __func__);
+                               goto cifs_parse_mount_err;
+                       }
+                       vol->bsize = option;
+                       break;
                case Opt_rsize:
                        if (get_option_ul(args, &option)) {
                                cifs_dbg(VFS, "%s: Invalid rsize value\n",
@@ -3839,6 +3860,7 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
        spin_lock_init(&cifs_sb->tlink_tree_lock);
        cifs_sb->tlink_tree = RB_ROOT;
 
+       cifs_sb->bsize = pvolume_info->bsize;
        /*
         * Temporarily set r/wsize for matching superblock. If we end up using
         * new sb then client will later negotiate it downward if needed.
index 4780036449160c1a6aec70fd28bc5db28a4697f8..53fdb5df0d2ebd67b2687b76d98441ee7faa41be 100644 (file)
@@ -2080,7 +2080,7 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
                return rc;
 
        generic_fillattr(inode, stat);
-       stat->blksize = CIFS_MAX_MSGSIZE;
+       stat->blksize = cifs_sb->bsize;
        stat->ino = CIFS_I(inode)->uniqueid;
 
        /* old CIFS Unix Extensions doesn't return create time */