Monitor marking dirty activity of underlying upper inode so that we have chance to mark overlayfs' own inode dirty. Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx> --- fs/overlayfs/inode.c | 4 +++- fs/overlayfs/overlayfs.h | 2 ++ fs/overlayfs/ovl_entry.h | 2 ++ fs/overlayfs/super.c | 11 +++++++++++ fs/overlayfs/util.c | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index b584dca..e75c7ec 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -632,8 +632,10 @@ void ovl_inode_init(struct inode *inode, struct ovl_inode_params *oip, { struct inode *realinode; - if (oip->upperdentry) + if (oip->upperdentry) { OVL_I(inode)->__upperdentry = oip->upperdentry; + ovl_register_mark_dirty_notify(OVL_I(inode)); + } if (oip->lowerpath && oip->lowerpath->dentry) OVL_I(inode)->lower = igrab(d_inode(oip->lowerpath->dentry)); if (oip->lowerdata) diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 7bce246..04ef778 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -247,6 +247,8 @@ static inline bool ovl_open_flags_need_copy_up(int flags) } /* util.c */ +void ovl_register_mark_dirty_notify(struct ovl_inode *oi); +void ovl_unregister_mark_dirty_notify(struct ovl_inode *oi); int ovl_want_write(struct dentry *dentry); void ovl_drop_write(struct dentry *dentry); struct dentry *ovl_workdir(struct dentry *dentry); diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 1b5a2094..fce5314 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -129,6 +129,8 @@ struct ovl_inode { /* synchronize copy up and more */ struct mutex lock; + /* moniter marking dirty behavior of upper inode */ + struct notifier_block mark_dirty_nb; }; static inline struct ovl_inode *OVL_I(struct inode *inode) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index dc22725..6d8f9da 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -390,11 +390,22 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data) return ret; } +void ovl_evict_inode(struct inode *inode) +{ + struct inode *upper; + + upper = ovl_inode_upper(inode); + if (upper) + ovl_unregister_mark_dirty_notify(OVL_I(inode)); + clear_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, + .evict_inode = ovl_evict_inode, .put_super = ovl_put_super, .sync_fs = ovl_sync_fs, .statfs = ovl_statfs, diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 23f4756..bdcfe55 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -417,6 +417,7 @@ void ovl_inode_update(struct inode *inode, struct dentry *upperdentry) inode->i_private = upperinode; __insert_inode_hash(inode, (unsigned long) upperinode); } + ovl_register_mark_dirty_notify(OVL_I(inode)); } static void ovl_dentry_version_inc(struct dentry *dentry, bool impurity) @@ -950,3 +951,36 @@ char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry, kfree(buf); return ERR_PTR(res); } + +int ovl_inode_dirty_notify(struct notifier_block *nb, + unsigned long dummy, void *param) +{ + 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); + return NOTIFY_OK; +} + +void ovl_register_mark_dirty_notify(struct ovl_inode *oi) +{ + struct inode *upper; + + upper = oi->__upperdentry->d_inode; + oi->mark_dirty_nb.notifier_call = ovl_inode_dirty_notify; + + blocking_notifier_chain_register( + &upper->notifier_lists[MARK_INODE_DIRTY_NOTIFIER], + &oi->mark_dirty_nb); +} + +void ovl_unregister_mark_dirty_notify(struct ovl_inode *oi) +{ + struct inode *upper; + + upper = oi->__upperdentry->d_inode; + blocking_notifier_chain_unregister( + &upper->notifier_lists[MARK_INODE_DIRTY_NOTIFIER], + &oi->mark_dirty_nb); +} -- 1.8.3.1