diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-06 20:02:07 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-06 20:02:07 -0500 |
commit | 40d7ee5d162203b40b5f4fbb312ab016edddb97f (patch) | |
tree | 432db33df85f7f244676127a189a828dfbf2877b /lib/klist.c | |
parent | 5fec8bdbf9a1c4df4ad3f20e52aa2d8caed490c8 (diff) | |
parent | b8ac9fc0e8cda9f9776019c5b0464b0c6d2d4c90 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (60 commits)
uio: make uio_info's name and version const
UIO: Documentation for UIO ioport info handling
UIO: Pass information about ioports to userspace (V2)
UIO: uio_pdrv_genirq: allow custom irq_flags
UIO: use pci_ioremap_bar() in drivers/uio
arm: struct device - replace bus_id with dev_name(), dev_set_name()
libata: struct device - replace bus_id with dev_name(), dev_set_name()
avr: struct device - replace bus_id with dev_name(), dev_set_name()
block: struct device - replace bus_id with dev_name(), dev_set_name()
chris: struct device - replace bus_id with dev_name(), dev_set_name()
dmi: struct device - replace bus_id with dev_name(), dev_set_name()
gadget: struct device - replace bus_id with dev_name(), dev_set_name()
gpio: struct device - replace bus_id with dev_name(), dev_set_name()
gpu: struct device - replace bus_id with dev_name(), dev_set_name()
hwmon: struct device - replace bus_id with dev_name(), dev_set_name()
i2o: struct device - replace bus_id with dev_name(), dev_set_name()
IA64: struct device - replace bus_id with dev_name(), dev_set_name()
i7300_idle: struct device - replace bus_id with dev_name(), dev_set_name()
infiniband: struct device - replace bus_id with dev_name(), dev_set_name()
ISDN: struct device - replace bus_id with dev_name(), dev_set_name()
...
Diffstat (limited to 'lib/klist.c')
-rw-r--r-- | lib/klist.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/lib/klist.c b/lib/klist.c index bbdd3015c2c7..573d6068a42e 100644 --- a/lib/klist.c +++ b/lib/klist.c | |||
@@ -36,6 +36,7 @@ | |||
36 | 36 | ||
37 | #include <linux/klist.h> | 37 | #include <linux/klist.h> |
38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
39 | #include <linux/sched.h> | ||
39 | 40 | ||
40 | /* | 41 | /* |
41 | * Use the lowest bit of n_klist to mark deleted nodes and exclude | 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 | static void klist_node_init(struct klist *k, struct klist_node *n) | 109 | static void klist_node_init(struct klist *k, struct klist_node *n) |
109 | { | 110 | { |
110 | INIT_LIST_HEAD(&n->n_node); | 111 | INIT_LIST_HEAD(&n->n_node); |
111 | init_completion(&n->n_removed); | ||
112 | kref_init(&n->n_ref); | 112 | kref_init(&n->n_ref); |
113 | knode_set_klist(n, k); | 113 | knode_set_klist(n, k); |
114 | if (k->get) | 114 | if (k->get) |
@@ -171,13 +171,34 @@ void klist_add_before(struct klist_node *n, struct klist_node *pos) | |||
171 | } | 171 | } |
172 | EXPORT_SYMBOL_GPL(klist_add_before); | 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 | static void klist_release(struct kref *kref) | 184 | static void klist_release(struct kref *kref) |
175 | { | 185 | { |
186 | struct klist_waiter *waiter, *tmp; | ||
176 | struct klist_node *n = container_of(kref, struct klist_node, n_ref); | 187 | struct klist_node *n = container_of(kref, struct klist_node, n_ref); |
177 | 188 | ||
178 | WARN_ON(!knode_dead(n)); | 189 | WARN_ON(!knode_dead(n)); |
179 | list_del(&n->n_node); | 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 | knode_set_klist(n, NULL); | 202 | knode_set_klist(n, NULL); |
182 | } | 203 | } |
183 | 204 | ||
@@ -217,8 +238,24 @@ EXPORT_SYMBOL_GPL(klist_del); | |||
217 | */ | 238 | */ |
218 | void klist_remove(struct klist_node *n) | 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 | klist_del(n); | 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 | EXPORT_SYMBOL_GPL(klist_remove); | 260 | EXPORT_SYMBOL_GPL(klist_remove); |
224 | 261 | ||