summaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2011-10-19 21:28:27 +0200
committerJeff Layton <jlayton@redhat.com>2011-10-19 21:28:27 +0200
commit1041e3f9919999b22c9c2a453aa0d92cd16b76ee (patch)
tree8793a5d636e7c565722bb4353b23c74d185cb28e /fs/cifs
parentcifs: turn read_from_socket into a wrapper around a vectorized version (diff)
downloadlinux-1041e3f9919999b22c9c2a453aa0d92cd16b76ee.tar.xz
linux-1041e3f9919999b22c9c2a453aa0d92cd16b76ee.zip
cifs: keep a reusable kvec array for receives
Having to continually allocate a new kvec array is expensive. Allocate one that's big enough, and only reallocate it as needed. Reviewed-and-Tested-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Jeff Layton <jlayton@redhat.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/connect.c22
2 files changed, 22 insertions, 2 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 55ebf39fb3fd..51ed2de23070 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 4860940b748b..ee70075c5fb1 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);