xref: /openbmc/linux/drivers/md/bcache/closure.c (revision ecc23d0a422a3118fcf6e4f0a46e17a6c2047b02)
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