Having to continually allocate a new kvec array is expensive. Allocate
one that's big enough, and only reallocate it as needed.

Signed-off-by: Jeff Layton <[email protected]>
---
 fs/cifs/cifsglob.h |    2 ++
 fs/cifs/connect.c  |   22 ++++++++++++++++++++--
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 55ebf39..51ed2de 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -292,6 +292,8 @@ struct TCP_Server_Info {
        bool    sec_kerberos;           /* supports plain Kerberos */
        bool    sec_mskerberos;         /* supports legacy MS Kerberos */
        struct delayed_work     echo; /* echo ping workqueue job */
+       struct kvec *iov;       /* reusable kvec array for receives */
+       unsigned int nr_iov;    /* number of kvecs in array */
 #ifdef CONFIG_CIFS_FSCACHE
        struct fscache_cookie   *fscache; /* client index cache cookie */
 #endif
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 4860940..ee70075 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -410,6 +410,24 @@ kvec_array_init(struct kvec *new, struct kvec *iov, 
unsigned int nr_segs,
        return nr_segs;
 }
 
+static struct kvec *
+get_server_iovec(struct TCP_Server_Info *server, unsigned int nr_segs)
+{
+       struct kvec *new_iov;
+
+       if (server->iov && nr_segs <= server->nr_iov)
+               return server->iov;
+
+       /* not big enough -- allocate a new one and release the old */
+       new_iov = kmalloc(sizeof(*new_iov) * nr_segs, GFP_NOFS);
+       if (new_iov) {
+               kfree(server->iov);
+               server->iov = new_iov;
+               server->nr_iov = nr_segs;
+       }
+       return new_iov;
+}
+
 static int
 readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
                  unsigned int nr_segs, unsigned int to_read)
@@ -420,7 +438,7 @@ readv_from_socket(struct TCP_Server_Info *server, struct 
kvec *iov_orig,
        struct msghdr smb_msg;
        struct kvec *iov;
 
-       iov = kmalloc(sizeof(*iov_orig) * nr_segs, GFP_NOFS);
+       iov = get_server_iovec(server, nr_segs);
        if (!iov)
                return -ENOMEM;
 
@@ -464,7 +482,6 @@ readv_from_socket(struct TCP_Server_Info *server, struct 
kvec *iov_orig,
                        break;
                }
        }
-       kfree(iov);
        return total_read;
 }
 
@@ -669,6 +686,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info 
*server)
        }
 
        kfree(server->hostname);
+       kfree(server->iov);
        kfree(server);
 
        length = atomic_dec_return(&tcpSesAllocCount);
-- 
1.7.6.4

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to