Skip to content

Commit

Permalink
cifs: on CONFIG_HIGHMEM machines, limit the rsize/wsize to the kmap s…
Browse files Browse the repository at this point in the history
…pace

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>
  • Loading branch information
jtlayton authored and smfrench committed Jul 17, 2012
1 parent ffc61cc commit 3ae629d
Showing 1 changed file with 18 additions and 0 deletions.
18 changes: 18 additions & 0 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -3445,6 +3445,18 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)

/*
* On hosts with high memory, we can't currently support wsize/rsize that are
* larger than we can kmap at once. Cap the rsize/wsize at
* LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
* larger than that anyway.
*/
#ifdef CONFIG_HIGHMEM
#define CIFS_KMAP_SIZE_LIMIT (LAST_PKMAP * PAGE_CACHE_SIZE)
#else /* CONFIG_HIGHMEM */
#define CIFS_KMAP_SIZE_LIMIT (1<<24)
#endif /* CONFIG_HIGHMEM */

static unsigned int
cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
{
Expand Down Expand Up @@ -3475,6 +3487,9 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
wsize = min_t(unsigned int, wsize,
server->maxBuf - sizeof(WRITE_REQ) + 4);

/* limit to the amount that we can kmap at once */
wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);

/* hard limit of CIFS_MAX_WSIZE */
wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);

Expand Down Expand Up @@ -3516,6 +3531,9 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
if (!(server->capabilities & CAP_LARGE_READ_X))
rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);

/* limit to the amount that we can kmap at once */
rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);

/* hard limit of CIFS_MAX_RSIZE */
rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);

Expand Down

0 comments on commit 3ae629d

Please sign in to comment.