diff --git a/fs/cifs/README b/fs/cifs/README index 4d01697..6ad722b 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -301,8 +301,19 @@ A partial list of the supported mount op during the local client kernel build will be used. If server does not support Unicode, this parameter is unused. - rsize default read size (usually 16K) - wsize default write size (usually 16K, 32K is often better over GigE) + rsize default read size (usually 16K). The client currently + can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize + defaults to 16K and may be changed (from 8K to the maximum + kmalloc size allowed by your kernel) at module install time + for cifs.ko. Setting CIFSMaxBufSize to a very large value + will cause cifs to use more memory and may reduce performance + in some cases. To use rsize greater than 127K (the original + cifs protocol maximum) also requires that the server support + a new Unix Capability flag (for very large read) which some + newer servers (e.g. Samba 3.0.26 or later) do. rsize can be + set from a minimum of 2048 to a maximum of 8388608 (depending + on the value of CIFSMaxBufSize) + wsize default write size (default 57344) maximum wsize currently allowed by CIFS is 57344 (14 4096 byte pages) rw mount the network share read-write (note that the diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d38c69b..8c4365d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -732,10 +732,21 @@ cifs_init_request_bufs(void) /* Buffer size can not be smaller than 2 * PATH_MAX since maximum Unicode path name has to fit in any SMB/CIFS path based frames */ CIFSMaxBufSize = 8192; - } else if (CIFSMaxBufSize > 1024*127) { - CIFSMaxBufSize = 1024 * 127; } else { - CIFSMaxBufSize &= 0x1FE00; /* Round size to even 512 byte mult*/ + if (CIFSMaxBufSize + MAX_CIFS_HDR_SIZE > KMALLOC_MAX_SIZE) { + CIFSMaxBufSize = KMALLOC_MAX_SIZE - MAX_CIFS_HDR_SIZE; + cERROR(1,("CIFSMaxBufSize too large, resetting to %ld", + KMALLOC_MAX_SIZE)); + } + + /* The length field is 3 bytes, but for time being we use only + * 23 of the available 24 length bits */ + if (CIFSMaxBufSize > 8388608) { + CIFSMaxBufSize = 8388608; + cERROR(1, + ("CIFSMaxBufSize set to protocol max 8388608")); + } else /* round buffer size to even 512 byte multiple */ + CIFSMaxBufSize &= 0x7FFE00; } /* cERROR(1,("CIFSMaxBufSize %d 0x%x",CIFSMaxBufSize,CIFSMaxBufSize)); */ cifs_req_cachep = kmem_cache_create("cifs_request", diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index d619ca7..6e6cda0 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1885,15 +1885,19 @@ typedef struct { #define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Allow POSIX path chars */ #define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based calls including posix open - and posix unlink */ + and posix unlink */ +#define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up + to 0xFFFF00 */ +#define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080 + #ifdef CONFIG_CIFS_POSIX /* Can not set pathnames cap yet until we send new posix create SMB since otherwise server can treat such handles opened with older ntcreatex (by a new client which knows how to send posix path ops) as non-posix handles (can affect write behavior with byte range locks. We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */ -/* #define CIFS_UNIX_CAP_MASK 0x0000003b */ -#define CIFS_UNIX_CAP_MASK 0x0000001b +/* #define CIFS_UNIX_CAP_MASK 0x000000fb */ +#define CIFS_UNIX_CAP_MASK 0x000000db #else #define CIFS_UNIX_CAP_MASK 0x00000013 #endif /* CONFIG_CIFS_POSIX */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f4e9266..0ba0d09 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1650,19 +1650,19 @@ void reset_cifs_unix_caps(int xid, struc } cap &= CIFS_UNIX_CAP_MASK; - if(vol_info && vol_info->no_psx_acl) + if (vol_info && vol_info->no_psx_acl) cap &= ~CIFS_UNIX_POSIX_ACL_CAP; - else if(CIFS_UNIX_POSIX_ACL_CAP & cap) { + else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { cFYI(1,("negotiated posix acl support")); if(sb) sb->s_flags |= MS_POSIXACL; } - if(vol_info && vol_info->posix_paths == 0) + if (vol_info && vol_info->posix_paths == 0) cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; - else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { + else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { cFYI(1,("negotiate posix pathnames")); - if(sb) + if (sb) CIFS_SB(sb)->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; } @@ -1670,21 +1670,32 @@ void reset_cifs_unix_caps(int xid, struc /* We might be setting the path sep back to a different form if we are reconnecting and the server switched its posix path capability for this share */ - if(sb && (CIFS_SB(sb)->prepathlen > 0)) + if (sb && (CIFS_SB(sb)->prepathlen > 0)) CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb)); + + if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) { + if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) { + CIFS_SB(sb)->rsize = 127 * 1024; + } + } + cFYI(1,("Negotiate caps 0x%x",(int)cap)); #ifdef CONFIG_CIFS_DEBUG2 - if(cap & CIFS_UNIX_FCNTL_CAP) + if (cap & CIFS_UNIX_FCNTL_CAP) cFYI(1,("FCNTL cap")); - if(cap & CIFS_UNIX_EXTATTR_CAP) + if (cap & CIFS_UNIX_EXTATTR_CAP) cFYI(1,("EXTATTR cap")); - if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) + if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) cFYI(1,("POSIX path cap")); - if(cap & CIFS_UNIX_XATTR_CAP) + if (cap & CIFS_UNIX_XATTR_CAP) cFYI(1,("XATTR cap")); - if(cap & CIFS_UNIX_POSIX_ACL_CAP) + if (cap & CIFS_UNIX_POSIX_ACL_CAP) cFYI(1,("POSIX ACL cap")); + if (cap & CIFS_UNIX_LARGE_READ_CAP) + cFYI(1,("very large read cap")); + if (cap & CIFS_UNIX_LARGE_WRITE_CAP) + cFYI(1,("very large write cap")); #endif /* CIFS_DEBUG2 */ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { cFYI(1,("setting capabilities failed")); @@ -1935,7 +1946,8 @@ cifs_mount(struct super_block *sb, struc cERROR(1,("rsize %d too large, using MaxBufSize", volume_info.rsize)); cifs_sb->rsize = CIFSMaxBufSize; - } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) + } else if ((volume_info.rsize) && + (volume_info.rsize <= CIFSMaxBufSize)) cifs_sb->rsize = volume_info.rsize; else /* default */ cifs_sb->rsize = CIFSMaxBufSize; @@ -2116,7 +2128,9 @@ cifs_mount(struct super_block *sb, struc /* tell server which Unix caps we support */ if (tcon->ses->capabilities & CAP_UNIX) reset_cifs_unix_caps(xid, tcon, sb, &volume_info); - + else if(cifs_sb->rsize > (1024 * 127)) { + cifs_sb->rsize = 1024 * 127; + } if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) cifs_sb->wsize = min(cifs_sb->wsize, (tcon->ses->server->maxBuf -