diff options
author | Jeff Layton <jlayton@redhat.com> | 2011-10-19 15:28:27 -0400 |
---|---|---|
committer | Jeff Layton <jlayton@redhat.com> | 2011-10-19 15:28:27 -0400 |
commit | 1041e3f9919999b22c9c2a453aa0d92cd16b76ee (patch) | |
tree | 8793a5d636e7c565722bb4353b23c74d185cb28e /fs | |
parent | 42c4dfc213190fafffc53815c2ee6064430bc379 (diff) |
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')
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | 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 55ebf39fb3fd..51ed2de23070 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -292,6 +292,8 @@ struct TCP_Server_Info { | |||
292 | bool sec_kerberos; /* supports plain Kerberos */ | 292 | bool sec_kerberos; /* supports plain Kerberos */ |
293 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 293 | bool sec_mskerberos; /* supports legacy MS Kerberos */ |
294 | struct delayed_work echo; /* echo ping workqueue job */ | 294 | struct delayed_work echo; /* echo ping workqueue job */ |
295 | struct kvec *iov; /* reusable kvec array for receives */ | ||
296 | unsigned int nr_iov; /* number of kvecs in array */ | ||
295 | #ifdef CONFIG_CIFS_FSCACHE | 297 | #ifdef CONFIG_CIFS_FSCACHE |
296 | struct fscache_cookie *fscache; /* client index cache cookie */ | 298 | struct fscache_cookie *fscache; /* client index cache cookie */ |
297 | #endif | 299 | #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, | |||
410 | return nr_segs; | 410 | return nr_segs; |
411 | } | 411 | } |
412 | 412 | ||
413 | static struct kvec * | ||
414 | get_server_iovec(struct TCP_Server_Info *server, unsigned int nr_segs) | ||
415 | { | ||
416 | struct kvec *new_iov; | ||
417 | |||
418 | if (server->iov && nr_segs <= server->nr_iov) | ||
419 | return server->iov; | ||
420 | |||
421 | /* not big enough -- allocate a new one and release the old */ | ||
422 | new_iov = kmalloc(sizeof(*new_iov) * nr_segs, GFP_NOFS); | ||
423 | if (new_iov) { | ||
424 | kfree(server->iov); | ||
425 | server->iov = new_iov; | ||
426 | server->nr_iov = nr_segs; | ||
427 | } | ||
428 | return new_iov; | ||
429 | } | ||
430 | |||
413 | static int | 431 | static int |
414 | readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | 432 | readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, |
415 | unsigned int nr_segs, unsigned int to_read) | 433 | unsigned int nr_segs, unsigned int to_read) |
@@ -420,7 +438,7 @@ readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | |||
420 | struct msghdr smb_msg; | 438 | struct msghdr smb_msg; |
421 | struct kvec *iov; | 439 | struct kvec *iov; |
422 | 440 | ||
423 | iov = kmalloc(sizeof(*iov_orig) * nr_segs, GFP_NOFS); | 441 | iov = get_server_iovec(server, nr_segs); |
424 | if (!iov) | 442 | if (!iov) |
425 | return -ENOMEM; | 443 | return -ENOMEM; |
426 | 444 | ||
@@ -464,7 +482,6 @@ readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | |||
464 | break; | 482 | break; |
465 | } | 483 | } |
466 | } | 484 | } |
467 | kfree(iov); | ||
468 | return total_read; | 485 | return total_read; |
469 | } | 486 | } |
470 | 487 | ||
@@ -669,6 +686,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) | |||
669 | } | 686 | } |
670 | 687 | ||
671 | kfree(server->hostname); | 688 | kfree(server->hostname); |
689 | kfree(server->iov); | ||
672 | kfree(server); | 690 | kfree(server); |
673 | 691 | ||
674 | length = atomic_dec_return(&tcpSesAllocCount); | 692 | length = atomic_dec_return(&tcpSesAllocCount); |