aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-20 13:44:51 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-20 13:44:51 -0500
commitc42de9dd67250fe984e0e31c9b542d721af6454b (patch)
treea4079b25a044f7124837f572e5342dc7614ca75d /include/linux
parent7d46a49f512e8d10b23353781a8ba85edd4fa640 (diff)
NFS: Fix a race in nfs_sync_inode()
Kudos to Neil Brown for spotting the problem: "in nfs_sync_inode, there is effectively the sequence: nfs_wait_on_requests nfs_flush_inode nfs_commit_inode This seems a bit racy to me as if the only requests are on the ->commit list, and nfs_commit_inode is called separately after nfs_wait_on_requests completes, and before nfs_commit_inode start (say: by nfs_write_inode) then none of these function will return >0, yet there will be some pending request that aren't waited for." The solution is to search for requests to wait upon, search for dirty requests, and search for uncommitted requests while holding the nfsi->req_lock The patch also cleans up nfs_sync_inode(), getting rid of the redundant FLUSH_WAIT flag. It turns out that we were always setting it. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/nfs_fs.h10
1 files changed, 4 insertions, 6 deletions
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 55de0770df4a..cbebd7d1b9e8 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -56,9 +56,7 @@
56 * When flushing a cluster of dirty pages, there can be different 56 * When flushing a cluster of dirty pages, there can be different
57 * strategies: 57 * strategies:
58 */ 58 */
59#define FLUSH_AGING 0 /* only flush old buffers */
60#define FLUSH_SYNC 1 /* file being synced, or contention */ 59#define FLUSH_SYNC 1 /* file being synced, or contention */
61#define FLUSH_WAIT 2 /* wait for completion */
62#define FLUSH_STABLE 4 /* commit to stable storage */ 60#define FLUSH_STABLE 4 /* commit to stable storage */
63#define FLUSH_LOWPRI 8 /* low priority background flush */ 61#define FLUSH_LOWPRI 8 /* low priority background flush */
64#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ 62#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
@@ -419,7 +417,7 @@ void nfs_commit_free(struct nfs_write_data *p);
419 * Try to write back everything synchronously (but check the 417 * Try to write back everything synchronously (but check the
420 * return value!) 418 * return value!)
421 */ 419 */
422extern int nfs_sync_inode(struct inode *, unsigned long, unsigned int, int); 420extern int nfs_sync_inode_wait(struct inode *, unsigned long, unsigned int, int);
423#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 421#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
424extern int nfs_commit_inode(struct inode *, int); 422extern int nfs_commit_inode(struct inode *, int);
425extern void nfs_commit_release(void *wdata); 423extern void nfs_commit_release(void *wdata);
@@ -440,7 +438,7 @@ nfs_have_writebacks(struct inode *inode)
440static inline int 438static inline int
441nfs_wb_all(struct inode *inode) 439nfs_wb_all(struct inode *inode)
442{ 440{
443 int error = nfs_sync_inode(inode, 0, 0, FLUSH_WAIT); 441 int error = nfs_sync_inode_wait(inode, 0, 0, 0);
444 return (error < 0) ? error : 0; 442 return (error < 0) ? error : 0;
445} 443}
446 444
@@ -449,8 +447,8 @@ nfs_wb_all(struct inode *inode)
449 */ 447 */
450static inline int nfs_wb_page_priority(struct inode *inode, struct page* page, int how) 448static inline int nfs_wb_page_priority(struct inode *inode, struct page* page, int how)
451{ 449{
452 int error = nfs_sync_inode(inode, page->index, 1, 450 int error = nfs_sync_inode_wait(inode, page->index, 1,
453 how | FLUSH_WAIT | FLUSH_STABLE); 451 how | FLUSH_STABLE);
454 return (error < 0) ? error : 0; 452 return (error < 0) ? error : 0;
455} 453}
456 454