Commit fde87268 authored by Theodore Ts'o's avatar Theodore Ts'o

ext4: force inode writes when nfsd calls commit_metadata()

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: default avatarTheodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
parent 8a363970
...@@ -1202,6 +1202,16 @@ static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid, ...@@ -1202,6 +1202,16 @@ static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
ext4_nfs_get_inode); 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 * Try to release metadata pages (indirect blocks, directories) which are
* mapped via the block device. Since these pages could have journal heads * mapped via the block device. Since these pages could have journal heads
...@@ -1406,6 +1416,7 @@ static const struct export_operations ext4_export_ops = { ...@@ -1406,6 +1416,7 @@ static const struct export_operations ext4_export_ops = {
.fh_to_dentry = ext4_fh_to_dentry, .fh_to_dentry = ext4_fh_to_dentry,
.fh_to_parent = ext4_fh_to_parent, .fh_to_parent = ext4_fh_to_parent,
.get_parent = ext4_get_parent, .get_parent = ext4_get_parent,
.commit_metadata = ext4_nfs_commit_metadata,
}; };
enum { enum {
......
...@@ -226,6 +226,26 @@ TRACE_EVENT(ext4_drop_inode, ...@@ -226,6 +226,26 @@ TRACE_EVENT(ext4_drop_inode,
(unsigned long) __entry->ino, __entry->drop) (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, TRACE_EVENT(ext4_mark_inode_dirty,
TP_PROTO(struct inode *inode, unsigned long IP), TP_PROTO(struct inode *inode, unsigned long IP),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment