struct inode and struct mount are both types of objects, which marks can be attached to. Let them "inherit" from a prototype struct, so that marks manipulation code can be made more generic. Introduce helpers fsnotify_obj_{inode,mount} to get the concrete object from the abstract object. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/inode.c | 2 +- fs/mount.h | 11 +++++++++-- fs/notify/dnotify/dnotify.c | 8 ++++---- fs/notify/fanotify/fanotify_user.c | 24 ++++++++++++------------ fs/notify/fsnotify.c | 22 +++++++++++----------- fs/notify/fsnotify.h | 4 ++-- fs/notify/inotify/inotify_user.c | 6 +++--- fs/notify/mark.c | 16 ++++++++-------- include/linux/fs.h | 6 ++---- include/linux/fsnotify_backend.h | 10 ++++++++-- include/linux/fsnotify_obj.h | 14 ++++++++++++++ kernel/audit_tree.c | 2 +- kernel/audit_watch.c | 2 +- kernel/auditsc.c | 4 ++-- 14 files changed, 78 insertions(+), 53 deletions(-) create mode 100644 include/linux/fsnotify_obj.h diff --git a/fs/inode.c b/fs/inode.c index 13ceb98c3bd3..9eadddd2be94 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -190,7 +190,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) #endif #ifdef CONFIG_FSNOTIFY - inode->i_fsnotify_mask = 0; + inode->i_fsnotify.mask = 0; #endif inode->i_flctx = NULL; this_cpu_inc(nr_inodes); diff --git a/fs/mount.h b/fs/mount.h index f39bc9da4d73..718bb8073b90 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -4,6 +4,7 @@ #include <linux/poll.h> #include <linux/ns_common.h> #include <linux/fs_pin.h> +#include <linux/fsnotify_obj.h> struct mnt_namespace { atomic_t count; @@ -61,8 +62,7 @@ struct mount { struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */ struct list_head mnt_umounting; /* list entry for umount propagation */ #ifdef CONFIG_FSNOTIFY - struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks; - __u32 mnt_fsnotify_mask; + struct fsnotify_obj mnt_fsnotify; #endif int mnt_id; /* mount identifier */ int mnt_group_id; /* peer group identifier */ @@ -79,6 +79,13 @@ static inline struct mount *real_mount(struct vfsmount *mnt) return container_of(mnt, struct mount, mnt); } +#ifdef CONFIG_FSNOTIFY +static inline struct mount *fsnotify_obj_mount(struct fsnotify_obj *obj) +{ + return container_of(obj, struct mount, mnt_fsnotify); +} +#endif + static inline int mnt_has_parent(struct mount *mnt) { return mnt != mnt->mnt_parent; diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index e2bea2ac5dfb..d46167c69c99 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c @@ -33,7 +33,7 @@ static struct kmem_cache *dnotify_mark_cache __read_mostly; static struct fsnotify_group *dnotify_group __read_mostly; /* - * dnotify will attach one of these to each inode (i_fsnotify_marks) which + * dnotify will attach one of these to each inode (i_fsnotify.marks) which * is being watched by dnotify. If multiple userspace applications are watching * the same directory with dnotify their information is chained in dn */ @@ -158,7 +158,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id) if (!S_ISDIR(inode->i_mode)) return; - fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group); + fsn_mark = fsnotify_find_mark(&inode->i_fsnotify.marks, dnotify_group); if (!fsn_mark) return; dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); @@ -218,7 +218,7 @@ static __u32 convert_arg(unsigned long arg) /* * If multiple processes watch the same inode with dnotify there is only one - * dnotify mark in inode->i_fsnotify_marks but we chain a dnotify_struct + * dnotify mark in inode->i_fsnotify.marks but we chain a dnotify_struct * onto that mark. This function either attaches the new dnotify_struct onto * that list, or it |= the mask onto an existing dnofiy_struct. */ @@ -314,7 +314,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) mutex_lock(&dnotify_group->mark_mutex); /* add the new_fsn_mark or find an old one. */ - fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group); + fsn_mark = fsnotify_find_mark(&inode->i_fsnotify.marks, dnotify_group); if (fsn_mark) { dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); spin_lock(&fsn_mark->lock); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index ec4d8c59d0e3..ed87880c42f0 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -533,7 +533,7 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, int destroy_mark; mutex_lock(&group->mark_mutex); - fsn_mark = fsnotify_find_mark(&real_mount(mnt)->mnt_fsnotify_marks, + fsn_mark = fsnotify_find_mark(&real_mount(mnt)->mnt_fsnotify.marks, group); if (!fsn_mark) { mutex_unlock(&group->mark_mutex); @@ -542,8 +542,8 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, &destroy_mark); - if (removed & real_mount(mnt)->mnt_fsnotify_mask) - fsnotify_recalc_mask(real_mount(mnt)->mnt_fsnotify_marks); + if (removed & real_mount(mnt)->mnt_fsnotify.mask) + fsnotify_recalc_mask(real_mount(mnt)->mnt_fsnotify.marks); if (destroy_mark) fsnotify_detach_mark(fsn_mark); mutex_unlock(&group->mark_mutex); @@ -563,7 +563,7 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, int destroy_mark; mutex_lock(&group->mark_mutex); - fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group); + fsn_mark = fsnotify_find_mark(&inode->i_fsnotify.marks, group); if (!fsn_mark) { mutex_unlock(&group->mark_mutex); return -ENOENT; @@ -571,8 +571,8 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, &destroy_mark); - if (removed & inode->i_fsnotify_mask) - fsnotify_recalc_mask(inode->i_fsnotify_marks); + if (removed & inode->i_fsnotify.mask) + fsnotify_recalc_mask(inode->i_fsnotify.marks); if (destroy_mark) fsnotify_detach_mark(fsn_mark); mutex_unlock(&group->mark_mutex); @@ -647,7 +647,7 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, __u32 added; mutex_lock(&group->mark_mutex); - fsn_mark = fsnotify_find_mark(&real_mount(mnt)->mnt_fsnotify_marks, + fsn_mark = fsnotify_find_mark(&real_mount(mnt)->mnt_fsnotify.marks, group); if (!fsn_mark) { fsn_mark = fanotify_add_new_mark(group, NULL, mnt); @@ -657,8 +657,8 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, } } added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); - if (added & ~real_mount(mnt)->mnt_fsnotify_mask) - fsnotify_recalc_mask(real_mount(mnt)->mnt_fsnotify_marks); + if (added & ~real_mount(mnt)->mnt_fsnotify.mask) + fsnotify_recalc_mask(real_mount(mnt)->mnt_fsnotify.marks); mutex_unlock(&group->mark_mutex); fsnotify_put_mark(fsn_mark); @@ -685,7 +685,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, return 0; mutex_lock(&group->mark_mutex); - fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group); + fsn_mark = fsnotify_find_mark(&inode->i_fsnotify.marks, group); if (!fsn_mark) { fsn_mark = fanotify_add_new_mark(group, inode, NULL); if (IS_ERR(fsn_mark)) { @@ -694,8 +694,8 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, } } added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); - if (added & ~inode->i_fsnotify_mask) - fsnotify_recalc_mask(inode->i_fsnotify_marks); + if (added & ~inode->i_fsnotify.mask) + fsnotify_recalc_mask(inode->i_fsnotify.marks); mutex_unlock(&group->mark_mutex); fsnotify_put_mark(fsn_mark); diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index f174397b63a0..ea1003bc39d3 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -160,7 +160,7 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask if (unlikely(!fsnotify_inode_watches_children(p_inode))) __fsnotify_update_child_dentry_flags(p_inode); - else if (p_inode->i_fsnotify_mask & mask) { + else if (p_inode->i_fsnotify.mask & mask) { struct name_snapshot name; /* we are notifying a parent so come up with the new mask which @@ -331,13 +331,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, /* * Optimization: srcu_read_lock() has a memory barrier which can - * be expensive. It protects walking the *_fsnotify_marks lists. + * be expensive. It protects walking the *_fsnotify.marks lists. * However, if we do not walk the lists, we do not have to do * SRCU because we have no references to any objects and do not * need SRCU to keep them "alive". */ - if (!to_tell->i_fsnotify_marks && - (!mnt || !mnt->mnt_fsnotify_marks)) + if (!to_tell->i_fsnotify.marks && + (!mnt || !mnt->mnt_fsnotify.marks)) return 0; /* * if this is a modify event we may need to clear the ignored masks @@ -345,24 +345,24 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, * this type of event. */ if (!(mask & FS_MODIFY) && - !(test_mask & to_tell->i_fsnotify_mask) && - !(mnt && test_mask & mnt->mnt_fsnotify_mask)) + !(test_mask & to_tell->i_fsnotify.mask) && + !(mnt && test_mask & mnt->mnt_fsnotify.mask)) return 0; iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); if ((mask & FS_MODIFY) || - (test_mask & to_tell->i_fsnotify_mask)) { + (test_mask & to_tell->i_fsnotify.mask)) { iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = - fsnotify_first_mark(&to_tell->i_fsnotify_marks); + fsnotify_first_mark(&to_tell->i_fsnotify.marks); } if (mnt && ((mask & FS_MODIFY) || - (test_mask & mnt->mnt_fsnotify_mask))) { + (test_mask & mnt->mnt_fsnotify.mask))) { iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = - fsnotify_first_mark(&to_tell->i_fsnotify_marks); + fsnotify_first_mark(&to_tell->i_fsnotify.marks); iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] = - fsnotify_first_mark(&mnt->mnt_fsnotify_marks); + fsnotify_first_mark(&mnt->mnt_fsnotify.marks); } /* diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 34515d2c4ba3..8f4d3e43b5b5 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h @@ -24,12 +24,12 @@ extern void fsnotify_destroy_marks(struct fsnotify_mark_connector __rcu **connp) /* run the list of all marks associated with inode and destroy them */ static inline void fsnotify_clear_marks_by_inode(struct inode *inode) { - fsnotify_destroy_marks(&inode->i_fsnotify_marks); + fsnotify_destroy_marks(&inode->i_fsnotify.marks); } /* run the list of all marks associated with vfsmount and destroy them */ static inline void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) { - fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify_marks); + fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify.marks); } /* Wait until all marks queued for destruction are destroyed */ extern void fsnotify_wait_marks_destroyed(void); diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 1cf5b779d862..8eaa3b468b5c 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -514,7 +514,7 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, mask = inotify_arg_to_mask(arg); - fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group); + fsn_mark = fsnotify_find_mark(&inode->i_fsnotify.marks, group); if (!fsn_mark) return -ENOENT; @@ -533,11 +533,11 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, /* more bits in old than in new? */ int dropped = (old_mask & ~new_mask); /* more bits in this fsn_mark than the inode's mask? */ - int do_inode = (new_mask & ~inode->i_fsnotify_mask); + int do_inode = (new_mask & ~inode->i_fsnotify.mask); /* update the inode with this new fsn_mark */ if (dropped || do_inode) - fsnotify_recalc_mask(inode->i_fsnotify_marks); + fsnotify_recalc_mask(inode->i_fsnotify.marks); } diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 61f4c5fa34c7..4f0c17e5db53 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -120,9 +120,9 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) new_mask |= mark->mask; } if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) - conn->inode->i_fsnotify_mask = new_mask; + conn->inode->i_fsnotify.mask = new_mask; else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) - real_mount(conn->mnt)->mnt_fsnotify_mask = new_mask; + real_mount(conn->mnt)->mnt_fsnotify.mask = new_mask; } /* @@ -168,14 +168,14 @@ static struct inode *fsnotify_detach_connector_from_object( if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { inode = conn->inode; - rcu_assign_pointer(inode->i_fsnotify_marks, NULL); - inode->i_fsnotify_mask = 0; + rcu_assign_pointer(inode->i_fsnotify.marks, NULL); + inode->i_fsnotify.mask = 0; conn->inode = NULL; conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { - rcu_assign_pointer(real_mount(conn->mnt)->mnt_fsnotify_marks, + rcu_assign_pointer(real_mount(conn->mnt)->mnt_fsnotify.marks, NULL); - real_mount(conn->mnt)->mnt_fsnotify_mask = 0; + real_mount(conn->mnt)->mnt_fsnotify.mask = 0; conn->mnt = NULL; conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; } @@ -515,9 +515,9 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, if (WARN_ON(!inode && !mnt)) return -EINVAL; if (inode) - connp = &inode->i_fsnotify_marks; + connp = &inode->i_fsnotify.marks; else - connp = &real_mount(mnt)->mnt_fsnotify_marks; + connp = &real_mount(mnt)->mnt_fsnotify.marks; restart: spin_lock(&mark->lock); conn = fsnotify_grab_connector(connp); diff --git a/include/linux/fs.h b/include/linux/fs.h index 760d8da1b6c7..46af8e9a1111 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -36,6 +36,7 @@ #include <linux/delayed_call.h> #include <linux/uuid.h> #include <linux/errseq.h> +#include <linux/fsnotify_obj.h> #include <asm/byteorder.h> #include <uapi/linux/fs.h> @@ -560,8 +561,6 @@ is_uncached_acl(struct posix_acl *acl) #define IOP_XATTR 0x0008 #define IOP_DEFAULT_READLINK 0x0010 -struct fsnotify_mark_connector; - /* * Keep mostly read-only and often accessed (especially for * the RCU path lookup and 'stat' data) fields at the beginning @@ -661,8 +660,7 @@ struct inode { __u32 i_generation; #ifdef CONFIG_FSNOTIFY - __u32 i_fsnotify_mask; /* all events this inode cares about */ - struct fsnotify_mark_connector __rcu *i_fsnotify_marks; + struct fsnotify_obj i_fsnotify; #endif #if IS_ENABLED(CONFIG_FS_ENCRYPTION) diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index b38964a7a521..a2cd8c51860e 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -19,6 +19,7 @@ #include <linux/atomic.h> #include <linux/user_namespace.h> #include <linux/refcount.h> +#include <linux/fsnotify_obj.h> /* * IN_* from inotfy.h lines up EXACTLY with FS_*, this is so we can easily @@ -268,6 +269,11 @@ struct fsnotify_mark_connector { struct hlist_head list; }; +static inline struct inode *fsnotify_obj_inode(struct fsnotify_obj *obj) +{ + return container_of(obj, struct inode, i_fsnotify); +} + /* * A mark is simply an object attached to an in core inode which allows an * fsnotify listener to indicate they are either no longer interested in events @@ -324,11 +330,11 @@ extern u32 fsnotify_get_cookie(void); static inline int fsnotify_inode_watches_children(struct inode *inode) { /* FS_EVENT_ON_CHILD is set if the inode may care */ - if (!(inode->i_fsnotify_mask & FS_EVENT_ON_CHILD)) + if (!(inode->i_fsnotify.mask & FS_EVENT_ON_CHILD)) return 0; /* this inode might care about child events, does it care about the * specific set of events that can happen on a child? */ - return inode->i_fsnotify_mask & FS_EVENTS_POSS_ON_CHILD; + return inode->i_fsnotify.mask & FS_EVENTS_POSS_ON_CHILD; } /* diff --git a/include/linux/fsnotify_obj.h b/include/linux/fsnotify_obj.h new file mode 100644 index 000000000000..437e78e60f82 --- /dev/null +++ b/include/linux/fsnotify_obj.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_FSNOTIFY_OBJ_H +#define _LINUX_FSNOTIFY_OBJ_H + +struct fsnotify_mark_connector; + +/* struct to embed in objects, which marks can be attached to */ +struct fsnotify_obj { + struct fsnotify_mark_connector __rcu *marks; + /* all events this object cares about */ + __u32 mask; +}; + +#endif diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index c99ebaae5abc..0124eb3999a5 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -393,7 +393,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) struct node *p; int n; - old_entry = fsnotify_find_mark(&inode->i_fsnotify_marks, + old_entry = fsnotify_find_mark(&inode->i_fsnotify.marks, audit_tree_group); if (!old_entry) return create_chunk(inode, tree); diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 439a3a01368c..1b017875b8d2 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -103,7 +103,7 @@ static inline struct audit_parent *audit_find_parent(struct inode *inode) struct audit_parent *parent = NULL; struct fsnotify_mark *entry; - entry = fsnotify_find_mark(&inode->i_fsnotify_marks, audit_watch_group); + entry = fsnotify_find_mark(&inode->i_fsnotify.marks, audit_watch_group); if (entry) parent = container_of(entry, struct audit_parent, mark); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 4e0a4ac803db..87098b93ab79 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1598,7 +1598,7 @@ static inline void handle_one(const struct inode *inode) struct audit_tree_refs *p; struct audit_chunk *chunk; int count; - if (likely(!inode->i_fsnotify_marks)) + if (likely(!inode->i_fsnotify.marks)) return; context = current->audit_context; p = context->trees; @@ -1641,7 +1641,7 @@ static void handle_path(const struct dentry *dentry) seq = read_seqbegin(&rename_lock); for(;;) { struct inode *inode = d_backing_inode(d); - if (inode && unlikely(inode->i_fsnotify_marks)) { + if (inode && unlikely(inode->i_fsnotify.marks)) { struct audit_chunk *chunk; chunk = audit_tree_lookup(inode); if (chunk) { -- 2.7.4