187418ef9SColy Li // SPDX-License-Identifier: GPL-2.0
2cafe5635SKent Overstreet /*
3cafe5635SKent Overstreet * Asynchronous refcounty things
4cafe5635SKent Overstreet *
5cafe5635SKent Overstreet * Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>
6cafe5635SKent Overstreet * Copyright 2012 Google, Inc.
7cafe5635SKent Overstreet */
8cafe5635SKent Overstreet
9cafe5635SKent Overstreet #include <linux/debugfs.h>
10cafe5635SKent Overstreet #include <linux/module.h>
11cafe5635SKent Overstreet #include <linux/seq_file.h>
12ce439bf7SKent Overstreet #include <linux/sched/debug.h>
13cafe5635SKent Overstreet
14cafe5635SKent Overstreet #include "closure.h"
15cafe5635SKent Overstreet
closure_put_after_sub(struct closure * cl,int flags)16cafe5635SKent Overstreet static inline void closure_put_after_sub(struct closure *cl, int flags)
17cafe5635SKent Overstreet {
18cafe5635SKent Overstreet int r = flags & CLOSURE_REMAINING_MASK;
19cafe5635SKent Overstreet
20*ecb4aaa6SKent Overstreet if (WARN(flags & CLOSURE_GUARD_MASK,
21*ecb4aaa6SKent Overstreet "closure has guard bits set: %x (%u)",
22*ecb4aaa6SKent Overstreet flags & CLOSURE_GUARD_MASK, (unsigned) __fls(r)))
23*ecb4aaa6SKent Overstreet r &= ~CLOSURE_GUARD_MASK;
24cafe5635SKent Overstreet
25cafe5635SKent Overstreet if (!r) {
26*ecb4aaa6SKent Overstreet WARN(flags & ~CLOSURE_DESTRUCTOR,
27*ecb4aaa6SKent Overstreet "closure ref hit 0 with incorrect flags set: %x (%u)",
28*ecb4aaa6SKent Overstreet flags & ~CLOSURE_DESTRUCTOR, (unsigned) __fls(flags));
29*ecb4aaa6SKent Overstreet
30cafe5635SKent Overstreet if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) {
31cafe5635SKent Overstreet atomic_set(&cl->remaining,
32cafe5635SKent Overstreet CLOSURE_REMAINING_INITIALIZER);
33cafe5635SKent Overstreet closure_queue(cl);
34cafe5635SKent Overstreet } else {
35cafe5635SKent Overstreet struct closure *parent = cl->parent;
366aa8f1a6SKent Overstreet closure_fn *destructor = cl->fn;
37cafe5635SKent Overstreet
38cafe5635SKent Overstreet closure_debug_destroy(cl);
39cafe5635SKent Overstreet
406aa8f1a6SKent Overstreet if (destructor)
416aa8f1a6SKent Overstreet destructor(cl);
42cafe5635SKent Overstreet
43cafe5635SKent Overstreet if (parent)
44cafe5635SKent Overstreet closure_put(parent);
45cafe5635SKent Overstreet }
46cafe5635SKent Overstreet }
47cafe5635SKent Overstreet }
48cafe5635SKent Overstreet
49cafe5635SKent Overstreet /* For clearing flags with the same atomic op as a put */
closure_sub(struct closure * cl,int v)50cafe5635SKent Overstreet void closure_sub(struct closure *cl, int v)
51cafe5635SKent Overstreet {
52cafe5635SKent Overstreet closure_put_after_sub(cl, atomic_sub_return(v, &cl->remaining));
53cafe5635SKent Overstreet }
54cafe5635SKent Overstreet
5547344e33SBart Van Assche /*
561dd13c8dSKent Overstreet * closure_put - decrement a closure's refcount
571dd13c8dSKent Overstreet */
closure_put(struct closure * cl)58cafe5635SKent Overstreet void closure_put(struct closure *cl)
59cafe5635SKent Overstreet {
60cafe5635SKent Overstreet closure_put_after_sub(cl, atomic_dec_return(&cl->remaining));
61cafe5635SKent Overstreet }
62cafe5635SKent Overstreet
6347344e33SBart Van Assche /*
641dd13c8dSKent Overstreet * closure_wake_up - wake up all closures on a wait list, without memory barrier
651dd13c8dSKent Overstreet */
__closure_wake_up(struct closure_waitlist * wait_list)66cafe5635SKent Overstreet void __closure_wake_up(struct closure_waitlist *wait_list)
67cafe5635SKent Overstreet {
68cafe5635SKent Overstreet struct llist_node *list;
69a5f3d8a5SColy Li struct closure *cl, *t;
70cafe5635SKent Overstreet struct llist_node *reverse = NULL;
71cafe5635SKent Overstreet
72cafe5635SKent Overstreet list = llist_del_all(&wait_list->list);
73cafe5635SKent Overstreet
74cafe5635SKent Overstreet /* We first reverse the list to preserve FIFO ordering and fairness */
7509b3efecSByungchul Park reverse = llist_reverse_order(list);
76cafe5635SKent Overstreet
77cafe5635SKent Overstreet /* Then do the wakeups */
78a5f3d8a5SColy Li llist_for_each_entry_safe(cl, t, reverse, list) {
791dd13c8dSKent Overstreet closure_set_waiting(cl, 0);
80cafe5635SKent Overstreet closure_sub(cl, CLOSURE_WAITING + 1);
81cafe5635SKent Overstreet }
82cafe5635SKent Overstreet }
83cafe5635SKent Overstreet
841dd13c8dSKent Overstreet /**
851dd13c8dSKent Overstreet * closure_wait - add a closure to a waitlist
8647344e33SBart Van Assche * @waitlist: will own a ref on @cl, which will be released when
871dd13c8dSKent Overstreet * closure_wake_up() is called on @waitlist.
8847344e33SBart Van Assche * @cl: closure pointer.
891dd13c8dSKent Overstreet *
901dd13c8dSKent Overstreet */
closure_wait(struct closure_waitlist * waitlist,struct closure * cl)911dd13c8dSKent Overstreet bool closure_wait(struct closure_waitlist *waitlist, struct closure *cl)
92cafe5635SKent Overstreet {
93cafe5635SKent Overstreet if (atomic_read(&cl->remaining) & CLOSURE_WAITING)
94cafe5635SKent Overstreet return false;
95cafe5635SKent Overstreet
961dd13c8dSKent Overstreet closure_set_waiting(cl, _RET_IP_);
97cafe5635SKent Overstreet atomic_add(CLOSURE_WAITING + 1, &cl->remaining);
981dd13c8dSKent Overstreet llist_add(&cl->list, &waitlist->list);
99cafe5635SKent Overstreet
100cafe5635SKent Overstreet return true;
101cafe5635SKent Overstreet }
102cafe5635SKent Overstreet
103e4bf7919SKent Overstreet struct closure_syncer {
104e4bf7919SKent Overstreet struct task_struct *task;
105e4bf7919SKent Overstreet int done;
106e4bf7919SKent Overstreet };
107e4bf7919SKent Overstreet
closure_sync_fn(struct closure * cl)108e4bf7919SKent Overstreet static void closure_sync_fn(struct closure *cl)
109cafe5635SKent Overstreet {
110a22a9602SKent Overstreet struct closure_syncer *s = cl->s;
111a22a9602SKent Overstreet struct task_struct *p;
112a22a9602SKent Overstreet
113a22a9602SKent Overstreet rcu_read_lock();
114a22a9602SKent Overstreet p = READ_ONCE(s->task);
115a22a9602SKent Overstreet s->done = 1;
116a22a9602SKent Overstreet wake_up_process(p);
117a22a9602SKent Overstreet rcu_read_unlock();
118e4bf7919SKent Overstreet }
119e4bf7919SKent Overstreet
__closure_sync(struct closure * cl)120ce439bf7SKent Overstreet void __sched __closure_sync(struct closure *cl)
121e4bf7919SKent Overstreet {
122e4bf7919SKent Overstreet struct closure_syncer s = { .task = current };
123e4bf7919SKent Overstreet
124e4bf7919SKent Overstreet cl->s = &s;
125e4bf7919SKent Overstreet continue_at(cl, closure_sync_fn, NULL);
126e4bf7919SKent Overstreet
127cafe5635SKent Overstreet while (1) {
128e4bf7919SKent Overstreet set_current_state(TASK_UNINTERRUPTIBLE);
129e4bf7919SKent Overstreet if (s.done)
130cafe5635SKent Overstreet break;
131cafe5635SKent Overstreet schedule();
132cafe5635SKent Overstreet }
133cafe5635SKent Overstreet
134e4bf7919SKent Overstreet __set_current_state(TASK_RUNNING);
135cafe5635SKent Overstreet }
136cafe5635SKent Overstreet
137cafe5635SKent Overstreet #ifdef CONFIG_BCACHE_CLOSURES_DEBUG
138cafe5635SKent Overstreet
139cafe5635SKent Overstreet static LIST_HEAD(closure_list);
140cafe5635SKent Overstreet static DEFINE_SPINLOCK(closure_list_lock);
141cafe5635SKent Overstreet
closure_debug_create(struct closure * cl)142cafe5635SKent Overstreet void closure_debug_create(struct closure *cl)
143cafe5635SKent Overstreet {
144cafe5635SKent Overstreet unsigned long flags;
145cafe5635SKent Overstreet
146cafe5635SKent Overstreet BUG_ON(cl->magic == CLOSURE_MAGIC_ALIVE);
147cafe5635SKent Overstreet cl->magic = CLOSURE_MAGIC_ALIVE;
148cafe5635SKent Overstreet
149cafe5635SKent Overstreet spin_lock_irqsave(&closure_list_lock, flags);
150cafe5635SKent Overstreet list_add(&cl->all, &closure_list);
151cafe5635SKent Overstreet spin_unlock_irqrestore(&closure_list_lock, flags);
152cafe5635SKent Overstreet }
153cafe5635SKent Overstreet
closure_debug_destroy(struct closure * cl)154cafe5635SKent Overstreet void closure_debug_destroy(struct closure *cl)
155cafe5635SKent Overstreet {
156cafe5635SKent Overstreet unsigned long flags;
157cafe5635SKent Overstreet
158cafe5635SKent Overstreet BUG_ON(cl->magic != CLOSURE_MAGIC_ALIVE);
159cafe5635SKent Overstreet cl->magic = CLOSURE_MAGIC_DEAD;
160cafe5635SKent Overstreet
161cafe5635SKent Overstreet spin_lock_irqsave(&closure_list_lock, flags);
162cafe5635SKent Overstreet list_del(&cl->all);
163cafe5635SKent Overstreet spin_unlock_irqrestore(&closure_list_lock, flags);
164cafe5635SKent Overstreet }
165cafe5635SKent Overstreet
166df2b9431SChengguang Xu static struct dentry *closure_debug;
167cafe5635SKent Overstreet
debug_show(struct seq_file * f,void * data)16884e5d136SQinglang Miao static int debug_show(struct seq_file *f, void *data)
169cafe5635SKent Overstreet {
170cafe5635SKent Overstreet struct closure *cl;
1711fae7cf0SColy Li
172cafe5635SKent Overstreet spin_lock_irq(&closure_list_lock);
173cafe5635SKent Overstreet
174cafe5635SKent Overstreet list_for_each_entry(cl, &closure_list, all) {
175cafe5635SKent Overstreet int r = atomic_read(&cl->remaining);
176cafe5635SKent Overstreet
177d9c61d30SColy Li seq_printf(f, "%p: %pS -> %pS p %p r %i ",
178cafe5635SKent Overstreet cl, (void *) cl->ip, cl->fn, cl->parent,
179cafe5635SKent Overstreet r & CLOSURE_REMAINING_MASK);
180cafe5635SKent Overstreet
181e4bf7919SKent Overstreet seq_printf(f, "%s%s\n",
1828d090f47SPetr Mladek test_bit(WORK_STRUCT_PENDING_BIT,
183cafe5635SKent Overstreet work_data_bits(&cl->work)) ? "Q" : "",
184e4bf7919SKent Overstreet r & CLOSURE_RUNNING ? "R" : "");
185cafe5635SKent Overstreet
186cafe5635SKent Overstreet if (r & CLOSURE_WAITING)
187d9c61d30SColy Li seq_printf(f, " W %pS\n",
188cafe5635SKent Overstreet (void *) cl->waiting_on);
189cafe5635SKent Overstreet
190cafe5635SKent Overstreet seq_printf(f, "\n");
191cafe5635SKent Overstreet }
192cafe5635SKent Overstreet
193cafe5635SKent Overstreet spin_unlock_irq(&closure_list_lock);
194cafe5635SKent Overstreet return 0;
195cafe5635SKent Overstreet }
196cafe5635SKent Overstreet
19784e5d136SQinglang Miao DEFINE_SHOW_ATTRIBUTE(debug);
198cafe5635SKent Overstreet
closure_debug_init(void)19978ac2107SColy Li void __init closure_debug_init(void)
200cafe5635SKent Overstreet {
20178ac2107SColy Li if (!IS_ERR_OR_NULL(bcache_debug))
20278ac2107SColy Li /*
20378ac2107SColy Li * it is unnecessary to check return value of
20478ac2107SColy Li * debugfs_create_file(), we should not care
20578ac2107SColy Li * about this.
20678ac2107SColy Li */
20778ac2107SColy Li closure_debug = debugfs_create_file(
20884e5d136SQinglang Miao "closures", 0400, bcache_debug, NULL, &debug_fops);
209cafe5635SKent Overstreet }
210cafe5635SKent Overstreet #endif
211cafe5635SKent Overstreet
212cafe5635SKent Overstreet MODULE_AUTHOR("Kent Overstreet <koverstreet@google.com>");
213cafe5635SKent Overstreet MODULE_LICENSE("GPL");
214