diff options
Diffstat (limited to 'lib/list_sort.c')
-rw-r--r-- | lib/list_sort.c | 174 |
1 files changed, 124 insertions, 50 deletions
diff --git a/lib/list_sort.c b/lib/list_sort.c index 4b5cb794c38..d7325c6b103 100644 --- a/lib/list_sort.c +++ b/lib/list_sort.c | |||
@@ -70,7 +70,7 @@ static void merge_and_restore_back_links(void *priv, | |||
70 | * element comparison is needed, so the client's cmp() | 70 | * element comparison is needed, so the client's cmp() |
71 | * routine can invoke cond_resched() periodically. | 71 | * routine can invoke cond_resched() periodically. |
72 | */ | 72 | */ |
73 | (*cmp)(priv, tail, tail); | 73 | (*cmp)(priv, tail->next, tail->next); |
74 | 74 | ||
75 | tail->next->prev = tail; | 75 | tail->next->prev = tail; |
76 | tail = tail->next; | 76 | tail = tail->next; |
@@ -141,77 +141,151 @@ void list_sort(void *priv, struct list_head *head, | |||
141 | } | 141 | } |
142 | EXPORT_SYMBOL(list_sort); | 142 | EXPORT_SYMBOL(list_sort); |
143 | 143 | ||
144 | #ifdef DEBUG_LIST_SORT | 144 | #ifdef CONFIG_TEST_LIST_SORT |
145 | |||
146 | #include <linux/random.h> | ||
147 | |||
148 | /* | ||
149 | * The pattern of set bits in the list length determines which cases | ||
150 | * are hit in list_sort(). | ||
151 | */ | ||
152 | #define TEST_LIST_LEN (512+128+2) /* not including head */ | ||
153 | |||
154 | #define TEST_POISON1 0xDEADBEEF | ||
155 | #define TEST_POISON2 0xA324354C | ||
156 | |||
145 | struct debug_el { | 157 | struct debug_el { |
146 | struct list_head l_h; | 158 | unsigned int poison1; |
159 | struct list_head list; | ||
160 | unsigned int poison2; | ||
147 | int value; | 161 | int value; |
148 | unsigned serial; | 162 | unsigned serial; |
149 | }; | 163 | }; |
150 | 164 | ||
151 | static int cmp(void *priv, struct list_head *a, struct list_head *b) | 165 | /* Array, containing pointers to all elements in the test list */ |
166 | static struct debug_el **elts __initdata; | ||
167 | |||
168 | static int __init check(struct debug_el *ela, struct debug_el *elb) | ||
152 | { | 169 | { |
153 | return container_of(a, struct debug_el, l_h)->value | 170 | if (ela->serial >= TEST_LIST_LEN) { |
154 | - container_of(b, struct debug_el, l_h)->value; | 171 | printk(KERN_ERR "list_sort_test: error: incorrect serial %d\n", |
172 | ela->serial); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | if (elb->serial >= TEST_LIST_LEN) { | ||
176 | printk(KERN_ERR "list_sort_test: error: incorrect serial %d\n", | ||
177 | elb->serial); | ||
178 | return -EINVAL; | ||
179 | } | ||
180 | if (elts[ela->serial] != ela || elts[elb->serial] != elb) { | ||
181 | printk(KERN_ERR "list_sort_test: error: phantom element\n"); | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | if (ela->poison1 != TEST_POISON1 || ela->poison2 != TEST_POISON2) { | ||
185 | printk(KERN_ERR "list_sort_test: error: bad poison: %#x/%#x\n", | ||
186 | ela->poison1, ela->poison2); | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | if (elb->poison1 != TEST_POISON1 || elb->poison2 != TEST_POISON2) { | ||
190 | printk(KERN_ERR "list_sort_test: error: bad poison: %#x/%#x\n", | ||
191 | elb->poison1, elb->poison2); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | return 0; | ||
155 | } | 195 | } |
156 | 196 | ||
157 | /* | 197 | static int __init cmp(void *priv, struct list_head *a, struct list_head *b) |
158 | * The pattern of set bits in the list length determines which cases | 198 | { |
159 | * are hit in list_sort(). | 199 | struct debug_el *ela, *elb; |
160 | */ | 200 | |
161 | #define LIST_SORT_TEST_LENGTH (512+128+2) /* not including head */ | 201 | ela = container_of(a, struct debug_el, list); |
202 | elb = container_of(b, struct debug_el, list); | ||
203 | |||
204 | check(ela, elb); | ||
205 | return ela->value - elb->value; | ||
206 | } | ||
162 | 207 | ||
163 | static int __init list_sort_test(void) | 208 | static int __init list_sort_test(void) |
164 | { | 209 | { |
165 | int i, r = 1, count; | 210 | int i, count = 1, err = -EINVAL; |
166 | struct list_head *head = kmalloc(sizeof(*head), GFP_KERNEL); | 211 | struct debug_el *el; |
167 | struct list_head *cur; | 212 | struct list_head *cur, *tmp; |
213 | LIST_HEAD(head); | ||
214 | |||
215 | printk(KERN_DEBUG "list_sort_test: start testing list_sort()\n"); | ||
168 | 216 | ||
169 | printk(KERN_WARNING "testing list_sort()\n"); | 217 | elts = kmalloc(sizeof(void *) * TEST_LIST_LEN, GFP_KERNEL); |
218 | if (!elts) { | ||
219 | printk(KERN_ERR "list_sort_test: error: cannot allocate " | ||
220 | "memory\n"); | ||
221 | goto exit; | ||
222 | } | ||
170 | 223 | ||
171 | cur = head; | 224 | for (i = 0; i < TEST_LIST_LEN; i++) { |
172 | for (i = 0; i < LIST_SORT_TEST_LENGTH; i++) { | 225 | el = kmalloc(sizeof(*el), GFP_KERNEL); |
173 | struct debug_el *el = kmalloc(sizeof(*el), GFP_KERNEL); | 226 | if (!el) { |
174 | BUG_ON(!el); | 227 | printk(KERN_ERR "list_sort_test: error: cannot " |
228 | "allocate memory\n"); | ||
229 | goto exit; | ||
230 | } | ||
175 | /* force some equivalencies */ | 231 | /* force some equivalencies */ |
176 | el->value = (r = (r * 725861) % 6599) % (LIST_SORT_TEST_LENGTH/3); | 232 | el->value = random32() % (TEST_LIST_LEN/3); |
177 | el->serial = i; | 233 | el->serial = i; |
178 | 234 | el->poison1 = TEST_POISON1; | |
179 | el->l_h.prev = cur; | 235 | el->poison2 = TEST_POISON2; |
180 | cur->next = &el->l_h; | 236 | elts[i] = el; |
181 | cur = cur->next; | 237 | list_add_tail(&el->list, &head); |
182 | } | 238 | } |
183 | head->prev = cur; | ||
184 | 239 | ||
185 | list_sort(NULL, head, cmp); | 240 | list_sort(NULL, &head, cmp); |
241 | |||
242 | for (cur = head.next; cur->next != &head; cur = cur->next) { | ||
243 | struct debug_el *el1; | ||
244 | int cmp_result; | ||
186 | 245 | ||
187 | count = 1; | ||
188 | for (cur = head->next; cur->next != head; cur = cur->next) { | ||
189 | struct debug_el *el = container_of(cur, struct debug_el, l_h); | ||
190 | int cmp_result = cmp(NULL, cur, cur->next); | ||
191 | if (cur->next->prev != cur) { | 246 | if (cur->next->prev != cur) { |
192 | printk(KERN_EMERG "list_sort() returned " | 247 | printk(KERN_ERR "list_sort_test: error: list is " |
193 | "a corrupted list!\n"); | 248 | "corrupted\n"); |
194 | return 1; | 249 | goto exit; |
195 | } else if (cmp_result > 0) { | 250 | } |
196 | printk(KERN_EMERG "list_sort() failed to sort!\n"); | 251 | |
197 | return 1; | 252 | cmp_result = cmp(NULL, cur, cur->next); |
198 | } else if (cmp_result == 0 && | 253 | if (cmp_result > 0) { |
199 | el->serial >= container_of(cur->next, | 254 | printk(KERN_ERR "list_sort_test: error: list is not " |
200 | struct debug_el, l_h)->serial) { | 255 | "sorted\n"); |
201 | printk(KERN_EMERG "list_sort() failed to preserve order" | 256 | goto exit; |
202 | " of equivalent elements!\n"); | 257 | } |
203 | return 1; | 258 | |
259 | el = container_of(cur, struct debug_el, list); | ||
260 | el1 = container_of(cur->next, struct debug_el, list); | ||
261 | if (cmp_result == 0 && el->serial >= el1->serial) { | ||
262 | printk(KERN_ERR "list_sort_test: error: order of " | ||
263 | "equivalent elements not preserved\n"); | ||
264 | goto exit; | ||
265 | } | ||
266 | |||
267 | if (check(el, el1)) { | ||
268 | printk(KERN_ERR "list_sort_test: error: element check " | ||
269 | "failed\n"); | ||
270 | goto exit; | ||
204 | } | 271 | } |
205 | kfree(cur->prev); | ||
206 | count++; | 272 | count++; |
207 | } | 273 | } |
208 | kfree(cur); | 274 | |
209 | if (count != LIST_SORT_TEST_LENGTH) { | 275 | if (count != TEST_LIST_LEN) { |
210 | printk(KERN_EMERG "list_sort() returned list of" | 276 | printk(KERN_ERR "list_sort_test: error: bad list length %d", |
211 | "different length!\n"); | 277 | count); |
212 | return 1; | 278 | goto exit; |
213 | } | 279 | } |
214 | return 0; | 280 | |
281 | err = 0; | ||
282 | exit: | ||
283 | kfree(elts); | ||
284 | list_for_each_safe(cur, tmp, &head) { | ||
285 | list_del(cur); | ||
286 | kfree(container_of(cur, struct debug_el, list)); | ||
287 | } | ||
288 | return err; | ||
215 | } | 289 | } |
216 | module_init(list_sort_test); | 290 | module_init(list_sort_test); |
217 | #endif | 291 | #endif /* CONFIG_TEST_LIST_SORT */ |