18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Asynchronous refcounty things
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>
68c2ecf20Sopenharmony_ci * Copyright 2012 Google, Inc.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
128c2ecf20Sopenharmony_ci#include <linux/sched/debug.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "closure.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic inline void closure_put_after_sub(struct closure *cl, int flags)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	int r = flags & CLOSURE_REMAINING_MASK;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	BUG_ON(flags & CLOSURE_GUARD_MASK);
218c2ecf20Sopenharmony_ci	BUG_ON(!r && (flags & ~CLOSURE_DESTRUCTOR));
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	if (!r) {
248c2ecf20Sopenharmony_ci		if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) {
258c2ecf20Sopenharmony_ci			atomic_set(&cl->remaining,
268c2ecf20Sopenharmony_ci				   CLOSURE_REMAINING_INITIALIZER);
278c2ecf20Sopenharmony_ci			closure_queue(cl);
288c2ecf20Sopenharmony_ci		} else {
298c2ecf20Sopenharmony_ci			struct closure *parent = cl->parent;
308c2ecf20Sopenharmony_ci			closure_fn *destructor = cl->fn;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci			closure_debug_destroy(cl);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci			if (destructor)
358c2ecf20Sopenharmony_ci				destructor(cl);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci			if (parent)
388c2ecf20Sopenharmony_ci				closure_put(parent);
398c2ecf20Sopenharmony_ci		}
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* For clearing flags with the same atomic op as a put */
448c2ecf20Sopenharmony_civoid closure_sub(struct closure *cl, int v)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	closure_put_after_sub(cl, atomic_sub_return(v, &cl->remaining));
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/*
508c2ecf20Sopenharmony_ci * closure_put - decrement a closure's refcount
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_civoid closure_put(struct closure *cl)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	closure_put_after_sub(cl, atomic_dec_return(&cl->remaining));
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/*
588c2ecf20Sopenharmony_ci * closure_wake_up - wake up all closures on a wait list, without memory barrier
598c2ecf20Sopenharmony_ci */
608c2ecf20Sopenharmony_civoid __closure_wake_up(struct closure_waitlist *wait_list)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct llist_node *list;
638c2ecf20Sopenharmony_ci	struct closure *cl, *t;
648c2ecf20Sopenharmony_ci	struct llist_node *reverse = NULL;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	list = llist_del_all(&wait_list->list);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* We first reverse the list to preserve FIFO ordering and fairness */
698c2ecf20Sopenharmony_ci	reverse = llist_reverse_order(list);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/* Then do the wakeups */
728c2ecf20Sopenharmony_ci	llist_for_each_entry_safe(cl, t, reverse, list) {
738c2ecf20Sopenharmony_ci		closure_set_waiting(cl, 0);
748c2ecf20Sopenharmony_ci		closure_sub(cl, CLOSURE_WAITING + 1);
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/**
798c2ecf20Sopenharmony_ci * closure_wait - add a closure to a waitlist
808c2ecf20Sopenharmony_ci * @waitlist: will own a ref on @cl, which will be released when
818c2ecf20Sopenharmony_ci * closure_wake_up() is called on @waitlist.
828c2ecf20Sopenharmony_ci * @cl: closure pointer.
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_cibool closure_wait(struct closure_waitlist *waitlist, struct closure *cl)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	if (atomic_read(&cl->remaining) & CLOSURE_WAITING)
888c2ecf20Sopenharmony_ci		return false;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	closure_set_waiting(cl, _RET_IP_);
918c2ecf20Sopenharmony_ci	atomic_add(CLOSURE_WAITING + 1, &cl->remaining);
928c2ecf20Sopenharmony_ci	llist_add(&cl->list, &waitlist->list);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return true;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistruct closure_syncer {
988c2ecf20Sopenharmony_ci	struct task_struct	*task;
998c2ecf20Sopenharmony_ci	int			done;
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void closure_sync_fn(struct closure *cl)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	struct closure_syncer *s = cl->s;
1058c2ecf20Sopenharmony_ci	struct task_struct *p;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	rcu_read_lock();
1088c2ecf20Sopenharmony_ci	p = READ_ONCE(s->task);
1098c2ecf20Sopenharmony_ci	s->done = 1;
1108c2ecf20Sopenharmony_ci	wake_up_process(p);
1118c2ecf20Sopenharmony_ci	rcu_read_unlock();
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_civoid __sched __closure_sync(struct closure *cl)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct closure_syncer s = { .task = current };
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	cl->s = &s;
1198c2ecf20Sopenharmony_ci	continue_at(cl, closure_sync_fn, NULL);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	while (1) {
1228c2ecf20Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
1238c2ecf20Sopenharmony_ci		if (s.done)
1248c2ecf20Sopenharmony_ci			break;
1258c2ecf20Sopenharmony_ci		schedule();
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	__set_current_state(TASK_RUNNING);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci#ifdef CONFIG_BCACHE_CLOSURES_DEBUG
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic LIST_HEAD(closure_list);
1348c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(closure_list_lock);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_civoid closure_debug_create(struct closure *cl)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	unsigned long flags;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	BUG_ON(cl->magic == CLOSURE_MAGIC_ALIVE);
1418c2ecf20Sopenharmony_ci	cl->magic = CLOSURE_MAGIC_ALIVE;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	spin_lock_irqsave(&closure_list_lock, flags);
1448c2ecf20Sopenharmony_ci	list_add(&cl->all, &closure_list);
1458c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&closure_list_lock, flags);
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_civoid closure_debug_destroy(struct closure *cl)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	unsigned long flags;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	BUG_ON(cl->magic != CLOSURE_MAGIC_ALIVE);
1538c2ecf20Sopenharmony_ci	cl->magic = CLOSURE_MAGIC_DEAD;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	spin_lock_irqsave(&closure_list_lock, flags);
1568c2ecf20Sopenharmony_ci	list_del(&cl->all);
1578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&closure_list_lock, flags);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic struct dentry *closure_debug;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int debug_show(struct seq_file *f, void *data)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct closure *cl;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	spin_lock_irq(&closure_list_lock);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	list_for_each_entry(cl, &closure_list, all) {
1698c2ecf20Sopenharmony_ci		int r = atomic_read(&cl->remaining);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		seq_printf(f, "%p: %pS -> %pS p %p r %i ",
1728c2ecf20Sopenharmony_ci			   cl, (void *) cl->ip, cl->fn, cl->parent,
1738c2ecf20Sopenharmony_ci			   r & CLOSURE_REMAINING_MASK);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		seq_printf(f, "%s%s\n",
1768c2ecf20Sopenharmony_ci			   test_bit(WORK_STRUCT_PENDING_BIT,
1778c2ecf20Sopenharmony_ci				    work_data_bits(&cl->work)) ? "Q" : "",
1788c2ecf20Sopenharmony_ci			   r & CLOSURE_RUNNING	? "R" : "");
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		if (r & CLOSURE_WAITING)
1818c2ecf20Sopenharmony_ci			seq_printf(f, " W %pS\n",
1828c2ecf20Sopenharmony_ci				   (void *) cl->waiting_on);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		seq_printf(f, "\n");
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	spin_unlock_irq(&closure_list_lock);
1888c2ecf20Sopenharmony_ci	return 0;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(debug);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_civoid  __init closure_debug_init(void)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(bcache_debug))
1968c2ecf20Sopenharmony_ci		/*
1978c2ecf20Sopenharmony_ci		 * it is unnecessary to check return value of
1988c2ecf20Sopenharmony_ci		 * debugfs_create_file(), we should not care
1998c2ecf20Sopenharmony_ci		 * about this.
2008c2ecf20Sopenharmony_ci		 */
2018c2ecf20Sopenharmony_ci		closure_debug = debugfs_create_file(
2028c2ecf20Sopenharmony_ci			"closures", 0400, bcache_debug, NULL, &debug_fops);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci#endif
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kent Overstreet <koverstreet@google.com>");
2078c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
208