diff options
author | Jeff Layton <jlayton@redhat.com> | 2012-07-11 09:09:35 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-07-17 00:57:09 -0400 |
commit | 3ae629d98bd5ed77585a878566f04f310adbc591 (patch) | |
tree | 11a55d0bdca06f3a8d0b37df19e668a400c7a62c /fs/cifs/connect.c | |
parent | ffc61ccbb96809df8d97ed609ac86b509eaf9056 (diff) |
cifs: on CONFIG_HIGHMEM machines, limit the rsize/wsize to the kmap space
We currently rely on being able to kmap all of the pages in an async
read or write request. If you're on a machine that has CONFIG_HIGHMEM
set then that kmap space is limited, sometimes to as low as 512 slots.
With 512 slots, we can only support up to a 2M r/wsize, and that's
assuming that we can get our greedy little hands on all of them. There
are other users however, so it's possible we'll end up stuck with a
size that large.
Since we can't handle a rsize or wsize larger than that currently, cap
those options at the number of kmap slots we have. We could consider
capping it even lower, but we currently default to a max of 1M. Might as
well allow those luddites on 32 bit arches enough rope to hang
themselves.
A more robust fix would be to teach the send and receive routines how
to contend with an array of pages so we don't need to marshal up a kvec
array at all. That's a fairly significant overhaul though, so we'll need
this limit in place until that's ready.
Cc: <stable@vger.kernel.org>
Reported-by: Jian Li <jiali@redhat.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0ae86ddf2213..94b7788c3189 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -3445,6 +3445,18 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
3445 | #define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024) | 3445 | #define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024) |
3446 | #define CIFS_DEFAULT_NON_POSIX_WSIZE (65536) | 3446 | #define CIFS_DEFAULT_NON_POSIX_WSIZE (65536) |
3447 | 3447 | ||
3448 | /* | ||
3449 | * On hosts with high memory, we can't currently support wsize/rsize that are | ||
3450 | * larger than we can kmap at once. Cap the rsize/wsize at | ||
3451 | * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request | ||
3452 | * larger than that anyway. | ||
3453 | */ | ||
3454 | #ifdef CONFIG_HIGHMEM | ||
3455 | #define CIFS_KMAP_SIZE_LIMIT (LAST_PKMAP * PAGE_CACHE_SIZE) | ||
3456 | #else /* CONFIG_HIGHMEM */ | ||
3457 | #define CIFS_KMAP_SIZE_LIMIT (1<<24) | ||
3458 | #endif /* CONFIG_HIGHMEM */ | ||
3459 | |||
3448 | static unsigned int | 3460 | static unsigned int |
3449 | cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | 3461 | cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) |
3450 | { | 3462 | { |
@@ -3475,6 +3487,9 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | |||
3475 | wsize = min_t(unsigned int, wsize, | 3487 | wsize = min_t(unsigned int, wsize, |
3476 | server->maxBuf - sizeof(WRITE_REQ) + 4); | 3488 | server->maxBuf - sizeof(WRITE_REQ) + 4); |
3477 | 3489 | ||
3490 | /* limit to the amount that we can kmap at once */ | ||
3491 | wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT); | ||
3492 | |||
3478 | /* hard limit of CIFS_MAX_WSIZE */ | 3493 | /* hard limit of CIFS_MAX_WSIZE */ |
3479 | wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); | 3494 | wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); |
3480 | 3495 | ||
@@ -3516,6 +3531,9 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | |||
3516 | if (!(server->capabilities & CAP_LARGE_READ_X)) | 3531 | if (!(server->capabilities & CAP_LARGE_READ_X)) |
3517 | rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); | 3532 | rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); |
3518 | 3533 | ||
3534 | /* limit to the amount that we can kmap at once */ | ||
3535 | rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT); | ||
3536 | |||
3519 | /* hard limit of CIFS_MAX_RSIZE */ | 3537 | /* hard limit of CIFS_MAX_RSIZE */ |
3520 | rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); | 3538 | rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); |
3521 | 3539 | ||