Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Revert "kernfs: Change kernfs_notify_list to llist."

This reverts commit b8f35fa1188b84035c59d4842826c4e93a1b1c9f.

This is causing regression due to same kernfs_node getting
added multiple times in kernfs_notify_list so revert it until
safe way of using llist in this context is found.

Reported-by: Nathan Chancellor <nathan@kernel.org>
Reported-by: Michael Walle <michael@walle.cc>
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Imran Khan <imran.f.khan@oracle.com>
Cc: Tejun Heo <tj@kernel.org>
Link: https://lore.kernel.org/r/20220705201026.2487665-1-imran.f.khan@oracle.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Imran Khan and committed by
Greg Kroah-Hartman
2fd26970 72b5d5ae

+28 -21
+27 -20
fs/kernfs/file.c
··· 25 25 struct list_head files; /* goes through kernfs_open_file.list */ 26 26 }; 27 27 28 - /** 29 - * attribute_to_node - get kernfs_node object corresponding to a kernfs attribute 30 - * @ptr: &struct kernfs_elem_attr 31 - * @type: struct kernfs_node 32 - * @member: name of member (i.e attr) 28 + /* 29 + * kernfs_notify() may be called from any context and bounces notifications 30 + * through a work item. To minimize space overhead in kernfs_node, the 31 + * pending queue is implemented as a singly linked list of kernfs_nodes. 32 + * The list is terminated with the self pointer so that whether a 33 + * kernfs_node is on the list or not can be determined by testing the next 34 + * pointer for NULL. 33 35 */ 34 - #define attribute_to_node(ptr, type, member) \ 35 - container_of(ptr, type, member) 36 + #define KERNFS_NOTIFY_EOL ((void *)&kernfs_notify_list) 36 37 37 - static LLIST_HEAD(kernfs_notify_list); 38 + static DEFINE_SPINLOCK(kernfs_notify_lock); 39 + static struct kernfs_node *kernfs_notify_list = KERNFS_NOTIFY_EOL; 38 40 39 41 static inline struct mutex *kernfs_open_file_mutex_ptr(struct kernfs_node *kn) 40 42 { ··· 911 909 struct kernfs_node *kn; 912 910 struct kernfs_super_info *info; 913 911 struct kernfs_root *root; 914 - struct llist_node *free; 915 - struct kernfs_elem_attr *attr; 916 912 repeat: 917 913 /* pop one off the notify_list */ 918 - free = llist_del_first(&kernfs_notify_list); 919 - if (free == NULL) 914 + spin_lock_irq(&kernfs_notify_lock); 915 + kn = kernfs_notify_list; 916 + if (kn == KERNFS_NOTIFY_EOL) { 917 + spin_unlock_irq(&kernfs_notify_lock); 920 918 return; 919 + } 920 + kernfs_notify_list = kn->attr.notify_next; 921 + kn->attr.notify_next = NULL; 922 + spin_unlock_irq(&kernfs_notify_lock); 921 923 922 - attr = llist_entry(free, struct kernfs_elem_attr, notify_next); 923 - kn = attribute_to_node(attr, struct kernfs_node, attr); 924 924 root = kernfs_root(kn); 925 925 /* kick fsnotify */ 926 926 down_write(&root->kernfs_rwsem); ··· 978 974 void kernfs_notify(struct kernfs_node *kn) 979 975 { 980 976 static DECLARE_WORK(kernfs_notify_work, kernfs_notify_workfn); 977 + unsigned long flags; 981 978 struct kernfs_open_node *on; 982 979 983 980 if (WARN_ON(kernfs_type(kn) != KERNFS_FILE)) 984 981 return; 985 - 986 - /* Because we are using llist for kernfs_notify_list */ 987 - WARN_ON_ONCE(in_nmi()); 988 982 989 983 /* kick poll immediately */ 990 984 rcu_read_lock(); ··· 994 992 rcu_read_unlock(); 995 993 996 994 /* schedule work to kick fsnotify */ 997 - kernfs_get(kn); 998 - llist_add(&kn->attr.notify_next, &kernfs_notify_list); 999 - schedule_work(&kernfs_notify_work); 995 + spin_lock_irqsave(&kernfs_notify_lock, flags); 996 + if (!kn->attr.notify_next) { 997 + kernfs_get(kn); 998 + kn->attr.notify_next = kernfs_notify_list; 999 + kernfs_notify_list = kn; 1000 + schedule_work(&kernfs_notify_work); 1001 + } 1002 + spin_unlock_irqrestore(&kernfs_notify_lock, flags); 1000 1003 } 1001 1004 EXPORT_SYMBOL_GPL(kernfs_notify); 1002 1005
+1 -1
include/linux/kernfs.h
··· 173 173 const struct kernfs_ops *ops; 174 174 struct kernfs_open_node __rcu *open; 175 175 loff_t size; 176 - struct llist_node notify_next; /* for kernfs_notify() */ 176 + struct kernfs_node *notify_next; /* for kernfs_notify() */ 177 177 }; 178 178 179 179 /*