diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-10 13:52:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-10 13:52:45 -0400 |
commit | e26feff647ef34423b048b940540a0059001ddb0 (patch) | |
tree | acafe68602ee2f6f1a438c113073ffcc0040e949 /lib | |
parent | d403a6484f0341bf0624d17ece46f24f741b6a92 (diff) | |
parent | b911e473d24633c19414b54b82b9ff0b1a2419d7 (diff) |
Merge branch 'for-2.6.28' of git://git.kernel.dk/linux-2.6-block
* 'for-2.6.28' of git://git.kernel.dk/linux-2.6-block: (132 commits)
doc/cdrom: Trvial documentation error, file not present
block_dev: fix kernel-doc in new functions
block: add some comments around the bio read-write flags
block: mark bio_split_pool static
block: Find bio sector offset given idx and offset
block: gendisk integrity wrapper
block: Switch blk_integrity_compare from bdev to gendisk
block: Fix double put in blk_integrity_unregister
block: Introduce integrity data ownership flag
block: revert part of d7533ad0e132f92e75c1b2eb7c26387b25a583c1
bio.h: Remove unused conditional code
block: remove end_{queued|dequeued}_request()
block: change elevator to use __blk_end_request()
gdrom: change to use __blk_end_request()
memstick: change to use __blk_end_request()
virtio_blk: change to use __blk_end_request()
blktrace: use BLKTRACE_BDEV_SIZE as the name size for setup structure
block: add lld busy state exporting interface
block: Fix blk_start_queueing() to not kick a stopped queue
include blktrace_api.h in headers_install
...
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig.debug | 35 | ||||
-rw-r--r-- | lib/klist.c | 96 |
2 files changed, 104 insertions, 27 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 0b504814e378..7d7a31d0ddeb 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -624,6 +624,28 @@ config BACKTRACE_SELF_TEST | |||
624 | 624 | ||
625 | Say N if you are unsure. | 625 | Say N if you are unsure. |
626 | 626 | ||
627 | config DEBUG_BLOCK_EXT_DEVT | ||
628 | bool "Force extended block device numbers and spread them" | ||
629 | depends on DEBUG_KERNEL | ||
630 | depends on BLOCK | ||
631 | default n | ||
632 | help | ||
633 | Conventionally, block device numbers are allocated from | ||
634 | predetermined contiguous area. However, extended block area | ||
635 | may introduce non-contiguous block device numbers. This | ||
636 | option forces most block device numbers to be allocated from | ||
637 | the extended space and spreads them to discover kernel or | ||
638 | userland code paths which assume predetermined contiguous | ||
639 | device number allocation. | ||
640 | |||
641 | Note that turning on this debug option shuffles all the | ||
642 | device numbers for all IDE and SCSI devices including libata | ||
643 | ones, so root partition specified using device number | ||
644 | directly (via rdev or root=MAJ:MIN) won't work anymore. | ||
645 | Textual device names (root=/dev/sdXn) will continue to work. | ||
646 | |||
647 | Say N if you are unsure. | ||
648 | |||
627 | config LKDTM | 649 | config LKDTM |
628 | tristate "Linux Kernel Dump Test Tool Module" | 650 | tristate "Linux Kernel Dump Test Tool Module" |
629 | depends on DEBUG_KERNEL | 651 | depends on DEBUG_KERNEL |
@@ -661,10 +683,21 @@ config FAIL_PAGE_ALLOC | |||
661 | 683 | ||
662 | config FAIL_MAKE_REQUEST | 684 | config FAIL_MAKE_REQUEST |
663 | bool "Fault-injection capability for disk IO" | 685 | bool "Fault-injection capability for disk IO" |
664 | depends on FAULT_INJECTION | 686 | depends on FAULT_INJECTION && BLOCK |
665 | help | 687 | help |
666 | Provide fault-injection capability for disk IO. | 688 | Provide fault-injection capability for disk IO. |
667 | 689 | ||
690 | config FAIL_IO_TIMEOUT | ||
691 | bool "Faul-injection capability for faking disk interrupts" | ||
692 | depends on FAULT_INJECTION && BLOCK | ||
693 | help | ||
694 | Provide fault-injection capability on end IO handling. This | ||
695 | will make the block layer "forget" an interrupt as configured, | ||
696 | thus exercising the error handling. | ||
697 | |||
698 | Only works with drivers that use the generic timeout handling, | ||
699 | for others it wont do anything. | ||
700 | |||
668 | config FAULT_INJECTION_DEBUG_FS | 701 | config FAULT_INJECTION_DEBUG_FS |
669 | bool "Debugfs entries for fault-injection capabilities" | 702 | bool "Debugfs entries for fault-injection capabilities" |
670 | depends on FAULT_INJECTION && SYSFS && DEBUG_FS | 703 | depends on FAULT_INJECTION && SYSFS && DEBUG_FS |
diff --git a/lib/klist.c b/lib/klist.c index cca37f96faa2..bbdd3015c2c7 100644 --- a/lib/klist.c +++ b/lib/klist.c | |||
@@ -37,6 +37,37 @@ | |||
37 | #include <linux/klist.h> | 37 | #include <linux/klist.h> |
38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
39 | 39 | ||
40 | /* | ||
41 | * Use the lowest bit of n_klist to mark deleted nodes and exclude | ||
42 | * dead ones from iteration. | ||
43 | */ | ||
44 | #define KNODE_DEAD 1LU | ||
45 | #define KNODE_KLIST_MASK ~KNODE_DEAD | ||
46 | |||
47 | static struct klist *knode_klist(struct klist_node *knode) | ||
48 | { | ||
49 | return (struct klist *) | ||
50 | ((unsigned long)knode->n_klist & KNODE_KLIST_MASK); | ||
51 | } | ||
52 | |||
53 | static bool knode_dead(struct klist_node *knode) | ||
54 | { | ||
55 | return (unsigned long)knode->n_klist & KNODE_DEAD; | ||
56 | } | ||
57 | |||
58 | static void knode_set_klist(struct klist_node *knode, struct klist *klist) | ||
59 | { | ||
60 | knode->n_klist = klist; | ||
61 | /* no knode deserves to start its life dead */ | ||
62 | WARN_ON(knode_dead(knode)); | ||
63 | } | ||
64 | |||
65 | static void knode_kill(struct klist_node *knode) | ||
66 | { | ||
67 | /* and no knode should die twice ever either, see we're very humane */ | ||
68 | WARN_ON(knode_dead(knode)); | ||
69 | *(unsigned long *)&knode->n_klist |= KNODE_DEAD; | ||
70 | } | ||
40 | 71 | ||
41 | /** | 72 | /** |
42 | * klist_init - Initialize a klist structure. | 73 | * klist_init - Initialize a klist structure. |
@@ -79,7 +110,7 @@ static void klist_node_init(struct klist *k, struct klist_node *n) | |||
79 | INIT_LIST_HEAD(&n->n_node); | 110 | INIT_LIST_HEAD(&n->n_node); |
80 | init_completion(&n->n_removed); | 111 | init_completion(&n->n_removed); |
81 | kref_init(&n->n_ref); | 112 | kref_init(&n->n_ref); |
82 | n->n_klist = k; | 113 | knode_set_klist(n, k); |
83 | if (k->get) | 114 | if (k->get) |
84 | k->get(n); | 115 | k->get(n); |
85 | } | 116 | } |
@@ -115,7 +146,7 @@ EXPORT_SYMBOL_GPL(klist_add_tail); | |||
115 | */ | 146 | */ |
116 | void klist_add_after(struct klist_node *n, struct klist_node *pos) | 147 | void klist_add_after(struct klist_node *n, struct klist_node *pos) |
117 | { | 148 | { |
118 | struct klist *k = pos->n_klist; | 149 | struct klist *k = knode_klist(pos); |
119 | 150 | ||
120 | klist_node_init(k, n); | 151 | klist_node_init(k, n); |
121 | spin_lock(&k->k_lock); | 152 | spin_lock(&k->k_lock); |
@@ -131,7 +162,7 @@ EXPORT_SYMBOL_GPL(klist_add_after); | |||
131 | */ | 162 | */ |
132 | void klist_add_before(struct klist_node *n, struct klist_node *pos) | 163 | void klist_add_before(struct klist_node *n, struct klist_node *pos) |
133 | { | 164 | { |
134 | struct klist *k = pos->n_klist; | 165 | struct klist *k = knode_klist(pos); |
135 | 166 | ||
136 | klist_node_init(k, n); | 167 | klist_node_init(k, n); |
137 | spin_lock(&k->k_lock); | 168 | spin_lock(&k->k_lock); |
@@ -144,9 +175,10 @@ static void klist_release(struct kref *kref) | |||
144 | { | 175 | { |
145 | struct klist_node *n = container_of(kref, struct klist_node, n_ref); | 176 | struct klist_node *n = container_of(kref, struct klist_node, n_ref); |
146 | 177 | ||
178 | WARN_ON(!knode_dead(n)); | ||
147 | list_del(&n->n_node); | 179 | list_del(&n->n_node); |
148 | complete(&n->n_removed); | 180 | complete(&n->n_removed); |
149 | n->n_klist = NULL; | 181 | knode_set_klist(n, NULL); |
150 | } | 182 | } |
151 | 183 | ||
152 | static int klist_dec_and_del(struct klist_node *n) | 184 | static int klist_dec_and_del(struct klist_node *n) |
@@ -154,22 +186,29 @@ static int klist_dec_and_del(struct klist_node *n) | |||
154 | return kref_put(&n->n_ref, klist_release); | 186 | return kref_put(&n->n_ref, klist_release); |
155 | } | 187 | } |
156 | 188 | ||
157 | /** | 189 | static void klist_put(struct klist_node *n, bool kill) |
158 | * klist_del - Decrement the reference count of node and try to remove. | ||
159 | * @n: node we're deleting. | ||
160 | */ | ||
161 | void klist_del(struct klist_node *n) | ||
162 | { | 190 | { |
163 | struct klist *k = n->n_klist; | 191 | struct klist *k = knode_klist(n); |
164 | void (*put)(struct klist_node *) = k->put; | 192 | void (*put)(struct klist_node *) = k->put; |
165 | 193 | ||
166 | spin_lock(&k->k_lock); | 194 | spin_lock(&k->k_lock); |
195 | if (kill) | ||
196 | knode_kill(n); | ||
167 | if (!klist_dec_and_del(n)) | 197 | if (!klist_dec_and_del(n)) |
168 | put = NULL; | 198 | put = NULL; |
169 | spin_unlock(&k->k_lock); | 199 | spin_unlock(&k->k_lock); |
170 | if (put) | 200 | if (put) |
171 | put(n); | 201 | put(n); |
172 | } | 202 | } |
203 | |||
204 | /** | ||
205 | * klist_del - Decrement the reference count of node and try to remove. | ||
206 | * @n: node we're deleting. | ||
207 | */ | ||
208 | void klist_del(struct klist_node *n) | ||
209 | { | ||
210 | klist_put(n, true); | ||
211 | } | ||
173 | EXPORT_SYMBOL_GPL(klist_del); | 212 | EXPORT_SYMBOL_GPL(klist_del); |
174 | 213 | ||
175 | /** | 214 | /** |
@@ -206,7 +245,6 @@ void klist_iter_init_node(struct klist *k, struct klist_iter *i, | |||
206 | struct klist_node *n) | 245 | struct klist_node *n) |
207 | { | 246 | { |
208 | i->i_klist = k; | 247 | i->i_klist = k; |
209 | i->i_head = &k->k_list; | ||
210 | i->i_cur = n; | 248 | i->i_cur = n; |
211 | if (n) | 249 | if (n) |
212 | kref_get(&n->n_ref); | 250 | kref_get(&n->n_ref); |
@@ -237,7 +275,7 @@ EXPORT_SYMBOL_GPL(klist_iter_init); | |||
237 | void klist_iter_exit(struct klist_iter *i) | 275 | void klist_iter_exit(struct klist_iter *i) |
238 | { | 276 | { |
239 | if (i->i_cur) { | 277 | if (i->i_cur) { |
240 | klist_del(i->i_cur); | 278 | klist_put(i->i_cur, false); |
241 | i->i_cur = NULL; | 279 | i->i_cur = NULL; |
242 | } | 280 | } |
243 | } | 281 | } |
@@ -258,27 +296,33 @@ static struct klist_node *to_klist_node(struct list_head *n) | |||
258 | */ | 296 | */ |
259 | struct klist_node *klist_next(struct klist_iter *i) | 297 | struct klist_node *klist_next(struct klist_iter *i) |
260 | { | 298 | { |
261 | struct list_head *next; | ||
262 | struct klist_node *lnode = i->i_cur; | ||
263 | struct klist_node *knode = NULL; | ||
264 | void (*put)(struct klist_node *) = i->i_klist->put; | 299 | void (*put)(struct klist_node *) = i->i_klist->put; |
300 | struct klist_node *last = i->i_cur; | ||
301 | struct klist_node *next; | ||
265 | 302 | ||
266 | spin_lock(&i->i_klist->k_lock); | 303 | spin_lock(&i->i_klist->k_lock); |
267 | if (lnode) { | 304 | |
268 | next = lnode->n_node.next; | 305 | if (last) { |
269 | if (!klist_dec_and_del(lnode)) | 306 | next = to_klist_node(last->n_node.next); |
307 | if (!klist_dec_and_del(last)) | ||
270 | put = NULL; | 308 | put = NULL; |
271 | } else | 309 | } else |
272 | next = i->i_head->next; | 310 | next = to_klist_node(i->i_klist->k_list.next); |
273 | 311 | ||
274 | if (next != i->i_head) { | 312 | i->i_cur = NULL; |
275 | knode = to_klist_node(next); | 313 | while (next != to_klist_node(&i->i_klist->k_list)) { |
276 | kref_get(&knode->n_ref); | 314 | if (likely(!knode_dead(next))) { |
315 | kref_get(&next->n_ref); | ||
316 | i->i_cur = next; | ||
317 | break; | ||
318 | } | ||
319 | next = to_klist_node(next->n_node.next); | ||
277 | } | 320 | } |
278 | i->i_cur = knode; | 321 | |
279 | spin_unlock(&i->i_klist->k_lock); | 322 | spin_unlock(&i->i_klist->k_lock); |
280 | if (put && lnode) | 323 | |
281 | put(lnode); | 324 | if (put && last) |
282 | return knode; | 325 | put(last); |
326 | return i->i_cur; | ||
283 | } | 327 | } |
284 | EXPORT_SYMBOL_GPL(klist_next); | 328 | EXPORT_SYMBOL_GPL(klist_next); |