Commit 29fa971b authored by Linus Torvalds's avatar Linus Torvalds

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

into home.osdl.org:/home/torvalds/v2.5/linux
parents a58eef7f e8aea2e4
......@@ -19,10 +19,11 @@ Patch Contributors
------------------
Zwane Mwaikambo
Andi Kleen
Amrut Joshi
Test case and Bug Report contributors
-------------------------------------
Thanks to those in the community who have submitted detailed bug reports
and debug of problems they have found: Jochen Dolze, David Blaine,
Rene Scharfe, Martin Josefsson and others.
Rene Scharfe, Martin Josefsson, Alexander Wild and others.
Version 0.87
------------
Fix oops on big endian readdir. Set blksize to be even power of two (2**blkbits) to fix
allocation size miscalculation. After oplock token lost do not read through
cache.
Version 0.86
------------
Fix oops on empty file readahead. Fix for file size handling for locally cached files.
Version 0.85
------------
Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files
during auto reconnection to server after server recovered from failure.
Version 0.84
------------
Finish support for Linux 2.5 open/create changes, which removes the
redundant NTCreate/QPathInfo/close that was sent during file create.
Enable oplock by default. Enable packet signing by default (needed to
access many recent Windows servers)
Version 0.83
------------
Fix oops when mounting to long server names caused by inverted parms to kmalloc.
......
......@@ -150,7 +150,10 @@ Configuration pseudo-files:
point and if the uids user/password mapping
information is available. (default is 0)
PacketSigningEnabled If set to one, cifs packet signing is enabled
(default 0)
and will be used if the server requires
it. If set to two, cifs packet signing is
required even if the server considers packet
signing optional. (default 1)
cifsFYI If set to one, additional debug information is
logged to the system error log. (default 0)
ExtendedSecurity If set to one, SPNEGO session establishment
......@@ -166,6 +169,7 @@ Configuration pseudo-files:
for one second improving performance of lookups
(default 1)
OplockEnabled If set to one, safe distributed caching enabled.
(default 1)
These experimental features and tracing can be enabled by changing flags in /proc/fs/cifs
(after the cifs module has been installed or built into the kernel, e.g. insmod cifs).
......
......@@ -47,12 +47,12 @@ extern struct file_system_type cifs_fs_type;
int cifsFYI = 0;
int cifsERROR = 1;
int traceSMB = 0;
unsigned int oplockEnabled = 0;
unsigned int oplockEnabled = 1;
unsigned int lookupCacheEnabled = 1;
unsigned int multiuser_mount = 0;
unsigned int extended_security = 0;
unsigned int ntlmv2_support = 0;
unsigned int sign_CIFS_PDUs = 0;
unsigned int sign_CIFS_PDUs = 1;
unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
struct task_struct * oplockThread = NULL;
......@@ -90,10 +90,10 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops;
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;
/* 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; */
sb->s_blocksize = CIFS_MAX_MSGSIZE;
sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
inode = iget(sb, ROOT_I);
......@@ -201,10 +201,14 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->cifsAttrs = 0x20; /* default */
atomic_set(&cifs_inode->inUse, 0);
cifs_inode->time = 0;
if(oplockEnabled) {
cifs_inode->clientCanCacheRead = 1;
cifs_inode->clientCanCacheAll = 1;
}
/* Until the file is open and we have gotten oplock
info back from the server, can not assume caching of
file data or metadata */
cifs_inode->clientCanCacheRead = FALSE;
cifs_inode->clientCanCacheAll = FALSE;
cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
INIT_LIST_HEAD(&cifs_inode->openFileList);
return &cifs_inode->vfs_inode;
}
......@@ -281,6 +285,27 @@ cifs_get_sb(struct file_system_type *fs_type,
return sb;
}
ssize_t
cifs_read_wrapper(struct file * file, char *read_data, size_t read_size,
loff_t * poffset)
{
if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead)
return generic_file_read(file,read_data,read_size,poffset);
else
return cifs_read(file,read_data,read_size,poffset);
}
ssize_t
cifs_write_wrapper(struct file * file, const char *write_data,
size_t write_size, loff_t * poffset)
{
if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) /* check caching for write */
return generic_file_write(file,write_data, write_size,poffset);
else
return cifs_write(file,write_data,write_size,poffset);
}
static struct file_system_type cifs_fs_type = {
.owner = THIS_MODULE,
.name = "cifs",
......@@ -439,8 +464,9 @@ static int cifs_oplock_thread(void * dummyarg)
struct list_head * tmp;
struct list_head * tmp1;
struct oplock_q_entry * oplock_item;
struct file * pfile;
struct cifsTconInfo *pTcon;
struct inode * inode;
__u16 netfid;
int rc;
daemonize("cifsoplockd");
......@@ -457,23 +483,20 @@ static int cifs_oplock_thread(void * dummyarg)
qhead);
if(oplock_item) {
pTcon = oplock_item->tcon;
pfile = oplock_item->file_to_flush;
cFYI(1,("process item on queue"));/* BB remove */
inode = oplock_item->pinode;
netfid = oplock_item->netfid;
DeleteOplockQEntry(oplock_item);
write_unlock(&GlobalMid_Lock);
rc = filemap_fdatawrite(pfile->f_dentry->d_inode->i_mapping);
rc = filemap_fdatawrite(inode->i_mapping);
if(rc)
CIFS_I(pfile->f_dentry->d_inode)->write_behind_rc
CIFS_I(inode)->write_behind_rc
= rc;
cFYI(1,("Oplock flush file %p rc %d",pfile,rc));
if(pfile->private_data) {
rc = CIFSSMBLock(0, pTcon,
((struct cifsFileInfo *) pfile->private_data)->netfid,
cFYI(1,("Oplock flush inode %p rc %d",inode,rc));
rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE,
0 /* wait flag */);
cFYI(1,("Oplock release rc = %d ",rc));
}
write_lock(&GlobalMid_Lock);
} else
break;
......
......@@ -208,6 +208,7 @@ struct cifsFileInfo {
/* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */
struct file * pfile; /* needed for writepage */
struct inode * pInode; /* needed for oplock break */
int endOfSearch:1; /* we have reached end of search */
int closePend:1; /* file is marked to close */
int emptyDir:1;
......@@ -263,8 +264,9 @@ struct mid_q_entry {
struct oplock_q_entry {
struct list_head qhead;
struct file * file_to_flush;
struct inode * pinode;
struct cifsTconInfo * tcon;
__u16 netfid;
};
#define MID_FREE 0
......
......@@ -633,6 +633,12 @@ typedef struct smb_com_open_req { /* also handles create */
char fileName[1];
} OPEN_REQ;
/* open response: oplock levels */
#define OPLOCK_NONE 0
#define OPLOCK_EXCLUSIVE 1
#define OPLOCK_BATCH 2
#define OPLOCK_READ 3 /* level 2 oplock */
typedef struct smb_com_open_rsp {
struct smb_hdr hdr; /* wct = 34 BB */
__u8 AndXCommand;
......
......@@ -57,7 +57,7 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int
/* length of fixed section (word count) in two byte units */
);
struct oplock_q_entry * AllocOplockQEntry(struct file *,struct cifsTconInfo *);
struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *);
void DeleteOplockQEntry(struct oplock_q_entry *);
extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
extern u64 cifs_UnixTimeToNT(struct timespec);
......@@ -69,6 +69,7 @@ extern void Ucode_to_RevUcode_with_Len(char *Unicode, char *revUnicodeName,
int Len);
extern int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path,
FILE_ALL_INFO * pfile_info,
struct super_block *sb);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
......@@ -195,7 +196,7 @@ extern int CIFSSMBQueryReparseLinkInfo(const int xid,
extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int disposition,
const int access_flags, const int omode,
__u16 * netfid, int *pOplock,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage);
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
const int smb_file_id);
......
......@@ -179,7 +179,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
cERROR(1,
("Server requires /proc/fs/cifs/PacketSigningEnabled"));
server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
} else if(sign_CIFS_PDUs == 1) {
if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
}
}
if (pSMB)
buf_release(pSMB);
......@@ -419,7 +423,8 @@ int
CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
const int access_flags, const int create_options, __u16 * netfid,
int *pOplock, const struct nls_table *nls_codepage)
int *pOplock, FILE_ALL_INFO * pfile_info,
const struct nls_table *nls_codepage)
{
int rc = -EACCES;
OPEN_REQ *pSMB = NULL;
......@@ -476,16 +481,23 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
pSMB->hdr.smb_buf_length += pSMB->ByteCount;
pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
/* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
(struct smb_hdr *) pSMBr, &bytes_returned, 1);
if (rc) {
cFYI(1, ("Error in Open = %d", rc));
} else {
*pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */
*netfid = pSMBr->Fid; /* cifs fid stays in le */
/* Do we care about the CreateAction in any cases? */
/* BB add code to update inode file sizes from create response */
if(pfile_info) {
memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
36 /* CreationTime to Attributes */);
/* the file_info buf is endian converted by caller */
pfile_info->AllocationSize = pSMBr->AllocationSize;
pfile_info->EndOfFile = pSMBr->EndOfFile;
pfile_info->NumberOfLinks = cpu_to_le32(1);
}
}
if (pSMB)
buf_release(pSMB);
......@@ -1231,11 +1243,12 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
/* BB also check enough total bytes returned */
if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512))
rc = -EIO; /* bad smb */
else {
else if (pFindData){
memcpy((char *) pFindData,
(char *) &pSMBr->hdr.Protocol +
pSMBr->DataOffset, sizeof (FILE_ALL_INFO));
}
} else
rc = -ENOMEM;
}
if (pSMB)
buf_release(pSMB);
......
......@@ -125,13 +125,16 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
{
int rc = -ENOENT;
int xid;
int oplock = REQ_OPLOCK;
int oplock = 0;
int desiredAccess = GENERIC_ALL;
__u16 fileHandle;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
FILE_ALL_INFO * buf = NULL;
struct inode *newinode = NULL;
struct cifsFileInfo * pCifsFile = NULL;
struct cifsInodeInfo * pCifsInode;
xid = GetXid();
......@@ -140,10 +143,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
full_path = build_path_from_dentry(direntry);
if(nd) {
cFYI(1,("In create nd flags = 0x%x for %s",nd->flags,full_path));
cFYI(1,("Intent flags: 0x%x", nd->intent.open.flags));
cFYI(1,("In create for inode %p dentry->inode %p nd flags = 0x%x for %s",inode, direntry->d_inode, nd->flags,full_path));
if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
desiredAccess = GENERIC_READ;
else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY)
......@@ -152,40 +154,91 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
desiredAccess = GENERIC_ALL;
}
/* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */
if (oplockEnabled)
oplock = REQ_OPLOCK;
/* BB add processing for setting the equivalent of mode - e.g. via CreateX with ACLs */
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF,
desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, cifs_sb->local_nls);
&fileHandle, &oplock, buf, cifs_sb->local_nls);
if (rc) {
cFYI(1, ("cifs_create returned 0x%x ", rc));
} else {
/* BB for case of overwriting existing file can we use the inode that was
passed in rather than creating new one?? */
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb);
else
rc = cifs_get_inode_info(&newinode, full_path,
inode->i_sb);
buf, inode->i_sb);
if (rc != 0) {
cFYI(1,("Create worked but get_inode_info failed with rc = %d",
rc));
/* close handle */
} else {
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode);
}
/* BB check oplock state before deciding to call following */
/* if(*oplock)
save off handle in inode and dontdoclose */
if((nd->flags & LOOKUP_OPEN) == FALSE) {
/* mknod case - do not leave file open */
CIFSSMBClose(xid, pTcon, fileHandle);
/* BB In the future chain close with the NTCreateX to narrow window */
if(newinode)
newinode->i_mode = mode;
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
(__u64)-1,
(__u64)-1,
0 /* dev */,
cifs_sb->local_nls);
else { /* BB implement via Windows security descriptors */
/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
/* in the meantime could set r/o dos attribute when perms are eg:
mode & 0222 == 0 */
}
} else if(newinode) {
newinode->i_mode = mode;
pCifsFile = (struct cifsFileInfo *)
kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
if (pCifsFile) {
memset((char *)pCifsFile, 0,
sizeof (struct cifsFileInfo));
pCifsFile->netfid = fileHandle;
pCifsFile->pid = current->pid;
pCifsFile->pInode = newinode;
/* pCifsFile->pfile = file; */ /* put in at open time */
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist,&pTcon->openFileList);
pCifsInode = CIFS_I(newinode);
if(pCifsInode) {
list_add(&pCifsFile->flist,&pCifsInode->openFileList);
if(oplock == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE;
cFYI(1,("Exclusive Oplock granted on inode %p",newinode));
} else if(oplock == OPLOCK_READ)
pCifsInode->clientCanCacheRead = TRUE;
}
write_unlock(&GlobalSMBSeslock);
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
(__u64)-1,
(__u64)-1,
0 /* dev */,
cifs_sb->local_nls);
else { /* BB implement via Windows security descriptors */
/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
/* in the meantime could set r/o dos attribute when perms are eg:
mode & 0222 == 0 */
}
}
}
}
if (buf)
kfree(buf);
if (full_path)
kfree(full_path);
FreeXid(xid);
......@@ -261,17 +314,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
cFYI(1,
(" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
if(nd) { /* BB remove begin */
cFYI(1,("In lookup nd flags = 0x%x",nd->flags));
cFYI(1,("Intent flags: 0x%x", nd->intent.open.flags));
}
/* BB remove end BB */
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&newInode, full_path,
parent_dir_inode->i_sb);
else
rc = cifs_get_inode_info(&newInode, full_path,
rc = cifs_get_inode_info(&newInode, full_path, NULL,
parent_dir_inode->i_sb);
if ((rc == 0) && (newInode != NULL)) {
......@@ -328,12 +375,6 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */
if(nd) { /* BB remove begin */
cFYI(1,("In d_revalidate nd flags = 0x%x",nd->flags));
cFYI(1,("Intent flags: 0x%x", nd->intent.open.flags));
}
/* BB remove end BB */
if (direntry->d_inode) {
if (cifs_revalidate(direntry)) {
/* unlock_kernel(); */
......
......@@ -45,16 +45,41 @@ cifs_open(struct inode *inode, struct file *file)
struct cifsTconInfo *pTcon;
struct cifsFileInfo *pCifsFile;
struct cifsInodeInfo *pCifsInode;
struct list_head * tmp;
char *full_path = NULL;
int desiredAccess = 0x20197;
int disposition = FILE_OPEN;
__u16 netfid;
FILE_ALL_INFO * buf = NULL;
xid = GetXid();
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
if (file->f_flags & O_CREAT) {
/* search inode for this file and fill in file->private_data = */
pCifsInode = CIFS_I(file->f_dentry->d_inode);
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &pCifsInode->openFileList) {
pCifsFile = list_entry(tmp,struct cifsFileInfo, flist);
if((pCifsFile->pfile == NULL)&& (pCifsFile->pid = current->pid)){
/* set mode ?? */
pCifsFile->pfile = file; /* needed for writepage */
file->private_data = pCifsFile;
break;
}
}
read_unlock(&GlobalSMBSeslock);
if(file->private_data != NULL) {
rc = 0;
FreeXid(xid);
return rc;
} else {
cERROR(1,("could not find file instance for new file %p ",file));
}
}
full_path = build_path_from_dentry(file->f_dentry);
cFYI(1, (" inode = 0x%p file flags are %x for %s", inode, file->f_flags,full_path));
......@@ -86,17 +111,19 @@ cifs_open(struct inode *inode, struct file *file)
if (file->f_flags & O_CREAT)
disposition = FILE_OVERWRITE;
/* BB first check if file has batch oplock (or oplock ?) */
/* BB finish adding in oplock support BB */
if (oplockEnabled)
oplock = REQ_OPLOCK;
else
oplock = FALSE;
/* BB pass O_SYNC flag through on file attributes .. BB */
/* Also refresh inode by passing in file_info buf returned by SMBOpen
and calling get_inode_info with returned buf (at least
helps non-Unix server case */
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
CREATE_NOT_DIR, &netfid, &oplock, cifs_sb->local_nls);
CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
if (rc) {
cFYI(1, ("cifs_open returned 0x%x ", rc));
cFYI(1, ("oplock: %d ", oplock));
......@@ -110,12 +137,27 @@ cifs_open(struct inode *inode, struct file *file)
pCifsFile->netfid = netfid;
pCifsFile->pid = current->pid;
pCifsFile->pfile = file; /* needed for writepage */
pCifsFile->pInode = inode;
write_lock(&file->f_owner.lock);
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist,&pTcon->openFileList);
pCifsInode = CIFS_I(file->f_dentry->d_inode);
if(pCifsInode->openFileList.next)
if(pCifsInode) {
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
full_path, inode->i_sb);
else
rc = cifs_get_inode_info(&file->f_dentry->d_inode,
full_path, buf, inode->i_sb);
list_add(&pCifsFile->flist,&pCifsInode->openFileList);
if(oplock == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE;
cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
} else if(oplock == OPLOCK_READ)
pCifsInode->clientCanCacheRead = TRUE;
}
write_unlock(&GlobalSMBSeslock);
write_unlock(&file->f_owner.lock);
if(file->f_flags & O_CREAT) {
......@@ -136,6 +178,8 @@ cifs_open(struct inode *inode, struct file *file)
}
}
if (buf)
kfree(buf);
if (full_path)
kfree(full_path);
FreeXid(xid);
......@@ -164,12 +208,14 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
/* list all files open on tree connection */
read_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
open_file = list_entry(tmp,struct cifsFileInfo, flist);
open_file = list_entry(tmp,struct cifsFileInfo, tlist);
if(open_file) {
if(open_file->search_resume_name) {
kfree(open_file->search_resume_name);
}
file = open_file->pfile;
list_del(&open_file->flist);
list_del(&open_file->tlist);
kfree(open_file);
if(file) {
file->private_data = NULL;
......@@ -206,7 +252,6 @@ cifs_close(struct inode *inode, struct file *file)
pTcon = cifs_sb->tcon;
if (pSMBFile) {
write_lock(&file->f_owner.lock);
if(pSMBFile->flist.next)
list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist);
write_unlock(&file->f_owner.lock);
......@@ -218,6 +263,13 @@ cifs_close(struct inode *inode, struct file *file)
} else
rc = -EBADF;
if(list_empty(&(CIFS_I(inode)->openFileList))) {
cFYI(1,("closing last open instance for inode %p",inode));
/* if the file is not open we do not know if we can cache
info on this inode, much less write behind and read ahead */
CIFS_I(inode)->clientCanCacheRead = FALSE;
CIFS_I(inode)->clientCanCacheAll = FALSE;
}
if((rc ==0) && CIFS_I(inode)->write_behind_rc)
rc = CIFS_I(inode)->write_behind_rc;
FreeXid(xid);
......@@ -463,7 +515,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
read_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
open_file = list_entry(tmp,struct cifsFileInfo, flist);
/* We could check if file is open for writing first */
/* We check if file is open for writing first */
if((open_file->pfile) &&
((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) {
......@@ -810,7 +862,13 @@ cifs_readpages(struct file *file, struct address_space *mapping,
break;
}
} else {
cFYI(1,("No bytes read"));
cFYI(1,("No bytes read cleaning remaining pages off readahead list"));
/* BB turn off caching and do new lookup on file size at server? */
while (!list_empty(page_list) && (i < num_pages)) {
page = list_entry(page_list->prev, struct page, list);
list_del(&page->list);
}
break;
}
if(smb_read_data) {
......@@ -927,7 +985,7 @@ fill_in_inode(struct inode *tmp_inode,
/* can not fill in nlink here as in qpathinfo version and Unx search */
tmp_inode->i_size = pfindData->EndOfFile;
tmp_inode->i_blocks =
do_div(pfindData->AllocationSize, tmp_inode->i_blksize);
(tmp_inode->i_blksize - 1 + pfindData->AllocationSize) >> tmp_inode->i_blkbits;
if (pfindData->AllocationSize < pfindData->EndOfFile)
cFYI(1, ("Possible sparse file: allocation size less than end of file "));
cFYI(1,
......@@ -1001,7 +1059,8 @@ unix_fill_in_inode(struct inode *tmp_inode,
pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
tmp_inode->i_size = pfindData->EndOfFile;
tmp_inode->i_blocks =
do_div(pfindData->NumOfBytes, tmp_inode->i_blksize);
(tmp_inode->i_blksize - 1 + pfindData->NumOfBytes) >> tmp_inode->i_blkbits;
if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, (" File inode "));
tmp_inode->i_op = &cifs_file_inode_ops;
......@@ -1040,6 +1099,10 @@ construct_dentry(struct qstr *qstring, struct file *file,
cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
*ptmp_inode = tmp_dentry->d_inode;
/* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
if(*ptmp_inode == NULL) {
*ptmp_inode = new_inode(file->f_dentry->d_sb);
d_instantiate(tmp_dentry, *ptmp_inode);
}
} else {
tmp_dentry = d_alloc(file->f_dentry, qstring);
*ptmp_inode = new_inode(file->f_dentry->d_sb);
......@@ -1193,7 +1256,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
renew_parental_timestamps(file->f_dentry);
lastFindData =
(FILE_DIRECTORY_INFO *) ((char *) pfindData +
le32_to_cpu(findParms.LastNameOffset));
findParms.LastNameOffset);
if((char *)lastFindData > (char *)pfindData + bufsize) {
cFYI(1,("last search entry past end of packet"));
rc = -EIO;
......@@ -1248,7 +1311,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
pfindDataUnix->FileName,
cifsFile->resume_name_length);
}
for (i = 2; i < findParms.SearchCount + 2; i++) {
for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) {
if (UnixSearch == FALSE) {
pfindData->FileNameLength =
le32_to_cpu(pfindData->FileNameLength);
......@@ -1353,7 +1416,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
/* BB save off resume key, key name and name length */
lastFindData =
(FILE_DIRECTORY_INFO *) ((char *) pfindData
+ le32_to_cpu(findNextParms.LastNameOffset));
+ findNextParms.LastNameOffset);
if((char *)lastFindData > (char *)pfindData + bufsize) {
cFYI(1,("last search entry past end of packet"));
rc = -EIO;
......
......@@ -43,6 +43,9 @@ cifs_get_inode_info_unix(struct inode **pinode,
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
char *tmp_path;
/* BB add caching check so we do not go to server to overwrite inode info to cached file
where the local file sizes are correct and the server info is stale BB */
xid = GetXid();
pTcon = cifs_sb->tcon;
......@@ -123,9 +126,13 @@ cifs_get_inode_info_unix(struct inode **pinode,
findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
inode->i_size = findData.EndOfFile;
inode->i_blksize =
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;
inode->i_blocks = do_div(findData.NumOfBytes, inode->i_blksize);
/* blksize needs to be multiple of two. So safer to default to blksize
and blkbits set in superblock so 2**blkbits and blksize will match */
/* inode->i_blksize =
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
inode->i_blocks =
(inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;
if (findData.NumOfBytes < findData.EndOfFile)
cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
cFYI(1,
......@@ -155,24 +162,38 @@ cifs_get_inode_info_unix(struct inode **pinode,
}
int
cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path, struct super_block *sb)
cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
FILE_ALL_INFO * pfindData, struct super_block *sb)
{
int xid;
int rc = 0;
FILE_ALL_INFO findData;
struct cifsTconInfo *pTcon;
struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
char *tmp_path;
char *buf = NULL;
xid = GetXid();
pTcon = cifs_sb->tcon;
cFYI(1, (" Getting info on %s ", search_path));
/* we could have done a find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, search_path, &findData,
cFYI(1,("Getting info on %s ", search_path));
if((pfindData == NULL) && (*pinode != NULL)) {
if(CIFS_I(*pinode)->clientCanCacheRead) {
cFYI(1,("No need to revalidate inode sizes on cached file "));
FreeXid(xid);
return rc;
}
}
/* if file info not passed in then get it from server */
if(pfindData == NULL) {
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
pfindData = (FILE_ALL_INFO *)buf;
/* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
cifs_sb->local_nls);
}
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) {
if (rc == -EREMOTE) {
......@@ -183,6 +204,8 @@ cifs_get_inode_info(struct inode **pinode,
strnlen(search_path, MAX_PATHCONF) + 1,
GFP_KERNEL);
if (tmp_path == NULL) {
if(buf)
kfree(buf);
FreeXid(xid);
return -ENOMEM;
}
......@@ -195,6 +218,8 @@ cifs_get_inode_info(struct inode **pinode,
kfree(tmp_path);
/* BB fix up inode etc. */
} else if (rc) {
if(buf)
kfree(buf);
FreeXid(xid);
return rc;
}
......@@ -208,32 +233,35 @@ cifs_get_inode_info(struct inode **pinode,
inode = *pinode;
cifsInfo = CIFS_I(inode);
findData.Attributes = le32_to_cpu(findData.Attributes);
cifsInfo->cifsAttrs = findData.Attributes;
pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
cifsInfo->cifsAttrs = pfindData->Attributes;
cFYI(1, (" Old time %ld ", cifsInfo->time));
cifsInfo->time = jiffies;
cFYI(1, (" New time %ld ", cifsInfo->time));
atomic_inc(&cifsInfo->inUse); /* inc on every refresh of inode */
inode->i_blksize =
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;
/* blksize needs to be multiple of two. So safer to default to blksize
and blkbits set in superblock so 2**blkbits and blksize will match */
/* inode->i_blksize =
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
/* Linux can not store file creation time unfortunately so we ignore it */
inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
inode->i_mtime =
cifs_NTtimeToUnix(le64_to_cpu(findData.LastWriteTime));
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(findData.ChangeTime));
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
cFYI(0,
(" Attributes came in as 0x%x ", findData.Attributes));
(" Attributes came in as 0x%x ", pfindData->Attributes));
/* set default mode. will override for dirs below */
inode->i_mode = cifs_sb->mnt_file_mode;
if (findData.Attributes & ATTR_REPARSE) {
if (pfindData->Attributes & ATTR_REPARSE) {
/* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
inode->i_mode |= S_IFLNK;
} else if (findData.Attributes & ATTR_DIRECTORY) {
} else if (pfindData->Attributes & ATTR_DIRECTORY) {
/* override default perms since we do not do byte range locking on dirs */
inode->i_mode = cifs_sb->mnt_dir_mode;
inode->i_mode |= S_IFDIR;
......@@ -244,14 +272,12 @@ cifs_get_inode_info(struct inode **pinode,
inode->i_mode &= ~(S_IWUGO);
/* BB add code here - validate if device or weird share or device type? */
}
inode->i_size = le64_to_cpu(findData.EndOfFile);
findData.AllocationSize = le64_to_cpu(findData.AllocationSize);
inode->i_size = le64_to_cpu(pfindData->EndOfFile);
pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
inode->i_blocks =
do_div(findData.AllocationSize, inode->i_blksize);
cFYI(1,
(" Size %ld and blocks %ld ",
(unsigned long) inode->i_size, inode->i_blocks));
inode->i_nlink = le32_to_cpu(findData.NumberOfLinks);
(inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits;
inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
/* BB fill in uid and gid here? with help from winbind?
or retrieve from NTFS stream extended attribute */
......@@ -275,6 +301,8 @@ cifs_get_inode_info(struct inode **pinode,
kdev_t_to_nr(inode->i_rdev));
}
}
if(buf)
kfree(buf);
FreeXid(xid);
return rc;
}
......@@ -290,7 +318,7 @@ cifs_read_inode(struct inode *inode)
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
cifs_get_inode_info_unix(&inode, "", inode->i_sb);
else
cifs_get_inode_info(&inode, "", inode->i_sb);
cifs_get_inode_info(&inode, "", NULL, inode->i_sb);
}
int
......@@ -323,7 +351,7 @@ cifs_unlink(struct inode *inode, struct dentry *direntry)
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, cifs_sb->local_nls);
&netfid, &oplock, NULL, cifs_sb->local_nls);
if(rc==0) {
CIFSSMBClose(xid, pTcon, netfid);
/* BB In the future chain close with the NTCreateX to narrow window */
......@@ -387,11 +415,12 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb);
else
rc = cifs_get_inode_info(&newinode, full_path,
rc = cifs_get_inode_info(&newinode, full_path,NULL,
inode->i_sb);
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode);
if(direntry->d_inode)
direntry->d_inode->i_nlink = 2;
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
......@@ -511,13 +540,13 @@ cifs_revalidate(struct dentry *direntry)
direntry->d_inode->i_count.counter, direntry,
direntry->d_time, jiffies));
cifsInode = CIFS_I(direntry->d_inode);
/* BB add check - do not need to revalidate oplocked files */
if (time_before(jiffies, cifsInode->time + HZ)) {
if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
(direntry->d_inode->i_nlink == 1) ||
(lookupCacheEnabled == 0)) {
(direntry->d_inode->i_nlink == 1)) {
if (full_path)
kfree(full_path);
FreeXid(xid);
......@@ -531,7 +560,7 @@ cifs_revalidate(struct dentry *direntry)
cifs_get_inode_info_unix(&direntry->d_inode, full_path,
direntry->d_sb);
else
cifs_get_inode_info(&direntry->d_inode, full_path,
cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
direntry->d_sb);
/* BB if not oplocked, invalidate inode pages if mtime has changed */
......
......@@ -160,7 +160,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb);
else
rc = cifs_get_inode_info(&newinode, full_path,
rc = cifs_get_inode_info(&newinode, full_path, NULL,
inode->i_sb);
if (rc != 0) {
......@@ -221,7 +221,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
cifs_sb->local_nls);
else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT,&fid, &oplock, cifs_sb->local_nls);
OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls);
if(!rc) {
rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
tmpbuffer,
......
......@@ -55,6 +55,8 @@ void
_FreeXid(unsigned int xid)
{
write_lock(&GlobalMid_Lock);
/* if(GlobalTotalActiveXid == 0)
BUG(); */
GlobalTotalActiveXid--;
write_unlock(&GlobalMid_Lock);
}
......@@ -390,12 +392,12 @@ is_valid_oplock_break(struct smb_hdr *buf)
read_unlock(&GlobalSMBSeslock);
cFYI(1,("Matching file id, processing oplock break"));
pCifsInode =
CIFS_I(netfile->pfile->f_dentry->d_inode);
CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = FALSE;
if(pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead = FALSE;
pCifsInode->oplockPending = TRUE;
AllocOplockQEntry(netfile->pfile, tcon);
AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon);
cFYI(1,("about to wake up oplock thd"));
wake_up_process(oplockThread);
return TRUE;
......
......@@ -27,26 +27,31 @@
#define NtLmChallenge 2
#define NtLmAuthenticate 3
#define UnknownMessage 8
/* Negotiate Flags */
#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode
#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM
#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm
#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability
#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality
#define NTLMSSP_NEGOTIATE_DGRAM 0x0040
#define NTLMSSP_NEGOTIATE_DGRAM 0x0040
#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal
#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
#define NTLMSSP_TARGET_TYPE_SERVER 0x20000
#define NTLMSSP_TARGET_TYPE_SHARE 0x40000
#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000
#define NTLMSSP_REQUEST_INIT_RESP 0x100000
#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000
#define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000
#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000
#define NTLMSSP_NEGOTIATE_128 0x20000000
#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
/* server only negotiate flags */
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 /* NEGOTIATE_DOMAIN 0x1000 ? */
#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 /* NEGOTIATE_WORKSTATION 0x2000 ? */
#define NTLMSSP_NEGOTIATE_56 0x80000000
/* Although typedefs are not commonly used for structure definitions */
/* in the Linux kernel, in this particular case they are useful */
......@@ -62,7 +67,7 @@ typedef struct _SECURITY_BUFFER {
typedef struct _NEGOTIATE_MESSAGE {
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
__u32 MessageType;
__u32 MessageType; /* 1 */
__u32 NegotiateFlags;
SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */
SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */
......@@ -72,7 +77,7 @@ typedef struct _NEGOTIATE_MESSAGE {
typedef struct _CHALLENGE_MESSAGE {
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
__u32 MessageType;
__u32 MessageType; /* 2 */
SECURITY_BUFFER TargetName;
__u32 NegotiateFlags;
__u8 Challenge[CIFS_CRYPTO_KEY_SIZE];
......@@ -82,7 +87,7 @@ typedef struct _CHALLENGE_MESSAGE {
typedef struct _AUTHENTICATE_MESSAGE {
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
__u32 MessageType;
__u32 MessageType; /* 3 */
SECURITY_BUFFER LmChallengeResponse;
SECURITY_BUFFER NtChallengeResponse;
SECURITY_BUFFER DomainName;
......
......@@ -101,10 +101,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
}
struct oplock_q_entry *
AllocOplockQEntry(struct file * file, struct cifsTconInfo * tcon)
AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
{
struct oplock_q_entry *temp;
if ((file == NULL) || (tcon == NULL)) {
if ((pinode== NULL) || (tcon == NULL)) {
cERROR(1, ("Null parms passed to AllocOplockQEntry"));
return NULL;
}
......@@ -113,8 +113,9 @@ AllocOplockQEntry(struct file * file, struct cifsTconInfo * tcon)
if (temp == NULL)
return temp;
else {
temp->file_to_flush = file;
temp->pinode = pinode;
temp->tcon = tcon;
temp->netfid = fid;
write_lock(&GlobalMid_Lock);
list_add_tail(&temp->qhead, &GlobalOplock_Q);
write_unlock(&GlobalMid_Lock);
......@@ -215,7 +216,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
if (long_op > 1) /* writes past end of file can take looooong time */
timeout = 300 * HZ;
else if (long_op == 1)
timeout = 60 * HZ;
timeout = 45 * HZ; /* should be greater than
servers oplock break timeout (about 43 seconds) */
else
timeout = 15 * HZ;
/* wait for 15 seconds or until woken up due to response arriving or
......@@ -234,6 +236,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
receive_len =
be32_to_cpu(midQ->resp_buf->smb_buf_length);
else {
cFYI(1,("No response buffer"));
DeleteMidQEntry(midQ);
return -EIO;
}
......@@ -286,8 +289,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
4 /* do not count RFC1001 header */ +
(2 * out_buf->WordCount) + 2 /* bcc */ )
BCC(out_buf) = le16_to_cpu(BCC(out_buf));
} else
} else {
rc = -EIO;
cFYI(1,("Bad MID state? "));
}
}
cifs_no_response_exit:
DeleteMidQEntry(midQ); /* BB what if process is killed?
......
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