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.

kernfs: Change kernfs_notify_list to llist.

At present kernfs_notify_list is implemented as a singly linked
list of kernfs_node(s), where last element points to itself and
value of ->attr.next tells if node is present on the list or not.
Both addition and deletion to list happen under kernfs_notify_lock.

Change kernfs_notify_list to llist so that addition to list can heppen
locklessly.

Suggested by: Al Viro <viro@zeniv.linux.org.uk>

Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Imran Khan <imran.f.khan@oracle.com>
Link: https://lore.kernel.org/r/20220615021059.862643-3-imran.f.khan@oracle.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Imran Khan and committed by
Greg Kroah-Hartman
b8f35fa1 086c00c7

+21 -28
+20 -27
fs/kernfs/file.c
··· 38 38 struct list_head files; /* goes through kernfs_open_file.list */ 39 39 }; 40 40 41 - /* 42 - * kernfs_notify() may be called from any context and bounces notifications 43 - * through a work item. To minimize space overhead in kernfs_node, the 44 - * pending queue is implemented as a singly linked list of kernfs_nodes. 45 - * The list is terminated with the self pointer so that whether a 46 - * kernfs_node is on the list or not can be determined by testing the next 47 - * pointer for NULL. 41 + /** 42 + * attribute_to_node - get kernfs_node object corresponding to a kernfs attribute 43 + * @ptr: &struct kernfs_elem_attr 44 + * @type: struct kernfs_node 45 + * @member: name of member (i.e attr) 48 46 */ 49 - #define KERNFS_NOTIFY_EOL ((void *)&kernfs_notify_list) 47 + #define attribute_to_node(ptr, type, member) \ 48 + container_of(ptr, type, member) 50 49 51 - static DEFINE_SPINLOCK(kernfs_notify_lock); 52 - static struct kernfs_node *kernfs_notify_list = KERNFS_NOTIFY_EOL; 50 + static LLIST_HEAD(kernfs_notify_list); 53 51 54 52 /** 55 53 * kernfs_deref_open_node - Get kernfs_open_node corresponding to @kn. ··· 900 902 struct kernfs_node *kn; 901 903 struct kernfs_super_info *info; 902 904 struct kernfs_root *root; 905 + struct llist_node *free; 906 + struct kernfs_elem_attr *attr; 903 907 repeat: 904 908 /* pop one off the notify_list */ 905 - spin_lock_irq(&kernfs_notify_lock); 906 - kn = kernfs_notify_list; 907 - if (kn == KERNFS_NOTIFY_EOL) { 908 - spin_unlock_irq(&kernfs_notify_lock); 909 + free = llist_del_first(&kernfs_notify_list); 910 + if (free == NULL) 909 911 return; 910 - } 911 - kernfs_notify_list = kn->attr.notify_next; 912 - kn->attr.notify_next = NULL; 913 - spin_unlock_irq(&kernfs_notify_lock); 914 912 913 + attr = llist_entry(free, struct kernfs_elem_attr, notify_next); 914 + kn = attribute_to_node(attr, struct kernfs_node, attr); 915 915 root = kernfs_root(kn); 916 916 /* kick fsnotify */ 917 917 down_write(&root->kernfs_rwsem); ··· 965 969 void kernfs_notify(struct kernfs_node *kn) 966 970 { 967 971 static DECLARE_WORK(kernfs_notify_work, kernfs_notify_workfn); 968 - unsigned long flags; 969 972 struct kernfs_open_node *on; 970 973 971 974 if (WARN_ON(kernfs_type(kn) != KERNFS_FILE)) 972 975 return; 976 + 977 + /* Because we are using llist for kernfs_notify_list */ 978 + WARN_ON_ONCE(in_nmi()); 973 979 974 980 /* kick poll immediately */ 975 981 rcu_read_lock(); ··· 983 985 rcu_read_unlock(); 984 986 985 987 /* schedule work to kick fsnotify */ 986 - spin_lock_irqsave(&kernfs_notify_lock, flags); 987 - if (!kn->attr.notify_next) { 988 - kernfs_get(kn); 989 - kn->attr.notify_next = kernfs_notify_list; 990 - kernfs_notify_list = kn; 991 - schedule_work(&kernfs_notify_work); 992 - } 993 - spin_unlock_irqrestore(&kernfs_notify_lock, flags); 988 + kernfs_get(kn); 989 + llist_add(&kn->attr.notify_next, &kernfs_notify_list); 990 + schedule_work(&kernfs_notify_work); 994 991 } 995 992 EXPORT_SYMBOL_GPL(kernfs_notify); 996 993
+1 -1
include/linux/kernfs.h
··· 116 116 const struct kernfs_ops *ops; 117 117 struct kernfs_open_node __rcu *open; 118 118 loff_t size; 119 - struct kernfs_node *notify_next; /* for kernfs_notify() */ 119 + struct llist_node notify_next; /* for kernfs_notify() */ 120 120 }; 121 121 122 122 /*