When inode is being inserted into inode cache, lookup whether there are some notification marks for this inode and reconnect them to it. Signed-off-by: Jan Kara --- fs/inode.c | 1 + fs/notify/mark.c | 37 ++++++++++++++++++++++++++++++++ include/linux/fsnotify_backend.h | 13 +++++++++++ 3 files changed, 51 insertions(+) diff --git a/fs/inode.c b/fs/inode.c index 01ebdc40021e..9f9507eea645 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1450,6 +1450,7 @@ struct inode *iget_locked(struct super_block *sb, unsigned long ino) spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); inode_sb_list_add(inode); + fsnotify_generic_reconnect_inode_marks(inode); /* Return the locked inode with I_NEW set, the * caller is responsible for filling in the contents diff --git a/fs/notify/mark.c b/fs/notify/mark.c index f6a197c63c1d..8fe7128f4122 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -731,6 +731,43 @@ fsnotify_alloc_inode_connector(struct inode *inode) return &iconn->common; } +/* + * If there are existing notification marks for the inode, attach them + * to it. + */ +void fsnotify_reconnect_inode_marks(struct inode *inode, void *key) +{ + struct fsnotify_sb_info *info = fsnotify_sb_info(inode->i_sb); + const struct rhashtable_params *params = + fsnotify_get_conn_hash_params(inode->i_sb); + struct fsnotify_inode_mark_connector *iconn; + struct fsnotify_mark_connector *conn; + int idx; + + if (!info) + return; + + idx = srcu_read_lock(&fsnotify_mark_srcu); + iconn = rhashtable_lookup_fast(&info->inode_conn_hash, key, *params); + if (!iconn) + goto out_srcu; + conn = &iconn->common; + spin_lock(&conn->lock); + /* The connector is just undergoing destruction? */ + if (hlist_empty(&conn->list)) + goto out_lock; + conn->type = FSNOTIFY_OBJ_TYPE_INODE; + conn->obj = inode; + rcu_assign_pointer(inode->i_fsnotify_marks, conn); + __fsnotify_recalc_mask(conn); + fsnotify_update_sb_watchers(conn); +out_lock: + spin_unlock(&conn->lock); +out_srcu: + srcu_read_unlock(&fsnotify_mark_srcu, idx); +} +EXPORT_SYMBOL(fsnotify_reconnect_inode_marks); + static void fsnotify_unhash_connector(struct fsnotify_mark_connector *conn) { if (!(conn->flags & FSNOTIFY_CONN_FLAG_HASHED)) diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index bf6796be7561..267c6587af97 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -921,6 +921,13 @@ static inline void fsnotify_init_event(struct fsnotify_event *event) int fsnotify_pre_content(const struct path *path, const loff_t *ppos, size_t count); +void fsnotify_reconnect_inode_marks(struct inode *inode, void *key); +/* Reconnection function for filesystems using fsnotify_inode_mark_connector */ +static inline void fsnotify_generic_reconnect_inode_marks(struct inode *inode) +{ + fsnotify_reconnect_inode_marks(inode, &inode->i_ino); +} + #else static inline int fsnotify_pre_content(const struct path *path, @@ -971,6 +978,12 @@ static inline void fsnotify_unmount_inodes(struct super_block *sb) static inline void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt) {} +static inline void fsnotify_reconnect_inode_marks(struct inode *inode, void *key) +{} + +static inline void fsnotify_generic_reconnect_inode_marks(struct inode *inode) +{} + #endif /* CONFIG_FSNOTIFY */ #endif /* __KERNEL __ */ -- 2.51.0