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

Fix various SMP/locking problems pointed out by Shoobhit Dayal and Arjan van de Ven

parent 3e753cea
......@@ -20,6 +20,7 @@ Patch Contributors
Zwane Mwaikambo
Andi Kleen
Amrut Joshi
Shobhit Dayal
Test case and Bug Report contributors
-------------------------------------
......
......@@ -207,14 +207,106 @@ int relock_files(struct cifsFileInfo * cifsFile)
return rc;
}
static int cifs_reopen_file(struct inode *inode, struct file *file)
{
int rc = -EACCES;
int xid, oplock;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
struct cifsFileInfo *pCifsFile;
struct cifsInodeInfo *pCifsInode;
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;
full_path = build_path_from_dentry(file->f_dentry);
cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
desiredAccess = GENERIC_READ;
else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
desiredAccess = GENERIC_WRITE;
else if ((file->f_flags & O_ACCMODE) == O_RDWR)
desiredAccess = GENERIC_ALL;
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);
if(buf==0) {
if (full_path)
kfree(full_path);
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
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));
} else {
if (file->private_data) {
pCifsFile = (struct cifsFileInfo *) file->private_data;
pCifsFile->netfid = netfid;
pCifsFile->invalidHandle = FALSE;
pCifsInode = CIFS_I(file->f_dentry->d_inode);
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);
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;
pCifsInode->clientCanCacheAll = FALSE;
} else {
pCifsInode->clientCanCacheRead = FALSE;
pCifsInode->clientCanCacheAll = FALSE;
}
}
} else
rc = -EBADF;
}
if (buf)
kfree(buf);
if (full_path)
kfree(full_path);
FreeXid(xid);
return rc;
}
/* Try to reopen files that were closed when session to server was lost */
int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
{
int rc = 0;
struct cifsFileInfo *open_file = NULL;
struct file * file = NULL;
struct list_head *tmp;
struct list_head *tmp1;
struct list_head invalid_file_list;
struct list_head * tmp;
struct list_head * tmp1;
INIT_LIST_HEAD(&invalid_file_list);
/* list all files open on tree connection and mark them invalid */
write_lock(&GlobalSMBSeslock);
......@@ -222,34 +314,29 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
open_file = list_entry(tmp,struct cifsFileInfo, tlist);
if(open_file) {
open_file->invalidHandle = TRUE;
list_move(&open_file->tlist,&invalid_file_list);
}
}
/* reopen files */
for(;;) {
list_for_each(tmp,&invalid_file_list) {
/* BB need to fix above to check list end and skip entries we do not need to reopen */
if(list_empty(&pTcon->openFileList)) {
open_file = list_entry(tmp,struct cifsFileInfo, tlist);
if(open_file == NULL) {
break;
} else {
open_file = list_entry(tmp,struct cifsFileInfo, tlist);
if(open_file) {
if(open_file->invalidHandle == FALSE)
if(open_file->invalidHandle == FALSE) {
list_move(&open_file->tlist,&pTcon->openFileList);
continue;
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;
if(file->f_dentry == 0) {
cFYI(1,("Null dentry for file %p",file));
} else {
write_unlock(&GlobalSMBSeslock);
rc = cifs_open(file->f_dentry->d_inode,file);
rc = cifs_reopen_file(file->f_dentry->d_inode,file);
write_lock(&GlobalSMBSeslock);
list_move(&open_file->tlist,&pTcon->openFileList);
if(rc) {
cFYI(1,("reconnecting file %s failed with %d",
file->f_dentry->d_name.name,rc));
......@@ -260,9 +347,6 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
}
}
}
}
}
write_unlock(&GlobalSMBSeslock);
return rc;
}
......
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