From: Trond Myklebust 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->i_sb->s_id, inode->i_ino); lock_kernel(); - status = nfs_wb_file(inode, file); + status = nfs_wb_all(inode); if (!status) { status = file->f_error; file->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->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 && req->wb_file != file) - continue; - if (req->wb_index < idx_start) continue; if (req->wb_index > 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 < 0) goto out; if (wbc->sync_mode == WB_SYNC_HOLD) @@ -339,7 +339,7 @@ nfs_writepages(struct address_space *map if (is_sync && wbc->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->wb_index + 1; - if (file && req->wb_file != file) - continue; if (!NFS_WBACK_BUSY(req)) continue; @@ -501,7 +499,6 @@ nfs_wait_on_requests(struct inode *inode if (error < 0) return error; spin_lock(&nfs_wreq_lock); - next = idx_start; res++; } spin_unlock(&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->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(&nfsi->dirty, dst, file, idx_start, npages); + res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages); nfsi->ndirty -= res; sub_page_state(nr_dirty,res); if ((nfsi->ndirty == 0) != list_empty(&nfsi->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->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(&nfsi->commit, dst, file, idx_start, npages); + res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); nfsi->ncommit -= res; if ((nfsi->ncommit == 0) != list_empty(&nfsi->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(&nfs_wreq_lock); - res = nfs_scan_dirty(inode, &head, file, idx_start, npages); + res = nfs_scan_dirty(inode, &head, idx_start, npages); spin_unlock(&nfs_wreq_lock); if (res) error = nfs_flush_list(&head, NFS_SERVER(inode)->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(&nfs_wreq_lock); - res = nfs_scan_commit(inode, &head, file, idx_start, npages); + res = nfs_scan_commit(inode, &head, idx_start, npages); if (res) { - res += nfs_scan_commit(inode, &head, NULL, 0, 0); + res += nfs_scan_commit(inode, &head, 0, 0); spin_unlock(&nfs_wreq_lock); error = nfs_commit_list(&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 & FLUSH_WAIT; how &= ~FLUSH_WAIT; - if (!inode && file) - inode = file->f_dentry->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 > 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 < 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->index, 1, + int error = nfs_sync_inode(inode, page->index, 1, FLUSH_WAIT | FLUSH_STABLE); return (error < 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 < 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 *); _