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