aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2010-03-05 03:21:21 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2010-03-05 13:25:10 -0500
commit26821ed40b4230259e770c9911180f38fcaa6f59 (patch)
tree40cd0fed705ec59dd3c909b96452bae1fc532796
parent64ba9926759792cf7b95f823402e2781edd1b5d4 (diff)
make sure data is on disk before calling ->write_inode
Similar to the fsync issue fixed a while ago in commit 2daea67e966dc0c42067ebea015ddac6834cef88 we need to write for data to actually hit the disk before writing out the metadata to guarantee data integrity for filesystems that modify the inode in the data I/O completion path. Currently XFS and NFS handle this manually, and AFS has a write_inode method that does nothing but waiting for data, while others are possibly missing out on this. Fortunately this change has a lot less impact than the fsync change as none of the write_inode methods starts data writeout of any form by itself. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/afs/internal.h1
-rw-r--r--fs/afs/super.c1
-rw-r--r--fs/afs/write.c21
-rw-r--r--fs/fs-writeback.c15
-rw-r--r--fs/nfs/inode.c7
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c4
6 files changed, 11 insertions, 38 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 6ece2a13bf71..c54dad4e6063 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -733,7 +733,6 @@ extern int afs_write_end(struct file *file, struct address_space *mapping,
733 struct page *page, void *fsdata); 733 struct page *page, void *fsdata);
734extern int afs_writepage(struct page *, struct writeback_control *); 734extern int afs_writepage(struct page *, struct writeback_control *);
735extern int afs_writepages(struct address_space *, struct writeback_control *); 735extern int afs_writepages(struct address_space *, struct writeback_control *);
736extern int afs_write_inode(struct inode *, int);
737extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); 736extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
738extern ssize_t afs_file_write(struct kiocb *, const struct iovec *, 737extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
739 unsigned long, loff_t); 738 unsigned long, loff_t);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index e1ea1c240b6a..14f6431598ad 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -48,7 +48,6 @@ struct file_system_type afs_fs_type = {
48static const struct super_operations afs_super_ops = { 48static const struct super_operations afs_super_ops = {
49 .statfs = afs_statfs, 49 .statfs = afs_statfs,
50 .alloc_inode = afs_alloc_inode, 50 .alloc_inode = afs_alloc_inode,
51 .write_inode = afs_write_inode,
52 .destroy_inode = afs_destroy_inode, 51 .destroy_inode = afs_destroy_inode,
53 .clear_inode = afs_clear_inode, 52 .clear_inode = afs_clear_inode,
54 .put_super = afs_put_super, 53 .put_super = afs_put_super,
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 5e15a21dbf9f..3bed54a294d4 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -585,27 +585,6 @@ int afs_writepages(struct address_space *mapping,
585} 585}
586 586
587/* 587/*
588 * write an inode back
589 */
590int afs_write_inode(struct inode *inode, int sync)
591{
592 struct afs_vnode *vnode = AFS_FS_I(inode);
593 int ret;
594
595 _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
596
597 ret = 0;
598 if (sync) {
599 ret = filemap_fdatawait(inode->i_mapping);
600 if (ret < 0)
601 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
602 }
603
604 _leave(" = %d", ret);
605 return ret;
606}
607
608/*
609 * completion of write to server 588 * completion of write to server
610 */ 589 */
611void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call) 590void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 1a7c42c64ff4..5f2721b1e4be 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -461,15 +461,20 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
461 461
462 ret = do_writepages(mapping, wbc); 462 ret = do_writepages(mapping, wbc);
463 463
464 /* Don't write the inode if only I_DIRTY_PAGES was set */ 464 /*
465 if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { 465 * Make sure to wait on the data before writing out the metadata.
466 int err = write_inode(inode, wait); 466 * This is important for filesystems that modify metadata on data
467 * I/O completion.
468 */
469 if (wait) {
470 int err = filemap_fdatawait(mapping);
467 if (ret == 0) 471 if (ret == 0)
468 ret = err; 472 ret = err;
469 } 473 }
470 474
471 if (wait) { 475 /* Don't write the inode if only I_DIRTY_PAGES was set */
472 int err = filemap_fdatawait(mapping); 476 if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
477 int err = write_inode(inode, wait);
473 if (ret == 0) 478 if (ret == 0)
474 ret = err; 479 ret = err;
475 } 480 }
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 7570573bdb30..5ecd952cae1d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -101,12 +101,7 @@ int nfs_write_inode(struct inode *inode, int sync)
101{ 101{
102 int ret; 102 int ret;
103 103
104 if (sync) { 104 ret = nfs_commit_inode(inode, sync ? FLUSH_SYNC : 0);
105 ret = filemap_fdatawait(inode->i_mapping);
106 if (ret == 0)
107 ret = nfs_commit_inode(inode, FLUSH_SYNC);
108 } else
109 ret = nfs_commit_inode(inode, 0);
110 if (ret >= 0) 105 if (ret >= 0)
111 return 0; 106 return 0;
112 __mark_inode_dirty(inode, I_DIRTY_DATASYNC); 107 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 25ea2408118f..8f117db6070e 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1075,10 +1075,6 @@ xfs_fs_write_inode(
1075 return XFS_ERROR(EIO); 1075 return XFS_ERROR(EIO);
1076 1076
1077 if (sync) { 1077 if (sync) {
1078 error = xfs_wait_on_pages(ip, 0, -1);
1079 if (error)
1080 goto out;
1081
1082 /* 1078 /*
1083 * Make sure the inode has hit stable storage. By using the 1079 * Make sure the inode has hit stable storage. By using the
1084 * log and the fsync transactions we reduce the IOs we have 1080 * log and the fsync transactions we reduce the IOs we have