aboutsummaryrefslogtreecommitdiffstats
path: root/lib/list_sort.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/list_sort.c')
-rw-r--r--lib/list_sort.c174
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}
142EXPORT_SYMBOL(list_sort); 142EXPORT_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
145struct debug_el { 157struct 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
151static int cmp(void *priv, struct list_head *a, struct list_head *b) 165/* Array, containing pointers to all elements in the test list */
166static struct debug_el **elts __initdata;
167
168static 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/* 197static 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
163static int __init list_sort_test(void) 208static 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;
282exit:
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}
216module_init(list_sort_test); 290module_init(list_sort_test);
217#endif 291#endif /* CONFIG_TEST_LIST_SORT */