On Mon 18-10-21 14:44:11, rong wang wrote: > In practical applications, a common requirement is to monitor the changes > of the entire file system, but the current inotify can only monitor the > specified target and cannot do anything to monitor the entire file system. > The limited monitoring of inotify originates from the inode-based event > dispatch mechanism of fsnotify. In order to monitor the changes of the > entire file system, consider adding a new event dispatch mechanism, the > core of which is to broadcast the event once before the event is filtered. > That is, other modules of the kernel first register the broadcast listener > with fsnotify. After receiving the event, fsnotify will send the event to > all the listeners without filtering. > > Signed-off-by: rong wang <wangrong@xxxxxxxxxxxxx> Thanks for the patch but can you ellaborate a bit more on why exactly you need this mechanism? What would be using it? Without in kernel users it is useless anyway. Also, since this will execute on each and every filesystem operation, there will be noticeable overhead on the system unless you are really careful. So more details please... Finally also note that fanotify already does support filesystem (superblock) wide notification events so maybe that is enough for your purposes? Honza > --- > fs/notify/fsnotify.c | 72 ++++++++++++++++++++++++++++++++ > include/linux/fsnotify.h | 8 ++++ > include/linux/fsnotify_backend.h | 16 +++++++ > 3 files changed, 96 insertions(+) > > diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c > index 963e6ce75b96..cd235af8c24b 100644 > --- a/fs/notify/fsnotify.c > +++ b/fs/notify/fsnotify.c > @@ -14,6 +14,78 @@ > #include <linux/fsnotify_backend.h> > #include "fsnotify.h" > > +/* fs event broadcast */ > +static unsigned int fsnotify_broadcast_listeners_count; > +static DEFINE_RWLOCK(fsnotify_broadcast_listeners_lock); > +static LIST_HEAD(fsnotify_broadcast_listeners); > + > +struct fsnotify_broadcast_listener { > + struct list_head list; > + fsnotify_broadcast_listener_t listener; > +}; > + > +int fsnotify_register_broadcast_listener(fsnotify_broadcast_listener_t listener) > +{ > + struct fsnotify_broadcast_listener *event_listener; > + > + if (unlikely(listener == 0)) > + return -EINVAL; > + > + event_listener = kmalloc(sizeof(*event_listener), GFP_KERNEL); > + if (unlikely(!event_listener)) > + return -ENOMEM; > + event_listener->listener = listener; > + > + write_lock(&fsnotify_broadcast_listeners_lock); > + list_add_tail(&event_listener->list, &fsnotify_broadcast_listeners); > + ++fsnotify_broadcast_listeners_count; > + write_unlock(&fsnotify_broadcast_listeners_lock); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(fsnotify_register_broadcast_listener); > + > +void fsnotify_unregister_broadcast_listener(fsnotify_broadcast_listener_t listener) > +{ > + struct list_head *p, *next; > + struct fsnotify_broadcast_listener *event_listener; > + > + write_lock(&fsnotify_broadcast_listeners_lock); > + list_for_each_safe(p, next, &fsnotify_broadcast_listeners) { > + event_listener = list_entry(p, struct fsnotify_broadcast_listener, list); > + if (listener == event_listener->listener) { > + list_del(p); > + kfree(event_listener); > + --fsnotify_broadcast_listeners_count; > + break; > + } > + } > + write_unlock(&fsnotify_broadcast_listeners_lock); > +} > +EXPORT_SYMBOL_GPL(fsnotify_unregister_broadcast_listener); > + > +void fsnotify_broadcast(__u32 mask, const void *data, int data_type, > + struct inode *dir, const struct qstr *file_name, > + struct inode *inode, u32 cookie) > +{ > + struct fsnotify_broadcast_listener *event_listener; > + > + if (!fsnotify_broadcast_listeners_count) > + return; > + > + if (inode && S_ISDIR(inode->i_mode)) > + mask |= FS_ISDIR; > + > + read_lock(&fsnotify_broadcast_listeners_lock); > + list_for_each_entry(event_listener, > + &fsnotify_broadcast_listeners, list) { > + event_listener->listener(mask, data, data_type, dir, > + file_name, inode, cookie); > + } > + read_unlock(&fsnotify_broadcast_listeners_lock); > +} > +EXPORT_SYMBOL_GPL(fsnotify_broadcast); > + > /* > * Clear all of the marks on an inode when it is being evicted from core > */ > diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h > index 12d3a7d308ab..22924cb22102 100644 > --- a/include/linux/fsnotify.h > +++ b/include/linux/fsnotify.h > @@ -30,6 +30,9 @@ static inline void fsnotify_name(struct inode *dir, __u32 mask, > struct inode *child, > const struct qstr *name, u32 cookie) > { > + fsnotify_broadcast(mask, child, FSNOTIFY_EVENT_INODE, > + dir, name, NULL, cookie); > + > if (atomic_long_read(&dir->i_sb->s_fsnotify_connectors) == 0) > return; > > @@ -44,6 +47,9 @@ static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, > > static inline void fsnotify_inode(struct inode *inode, __u32 mask) > { > + fsnotify_broadcast(mask, inode, FSNOTIFY_EVENT_INODE, > + NULL, NULL, inode, 0); > + > if (atomic_long_read(&inode->i_sb->s_fsnotify_connectors) == 0) > return; > > @@ -59,6 +65,8 @@ static inline int fsnotify_parent(struct dentry *dentry, __u32 mask, > { > struct inode *inode = d_inode(dentry); > > + fsnotify_broadcast(mask, data, data_type, NULL, NULL, inode, 0); > + > if (atomic_long_read(&inode->i_sb->s_fsnotify_connectors) == 0) > return 0; > > diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h > index 1ce66748a2d2..27d926c38eb5 100644 > --- a/include/linux/fsnotify_backend.h > +++ b/include/linux/fsnotify_backend.h > @@ -418,6 +418,9 @@ extern void __fsnotify_inode_delete(struct inode *inode); > extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); > extern void fsnotify_sb_delete(struct super_block *sb); > extern u32 fsnotify_get_cookie(void); > +extern void fsnotify_broadcast(__u32 mask, const void *data, int data_type, > + struct inode *dir, const struct qstr *file_name, > + struct inode *inode, u32 cookie); > > static inline __u32 fsnotify_parent_needed_mask(__u32 mask) > { > @@ -586,6 +589,13 @@ static inline void fsnotify_init_event(struct fsnotify_event *event) > INIT_LIST_HEAD(&event->list); > } > > +/* fs event broadcast */ > +typedef void (*fsnotify_broadcast_listener_t) (__u32 mask, const void *data, int data_type, > + struct inode *dir, const struct qstr *file_name, > + struct inode *inode, u32 cookie); > +extern int fsnotify_register_broadcast_listener(fsnotify_broadcast_listener_t listener); > +extern void fsnotify_unregister_broadcast_listener(fsnotify_broadcast_listener_t listener); > + > #else > > static inline int fsnotify(__u32 mask, const void *data, int data_type, > @@ -618,6 +628,12 @@ static inline u32 fsnotify_get_cookie(void) > return 0; > } > > +static inline void fsnotify_broadcast(__u32 mask, const void *data, > + int data_type, struct inode *dir, > + const struct qstr *file_name, > + struct inode *inode, u32 cookie) > +{} > + > static inline void fsnotify_unmount_inodes(struct super_block *sb) > {} > > -- > 2.20.1 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR