Commit 41bde9e7 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://cifs.bkbits.net/linux-2.5cifs

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 23850f8d dfeb4d11
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.
Fix writepage code to release kmap on write data. Allow "-ip=" new
mount option to be passed in on parameter distinct from the first part
(server name portion of) the UNC name. Allow override of the
tcp port of the target server via new mount option "-port="
Version 0.68
------------
Fix search handle leak on rewind. Fix setuid and gid so that they are
......
......@@ -42,13 +42,24 @@ extra copy in/out of the socket buffers in some cases.
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
=================
......
......@@ -227,7 +227,7 @@ cifs_proc_init(void)
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;
......@@ -269,7 +269,7 @@ cifs_proc_clean(void)
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);
......
......@@ -20,8 +20,9 @@
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 */
......@@ -52,6 +52,7 @@ unsigned int multiuser_mount = 0;
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 *);
......@@ -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_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)
......@@ -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? */
}
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;
......@@ -270,6 +280,7 @@ struct inode_operations cifs_dir_inode_ops = {
.mkdir = cifs_mkdir,
.rmdir = cifs_rmdir,
.rename = cifs_rename,
.permission = cifs_permission,
/* revalidate:cifs_revalidate, */
.setattr = cifs_setattr,
.symlink = cifs_symlink,
......@@ -280,18 +291,19 @@ struct inode_operations cifs_file_inode_ops = {
.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 */
......@@ -318,6 +330,7 @@ struct file_operations cifs_file_ops = {
struct file_operations cifs_dir_ops = {
.readdir = cifs_readdir,
.release = cifs_closedir,
.read = generic_read_dir,
};
static void
......
......@@ -519,8 +519,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
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 */
......@@ -710,9 +709,9 @@ CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
, nls_codepage);
name_len++; /* trailing null */
name_len *= 2;
pSMB->OldFileName[name_len] = 0; /* pad */
pSMB->OldFileName[name_len] = 0x04; /* pad */
/* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x04;
pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 =
cifs_strtoUCS((wchar_t *) & pSMB->
OldFileName[name_len + 2], toName, 530,
......
......@@ -25,6 +25,7 @@
#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"
......@@ -56,6 +57,9 @@ struct smb_vol {
mode_t file_mode;
mode_t dir_mode;
int rw;
unsigned int rsize;
unsigned int wsize;
unsigned short int port;
};
int ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket);
......@@ -343,11 +347,7 @@ parse_mount_options(char *options, char *devname, struct smb_vol *vol)
char *value;
char *data;
vol->username = NULL;
vol->password = NULL;
vol->domainname = NULL;
vol->UNC = NULL;
vol->UNCip = NULL;
memset(vol,0,sizeof(struct smb_vol));
vol->linux_uid = current->uid; /* current->euid instead? */
vol->linux_gid = current->gid;
vol->rw = TRUE;
......@@ -381,6 +381,15 @@ parse_mount_options(char *options, char *devname, struct smb_vol *vol)
printk(KERN_WARNING "CIFS: password too long\n");
return 1;
}
} else if (strnicmp(data, "ip", 2) == 0) {
if (!value || !*value) {
vol->UNCip = NULL;
} else if (strnlen(value, 35) < 35) {
vol->UNCip = value;
} else {
printk(KERN_WARNING "CIFS: ip address too long\n");
return 1;
}
} else if ((strnicmp(data, "unc", 3) == 0)
|| (strnicmp(data, "target", 6) == 0)
|| (strnicmp(data, "path", 4) == 0)) {
......@@ -399,7 +408,6 @@ parse_mount_options(char *options, char *devname, struct smb_vol *vol)
"CIFS: UNC Path does not begin with // or \\\\ \n");
return 1;
}
vol->UNCip = &vol->UNC[2];
} else {
printk(KERN_WARNING "CIFS: UNC name too long\n");
return 1;
......@@ -420,22 +428,37 @@ parse_mount_options(char *options, char *devname, struct smb_vol *vol)
} else if (strnicmp(data, "uid", 3) == 0) {
if (value && *value) {
vol->linux_uid =
simple_strtoul(value, &value, 0);
simple_strtoul(value, &value, 0);
}
} else if (strnicmp(data, "gid", 3) == 0) {
if (value && *value) {
vol->linux_gid =
simple_strtoul(value, &value, 0);
simple_strtoul(value, &value, 0);
}
} else if (strnicmp(data, "file_mode", 4) == 0) {
if (value && *value) {
vol->file_mode =
simple_strtoul(value, &value, 0);
simple_strtoul(value, &value, 0);
}
} else if (strnicmp(data, "dir_mode", 3) == 0) {
if (value && *value) {
vol->dir_mode =
simple_strtoul(value, &value, 0);
simple_strtoul(value, &value, 0);
}
} else if (strnicmp(data, "port", 4) == 0) {
if (value && *value) {
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 */
......@@ -458,12 +481,14 @@ parse_mount_options(char *options, char *devname, struct smb_vol *vol)
printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
return 1;
}
vol->UNCip = &vol->UNC[2];
} else {
printk(KERN_WARNING "CIFS: UNC name too long\n");
return 1;
}
}
if(vol->UNCip == 0)
vol->UNCip = &vol->UNC[2];
return 0;
}
......@@ -553,20 +578,16 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
unsigned char *referrals = NULL;
if (pSesInfo->ipc_tid == 0) {
temp_unc =
kmalloc(2 +
strnlen(pSesInfo->serverName,
SERVER_NAME_LEN_WITH_NULL * 2) + 1 +
4 /* IPC$ */ + 1, GFP_KERNEL);
temp_unc = kmalloc(2 /* for slashes */ +
strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
+ 1 + 4 /* slash IPC$ */ + 2,
GFP_KERNEL);
if (temp_unc == NULL)
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$", 6);
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));
......@@ -587,6 +608,7 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab
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;
......@@ -670,11 +692,23 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket)
}
psin_server->sin_family = AF_INET;
psin_server->sin_port = htons(CIFS_PORT);
if(psin_server->sin_port) { /* user overrode default port */
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
sizeof (struct sockaddr_in),0);
if (rc >= 0) {
return rc;
}
}
rc = (*csocket)->ops->connect(*csocket,
/* do not retry on the same port we just failed on */
if(psin_server->sin_port != htons(CIFS_PORT)) {
psin_server->sin_port = htons(CIFS_PORT);
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
sizeof (struct sockaddr_in),0);
}
if (rc < 0) {
psin_server->sin_port = htons(RFC1001_PORT);
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
......@@ -703,13 +737,24 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
}
psin_server->sin6_family = AF_INET6;
psin_server->sin6_port = htons(CIFS_PORT);
if(psin_server->sin6_port) { /* user overrode default port */
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
sizeof (struct sockaddr_in6),0);
if (rc >= 0) {
return rc;
}
}
/* do not retry on the same port we just failed on */
if(psin_server->sin6_port != htons(CIFS_PORT)) {
psin_server->sin6_port = htons(CIFS_PORT);
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
sizeof (struct sockaddr_in6), 0
/* BB fix the timeout to be shorter - and check flags */
);
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
sizeof (struct sockaddr_in6), 0);
/* BB fix the timeout to be shorter above - and check flags */
}
if (rc < 0) {
psin_server->sin6_port = htons(RFC1001_PORT);
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
......@@ -744,7 +789,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
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);
......@@ -778,7 +823,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
volume_info.username, &srvTcp);
if (srvTcp) {
cFYI(1, ("Existing tcp session with server found "));
} else { /* create socket */
} else { /* create socket */
if(volume_info.port)
sin_server.sin_port = htons(volume_info.port);
rc = ipv4_connect(&sin_server, &csocket);
if (rc < 0) {
cERROR(1,
......@@ -839,9 +886,23 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
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);
......@@ -944,7 +1005,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
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 */
......
......@@ -393,7 +393,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
{
struct address_space *mapping = page->mapping;
loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
char * write_data = kmap(page);
char * write_data;
int rc = -EFAULT;
int bytes_written = 0;
struct cifs_sb_info *cifs_sb;
......@@ -411,8 +411,9 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
/* figure out which file struct to use
if (file->private_data == NULL) {
FreeXid(xid);
return -EBADF;
kunmap(page);
FreeXid(xid);
return -EBADF;
}
*/
if (!mapping) {
......@@ -424,15 +425,17 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
}
offset += (loff_t)from;
write_data = kmap(page);
write_data += from;
if((to > PAGE_CACHE_SIZE) || (from > to) || (offset > mapping->host->i_size)) {
kunmap(page);
FreeXid(xid);
return -EIO;
}
/* check to make sure that we are not extending the file */
if(mapping->host->i_size - offset < (loff_t)to)
if(mapping->host->i_size - offset < (loff_t)to)
to = (unsigned)(mapping->host->i_size - offset);
......@@ -459,6 +462,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
rc = -EIO;
}
kunmap(page);
FreeXid(xid);
return rc;
}
......@@ -604,6 +608,7 @@ cifs_read(struct file * file, char *read_data, size_t read_size,
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;
......@@ -620,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;
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, &current_offset);
if (rc || (bytes_read == 0)) {
if (total_read) {
......@@ -740,6 +746,8 @@ cifs_readpages(struct file *file, struct address_space *mapping,
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,
......@@ -1061,11 +1069,11 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
xid = GetXid();
data = kmalloc(4096, GFP_KERNEL);
pfindData = (FILE_DIRECTORY_INFO *) data;
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon;
data = kmalloc(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE,
GFP_KERNEL);
pfindData = (FILE_DIRECTORY_INFO *) data;
full_path = build_wildcard_path_from_dentry(file->f_dentry);
......
......@@ -153,7 +153,8 @@ buf_get(void)
/* 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);
......
......@@ -159,7 +159,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
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));
......
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