Commit dfeb4d11 authored by Steve French's avatar Steve French Committed by Steve French

Fix oops in getdfs when null path passed in on mount. Fix oops when changed...

Fix oops in getdfs when null path passed in on mount.  Fix oops when changed readsize caused readpages problem.  Add support for altering rsize so can reduce pages read across net
below default of 4
parent 0cfcdb1c
Version 0.70
------------
Fix oops in get dfs referral (triggered when null path sent in to
mount). Add support for overriding rsize at mount time.
Version 0.69 Version 0.69
------------ ------------
Fix buffer overrun in readdir which caused intermittent kernel oopses. Fix buffer overrun in readdir which caused intermittent kernel oopses.
......
...@@ -42,13 +42,24 @@ extra copy in/out of the socket buffers in some cases. ...@@ -42,13 +42,24 @@ extra copy in/out of the socket buffers in some cases.
m) finish support for IPv6 m) finish support for IPv6
KNOWN BUGS (updated February 15, 2003) n) send oplock break response when sent (oplock currently disabled in
/proc/fs/cifs)
o) remove calls to set end of file by name when we already have file open
(use the existing handle since some servers only support that and it
reduces the oplock breaks coming from windows). Piggyback identical
file opens on top of each other by incrementing reference count rather
than resending (helps reduce server resource utilization and avoid
spurious oplock breaks).
KNOWN BUGS (updated March 7, 2003)
==================================== ====================================
1) existing symbolic links (Windows reparse points) are recognized but 1) existing symbolic links (Windows reparse points) are recognized but
can not be created remotely. They are implemented for Samba and those that can not be created remotely. They are implemented for Samba and those that
support the CIFS Unix extensions but Samba has a bug currently handling support the CIFS Unix extensions but Samba has a bug currently handling
symlink text beginning with slash symlink text beginning with slash
2) delete of file with read-only attribute set will fail (may be ok) 2) delete of file with read-only attribute set will fail (may be ok)
3) mount helper syntax not quite matching man page
Misc testing to do Misc testing to do
================= =================
......
...@@ -227,7 +227,7 @@ cifs_proc_init(void) ...@@ -227,7 +227,7 @@ cifs_proc_init(void)
if (pde) if (pde)
pde->write_proc = traceSMB_write; pde->write_proc = traceSMB_write;
pde = create_proc_read_entry("oplockEnabled", 0, proc_fs_cifs, pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs,
oplockEnabled_read, 0); oplockEnabled_read, 0);
if (pde) if (pde)
pde->write_proc = oplockEnabled_write; pde->write_proc = oplockEnabled_write;
...@@ -269,7 +269,7 @@ cifs_proc_clean(void) ...@@ -269,7 +269,7 @@ cifs_proc_clean(void)
remove_proc_entry("SimultaneousOps", proc_fs_cifs); remove_proc_entry("SimultaneousOps", proc_fs_cifs);
remove_proc_entry("TotalOps", proc_fs_cifs); remove_proc_entry("TotalOps", proc_fs_cifs);
remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("MultiuserMount", proc_fs_cifs);
remove_proc_entry("oplockEnabled", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs);
remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
remove_proc_entry("ExtendedSecurity",proc_fs_cifs); remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
......
...@@ -20,8 +20,9 @@ ...@@ -20,8 +20,9 @@
struct cifs_sb_info { struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */
/* list of implicit mounts beneath this mount point - needed in dfs case */
struct list_head nested_tcon_q; struct list_head nested_tcon_q;
struct nls_table *local_nls; struct nls_table *local_nls;
unsigned int rsize;
unsigned int wsize;
}; };
#endif /* _CIFS_FS_SB_H */ #endif /* _CIFS_FS_SB_H */
...@@ -52,6 +52,7 @@ unsigned int multiuser_mount = 0; ...@@ -52,6 +52,7 @@ unsigned int multiuser_mount = 0;
unsigned int extended_security = 0; unsigned int extended_security = 0;
unsigned int ntlmv2_support = 0; unsigned int ntlmv2_support = 0;
unsigned int sign_CIFS_PDUs = 0; unsigned int sign_CIFS_PDUs = 0;
unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
char *); char *);
...@@ -83,8 +84,11 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent) ...@@ -83,8 +84,11 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
sb->s_magic = CIFS_MAGIC_NUMBER; sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops; sb->s_op = &cifs_super_ops;
sb->s_blocksize = CIFS_MAX_MSGSIZE; /* BB check SMBSessSetup negotiated size */ if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
sb->s_blocksize_bits = 10; /* 2**10 = CIFS_MAX_MSGSIZE */ sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
else
sb->s_blocksize = CIFSMaximumBufferSize;
sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
inode = iget(sb, ROOT_I); inode = iget(sb, ROOT_I);
if (!inode) if (!inode)
...@@ -162,6 +166,12 @@ cifs_statfs(struct super_block *sb, struct statfs *buf) ...@@ -162,6 +166,12 @@ cifs_statfs(struct super_block *sb, struct statfs *buf)
return 0; /* always return success? what if volume is no longer available? */ return 0; /* always return success? what if volume is no longer available? */
} }
static int cifs_permission(struct inode * inode, int mask)
{
/* the server does permission checks, we do not need to do it here */
return 0;
}
static kmem_cache_t *cifs_inode_cachep; static kmem_cache_t *cifs_inode_cachep;
kmem_cache_t *cifs_req_cachep; kmem_cache_t *cifs_req_cachep;
kmem_cache_t *cifs_mid_cachep; kmem_cache_t *cifs_mid_cachep;
...@@ -270,6 +280,7 @@ struct inode_operations cifs_dir_inode_ops = { ...@@ -270,6 +280,7 @@ struct inode_operations cifs_dir_inode_ops = {
.mkdir = cifs_mkdir, .mkdir = cifs_mkdir,
.rmdir = cifs_rmdir, .rmdir = cifs_rmdir,
.rename = cifs_rename, .rename = cifs_rename,
.permission = cifs_permission,
/* revalidate:cifs_revalidate, */ /* revalidate:cifs_revalidate, */
.setattr = cifs_setattr, .setattr = cifs_setattr,
.symlink = cifs_symlink, .symlink = cifs_symlink,
...@@ -280,18 +291,19 @@ struct inode_operations cifs_file_inode_ops = { ...@@ -280,18 +291,19 @@ struct inode_operations cifs_file_inode_ops = {
.setattr = cifs_setattr, .setattr = cifs_setattr,
.getattr = cifs_getattr, /* do we need this anymore? */ .getattr = cifs_getattr, /* do we need this anymore? */
.rename = cifs_rename, .rename = cifs_rename,
.permission = cifs_permission,
#ifdef CIFS_XATTR #ifdef CIFS_XATTR
.setxattr = cifs_setxattr, .setxattr = cifs_setxattr,
.getxattr = cifs_getxattr, .getxattr = cifs_getxattr,
.listxattr = cifs_listxattr, .listxattr = cifs_listxattr,
.removexattr = cifs_removexattr, .removexattr = cifs_removexattr,
.permission = cifs_permission,
#endif #endif
}; };
struct inode_operations cifs_symlink_inode_ops = { struct inode_operations cifs_symlink_inode_ops = {
.readlink = cifs_readlink, .readlink = cifs_readlink,
.follow_link = cifs_follow_link, .follow_link = cifs_follow_link,
.permission = cifs_permission,
/* BB add the following two eventually */ /* BB add the following two eventually */
/* revalidate: cifs_revalidate, /* revalidate: cifs_revalidate,
setattr: cifs_notify_change, *//* BB do we need notify change */ setattr: cifs_notify_change, *//* BB do we need notify change */
......
...@@ -519,8 +519,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, ...@@ -519,8 +519,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
pSMB->Remaining = 0; pSMB->Remaining = 0;
pSMB->MaxCount = cpu_to_le16(min_t(const unsigned int, count, pSMB->MaxCount = cpu_to_le16(count);
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00));
pSMB->MaxCountHigh = 0; pSMB->MaxCountHigh = 0;
pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/pagemap.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/processor.h> #include <asm/processor.h>
#include "cifspdu.h" #include "cifspdu.h"
...@@ -56,6 +57,8 @@ struct smb_vol { ...@@ -56,6 +57,8 @@ struct smb_vol {
mode_t file_mode; mode_t file_mode;
mode_t dir_mode; mode_t dir_mode;
int rw; int rw;
unsigned int rsize;
unsigned int wsize;
unsigned short int port; unsigned short int port;
}; };
...@@ -447,6 +450,16 @@ parse_mount_options(char *options, char *devname, struct smb_vol *vol) ...@@ -447,6 +450,16 @@ parse_mount_options(char *options, char *devname, struct smb_vol *vol)
vol->port = vol->port =
simple_strtoul(value, &value, 0); simple_strtoul(value, &value, 0);
} }
} else if (strnicmp(data, "rsize", 5) == 0) {
if (value && *value) {
vol->rsize =
simple_strtoul(value, &value, 0);
}
} else if (strnicmp(data, "wsize", 5) == 0) {
if (value && *value) {
vol->wsize =
simple_strtoul(value, &value, 0);
}
} else if (strnicmp(data, "version", 3) == 0) { } else if (strnicmp(data, "version", 3) == 0) {
/* ignore */ /* ignore */
} else if (strnicmp(data, "rw", 2) == 0) { } else if (strnicmp(data, "rw", 2) == 0) {
...@@ -573,11 +586,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -573,11 +586,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
return -ENOMEM; return -ENOMEM;
temp_unc[0] = '\\'; temp_unc[0] = '\\';
temp_unc[1] = '\\'; temp_unc[1] = '\\';
strncpy(temp_unc + 2, pSesInfo->serverName, strcpy(temp_unc + 2, pSesInfo->serverName);
SERVER_NAME_LEN_WITH_NULL * 2); strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
strncpy(temp_unc + 2 +
strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2),
"\\IPC$", 5);
rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage); rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
cFYI(1, cFYI(1,
("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid)); ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
...@@ -598,6 +608,7 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab ...@@ -598,6 +608,7 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab
char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
int ntlmv2_flag = FALSE; int ntlmv2_flag = FALSE;
/* what if server changes its buffer size after dropping the session? */
if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */
rc = CIFSSMBNegotiate(xid, pSesInfo); rc = CIFSSMBNegotiate(xid, pSesInfo);
pSesInfo->capabilities = pSesInfo->server->capabilities; pSesInfo->capabilities = pSesInfo->server->capabilities;
...@@ -778,7 +789,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -778,7 +789,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
struct TCP_Server_Info *srvTcp = NULL; struct TCP_Server_Info *srvTcp = NULL;
xid = GetXid(); xid = GetXid();
cFYI(0, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data));
if(parse_mount_options(mount_data, devname, &volume_info)) { if(parse_mount_options(mount_data, devname, &volume_info)) {
FreeXid(xid); FreeXid(xid);
...@@ -875,9 +886,23 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -875,9 +886,23 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
atomic_inc(&srvTcp->socketUseCount); atomic_inc(&srvTcp->socketUseCount);
} }
} }
/* search for existing tcon to this server share */ /* search for existing tcon to this server share */
if (!rc) { if (!rc) {
if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
cifs_sb->rsize = volume_info.rsize;
else
cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
cifs_sb->wsize = volume_info.wsize;
else
cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
cifs_sb->rsize = PAGE_CACHE_SIZE;
cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
}
tcon = tcon =
find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
volume_info.username); volume_info.username);
...@@ -980,7 +1005,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -980,7 +1005,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (smb_buffer == 0) { if (smb_buffer == 0) {
return -ENOMEM; return -ENOMEM;
} }
smb_buffer_response = smb_buffer; smb_buffer_response = smb_buffer;
pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
/* send SMBsessionSetup here */ /* send SMBsessionSetup here */
......
...@@ -608,6 +608,7 @@ cifs_read(struct file * file, char *read_data, size_t read_size, ...@@ -608,6 +608,7 @@ cifs_read(struct file * file, char *read_data, size_t read_size,
int rc = -EACCES; int rc = -EACCES;
int bytes_read = 0; int bytes_read = 0;
int total_read; int total_read;
int current_read_size;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
int xid; int xid;
...@@ -624,10 +625,11 @@ cifs_read(struct file * file, char *read_data, size_t read_size, ...@@ -624,10 +625,11 @@ cifs_read(struct file * file, char *read_data, size_t read_size,
for (total_read = 0,current_offset=read_data; read_size > total_read; for (total_read = 0,current_offset=read_data; read_size > total_read;
total_read += bytes_read,current_offset+=bytes_read) { total_read += bytes_read,current_offset+=bytes_read) {
current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
rc = CIFSSMBRead(xid, pTcon, rc = CIFSSMBRead(xid, pTcon,
((struct cifsFileInfo *) file-> ((struct cifsFileInfo *) file->
private_data)->netfid, private_data)->netfid,
read_size - total_read, *poffset, current_read_size, *poffset,
&bytes_read, &current_offset); &bytes_read, &current_offset);
if (rc || (bytes_read == 0)) { if (rc || (bytes_read == 0)) {
if (total_read) { if (total_read) {
...@@ -744,6 +746,8 @@ cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -744,6 +746,8 @@ cifs_readpages(struct file *file, struct address_space *mapping,
num_pages-i, (unsigned long) offset)); num_pages-i, (unsigned long) offset));
read_size = (num_pages - i) * PAGE_CACHE_SIZE; read_size = (num_pages - i) * PAGE_CACHE_SIZE;
/* Read size needs to be in multiples of one page */
read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
rc = CIFSSMBRead(xid, pTcon, rc = CIFSSMBRead(xid, pTcon,
((struct cifsFileInfo *) file-> ((struct cifsFileInfo *) file->
private_data)->netfid, private_data)->netfid,
......
...@@ -153,7 +153,8 @@ buf_get(void) ...@@ -153,7 +153,8 @@ buf_get(void)
/* We could use negotiated size instead of max_msgsize - /* We could use negotiated size instead of max_msgsize -
but it may be more efficient to always alloc same size but it may be more efficient to always alloc same size
albeit slightly larger */ albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */
ret_buf = ret_buf =
(struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL); (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL);
......
...@@ -159,7 +159,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -159,7 +159,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
midQ = AllocMidQEntry(in_buf, ses); midQ = AllocMidQEntry(in_buf, ses);
if (midQ == NULL) if (midQ == NULL)
return -EIO; return -EIO;
if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) {
cERROR(1, cERROR(1,
("Illegal length, greater than maximum frame, %d ", ("Illegal length, greater than maximum frame, %d ",
in_buf->smb_buf_length)); in_buf->smb_buf_length));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment