+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
------------
Fix buffer overrun in readdir which caused intermittent kernel oopses.
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
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
symlink text beginning with slash
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
=================
if (pde)
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);
if (pde)
pde->write_proc = oplockEnabled_write;
remove_proc_entry("SimultaneousOps", proc_fs_cifs);
remove_proc_entry("TotalOps", 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("ExtendedSecurity",proc_fs_cifs);
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
- /* list of implicit mounts beneath this mount point - needed in dfs case */
struct list_head nested_tcon_q;
struct nls_table *local_nls;
+ unsigned int rsize;
+ unsigned int wsize;
};
#endif /* _CIFS_FS_SB_H */
unsigned int extended_security = 0;
unsigned int ntlmv2_support = 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 *,
char *);
sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops;
- sb->s_blocksize = CIFS_MAX_MSGSIZE; /* BB check SMBSessSetup negotiated size */
- sb->s_blocksize_bits = 10; /* 2**10 = CIFS_MAX_MSGSIZE */
+ if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
+ 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);
if (!inode)
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;
kmem_cache_t *cifs_req_cachep;
kmem_cache_t *cifs_mid_cachep;
.mkdir = cifs_mkdir,
.rmdir = cifs_rmdir,
.rename = cifs_rename,
+ .permission = cifs_permission,
/* revalidate:cifs_revalidate, */
.setattr = cifs_setattr,
.symlink = cifs_symlink,
.setattr = cifs_setattr,
.getattr = cifs_getattr, /* do we need this anymore? */
.rename = cifs_rename,
+ .permission = cifs_permission,
#ifdef CIFS_XATTR
.setxattr = cifs_setxattr,
.getxattr = cifs_getxattr,
.listxattr = cifs_listxattr,
.removexattr = cifs_removexattr,
- .permission = cifs_permission,
#endif
};
struct inode_operations cifs_symlink_inode_ops = {
.readlink = cifs_readlink,
.follow_link = cifs_follow_link,
+ .permission = cifs_permission,
/* BB add the following two eventually */
/* revalidate: cifs_revalidate,
setattr: cifs_notify_change, *//* BB do we need notify change */
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
pSMB->Remaining = 0;
- pSMB->MaxCount = cpu_to_le16(min_t(const unsigned int, count,
- (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00));
+ pSMB->MaxCount = cpu_to_le16(count);
pSMB->MaxCountHigh = 0;
pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
#include <linux/wait.h>
#include <linux/version.h>
#include <linux/ipv6.h>
+#include <linux/pagemap.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include "cifspdu.h"
mode_t file_mode;
mode_t dir_mode;
int rw;
+ unsigned int rsize;
+ unsigned int wsize;
unsigned short int port;
};
vol->port =
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) {
/* ignore */
} else if (strnicmp(data, "rw", 2) == 0) {
return -ENOMEM;
temp_unc[0] = '\\';
temp_unc[1] = '\\';
- strncpy(temp_unc + 2, pSesInfo->serverName,
- SERVER_NAME_LEN_WITH_NULL * 2);
- strncpy(temp_unc + 2 +
- strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2),
- "\\IPC$", 5);
+ strcpy(temp_unc + 2, pSesInfo->serverName);
+ strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
cFYI(1,
("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
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 */
rc = CIFSSMBNegotiate(xid, pSesInfo);
pSesInfo->capabilities = pSesInfo->server->capabilities;
struct TCP_Server_Info *srvTcp = NULL;
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)) {
FreeXid(xid);
atomic_inc(&srvTcp->socketUseCount);
}
}
-
+
/* search for existing tcon to this server share */
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 =
find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
volume_info.username);
if (smb_buffer == 0) {
return -ENOMEM;
}
- smb_buffer_response = smb_buffer;
+ smb_buffer_response = smb_buffer;
pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
/* send SMBsessionSetup here */
int rc = -EACCES;
int bytes_read = 0;
int total_read;
+ int current_read_size;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
int xid;
for (total_read = 0,current_offset=read_data; read_size > total_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,
((struct cifsFileInfo *) file->
private_data)->netfid,
- read_size - total_read, *poffset,
+ current_read_size, *poffset,
&bytes_read, ¤t_offset);
if (rc || (bytes_read == 0)) {
if (total_read) {
num_pages-i, (unsigned long) offset));
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,
((struct cifsFileInfo *) file->
private_data)->netfid,
/* We could use negotiated size instead of max_msgsize -
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 =
(struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL);
midQ = AllocMidQEntry(in_buf, ses);
if (midQ == NULL)
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,
("Illegal length, greater than maximum frame, %d ",
in_buf->smb_buf_length));