Mark overlayfs' inode dirty when underlying upper inode becomes dirty, then only sync overlayfs' dirty inodes while syncfs. Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx> --- fs/overlayfs/inode.c | 24 ++++++++++++++++++++++++ fs/overlayfs/super.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- fs/overlayfs/util.c | 3 +-- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index e75c7ec..c709aed 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -11,6 +11,7 @@ #include <linux/posix_acl.h> #include <linux/ratelimit.h> #include <linux/fiemap.h> +#include <linux/writeback.h> #include "overlayfs.h" @@ -516,7 +517,30 @@ static int ovl_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, .update_time = ovl_update_time, }; +static int ovl_writepages(struct address_space *mapping, struct writeback_control *wbc) +{ + struct inode *inode = mapping->host; + struct inode *upper_inode = ovl_inode_upper(inode); + struct ovl_fs *ofs = inode->i_sb->s_fs_info; + struct writeback_control upper_wbc = { + .nr_to_write = LONG_MAX, + .sync_mode = WB_SYNC_ALL, + .for_kupdate = wbc->for_kupdate, + .for_background = wbc->for_background, + .for_sync = 0, + .range_cyclic = wbc->range_cyclic, + .range_start = 0, + .range_end = LLONG_MAX, + }; + + if (!ovl_should_sync(ofs)) + return 0; + + return writeback_single_inode(upper_inode, &upper_wbc); +} + static const struct address_space_operations ovl_aops = { + .writepages = ovl_writepages, /* For O_DIRECT dentry_open() checks f_mapping->a_ops->direct_IO */ .direct_IO = noop_direct_IO, }; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 6d8f9da..da1b65a 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -15,6 +15,9 @@ #include <linux/seq_file.h> #include <linux/posix_acl_xattr.h> #include <linux/exportfs.h> +#include <linux/notifier.h> +#include <linux/writeback.h> +#include <linux/blkdev.h> #include "overlayfs.h" MODULE_AUTHOR("Miklos Szeredi <miklos@xxxxxxxxxx>"); @@ -279,9 +282,13 @@ static int ovl_sync_fs(struct super_block *sb, int wait) upper_sb = ovl_upper_mnt(ofs)->mnt_sb; - down_read(&upper_sb->s_umount); - ret = sync_filesystem(upper_sb); - up_read(&upper_sb->s_umount); + if (upper_sb->s_op->sync_fs) { + down_read(&upper_sb->s_umount); + ret = upper_sb->s_op->sync_fs(upper_sb, wait); + if (!ret) + ret = sync_blockdev(upper_sb->s_bdev); + up_read(&upper_sb->s_umount); + } return ret; } @@ -400,11 +407,47 @@ void ovl_evict_inode(struct inode *inode) clear_inode(inode); } +int ovl_write_inode(struct inode *inode, struct writeback_control *wbc) +{ + struct ovl_fs *ofs = inode->i_sb->s_fs_info; + struct super_block *upper_sb = ovl_upper_mnt(ofs)->mnt_sb; + struct inode *upper_inode = ovl_inode_upper(inode); + struct writeback_control upper_wbc = { + .nr_to_write = LONG_MAX, + .sync_mode = WB_SYNC_ALL, + .tagged_writepages = wbc->tagged_writepages, + .for_kupdate = wbc->for_kupdate, + .for_background = wbc->for_background, + .for_sync = 0, + .range_cyclic = wbc->range_cyclic, + .range_start = wbc->range_start, + .range_end = wbc->range_end, + }; + + if (!upper_sb->s_op->write_inode || !upper_inode) + return 0; + return upper_sb->s_op->write_inode(upper_inode, &upper_wbc); +} + +int ovl_drop_inode(struct inode *inode) +{ + struct inode *upper_inode; + + upper_inode = ovl_inode_upper(inode); + if (!upper_inode) + return 1; + if (!(upper_inode->i_state & I_DIRTY_ALL)) + return 1; + + return generic_drop_inode(inode); +} + static const struct super_operations ovl_super_operations = { .alloc_inode = ovl_alloc_inode, .free_inode = ovl_free_inode, .destroy_inode = ovl_destroy_inode, - .drop_inode = generic_delete_inode, + .drop_inode = ovl_drop_inode, + .write_inode = ovl_write_inode, .evict_inode = ovl_evict_inode, .put_super = ovl_put_super, .sync_fs = ovl_sync_fs, diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index bdcfe55..93d0493 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -958,8 +958,7 @@ int ovl_inode_dirty_notify(struct notifier_block *nb, struct ovl_inode *oi = container_of(nb, struct ovl_inode, mark_dirty_nb); int *flags = (int *)param; - // add later - //__mark_inode_dirty(&oi->vfs_inode, *flags); + __mark_inode_dirty(&oi->vfs_inode, *flags); return NOTIFY_OK; } -- 1.8.3.1