ext4: force inode writes when nfsd calls commit_metadata()
authorTheodore Ts'o <tytso@mit.edu>
Wed, 19 Dec 2018 19:07:58 +0000 (14:07 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Jan 2019 15:16:44 +0000 (16:16 +0100)
commit fde872682e175743e0c3ef939c89e3c6008a1529 upstream.

Some time back, nfsd switched from calling vfs_fsync() to using a new
commit_metadata() hook in export_operations().  If the file system did
not provide a commit_metadata() hook, it fell back to using
sync_inode_metadata().  Unfortunately doesn't work on all file
systems.  In particular, it doesn't work on ext4 due to how the inode
gets journalled --- the VFS writeback code will not always call
ext4_write_inode().

So we need to provide our own ext4_nfs_commit_metdata() method which
calls ext4_write_inode() directly.

Google-Bug-Id: 121195940
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ext4/super.c
include/trace/events/ext4.h

index 67d9e3ce47e9b4304b8522b6b20edfb30e744ba1..6810234b0b270eef89e15b1320fe2871d03cc9d9 100644 (file)
@@ -1076,6 +1076,16 @@ static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
                                    ext4_nfs_get_inode);
 }
 
+static int ext4_nfs_commit_metadata(struct inode *inode)
+{
+       struct writeback_control wbc = {
+               .sync_mode = WB_SYNC_ALL
+       };
+
+       trace_ext4_nfs_commit_metadata(inode);
+       return ext4_write_inode(inode, &wbc);
+}
+
 /*
  * Try to release metadata pages (indirect blocks, directories) which are
  * mapped via the block device.  Since these pages could have journal heads
@@ -1258,6 +1268,7 @@ static const struct export_operations ext4_export_ops = {
        .fh_to_dentry = ext4_fh_to_dentry,
        .fh_to_parent = ext4_fh_to_parent,
        .get_parent = ext4_get_parent,
+       .commit_metadata = ext4_nfs_commit_metadata,
 };
 
 enum {
index 09c71e9aaebf7d7bf83857294b9ec37a13d0920e..215668b14f61303b92c12721f1c6e1da5b831cfe 100644 (file)
@@ -223,6 +223,26 @@ TRACE_EVENT(ext4_drop_inode,
                  (unsigned long) __entry->ino, __entry->drop)
 );
 
+TRACE_EVENT(ext4_nfs_commit_metadata,
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        ino_t,  ino                     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->ino    = inode->i_ino;
+       ),
+
+       TP_printk("dev %d,%d ino %lu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino)
+);
+
 TRACE_EVENT(ext4_mark_inode_dirty,
        TP_PROTO(struct inode *inode, unsigned long IP),