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