]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcache/closure.c
bcache in userspace; userspace fsck
[bcachefs-tools-debian] / libbcache / closure.c
1 /*
2  * Asynchronous refcounty things
3  *
4  * Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>
5  * Copyright 2012 Google, Inc.
6  */
7
8 #include <linux/debugfs.h>
9 #include <linux/module.h>
10 #include <linux/seq_file.h>
11
12 #include "closure.h"
13
14 static inline void closure_put_after_sub(struct closure *cl, int flags)
15 {
16         int r = flags & CLOSURE_REMAINING_MASK;
17
18         BUG_ON(flags & CLOSURE_GUARD_MASK);
19         BUG_ON(!r && (flags & ~CLOSURE_DESTRUCTOR));
20
21         if (!r) {
22                 if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) {
23                         atomic_set(&cl->remaining,
24                                    CLOSURE_REMAINING_INITIALIZER);
25                         closure_queue(cl);
26                 } else {
27                         struct closure *parent = cl->parent;
28                         closure_fn *destructor = cl->fn;
29
30                         closure_debug_destroy(cl);
31
32                         if (destructor)
33                                 destructor(cl);
34
35                         if (parent)
36                                 closure_put(parent);
37                 }
38         }
39 }
40
41 /* For clearing flags with the same atomic op as a put */
42 void closure_sub(struct closure *cl, int v)
43 {
44         closure_put_after_sub(cl, atomic_sub_return(v, &cl->remaining));
45 }
46 EXPORT_SYMBOL(closure_sub);
47
48 /**
49  * closure_put - decrement a closure's refcount
50  */
51 void closure_put(struct closure *cl)
52 {
53         closure_put_after_sub(cl, atomic_dec_return(&cl->remaining));
54 }
55 EXPORT_SYMBOL(closure_put);
56
57 /**
58  * closure_wake_up - wake up all closures on a wait list, without memory barrier
59  */
60 void __closure_wake_up(struct closure_waitlist *wait_list)
61 {
62         struct llist_node *list, *next;
63         struct closure *cl;
64
65         /*
66          * Grab entire list, reverse order to preserve FIFO ordering, and wake
67          * everything up
68          */
69         for (list = llist_reverse_order(llist_del_all(&wait_list->list));
70              list;
71              list = next) {
72                 next = llist_next(list);
73                 cl = container_of(list, struct closure, list);
74
75                 closure_set_waiting(cl, 0);
76                 closure_sub(cl, CLOSURE_WAITING + 1);
77         }
78 }
79 EXPORT_SYMBOL(__closure_wake_up);
80
81 /**
82  * closure_wait - add a closure to a waitlist
83  *
84  * @waitlist will own a ref on @cl, which will be released when
85  * closure_wake_up() is called on @waitlist.
86  *
87  */
88 bool closure_wait(struct closure_waitlist *waitlist, struct closure *cl)
89 {
90         if (atomic_read(&cl->remaining) & CLOSURE_WAITING)
91                 return false;
92
93         closure_set_waiting(cl, _RET_IP_);
94         atomic_add(CLOSURE_WAITING + 1, &cl->remaining);
95         llist_add(&cl->list, &waitlist->list);
96
97         return true;
98 }
99 EXPORT_SYMBOL(closure_wait);
100
101 struct closure_syncer {
102         struct task_struct      *task;
103         int                     done;
104 };
105
106 static void closure_sync_fn(struct closure *cl)
107 {
108         cl->s->done = 1;
109         wake_up_process(cl->s->task);
110 }
111
112 void __sched __closure_sync(struct closure *cl)
113 {
114         struct closure_syncer s = { .task = current };
115
116         cl->s = &s;
117         continue_at_noreturn(cl, closure_sync_fn, NULL);
118
119         while (1) {
120                 __set_current_state(TASK_UNINTERRUPTIBLE);
121                 smp_mb();
122                 if (s.done)
123                         break;
124                 schedule();
125         }
126
127         __set_current_state(TASK_RUNNING);
128 }
129 EXPORT_SYMBOL(__closure_sync);
130
131 #ifdef CONFIG_BCACHE_CLOSURES_DEBUG
132
133 static LIST_HEAD(closure_list);
134 static DEFINE_SPINLOCK(closure_list_lock);
135
136 void closure_debug_create(struct closure *cl)
137 {
138         unsigned long flags;
139
140         BUG_ON(cl->magic == CLOSURE_MAGIC_ALIVE);
141         cl->magic = CLOSURE_MAGIC_ALIVE;
142
143         spin_lock_irqsave(&closure_list_lock, flags);
144         list_add(&cl->all, &closure_list);
145         spin_unlock_irqrestore(&closure_list_lock, flags);
146 }
147 EXPORT_SYMBOL(closure_debug_create);
148
149 void closure_debug_destroy(struct closure *cl)
150 {
151         unsigned long flags;
152
153         BUG_ON(cl->magic != CLOSURE_MAGIC_ALIVE);
154         cl->magic = CLOSURE_MAGIC_DEAD;
155
156         spin_lock_irqsave(&closure_list_lock, flags);
157         list_del(&cl->all);
158         spin_unlock_irqrestore(&closure_list_lock, flags);
159 }
160 EXPORT_SYMBOL(closure_debug_destroy);
161
162 static struct dentry *debug;
163
164 static int debug_seq_show(struct seq_file *f, void *data)
165 {
166         struct closure *cl;
167
168         spin_lock_irq(&closure_list_lock);
169
170         list_for_each_entry(cl, &closure_list, all) {
171                 int r = atomic_read(&cl->remaining);
172
173                 seq_printf(f, "%p: %pF -> %pf p %p r %i ",
174                            cl, (void *) cl->ip, cl->fn, cl->parent,
175                            r & CLOSURE_REMAINING_MASK);
176
177                 seq_printf(f, "%s%s\n",
178                            test_bit(WORK_STRUCT_PENDING_BIT,
179                                     work_data_bits(&cl->work)) ? "Q" : "",
180                            r & CLOSURE_RUNNING  ? "R" : "");
181
182                 if (r & CLOSURE_WAITING)
183                         seq_printf(f, " W %pF\n",
184                                    (void *) cl->waiting_on);
185
186                 seq_puts(f, "\n");
187         }
188
189         spin_unlock_irq(&closure_list_lock);
190         return 0;
191 }
192
193 static int debug_seq_open(struct inode *inode, struct file *file)
194 {
195         return single_open(file, debug_seq_show, NULL);
196 }
197
198 static const struct file_operations debug_ops = {
199         .owner          = THIS_MODULE,
200         .open           = debug_seq_open,
201         .read           = seq_read,
202         .release        = single_release
203 };
204
205 void __init closure_debug_init(void)
206 {
207         debug = debugfs_create_file("closures", 0400, NULL, NULL, &debug_ops);
208 }
209
210 #endif