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