<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Trond Myklebust &lt;trond.myklebust@fys.uio.no&gt;

NFSv2/v3/v4: Ensure that fsync() flushes all writebacks to disk rather than
just the ones labelled as belonging to our file.  This fixes a bug whereby
msync() will fail to flush its pages to disk.


---

 fs/nfs/file.c            |    2 +-
 fs/nfs/inode.c           |    2 +-
 fs/nfs/pagelist.c        |    5 -----
 fs/nfs/write.c           |   40 ++++++++++++++++------------------------
 include/linux/nfs_fs.h   |   23 ++++++-----------------
 include/linux/nfs_page.h |    2 +-
 6 files changed, 25 insertions(+), 49 deletions(-)

diff -puN fs/nfs/file.c~nfs-fix-msync fs/nfs/file.c
--- 25/fs/nfs/file.c~nfs-fix-msync	2004-02-29 14:47:53.000000000 -0800
+++ 25-akpm/fs/nfs/file.c	2004-02-29 14:47:53.000000000 -0800
@@ -184,7 +184,7 @@ nfs_fsync(struct file *file, struct dent
 	dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode-&gt;i_sb-&gt;s_id, inode-&gt;i_ino);
 
 	lock_kernel();
-	status = nfs_wb_file(inode, file);
+	status = nfs_wb_all(inode);
 	if (!status) {
 		status = file-&gt;f_error;
 		file-&gt;f_error = 0;
diff -puN fs/nfs/inode.c~nfs-fix-msync fs/nfs/inode.c
--- 25/fs/nfs/inode.c~nfs-fix-msync	2004-02-29 14:47:53.000000000 -0800
+++ 25-akpm/fs/nfs/inode.c	2004-02-29 14:47:53.000000000 -0800
@@ -118,7 +118,7 @@ nfs_write_inode(struct inode *inode, int
 {
 	int flags = sync ? FLUSH_WAIT : 0;
 
-	nfs_commit_file(inode, NULL, 0, 0, flags);
+	nfs_commit_inode(inode, 0, 0, flags);
 }
 
 static void
diff -puN fs/nfs/pagelist.c~nfs-fix-msync fs/nfs/pagelist.c
--- 25/fs/nfs/pagelist.c~nfs-fix-msync	2004-02-29 14:47:53.000000000 -0800
+++ 25-akpm/fs/nfs/pagelist.c	2004-02-29 14:47:53.000000000 -0800
@@ -246,7 +246,6 @@ nfs_coalesce_requests(struct list_head *
  * nfs_scan_list - Scan a list for matching requests
  * @head: One of the NFS inode request lists
  * @dst: Destination list
- * @file: if set, ensure we match requests from this file
  * @idx_start: lower bound of page-&gt;index to scan
  * @npages: idx_start + npages sets the upper bound to scan.
  *
@@ -258,7 +257,6 @@ nfs_coalesce_requests(struct list_head *
  */
 int
 nfs_scan_list(struct list_head *head, struct list_head *dst,
-	      struct file *file,
 	      unsigned long idx_start, unsigned int npages)
 {
 	struct list_head	*pos, *tmp;
@@ -276,9 +274,6 @@ nfs_scan_list(struct list_head *head, st
 
 		req = nfs_list_entry(pos);
 
-		if (file &amp;&amp; req-&gt;wb_file != file)
-			continue;
-
 		if (req-&gt;wb_index &lt; idx_start)
 			continue;
 		if (req-&gt;wb_index &gt; idx_end)
diff -puN fs/nfs/write.c~nfs-fix-msync fs/nfs/write.c
--- 25/fs/nfs/write.c~nfs-fix-msync	2004-02-29 14:47:53.000000000 -0800
+++ 25-akpm/fs/nfs/write.c	2004-02-29 14:47:53.000000000 -0800
@@ -331,7 +331,7 @@ nfs_writepages(struct address_space *map
 	err = generic_writepages(mapping, wbc);
 	if (err)
 		goto out;
-	err = nfs_flush_file(inode, NULL, 0, 0, 0);
+	err = nfs_flush_inode(inode, 0, 0, 0);
 	if (err &lt; 0)
 		goto out;
 	if (wbc-&gt;sync_mode == WB_SYNC_HOLD)
@@ -339,7 +339,7 @@ nfs_writepages(struct address_space *map
 	if (is_sync &amp;&amp; wbc-&gt;sync_mode == WB_SYNC_ALL) {
 		err = nfs_wb_all(inode);
 	} else
-		nfs_commit_file(inode, NULL, 0, 0, 0);
+		nfs_commit_inode(inode, 0, 0, 0);
 out:
 	return err;
 }
@@ -469,7 +469,7 @@ nfs_mark_request_commit(struct nfs_page 
  * Interruptible by signals only if mounted with intr flag.
  */
 static int
-nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
+nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct nfs_page *req;
@@ -489,8 +489,6 @@ nfs_wait_on_requests(struct inode *inode
 			break;
 
 		next = req-&gt;wb_index + 1;
-		if (file &amp;&amp; req-&gt;wb_file != file)
-			continue;
 		if (!NFS_WBACK_BUSY(req))
 			continue;
 
@@ -501,7 +499,6 @@ nfs_wait_on_requests(struct inode *inode
 		if (error &lt; 0)
 			return error;
 		spin_lock(&amp;nfs_wreq_lock);
-		next = idx_start;
 		res++;
 	}
 	spin_unlock(&amp;nfs_wreq_lock);
@@ -512,7 +509,6 @@ nfs_wait_on_requests(struct inode *inode
  * nfs_scan_dirty - Scan an inode for dirty requests
  * @inode: NFS inode to scan
  * @dst: destination list
- * @file: if set, ensure we match requests from this file
  * @idx_start: lower bound of page-&gt;index to scan.
  * @npages: idx_start + npages sets the upper bound to scan.
  *
@@ -520,11 +516,11 @@ nfs_wait_on_requests(struct inode *inode
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	int	res;
-	res = nfs_scan_list(&amp;nfsi-&gt;dirty, dst, file, idx_start, npages);
+	res = nfs_scan_list(&amp;nfsi-&gt;dirty, dst, idx_start, npages);
 	nfsi-&gt;ndirty -= res;
 	sub_page_state(nr_dirty,res);
 	if ((nfsi-&gt;ndirty == 0) != list_empty(&amp;nfsi-&gt;dirty))
@@ -537,7 +533,6 @@ nfs_scan_dirty(struct inode *inode, stru
  * nfs_scan_commit - Scan an inode for commit requests
  * @inode: NFS inode to scan
  * @dst: destination list
- * @file: if set, ensure we collect requests from this file only.
  * @idx_start: lower bound of page-&gt;index to scan.
  * @npages: idx_start + npages sets the upper bound to scan.
  *
@@ -545,11 +540,11 @@ nfs_scan_dirty(struct inode *inode, stru
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	int	res;
-	res = nfs_scan_list(&amp;nfsi-&gt;commit, dst, file, idx_start, npages);
+	res = nfs_scan_list(&amp;nfsi-&gt;commit, dst, idx_start, npages);
 	nfsi-&gt;ncommit -= res;
 	if ((nfsi-&gt;ncommit == 0) != list_empty(&amp;nfsi-&gt;commit))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
@@ -1082,7 +1077,7 @@ nfs_commit_done(struct rpc_task *task)
 }
 #endif
 
-int nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start,
+int nfs_flush_inode(struct inode *inode, unsigned long idx_start,
 		   unsigned int npages, int how)
 {
 	LIST_HEAD(head);
@@ -1090,7 +1085,7 @@ int nfs_flush_file(struct inode *inode, 
 				error = 0;
 
 	spin_lock(&amp;nfs_wreq_lock);
-	res = nfs_scan_dirty(inode, &amp;head, file, idx_start, npages);
+	res = nfs_scan_dirty(inode, &amp;head, idx_start, npages);
 	spin_unlock(&amp;nfs_wreq_lock);
 	if (res)
 		error = nfs_flush_list(&amp;head, NFS_SERVER(inode)-&gt;wpages, how);
@@ -1100,7 +1095,7 @@ int nfs_flush_file(struct inode *inode, 
 }
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start,
+int nfs_commit_inode(struct inode *inode, unsigned long idx_start,
 		    unsigned int npages, int how)
 {
 	LIST_HEAD(head);
@@ -1108,9 +1103,9 @@ int nfs_commit_file(struct inode *inode,
 				error = 0;
 
 	spin_lock(&amp;nfs_wreq_lock);
-	res = nfs_scan_commit(inode, &amp;head, file, idx_start, npages);
+	res = nfs_scan_commit(inode, &amp;head, idx_start, npages);
 	if (res) {
-		res += nfs_scan_commit(inode, &amp;head, NULL, 0, 0);
+		res += nfs_scan_commit(inode, &amp;head, 0, 0);
 		spin_unlock(&amp;nfs_wreq_lock);
 		error = nfs_commit_list(&amp;head, how);
 	} else
@@ -1121,7 +1116,7 @@ int nfs_commit_file(struct inode *inode,
 }
 #endif
 
-int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start,
+int nfs_sync_inode(struct inode *inode, unsigned long idx_start,
 		  unsigned int npages, int how)
 {
 	int	error,
@@ -1130,18 +1125,15 @@ int nfs_sync_file(struct inode *inode, s
 	wait = how &amp; FLUSH_WAIT;
 	how &amp;= ~FLUSH_WAIT;
 
-	if (!inode &amp;&amp; file)
-		inode = file-&gt;f_dentry-&gt;d_inode;
-
 	do {
 		error = 0;
 		if (wait)
-			error = nfs_wait_on_requests(inode, file, idx_start, npages);
+			error = nfs_wait_on_requests(inode, idx_start, npages);
 		if (error == 0)
-			error = nfs_flush_file(inode, file, idx_start, npages, how);
+			error = nfs_flush_inode(inode, idx_start, npages, how);
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 		if (error == 0)
-			error = nfs_commit_file(inode, file, idx_start, npages, how);
+			error = nfs_commit_inode(inode, idx_start, npages, how);
 #endif
 	} while (error &gt; 0);
 	return error;
diff -puN include/linux/nfs_fs.h~nfs-fix-msync include/linux/nfs_fs.h
--- 25/include/linux/nfs_fs.h~nfs-fix-msync	2004-02-29 14:47:53.000000000 -0800
+++ 25-akpm/include/linux/nfs_fs.h	2004-02-29 14:47:53.000000000 -0800
@@ -343,16 +343,15 @@ extern void nfs_commit_done(struct rpc_t
  * Try to write back everything synchronously (but check the
  * return value!)
  */
-extern int  nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int);
-extern int  nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_sync_inode(struct inode *, unsigned long, unsigned int, int);
+extern int  nfs_flush_inode(struct inode *, unsigned long, unsigned int, int);
 extern int  nfs_flush_list(struct list_head *, int, int);
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-extern int  nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_commit_inode(struct inode *, unsigned long, unsigned int, int);
 extern int  nfs_commit_list(struct list_head *, int);
 #else
 static inline int
-nfs_commit_file(struct inode *inode, struct file *file, unsigned long offset,
-		unsigned int len, int flags)
+nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how)
 {
 	return 0;
 }
@@ -367,7 +366,7 @@ nfs_have_writebacks(struct inode *inode)
 static inline int
 nfs_wb_all(struct inode *inode)
 {
-	int error = nfs_sync_file(inode, 0, 0, 0, FLUSH_WAIT);
+	int error = nfs_sync_inode(inode, 0, 0, FLUSH_WAIT);
 	return (error &lt; 0) ? error : 0;
 }
 
@@ -377,21 +376,11 @@ nfs_wb_all(struct inode *inode)
 static inline int
 nfs_wb_page(struct inode *inode, struct page* page)
 {
-	int error = nfs_sync_file(inode, 0, page-&gt;index, 1,
+	int error = nfs_sync_inode(inode, page-&gt;index, 1,
 						FLUSH_WAIT | FLUSH_STABLE);
 	return (error &lt; 0) ? error : 0;
 }
 
-/*
- * Write back all pending writes for one user.. 
- */
-static inline int
-nfs_wb_file(struct inode *inode, struct file *file)
-{
-	int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT);
-	return (error &lt; 0) ? error : 0;
-}
-
 /* Hack for future NFS swap support */
 #ifndef IS_SWAPFILE
 # define IS_SWAPFILE(inode)	(0)
diff -puN include/linux/nfs_page.h~nfs-fix-msync include/linux/nfs_page.h
--- 25/include/linux/nfs_page.h~nfs-fix-msync	2004-02-29 14:47:53.000000000 -0800
+++ 25-akpm/include/linux/nfs_page.h	2004-02-29 14:47:53.000000000 -0800
@@ -53,7 +53,7 @@ extern	void nfs_release_request(struct n
 extern	void nfs_list_add_request(struct nfs_page *, struct list_head *);
 
 extern	int nfs_scan_list(struct list_head *, struct list_head *,
-			  struct file *, unsigned long, unsigned int);
+			  unsigned long, unsigned int);
 extern	int nfs_coalesce_requests(struct list_head *, struct list_head *,
 				  unsigned int);
 extern  int nfs_wait_on_request(struct nfs_page *);

_
</pre></body></html>