Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 12075
b: refs/heads/master
c: 23e7dd7
h: refs/heads/master
i:
  12073: fdcdefb
  12071: 3eae0c3
v: v3
  • Loading branch information
Steve French committed Oct 20, 2005
1 parent 7571046 commit fba8b56
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 26 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 84d2f07e8e5e2424eec0f5acfef6792c924a0549
refs/heads/master: 23e7dd7d95f6fdc167a6d6ddea79ced0af33bbff
6 changes: 6 additions & 0 deletions trunk/fs/cifs/CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Version 1.39
------------
Defer close of a file handle slightly if pending writes depend on that file handle
(this reduces the EBADF bad file handle errors that can be logged under heavy
stress on writes).

Version 1.38
------------
Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
Expand Down
2 changes: 1 addition & 1 deletion trunk/fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl (struct inode * inode, struct file * filep,
unsigned int command, unsigned long arg);
#define CIFS_VERSION "1.38"
#define CIFS_VERSION "1.39"
#endif /* _CIFSFS_H */
1 change: 1 addition & 0 deletions trunk/fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ struct cifsFileInfo {
struct inode * pInode; /* needed for oplock break */
unsigned closePend:1; /* file is marked to close */
unsigned invalidHandle:1; /* file closed via session abend */
atomic_t wrtPending; /* handle in use - defer close */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/
char * search_resume_name; /* BB removeme BB */
unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
Expand Down
88 changes: 64 additions & 24 deletions trunk/fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <linux/pagevec.h>
#include <linux/smp_lock.h>
#include <linux/writeback.h>
#include <linux/delay.h>
#include <asm/div64.h>
#include "cifsfs.h"
#include "cifspdu.h"
Expand All @@ -50,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private(
private_data->pInode = inode;
private_data->invalidHandle = FALSE;
private_data->closePend = FALSE;
/* we have to track num writers to the inode, since writepages
does not tell us which handle the write is for so there can
be a close (overlapping with write) of the filehandle that
cifs_writepages chose to use */
atomic_set(&private_data->wrtPending,0);

return private_data;
}
Expand Down Expand Up @@ -473,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file)
/* no sense reconnecting to close a file that is
already closed */
if (pTcon->tidStatus != CifsNeedReconnect) {
int timeout = 2;
while((atomic_read(&pSMBFile->wrtPending) != 0)
&& (timeout < 1000) ) {
/* Give write a better chance to get to
server ahead of the close. We do not
want to add a wait_q here as it would
increase the memory utilization as
the struct would be in each open file,
but this should give enough time to
clear the socket */
cERROR(1,("close with pending writes"));
msleep(timeout);
timeout *= 4;
}
write_unlock(&file->f_owner.lock);
rc = CIFSSMBClose(xid, pTcon,
pSMBFile->netfid);
Expand Down Expand Up @@ -919,16 +939,21 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
if (open_file->pfile &&
((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) {
atomic_inc(&open_file->wrtPending);
read_unlock(&GlobalSMBSeslock);
if((open_file->invalidHandle) &&
(!open_file->closePend)) {
(!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
rc = cifs_reopen_file(&cifs_inode->vfs_inode,
open_file->pfile, FALSE);
/* if it fails, try another handle - might be */
/* dangerous to hold up writepages with retry */
if(rc) {
cFYI(1,("failed on reopen file in wp"));
read_lock(&GlobalSMBSeslock);
/* can not use this handle, no write
pending on this one after all */
atomic_dec
(&open_file->wrtPending);
continue;
}
}
Expand Down Expand Up @@ -981,6 +1006,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
if (open_file) {
bytes_written = cifs_write(open_file->pfile, write_data,
to-from, &offset);
atomic_dec(&open_file->wrtPending);
/* Does mm or vfs already set times? */
inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
if ((bytes_written > 0) && (offset)) {
Expand Down Expand Up @@ -1016,7 +1042,7 @@ static int cifs_writepages(struct address_space *mapping,
pgoff_t next;
int nr_pages;
__u64 offset = 0;
struct cifsFileInfo *open_file = NULL;
struct cifsFileInfo *open_file;
struct page *page;
struct pagevec pvec;
int rc = 0;
Expand Down Expand Up @@ -1071,15 +1097,6 @@ static int cifs_writepages(struct address_space *mapping,
int first;
unsigned int i;

if (!open_file) {
open_file = find_writable_file(CIFS_I(mapping->host));
if (!open_file) {
pagevec_release(&pvec);
cERROR(1, ("No writable handles for inode"));
return -EIO;
}
}

first = -1;
next = 0;
n_iov = 0;
Expand Down Expand Up @@ -1155,18 +1172,32 @@ static int cifs_writepages(struct address_space *mapping,
break;
}
if (n_iov) {
rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
open_file->netfid, bytes_to_write,
offset, &bytes_written, iov, n_iov,
1);
if (rc || bytes_written < bytes_to_write) {
cERROR(1,("CIFSSMBWrite2 returned %d, written = %x",
rc, bytes_written));
set_bit(AS_EIO, &mapping->flags);
SetPageError(page);
/* Search for a writable handle every time we call
* CIFSSMBWrite2. We can't rely on the last handle
* we used to still be valid
*/
open_file = find_writable_file(CIFS_I(mapping->host));
if (!open_file) {
cERROR(1, ("No writable handles for inode"));
rc = -EBADF;
} else {
cifs_stats_bytes_written(cifs_sb->tcon,
bytes_written);
rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
open_file->netfid,
bytes_to_write, offset,
&bytes_written, iov, n_iov,
1);
atomic_dec(&open_file->wrtPending);
if (rc || bytes_written < bytes_to_write) {
cERROR(1,("Write2 ret %d, written = %d",
rc, bytes_written));
/* BB what if continued retry is
requested via mount flags? */
set_bit(AS_EIO, &mapping->flags);
SetPageError(page);
} else {
cifs_stats_bytes_written(cifs_sb->tcon,
bytes_written);
}
}
for (i = 0; i < n_iov; i++) {
page = pvec.pages[first + i];
Expand Down Expand Up @@ -1788,9 +1819,18 @@ static int cifs_readpage(struct file *file, struct page *page)
page caching in the current Linux kernel design */
int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
{
if (cifsInode && find_writable_file(cifsInode))
struct cifsFileInfo *open_file = NULL;

if (cifsInode)
open_file = find_writable_file(cifsInode);

if(open_file) {
/* there is not actually a write pending so let
this handle go free and allow it to
be closable if needed */
atomic_dec(&open_file->wrtPending);
return 0;
else
} else
return 1;
}

Expand Down
1 change: 1 addition & 0 deletions trunk/fs/cifs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
__u32 npid = open_file->pid;
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
nfid, npid, FALSE);
atomic_dec(&open_file->wrtPending);
cFYI(1,("SetFSize for attrs rc = %d", rc));
if(rc == -EINVAL) {
int bytes_written;
Expand Down

0 comments on commit fba8b56

Please sign in to comment.