| From fde872682e175743e0c3ef939c89e3c6008a1529 Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Wed, 19 Dec 2018 14:07:58 -0500 |
| Subject: ext4: force inode writes when nfsd calls commit_metadata() |
| |
| From: Theodore Ts'o <tytso@mit.edu> |
| |
| 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 | 11 +++++++++++ |
| include/trace/events/ext4.h | 20 ++++++++++++++++++++ |
| 2 files changed, 31 insertions(+) |
| |
| --- a/fs/ext4/super.c |
| +++ b/fs/ext4/super.c |
| @@ -1076,6 +1076,16 @@ static struct dentry *ext4_fh_to_parent( |
| 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 ex |
| .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 { |
| --- a/include/trace/events/ext4.h |
| +++ b/include/trace/events/ext4.h |
| @@ -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), |
| |