]>
Commit | Line | Data |
---|---|---|
716154c5 BB |
1 | /*****************************************************************************\ |
2 | * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. | |
3 | * Copyright (C) 2007 The Regents of the University of California. | |
4 | * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). | |
5 | * Written by Brian Behlendorf <behlendorf1@llnl.gov>. | |
d702c04f BB |
6 | * UCRL-CODE-235197 |
7 | * | |
716154c5 | 8 | * This file is part of the SPL, Solaris Porting Layer. |
3d6af2dd | 9 | * For details, see <http://zfsonlinux.org/>. |
716154c5 BB |
10 | * |
11 | * The SPL is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2 of the License, or (at your | |
14 | * option) any later version. | |
d702c04f | 15 | * |
716154c5 | 16 | * The SPL is distributed in the hope that it will be useful, but WITHOUT |
d702c04f BB |
17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
18 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
19 | * for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License along | |
716154c5 BB |
22 | * with the SPL. If not, see <http://www.gnu.org/licenses/>. |
23 | ***************************************************************************** | |
24 | * Solaris Porting LAyer Tests (SPLAT) List Tests. | |
25 | \*****************************************************************************/ | |
d702c04f | 26 | |
df870a69 BB |
27 | #include <sys/list.h> |
28 | #include <sys/kmem.h> | |
d702c04f BB |
29 | #include "splat-internal.h" |
30 | ||
d702c04f BB |
31 | #define SPLAT_LIST_NAME "list" |
32 | #define SPLAT_LIST_DESC "Kernel List Tests" | |
33 | ||
34 | #define SPLAT_LIST_TEST1_ID 0x0c01 | |
35 | #define SPLAT_LIST_TEST1_NAME "create/destroy" | |
36 | #define SPLAT_LIST_TEST1_DESC "Create/destroy Test" | |
37 | ||
38 | #define SPLAT_LIST_TEST2_ID 0x0c02 | |
434d1d0f | 39 | #define SPLAT_LIST_TEST2_NAME "ins/rm head" |
d702c04f BB |
40 | #define SPLAT_LIST_TEST2_DESC "Insert/remove head Test" |
41 | ||
42 | #define SPLAT_LIST_TEST3_ID 0x0c03 | |
434d1d0f | 43 | #define SPLAT_LIST_TEST3_NAME "ins/rm tail" |
d702c04f BB |
44 | #define SPLAT_LIST_TEST3_DESC "Insert/remove tail Test" |
45 | ||
46 | #define SPLAT_LIST_TEST4_ID 0x0c04 | |
47 | #define SPLAT_LIST_TEST4_NAME "insert_after" | |
48 | #define SPLAT_LIST_TEST4_DESC "Insert_after Test" | |
49 | ||
50 | #define SPLAT_LIST_TEST5_ID 0x0c05 | |
51 | #define SPLAT_LIST_TEST5_NAME "insert_before" | |
52 | #define SPLAT_LIST_TEST5_DESC "Insert_before Test" | |
53 | ||
54 | #define SPLAT_LIST_TEST6_ID 0x0c06 | |
55 | #define SPLAT_LIST_TEST6_NAME "remove" | |
56 | #define SPLAT_LIST_TEST6_DESC "Remove Test" | |
57 | ||
434d1d0f BB |
58 | #define SPLAT_LIST_TEST7_ID 0x0c7 |
59 | #define SPLAT_LIST_TEST7_NAME "active" | |
60 | #define SPLAT_LIST_TEST7_DESC "Active Test" | |
d702c04f BB |
61 | |
62 | /* It is important that li_node is not the first element, this | |
63 | * ensures the list_d2l/list_object macros are working correctly. */ | |
64 | typedef struct list_item { | |
65 | int li_data; | |
66 | list_node_t li_node; | |
67 | } list_item_t; | |
68 | ||
69 | #define LIST_ORDER_STACK 0 | |
70 | #define LIST_ORDER_QUEUE 1 | |
71 | ||
72 | static int | |
73 | splat_list_test1(struct file *file, void *arg) | |
74 | { | |
75 | list_t list; | |
76 | ||
77 | splat_vprint(file, SPLAT_LIST_TEST1_NAME, "Creating list\n%s", ""); | |
78 | list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); | |
79 | ||
80 | if (!list_is_empty(&list)) { | |
81 | splat_vprint(file, SPLAT_LIST_TEST1_NAME, | |
82 | "New list NOT empty%s\n", ""); | |
83 | /* list_destroy() intentionally skipped to avoid assert */ | |
84 | return -EEXIST; | |
85 | } | |
86 | ||
87 | splat_vprint(file, SPLAT_LIST_TEST1_NAME, "Destroying list\n%s", ""); | |
88 | list_destroy(&list); | |
89 | ||
90 | /* Validate the list has been destroyed */ | |
91 | if (list_link_active(&list.list_head)) { | |
92 | splat_vprint(file, SPLAT_LIST_TEST1_NAME, | |
93 | "Destroyed list still active%s", ""); | |
94 | return -EIO; | |
95 | } | |
96 | ||
97 | return 0; | |
98 | } | |
99 | ||
100 | static int | |
101 | splat_list_validate(list_t *list, int size, int order, int mult) | |
102 | { | |
103 | list_item_t *li; | |
104 | int i; | |
105 | ||
106 | /* Walk all items in list from head to verify stack or queue | |
107 | * ordering. We bound the for loop by size+1 to ensure that | |
108 | * we still terminate if there is list corruption. We also | |
109 | * intentionally make things a little more complex than they | |
110 | * need to be by using list_head/list_next for queues, and | |
111 | * list_tail/list_prev for stacks. This is simply done for | |
112 | * coverage and to ensure these function are working right. | |
113 | */ | |
114 | for (i = 0, li = (order ? list_head(list) : list_tail(list)); | |
115 | i < size + 1 && li != NULL; | |
116 | i++, li = (order ? list_next(list, li) : list_prev(list, li))) | |
117 | if (li->li_data != i * mult) | |
118 | return -EIDRM; | |
119 | ||
120 | if (i != size) | |
121 | return -E2BIG; | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | static int | |
127 | splat_list_test2(struct file *file, void *arg) | |
128 | { | |
129 | list_t list; | |
130 | list_item_t *li; | |
131 | int i, list_size = 8, rc = 0; | |
132 | ||
133 | splat_vprint(file, SPLAT_LIST_TEST2_NAME, "Creating list\n%s", ""); | |
134 | list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); | |
135 | ||
136 | /* Insert all items at the list head to form a stack */ | |
137 | splat_vprint(file, SPLAT_LIST_TEST2_NAME, | |
138 | "Adding %d items to list head\n", list_size); | |
139 | for (i = 0; i < list_size; i++) { | |
140 | li = kmem_alloc(sizeof(list_item_t), KM_SLEEP); | |
141 | if (li == NULL) { | |
142 | rc = -ENOMEM; | |
143 | goto out; | |
144 | } | |
145 | ||
146 | list_link_init(&li->li_node); | |
147 | li->li_data = i; | |
148 | list_insert_head(&list, li); | |
149 | } | |
150 | ||
151 | splat_vprint(file, SPLAT_LIST_TEST2_NAME, | |
152 | "Validating %d item list is a stack\n", list_size); | |
153 | rc = splat_list_validate(&list, list_size, LIST_ORDER_STACK, 1); | |
154 | if (rc) | |
155 | splat_vprint(file, SPLAT_LIST_TEST2_NAME, | |
156 | "List validation failed, %d\n", rc); | |
157 | out: | |
158 | /* Remove all items */ | |
159 | splat_vprint(file, SPLAT_LIST_TEST2_NAME, | |
160 | "Removing %d items from list head\n", list_size); | |
161 | while ((li = list_remove_head(&list))) | |
162 | kmem_free(li, sizeof(list_item_t)); | |
163 | ||
164 | splat_vprint(file, SPLAT_LIST_TEST2_NAME, "Destroying list\n%s", ""); | |
165 | list_destroy(&list); | |
166 | ||
167 | return rc; | |
168 | } | |
169 | ||
170 | static int | |
171 | splat_list_test3(struct file *file, void *arg) | |
172 | { | |
173 | list_t list; | |
174 | list_item_t *li; | |
175 | int i, list_size = 8, rc = 0; | |
176 | ||
177 | splat_vprint(file, SPLAT_LIST_TEST3_NAME, "Creating list\n%s", ""); | |
178 | list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); | |
179 | ||
180 | /* Insert all items at the list tail to form a queue */ | |
181 | splat_vprint(file, SPLAT_LIST_TEST3_NAME, | |
182 | "Adding %d items to list tail\n", list_size); | |
183 | for (i = 0; i < list_size; i++) { | |
184 | li = kmem_alloc(sizeof(list_item_t), KM_SLEEP); | |
185 | if (li == NULL) { | |
186 | rc = -ENOMEM; | |
187 | goto out; | |
188 | } | |
189 | ||
190 | list_link_init(&li->li_node); | |
191 | li->li_data = i; | |
192 | list_insert_tail(&list, li); | |
193 | } | |
194 | ||
195 | splat_vprint(file, SPLAT_LIST_TEST3_NAME, | |
196 | "Validating %d item list is a queue\n", list_size); | |
197 | rc = splat_list_validate(&list, list_size, LIST_ORDER_QUEUE, 1); | |
198 | if (rc) | |
199 | splat_vprint(file, SPLAT_LIST_TEST3_NAME, | |
200 | "List validation failed, %d\n", rc); | |
201 | out: | |
202 | /* Remove all items */ | |
203 | splat_vprint(file, SPLAT_LIST_TEST3_NAME, | |
204 | "Removing %d items from list tail\n", list_size); | |
205 | while ((li = list_remove_tail(&list))) | |
206 | kmem_free(li, sizeof(list_item_t)); | |
207 | ||
208 | splat_vprint(file, SPLAT_LIST_TEST3_NAME, "Destroying list\n%s", ""); | |
209 | list_destroy(&list); | |
210 | ||
211 | return rc; | |
212 | } | |
213 | ||
214 | static int | |
215 | splat_list_test4(struct file *file, void *arg) | |
216 | { | |
217 | list_t list; | |
218 | list_item_t *li_new, *li_last = NULL; | |
219 | int i, list_size = 8, rc = 0; | |
220 | ||
221 | splat_vprint(file, SPLAT_LIST_TEST4_NAME, "Creating list\n%s", ""); | |
222 | list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); | |
223 | ||
224 | /* Insert all items after the last item to form a queue */ | |
225 | splat_vprint(file, SPLAT_LIST_TEST4_NAME, | |
226 | "Adding %d items each after the last item\n", list_size); | |
227 | for (i = 0; i < list_size; i++) { | |
228 | li_new = kmem_alloc(sizeof(list_item_t), KM_SLEEP); | |
229 | if (li_new == NULL) { | |
230 | rc = -ENOMEM; | |
231 | goto out; | |
232 | } | |
233 | ||
234 | list_link_init(&li_new->li_node); | |
235 | li_new->li_data = i; | |
236 | list_insert_after(&list, li_last, li_new); | |
237 | li_last = li_new; | |
238 | } | |
239 | ||
240 | splat_vprint(file, SPLAT_LIST_TEST4_NAME, | |
241 | "Validating %d item list is a queue\n", list_size); | |
242 | rc = splat_list_validate(&list, list_size, LIST_ORDER_QUEUE, 1); | |
243 | if (rc) | |
244 | splat_vprint(file, SPLAT_LIST_TEST4_NAME, | |
245 | "List validation failed, %d\n", rc); | |
246 | out: | |
247 | /* Remove all items */ | |
248 | splat_vprint(file, SPLAT_LIST_TEST4_NAME, | |
249 | "Removing %d items from list tail\n", list_size); | |
250 | while ((li_new = list_remove_head(&list))) | |
251 | kmem_free(li_new, sizeof(list_item_t)); | |
252 | ||
253 | splat_vprint(file, SPLAT_LIST_TEST4_NAME, "Destroying list\n%s", ""); | |
254 | list_destroy(&list); | |
255 | ||
256 | return rc; | |
257 | } | |
258 | ||
259 | static int | |
260 | splat_list_test5(struct file *file, void *arg) | |
261 | { | |
262 | list_t list; | |
263 | list_item_t *li_new, *li_last = NULL; | |
264 | int i, list_size = 8, rc = 0; | |
265 | ||
266 | splat_vprint(file, SPLAT_LIST_TEST5_NAME, "Creating list\n%s", ""); | |
267 | list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); | |
268 | ||
269 | /* Insert all items before the last item to form a stack */ | |
270 | splat_vprint(file, SPLAT_LIST_TEST5_NAME, | |
271 | "Adding %d items each before the last item\n", list_size); | |
272 | for (i = 0; i < list_size; i++) { | |
273 | li_new = kmem_alloc(sizeof(list_item_t), KM_SLEEP); | |
274 | if (li_new == NULL) { | |
275 | rc = -ENOMEM; | |
276 | goto out; | |
277 | } | |
278 | ||
279 | list_link_init(&li_new->li_node); | |
280 | li_new->li_data = i; | |
281 | list_insert_before(&list, li_last, li_new); | |
282 | li_last = li_new; | |
283 | } | |
284 | ||
285 | splat_vprint(file, SPLAT_LIST_TEST5_NAME, | |
286 | "Validating %d item list is a queue\n", list_size); | |
287 | rc = splat_list_validate(&list, list_size, LIST_ORDER_STACK, 1); | |
288 | if (rc) | |
289 | splat_vprint(file, SPLAT_LIST_TEST5_NAME, | |
290 | "List validation failed, %d\n", rc); | |
291 | out: | |
292 | /* Remove all items */ | |
293 | splat_vprint(file, SPLAT_LIST_TEST5_NAME, | |
294 | "Removing %d items from list tail\n", list_size); | |
295 | while ((li_new = list_remove_tail(&list))) | |
296 | kmem_free(li_new, sizeof(list_item_t)); | |
297 | ||
298 | splat_vprint(file, SPLAT_LIST_TEST5_NAME, "Destroying list\n%s", ""); | |
299 | list_destroy(&list); | |
300 | ||
301 | return rc; | |
302 | } | |
303 | ||
304 | static int | |
305 | splat_list_test6(struct file *file, void *arg) | |
306 | { | |
307 | list_t list; | |
308 | list_item_t *li, *li_prev; | |
309 | int i, list_size = 8, rc = 0; | |
310 | ||
311 | splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Creating list\n%s", ""); | |
312 | list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); | |
313 | ||
314 | /* Insert all items at the list tail to form a queue */ | |
315 | splat_vprint(file, SPLAT_LIST_TEST6_NAME, | |
316 | "Adding %d items to list tail\n", list_size); | |
317 | for (i = 0; i < list_size; i++) { | |
318 | li = kmem_alloc(sizeof(list_item_t), KM_SLEEP); | |
319 | if (li == NULL) { | |
320 | rc = -ENOMEM; | |
321 | goto out; | |
322 | } | |
323 | ||
324 | list_link_init(&li->li_node); | |
325 | li->li_data = i; | |
326 | list_insert_tail(&list, li); | |
327 | } | |
328 | ||
329 | /* Remove all odd items from the queue */ | |
330 | splat_vprint(file, SPLAT_LIST_TEST6_NAME, | |
96dded38 | 331 | "Removing %d odd items from the list\n", list_size >> 1); |
d702c04f BB |
332 | for (li = list_head(&list); li != NULL; li = list_next(&list, li)) { |
333 | if (li->li_data % 2 == 1) { | |
334 | li_prev = list_prev(&list, li); | |
335 | list_remove(&list, li); | |
ae3b87f9 | 336 | kmem_free(li, sizeof(list_item_t)); |
d702c04f BB |
337 | li = li_prev; |
338 | } | |
339 | } | |
340 | ||
341 | splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Validating %d item " | |
342 | "list is a queue of only even elements\n", list_size / 2); | |
343 | rc = splat_list_validate(&list, list_size / 2, LIST_ORDER_QUEUE, 2); | |
344 | if (rc) | |
345 | splat_vprint(file, SPLAT_LIST_TEST6_NAME, | |
346 | "List validation failed, %d\n", rc); | |
347 | out: | |
348 | /* Remove all items */ | |
349 | splat_vprint(file, SPLAT_LIST_TEST6_NAME, | |
350 | "Removing %d items from list tail\n", list_size / 2); | |
351 | while ((li = list_remove_tail(&list))) | |
352 | kmem_free(li, sizeof(list_item_t)); | |
353 | ||
354 | splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Destroying list\n%s", ""); | |
355 | list_destroy(&list); | |
356 | ||
357 | return rc; | |
358 | } | |
359 | ||
434d1d0f BB |
360 | static int |
361 | splat_list_test7(struct file *file, void *arg) | |
362 | { | |
363 | list_t list; | |
364 | list_item_t *li; | |
365 | int rc = 0; | |
366 | ||
367 | splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Creating list\n%s", ""); | |
368 | list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); | |
369 | ||
370 | li = kmem_alloc(sizeof(list_item_t), KM_SLEEP); | |
371 | if (li == NULL) { | |
372 | rc = -ENOMEM; | |
373 | goto out; | |
374 | } | |
375 | ||
376 | /* Validate newly initialized node is inactive */ | |
377 | splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Init list node\n%s", ""); | |
378 | list_link_init(&li->li_node); | |
379 | if (list_link_active(&li->li_node)) { | |
380 | splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Newly initialized " | |
381 | "list node should inactive %p/%p\n", | |
382 | li->li_node.prev, li->li_node.next); | |
383 | rc = -EINVAL; | |
63a93055 | 384 | goto out_li; |
434d1d0f BB |
385 | } |
386 | ||
387 | /* Validate node is active when linked in to a list */ | |
388 | splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Insert list node\n%s", ""); | |
389 | list_insert_head(&list, li); | |
390 | if (!list_link_active(&li->li_node)) { | |
391 | splat_vprint(file, SPLAT_LIST_TEST7_NAME, "List node " | |
392 | "inserted in list should be active %p/%p\n", | |
393 | li->li_node.prev, li->li_node.next); | |
394 | rc = -EINVAL; | |
395 | goto out; | |
396 | } | |
397 | ||
398 | /* Validate node is inactive when removed from list */ | |
399 | splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Remove list node\n%s", ""); | |
400 | list_remove(&list, li); | |
401 | if (list_link_active(&li->li_node)) { | |
402 | splat_vprint(file, SPLAT_LIST_TEST7_NAME, "List node " | |
403 | "removed from list should be inactive %p/%p\n", | |
404 | li->li_node.prev, li->li_node.next); | |
405 | rc = -EINVAL; | |
406 | } | |
63a93055 | 407 | out_li: |
434d1d0f BB |
408 | kmem_free(li, sizeof(list_item_t)); |
409 | out: | |
410 | /* Remove all items */ | |
411 | while ((li = list_remove_head(&list))) | |
412 | kmem_free(li, sizeof(list_item_t)); | |
413 | ||
414 | splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Destroying list\n%s", ""); | |
415 | list_destroy(&list); | |
416 | ||
417 | return rc; | |
418 | } | |
419 | ||
d702c04f BB |
420 | splat_subsystem_t * |
421 | splat_list_init(void) | |
422 | { | |
423 | splat_subsystem_t *sub; | |
424 | ||
425 | sub = kmalloc(sizeof(*sub), GFP_KERNEL); | |
426 | if (sub == NULL) | |
427 | return NULL; | |
428 | ||
429 | memset(sub, 0, sizeof(*sub)); | |
430 | strncpy(sub->desc.name, SPLAT_LIST_NAME, SPLAT_NAME_SIZE); | |
431 | strncpy(sub->desc.desc, SPLAT_LIST_DESC, SPLAT_DESC_SIZE); | |
432 | INIT_LIST_HEAD(&sub->subsystem_list); | |
433 | INIT_LIST_HEAD(&sub->test_list); | |
434 | spin_lock_init(&sub->test_lock); | |
435 | sub->desc.id = SPLAT_SUBSYSTEM_LIST; | |
436 | ||
ec06701b | 437 | splat_test_init(sub, SPLAT_LIST_TEST1_NAME, SPLAT_LIST_TEST1_DESC, |
d702c04f | 438 | SPLAT_LIST_TEST1_ID, splat_list_test1); |
ec06701b | 439 | splat_test_init(sub, SPLAT_LIST_TEST2_NAME, SPLAT_LIST_TEST2_DESC, |
d702c04f | 440 | SPLAT_LIST_TEST2_ID, splat_list_test2); |
ec06701b | 441 | splat_test_init(sub, SPLAT_LIST_TEST3_NAME, SPLAT_LIST_TEST3_DESC, |
d702c04f | 442 | SPLAT_LIST_TEST3_ID, splat_list_test3); |
ec06701b | 443 | splat_test_init(sub, SPLAT_LIST_TEST4_NAME, SPLAT_LIST_TEST4_DESC, |
d702c04f | 444 | SPLAT_LIST_TEST4_ID, splat_list_test4); |
ec06701b | 445 | splat_test_init(sub, SPLAT_LIST_TEST5_NAME, SPLAT_LIST_TEST5_DESC, |
d702c04f | 446 | SPLAT_LIST_TEST5_ID, splat_list_test5); |
ec06701b | 447 | splat_test_init(sub, SPLAT_LIST_TEST6_NAME, SPLAT_LIST_TEST6_DESC, |
d702c04f | 448 | SPLAT_LIST_TEST6_ID, splat_list_test6); |
ec06701b | 449 | splat_test_init(sub, SPLAT_LIST_TEST7_NAME, SPLAT_LIST_TEST7_DESC, |
434d1d0f | 450 | SPLAT_LIST_TEST7_ID, splat_list_test7); |
d702c04f BB |
451 | |
452 | return sub; | |
453 | } | |
454 | ||
455 | void | |
456 | splat_list_fini(splat_subsystem_t *sub) | |
457 | { | |
458 | ASSERT(sub); | |
459 | ||
ec06701b AX |
460 | splat_test_fini(sub, SPLAT_LIST_TEST7_ID); |
461 | splat_test_fini(sub, SPLAT_LIST_TEST6_ID); | |
462 | splat_test_fini(sub, SPLAT_LIST_TEST5_ID); | |
463 | splat_test_fini(sub, SPLAT_LIST_TEST4_ID); | |
464 | splat_test_fini(sub, SPLAT_LIST_TEST3_ID); | |
465 | splat_test_fini(sub, SPLAT_LIST_TEST2_ID); | |
466 | splat_test_fini(sub, SPLAT_LIST_TEST1_ID); | |
d702c04f BB |
467 | |
468 | kfree(sub); | |
469 | } | |
470 | ||
471 | int | |
472 | splat_list_id(void) | |
473 | { | |
474 | return SPLAT_SUBSYSTEM_LIST; | |
475 | } |