aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-10-20 16:44:56 -0400
committerSteve French <sfrench@us.ibm.com>2005-10-20 16:44:56 -0400
commit23e7dd7d95f6fdc167a6d6ddea79ced0af33bbff (patch)
treedc7f5947df09eaca23c25a4d4a908e4dfe81cf40
parent84d2f07e8e5e2424eec0f5acfef6792c924a0549 (diff)
[CIFS] Defer close of file handle slightly if there are pending writes that
need to get in ahead of it that depend on that file handle. Fixes occassional bad file handle errors on write with heavy use multiple process cases. Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/CHANGES6
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/file.c88
-rw-r--r--fs/cifs/inode.c1
5 files changed, 73 insertions, 25 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index f554a70c9cf3..5bab24f59053 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,9 @@
1Version 1.39
2------------
3Defer close of a file handle slightly if pending writes depend on that file handle
4(this reduces the EBADF bad file handle errors that can be logged under heavy
5stress on writes).
6
1Version 1.38 7Version 1.38
2------------ 8------------
3Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket) 9Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 4cdb29fdc8c2..1223fa81dbd2 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -97,5 +97,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
97extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); 97extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
98extern int cifs_ioctl (struct inode * inode, struct file * filep, 98extern int cifs_ioctl (struct inode * inode, struct file * filep,
99 unsigned int command, unsigned long arg); 99 unsigned int command, unsigned long arg);
100#define CIFS_VERSION "1.38" 100#define CIFS_VERSION "1.39"
101#endif /* _CIFSFS_H */ 101#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 839a55667c3c..1ba08f8c5bc4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -299,6 +299,7 @@ struct cifsFileInfo {
299 struct inode * pInode; /* needed for oplock break */ 299 struct inode * pInode; /* needed for oplock break */
300 unsigned closePend:1; /* file is marked to close */ 300 unsigned closePend:1; /* file is marked to close */
301 unsigned invalidHandle:1; /* file closed via session abend */ 301 unsigned invalidHandle:1; /* file closed via session abend */
302 atomic_t wrtPending; /* handle in use - defer close */
302 struct semaphore fh_sem; /* prevents reopen race after dead ses*/ 303 struct semaphore fh_sem; /* prevents reopen race after dead ses*/
303 char * search_resume_name; /* BB removeme BB */ 304 char * search_resume_name; /* BB removeme BB */
304 unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ 305 unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 23af20d5af7c..da4f5e10b3cc 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -29,6 +29,7 @@
29#include <linux/pagevec.h> 29#include <linux/pagevec.h>
30#include <linux/smp_lock.h> 30#include <linux/smp_lock.h>
31#include <linux/writeback.h> 31#include <linux/writeback.h>
32#include <linux/delay.h>
32#include <asm/div64.h> 33#include <asm/div64.h>
33#include "cifsfs.h" 34#include "cifsfs.h"
34#include "cifspdu.h" 35#include "cifspdu.h"
@@ -50,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private(
50 private_data->pInode = inode; 51 private_data->pInode = inode;
51 private_data->invalidHandle = FALSE; 52 private_data->invalidHandle = FALSE;
52 private_data->closePend = FALSE; 53 private_data->closePend = FALSE;
54 /* we have to track num writers to the inode, since writepages
55 does not tell us which handle the write is for so there can
56 be a close (overlapping with write) of the filehandle that
57 cifs_writepages chose to use */
58 atomic_set(&private_data->wrtPending,0);
53 59
54 return private_data; 60 return private_data;
55} 61}
@@ -473,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file)
473 /* no sense reconnecting to close a file that is 479 /* no sense reconnecting to close a file that is
474 already closed */ 480 already closed */
475 if (pTcon->tidStatus != CifsNeedReconnect) { 481 if (pTcon->tidStatus != CifsNeedReconnect) {
482 int timeout = 2;
483 while((atomic_read(&pSMBFile->wrtPending) != 0)
484 && (timeout < 1000) ) {
485 /* Give write a better chance to get to
486 server ahead of the close. We do not
487 want to add a wait_q here as it would
488 increase the memory utilization as
489 the struct would be in each open file,
490 but this should give enough time to
491 clear the socket */
492 cERROR(1,("close with pending writes"));
493 msleep(timeout);
494 timeout *= 4;
495 }
476 write_unlock(&file->f_owner.lock); 496 write_unlock(&file->f_owner.lock);
477 rc = CIFSSMBClose(xid, pTcon, 497 rc = CIFSSMBClose(xid, pTcon,
478 pSMBFile->netfid); 498 pSMBFile->netfid);
@@ -919,9 +939,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
919 if (open_file->pfile && 939 if (open_file->pfile &&
920 ((open_file->pfile->f_flags & O_RDWR) || 940 ((open_file->pfile->f_flags & O_RDWR) ||
921 (open_file->pfile->f_flags & O_WRONLY))) { 941 (open_file->pfile->f_flags & O_WRONLY))) {
942 atomic_inc(&open_file->wrtPending);
922 read_unlock(&GlobalSMBSeslock); 943 read_unlock(&GlobalSMBSeslock);
923 if((open_file->invalidHandle) && 944 if((open_file->invalidHandle) &&
924 (!open_file->closePend)) { 945 (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
925 rc = cifs_reopen_file(&cifs_inode->vfs_inode, 946 rc = cifs_reopen_file(&cifs_inode->vfs_inode,
926 open_file->pfile, FALSE); 947 open_file->pfile, FALSE);
927 /* if it fails, try another handle - might be */ 948 /* if it fails, try another handle - might be */
@@ -929,6 +950,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
929 if(rc) { 950 if(rc) {
930 cFYI(1,("failed on reopen file in wp")); 951 cFYI(1,("failed on reopen file in wp"));
931 read_lock(&GlobalSMBSeslock); 952 read_lock(&GlobalSMBSeslock);
953 /* can not use this handle, no write
954 pending on this one after all */
955 atomic_dec
956 (&open_file->wrtPending);
932 continue; 957 continue;
933 } 958 }
934 } 959 }
@@ -981,6 +1006,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
981 if (open_file) { 1006 if (open_file) {
982 bytes_written = cifs_write(open_file->pfile, write_data, 1007 bytes_written = cifs_write(open_file->pfile, write_data,
983 to-from, &offset); 1008 to-from, &offset);
1009 atomic_dec(&open_file->wrtPending);
984 /* Does mm or vfs already set times? */ 1010 /* Does mm or vfs already set times? */
985 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); 1011 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
986 if ((bytes_written > 0) && (offset)) { 1012 if ((bytes_written > 0) && (offset)) {
@@ -1016,7 +1042,7 @@ static int cifs_writepages(struct address_space *mapping,
1016 pgoff_t next; 1042 pgoff_t next;
1017 int nr_pages; 1043 int nr_pages;
1018 __u64 offset = 0; 1044 __u64 offset = 0;
1019 struct cifsFileInfo *open_file = NULL; 1045 struct cifsFileInfo *open_file;
1020 struct page *page; 1046 struct page *page;
1021 struct pagevec pvec; 1047 struct pagevec pvec;
1022 int rc = 0; 1048 int rc = 0;
@@ -1071,15 +1097,6 @@ retry:
1071 int first; 1097 int first;
1072 unsigned int i; 1098 unsigned int i;
1073 1099
1074 if (!open_file) {
1075 open_file = find_writable_file(CIFS_I(mapping->host));
1076 if (!open_file) {
1077 pagevec_release(&pvec);
1078 cERROR(1, ("No writable handles for inode"));
1079 return -EIO;
1080 }
1081 }
1082
1083 first = -1; 1100 first = -1;
1084 next = 0; 1101 next = 0;
1085 n_iov = 0; 1102 n_iov = 0;
@@ -1155,18 +1172,32 @@ retry:
1155 break; 1172 break;
1156 } 1173 }
1157 if (n_iov) { 1174 if (n_iov) {
1158 rc = CIFSSMBWrite2(xid, cifs_sb->tcon, 1175 /* Search for a writable handle every time we call
1159 open_file->netfid, bytes_to_write, 1176 * CIFSSMBWrite2. We can't rely on the last handle
1160 offset, &bytes_written, iov, n_iov, 1177 * we used to still be valid
1161 1); 1178 */
1162 if (rc || bytes_written < bytes_to_write) { 1179 open_file = find_writable_file(CIFS_I(mapping->host));
1163 cERROR(1,("CIFSSMBWrite2 returned %d, written = %x", 1180 if (!open_file) {
1164 rc, bytes_written)); 1181 cERROR(1, ("No writable handles for inode"));
1165 set_bit(AS_EIO, &mapping->flags); 1182 rc = -EBADF;
1166 SetPageError(page);
1167 } else { 1183 } else {
1168 cifs_stats_bytes_written(cifs_sb->tcon, 1184 rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
1169 bytes_written); 1185 open_file->netfid,
1186 bytes_to_write, offset,
1187 &bytes_written, iov, n_iov,
1188 1);
1189 atomic_dec(&open_file->wrtPending);
1190 if (rc || bytes_written < bytes_to_write) {
1191 cERROR(1,("Write2 ret %d, written = %d",
1192 rc, bytes_written));
1193 /* BB what if continued retry is
1194 requested via mount flags? */
1195 set_bit(AS_EIO, &mapping->flags);
1196 SetPageError(page);
1197 } else {
1198 cifs_stats_bytes_written(cifs_sb->tcon,
1199 bytes_written);
1200 }
1170 } 1201 }
1171 for (i = 0; i < n_iov; i++) { 1202 for (i = 0; i < n_iov; i++) {
1172 page = pvec.pages[first + i]; 1203 page = pvec.pages[first + i];
@@ -1788,9 +1819,18 @@ static int cifs_readpage(struct file *file, struct page *page)
1788 page caching in the current Linux kernel design */ 1819 page caching in the current Linux kernel design */
1789int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) 1820int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
1790{ 1821{
1791 if (cifsInode && find_writable_file(cifsInode)) 1822 struct cifsFileInfo *open_file = NULL;
1823
1824 if (cifsInode)
1825 open_file = find_writable_file(cifsInode);
1826
1827 if(open_file) {
1828 /* there is not actually a write pending so let
1829 this handle go free and allow it to
1830 be closable if needed */
1831 atomic_dec(&open_file->wrtPending);
1792 return 0; 1832 return 0;
1793 else 1833 } else
1794 return 1; 1834 return 1;
1795} 1835}
1796 1836
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ff4d1cc7c248..912d401600f6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1006,6 +1006,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1006 __u32 npid = open_file->pid; 1006 __u32 npid = open_file->pid;
1007 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, 1007 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
1008 nfid, npid, FALSE); 1008 nfid, npid, FALSE);
1009 atomic_dec(&open_file->wrtPending);
1009 cFYI(1,("SetFSize for attrs rc = %d", rc)); 1010 cFYI(1,("SetFSize for attrs rc = %d", rc));
1010 if(rc == -EINVAL) { 1011 if(rc == -EINVAL) {
1011 int bytes_written; 1012 int bytes_written;