summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/connect.c69
1 files changed, 49 insertions, 20 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 6070ba69647..2e7a79cd2b9 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2647,23 +2647,6 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
else /* default */
cifs_sb->rsize = CIFSMaxBufSize;
- if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
- cERROR(1, "wsize %d too large, using 4096 instead",
- pvolume_info->wsize);
- cifs_sb->wsize = 4096;
- } else if (pvolume_info->wsize)
- cifs_sb->wsize = pvolume_info->wsize;
- else
- cifs_sb->wsize = min_t(const int,
- PAGEVEC_SIZE * PAGE_CACHE_SIZE,
- 127*1024);
- /* old default of CIFSMaxBufSize was too small now
- that SMB Write2 can send multiple pages in kvec.
- RFC1001 does not describe what happens when frame
- bigger than 128K is sent so use that as max in
- conjunction with 52K kvec constraint on arch with 4K
- page size */
-
if (cifs_sb->rsize < 2048) {
cifs_sb->rsize = 2048;
/* Windows ME may prefer this */
@@ -2742,6 +2725,53 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
"mount option supported");
}
+/*
+ * When the server supports very large writes via POSIX extensions, we can
+ * allow up to 2^24 - PAGE_CACHE_SIZE.
+ *
+ * Note that this might make for "interesting" allocation problems during
+ * writeback however (as we have to allocate an array of pointers for the
+ * pages). A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+ */
+#define CIFS_MAX_WSIZE ((1<<24) - PAGE_CACHE_SIZE)
+
+/*
+ * When the server doesn't allow large posix writes, default to a wsize of
+ * 128k - PAGE_CACHE_SIZE -- one page less than the largest frame size
+ * described in RFC1001. This allows space for the header without going over
+ * that by default.
+ */
+#define CIFS_MAX_RFC1001_WSIZE (128 * 1024 - PAGE_CACHE_SIZE)
+
+/*
+ * The default wsize is 1M. find_get_pages seems to return a maximum of 256
+ * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
+ * a single wsize request with a single call.
+ */
+#define CIFS_DEFAULT_WSIZE (1024 * 1024)
+
+static unsigned int
+cifs_negotiate_wsize(struct cifsTconInfo *tcon, struct smb_vol *pvolume_info)
+{
+ __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+ struct TCP_Server_Info *server = tcon->ses->server;
+ unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize :
+ CIFS_DEFAULT_WSIZE;
+
+ /* can server support 24-bit write sizes? (via UNIX extensions) */
+ if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+ wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1001_WSIZE);
+
+ /* no CAP_LARGE_WRITE_X? Limit it to 16 bits */
+ if (!(server->capabilities & CAP_LARGE_WRITE_X))
+ wsize = min_t(unsigned int, wsize, USHRT_MAX);
+
+ /* hard limit of CIFS_MAX_WSIZE */
+ wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
+
+ return wsize;
+}
+
static int
is_path_accessible(int xid, struct cifsTconInfo *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -3014,13 +3044,12 @@ try_mount_again:
cifs_sb->rsize = 1024 * 127;
cFYI(DBG2, "no very large read support, rsize now 127K");
}
- if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
- cifs_sb->wsize = min(cifs_sb->wsize,
- (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
cifs_sb->rsize = min(cifs_sb->rsize,
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
+ cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
+
remote_path_check:
#ifdef CONFIG_CIFS_DFS_UPCALL
/*