|
36 | 36 |
|
37 | 37 | #include <linux/klist.h>
|
38 | 38 | #include <linux/module.h>
|
| 39 | +#include <linux/sched.h> |
39 | 40 |
|
40 | 41 | /*
|
41 | 42 | * Use the lowest bit of n_klist to mark deleted nodes and exclude
|
@@ -108,7 +109,6 @@ static void add_tail(struct klist *k, struct klist_node *n)
|
108 | 109 | static void klist_node_init(struct klist *k, struct klist_node *n)
|
109 | 110 | {
|
110 | 111 | INIT_LIST_HEAD(&n->n_node);
|
111 |
| - init_completion(&n->n_removed); |
112 | 112 | kref_init(&n->n_ref);
|
113 | 113 | knode_set_klist(n, k);
|
114 | 114 | if (k->get)
|
@@ -171,13 +171,34 @@ void klist_add_before(struct klist_node *n, struct klist_node *pos)
|
171 | 171 | }
|
172 | 172 | EXPORT_SYMBOL_GPL(klist_add_before);
|
173 | 173 |
|
| 174 | +struct klist_waiter { |
| 175 | + struct list_head list; |
| 176 | + struct klist_node *node; |
| 177 | + struct task_struct *process; |
| 178 | + int woken; |
| 179 | +}; |
| 180 | + |
| 181 | +static DEFINE_SPINLOCK(klist_remove_lock); |
| 182 | +static LIST_HEAD(klist_remove_waiters); |
| 183 | + |
174 | 184 | static void klist_release(struct kref *kref)
|
175 | 185 | {
|
| 186 | + struct klist_waiter *waiter, *tmp; |
176 | 187 | struct klist_node *n = container_of(kref, struct klist_node, n_ref);
|
177 | 188 |
|
178 | 189 | WARN_ON(!knode_dead(n));
|
179 | 190 | list_del(&n->n_node);
|
180 |
| - complete(&n->n_removed); |
| 191 | + spin_lock(&klist_remove_lock); |
| 192 | + list_for_each_entry_safe(waiter, tmp, &klist_remove_waiters, list) { |
| 193 | + if (waiter->node != n) |
| 194 | + continue; |
| 195 | + |
| 196 | + waiter->woken = 1; |
| 197 | + mb(); |
| 198 | + wake_up_process(waiter->process); |
| 199 | + list_del(&waiter->list); |
| 200 | + } |
| 201 | + spin_unlock(&klist_remove_lock); |
181 | 202 | knode_set_klist(n, NULL);
|
182 | 203 | }
|
183 | 204 |
|
@@ -217,8 +238,24 @@ EXPORT_SYMBOL_GPL(klist_del);
|
217 | 238 | */
|
218 | 239 | void klist_remove(struct klist_node *n)
|
219 | 240 | {
|
| 241 | + struct klist_waiter waiter; |
| 242 | + |
| 243 | + waiter.node = n; |
| 244 | + waiter.process = current; |
| 245 | + waiter.woken = 0; |
| 246 | + spin_lock(&klist_remove_lock); |
| 247 | + list_add(&waiter.list, &klist_remove_waiters); |
| 248 | + spin_unlock(&klist_remove_lock); |
| 249 | + |
220 | 250 | klist_del(n);
|
221 |
| - wait_for_completion(&n->n_removed); |
| 251 | + |
| 252 | + for (;;) { |
| 253 | + set_current_state(TASK_UNINTERRUPTIBLE); |
| 254 | + if (waiter.woken) |
| 255 | + break; |
| 256 | + schedule(); |
| 257 | + } |
| 258 | + __set_current_state(TASK_RUNNING); |
222 | 259 | }
|
223 | 260 | EXPORT_SYMBOL_GPL(klist_remove);
|
224 | 261 |
|
|
0 commit comments