Commit 629d5ab8 authored by Steve French's avatar Steve French Committed by Steve French

Fix oops caused by lack of spinlock protection on some lists. Fix display

of NTFS dfs junctions (which now correctly appear as symlinks).
Return writebehind caching errors on file close.
parent 4708c3cd
......@@ -20,3 +20,9 @@ Patch Contributors
Zwane Mwaikambo
Andi Kleen
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.
Version 0.77
------------
Fix display of NTFS DFS junctions to display as symlinks.
They are the network equivalent. Fix oops in
cifs_partialpagewrite caused by missing spinlock protection
of openfile linked list. Allow writebehind caching errors to
be returned to the application at file close.
Version 0.76
------------
Clean up options displayed in /proc/mounts by show_options to
......
......@@ -18,6 +18,8 @@ c) multi-user mounts - multiplexed sessionsetups over single vc
d) Kerberos/SPNEGO session setup support - (started)
e) NTLMv2 authentication and MD5-HMAC signing SMB PDUs - (mostly implemented)
signing necessary for some Windows 2003 servers in domain
controller mode.
f) oplock support (ie safe CIFS distributed file caching) is not quite complete.
In addition Directory entry caching relies on a 1 second timer, rather than
......@@ -52,7 +54,8 @@ file opens on top of each other by incrementing reference count rather
than resending (helps reduce server resource utilization and avoid
spurious oplock breaks).
KNOWN BUGS (updated March 7, 2003)
KNOWN BUGS (updated May 16, 2003)
====================================
1) existing symbolic links (Windows reparse points) are recognized but
can not be created remotely. They are implemented for Samba and those that
......@@ -60,6 +63,11 @@ support the CIFS Unix extensions but Samba has a bug currently handling
symlink text beginning with slash
2) delete of file with read-only attribute set will fail (may be ok)
3) mount helper syntax not quite matching man page
4) follow_link and readdir code does not follow dfs junctions
but recognizes them
5) create of new files to FAT partitions on Windows servers can
succeed but still return access denied (appears to be Windows
not client problem). NTFS partitions do not have this problem.
Misc testing to do
=================
......@@ -68,6 +76,6 @@ types.
2) Run dbench
3) Finish FSX testing on SMP now that we workaround the Samba bug
3) Finish high stress fsx testing on SMP clients
4) Additional performance testing and optimization
......@@ -89,8 +89,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses->serverOS, ses->serverNOS, ses->capabilities);
buf += length;
if(ses->server)
buf += sprintf(buf, "\tLocal Users To Same Server: %d ",
atomic_read(&ses->server->socketUseCount));
buf += sprintf(buf, "\tLocal Users To Same Server: %d ",
atomic_read(&ses->server->socketUseCount));
}
read_unlock(&GlobalSMBSeslock);
sprintf(buf, "\n");
......
......@@ -427,6 +427,7 @@ cifs_destroy_mids(void)
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;
......@@ -442,9 +443,8 @@ static int cifs_oplock_thread(void * dummyarg)
/* BB add missing code */
cFYI(1,("oplock thread woken up - flush inode")); /* BB remove */
write_lock(&GlobalMid_Lock);
list_for_each(tmp, &GlobalOplock_Q) {
oplock_item = list_entry(tmp, struct
oplock_q_entry,
list_for_each_safe(tmp, tmp1, &GlobalOplock_Q) {
oplock_item = list_entry(tmp, struct oplock_q_entry,
qhead);
if(oplock_item) {
pTcon = oplock_item->tcon;
......@@ -453,6 +453,9 @@ static int cifs_oplock_thread(void * dummyarg)
DeleteOplockQEntry(oplock_item);
write_unlock(&GlobalMid_Lock);
rc = filemap_fdatawrite(pfile->f_dentry->d_inode->i_mapping);
if(rc)
CIFS_I(pfile->f_dentry->d_inode)->write_behind_rc
= rc;
cFYI(1,("Oplock flush file %p rc %d",pfile,rc));
/* send oplock break */
write_lock(&GlobalMid_Lock);
......
......@@ -204,7 +204,7 @@ struct cifsFileInfo {
__u16 netfid; /* file id from remote */
/* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */
struct file * pfile; /* needed for writepage */
struct file * pfile; /* needed for writepage */
int endOfSearch:1; /* we have reached end of search */
int closePend:1; /* file is marked to close */
int emptyDir:1;
......@@ -221,6 +221,7 @@ struct cifsInodeInfo {
struct list_head lockList;
/* BB add in lists for dirty pages - i.e. write caching info for oplock */
struct list_head openFileList;
int write_behind_rc;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
atomic_t inUse; /* num concurrent users (local openers cifs) of file*/
unsigned long time; /* jiffies of last update/check of inode */
......
......@@ -110,10 +110,14 @@ cifs_open(struct inode *inode, struct file *file)
pCifsFile->netfid = netfid;
pCifsFile->pid = current->pid;
pCifsFile->pfile = file; /* needed for writepage */
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)
list_add(&pCifsFile->flist,&pCifsInode->openFileList);
write_unlock(&GlobalSMBSeslock);
write_unlock(&file->f_owner.lock);
if(file->f_flags & O_CREAT) {
/* time to set mode which we can not set earlier due
to problems creating new read-only files */
......@@ -152,11 +156,13 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
{
int rc = 0;
struct cifsFileInfo *open_file = NULL;
struct file * file = NULL;
struct file * file = NULL;
struct list_head *tmp;
struct list_head *tmp1;
/* list all files open on tree connection */
list_for_each(tmp, &pTcon->openFileList) {
read_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
open_file = list_entry(tmp,struct cifsFileInfo, flist);
if(open_file) {
if(open_file->search_resume_name) {
......@@ -166,7 +172,9 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
kfree(open_file);
if(file) {
file->private_data = NULL;
read_unlock(&GlobalSMBSeslock);
rc = cifs_open(file->f_dentry->d_inode,file);
read_lock(&GlobalSMBSeslock);
if(rc) {
cFYI(1,("reconnecting file %s failed with %d",
file->f_dentry->d_name.name,rc));
......@@ -177,6 +185,7 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
}
}
}
read_unlock(&GlobalSMBSeslock);
return rc;
}
......@@ -195,9 +204,11 @@ cifs_close(struct inode *inode, struct file *file)
cifs_sb = CIFS_SB(inode->i_sb);
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);
rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid);
if(pSMBFile->search_resume_name)
kfree(pSMBFile->search_resume_name);
......@@ -206,6 +217,8 @@ cifs_close(struct inode *inode, struct file *file)
} else
rc = -EBADF;
if((rc ==0) && CIFS_I(inode)->write_behind_rc)
rc = CIFS_I(inode)->write_behind_rc;
FreeXid(xid);
return rc;
}
......@@ -407,6 +420,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
struct cifsInodeInfo *cifsInode;
struct cifsFileInfo *open_file = NULL;
struct list_head *tmp;
struct list_head *tmp1;
int xid;
xid = GetXid();
......@@ -445,14 +459,17 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
cifsInode = CIFS_I(mapping->host);
list_for_each(tmp, &cifsInode->openFileList) {
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 */
if((open_file->pfile) &&
((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) {
read_unlock(&GlobalSMBSeslock);
bytes_written = cifs_write(open_file->pfile, write_data,
to-from, &offset);
to-from, &offset);
read_lock(&GlobalSMBSeslock);
/* Does mm or vfs already set times? */
inode->i_atime = inode->i_mtime = CURRENT_TIME;
if ((bytes_written > 0) && (offset)) {
......@@ -462,6 +479,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
}
}
}
read_unlock(&GlobalSMBSeslock);
if(open_file == NULL) {
cFYI(1,("No writeable filehandles for inode"));
rc = -EIO;
......@@ -548,7 +566,8 @@ cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
dentry->d_name.name, datasync));
rc = filemap_fdatawrite(inode->i_mapping);
if(rc == 0)
CIFS_I(inode)->write_behind_rc = 0;
FreeXid(xid);
return rc;
}
......@@ -600,6 +619,9 @@ int cifs_flush(struct file *file)
/* filemapfdatawrite appears easier for the time being */
rc = filemap_fdatawrite(inode->i_mapping);
if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
CIFS_I(inode)->write_behind_rc = 0;
cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
return rc;
......@@ -678,12 +700,16 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
while (bytes_read > 0) {
if(list_empty(pages))
break;
spin_lock(&mapping->page_lock);
page = list_entry(pages->prev, struct page, list);
list_del(&page->list);
spin_unlock(&mapping->page_lock);
if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
page_cache_release(page);
cFYI(1,("Add page cache failed"));
cFYI(1,("Add page cache failed"));
continue;
}
......@@ -739,12 +765,14 @@ cifs_readpages(struct file *file, struct address_space *mapping,
pagevec_init(&lru_pvec, 0);
for(i = 0;i<num_pages;) {
spin_lock(&mapping->page_lock);
if(list_empty(page_list)) {
break;
}
page = list_entry(page_list->prev, struct page, list);
offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
spin_unlock(&mapping->page_lock);
/* for reads over a certain size could initiate async read ahead */
cFYI(0,("Read %d pages into cache at offset %ld ",
......@@ -762,12 +790,15 @@ cifs_readpages(struct file *file, struct address_space *mapping,
if ((rc < 0) || (smb_read_data == NULL)) {
cFYI(1,("Read error in readpages: %d",rc));
/* clean up remaing pages off list */
spin_lock(&mapping->page_lock);
while (!list_empty(page_list) && (i < num_pages)) {
page = list_entry(page_list->prev, struct page, list);
list_del(&page->list);
}
spin_unlock(&mapping->page_lock);
break;
} else if (bytes_read > 0){
} else if (bytes_read > 0) {
pSMBr = (struct smb_com_read_rsp *)smb_read_data;
cifs_copy_cache_pages(mapping, page_list, bytes_read,
smb_read_data + 4 /* RFC1000 hdr */ +
......@@ -783,9 +814,9 @@ cifs_readpages(struct file *file, struct address_space *mapping,
}
if(smb_read_data) {
buf_release(smb_read_data);
smb_read_data = 0;
}
bytes_read = 0;
smb_read_data = 0;
}
bytes_read = 0;
}
pagevec_lru_add(&lru_pvec);
......
......@@ -115,7 +115,7 @@ AllocOplockQEntry(struct file * file, struct cifsTconInfo * tcon)
list_add_tail(&temp->qhead, &GlobalOplock_Q);
write_unlock(&GlobalMid_Lock);
}
return temp;
return temp;
}
......
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