]> git.proxmox.com Git - mirror_spl.git/blob - module/splat/splat-ctl.c
Remove compat includes from sys/types.h
[mirror_spl.git] / module / splat / splat-ctl.c
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>.
6 * UCRL-CODE-235197
7 *
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://zfsonlinux.org/>.
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.
15 *
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
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
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) Test Control Interface.
25 *
26 * The 'splat' (Solaris Porting LAyer Tests) module is designed as a
27 * framework which runs various in kernel regression tests to validate
28 * the SPL primitives honor the Solaris ABI.
29 *
30 * The splat module is constructed of various splat_* source files each
31 * of which contain regression tests for a particular subsystem. For
32 * example, the splat_kmem.c file contains all the tests for validating
33 * the kmem interfaces have been implemented correctly. When the splat
34 * module is loaded splat_*_init() will be called for each subsystems
35 * tests. It is the responsibility of splat_*_init() to register all
36 * the tests for this subsystem using the SPLAT_TEST_INIT() macro.
37 * Similarly splat_*_fini() is called when the splat module is removed
38 * and is responsible for unregistering its tests via the SPLAT_TEST_FINI
39 * macro. Once a test is registered it can then be run with an ioctl()
40 * call which specifies the subsystem and test to be run. The provided
41 * splat command line tool can be used to display all available
42 * subsystems and tests. It can also be used to run the full suite
43 * of regression tests or particular tests.
44 \*****************************************************************************/
45
46 #include <sys/debug.h>
47 #include <sys/mutex.h>
48 #include <sys/types.h>
49 #include <linux/cdev.h>
50 #include <linux/fs.h>
51 #include <linux/miscdevice.h>
52 #include <linux/module.h>
53 #include <linux/module_compat.h>
54 #include <linux/slab.h>
55 #include <linux/uaccess.h>
56 #include <linux/vmalloc.h>
57 #include "splat-internal.h"
58
59 static struct list_head splat_module_list;
60 static spinlock_t splat_module_lock;
61
62 static int
63 splat_open(struct inode *inode, struct file *file)
64 {
65 splat_info_t *info;
66
67 info = (splat_info_t *)kmalloc(sizeof(*info), GFP_KERNEL);
68 if (info == NULL)
69 return -ENOMEM;
70
71 mutex_init(&info->info_lock, SPLAT_NAME, MUTEX_DEFAULT, NULL);
72 info->info_size = SPLAT_INFO_BUFFER_SIZE;
73 info->info_buffer = (char *)vmalloc(SPLAT_INFO_BUFFER_SIZE);
74 if (info->info_buffer == NULL) {
75 kfree(info);
76 return -ENOMEM;
77 }
78 memset(info->info_buffer, 0, info->info_size);
79
80 info->info_head = info->info_buffer;
81 file->private_data = (void *)info;
82
83 splat_print(file, "%s\n", spl_version);
84
85 return 0;
86 }
87
88 static int
89 splat_release(struct inode *inode, struct file *file)
90 {
91 splat_info_t *info = (splat_info_t *)file->private_data;
92
93 ASSERT(info);
94 ASSERT(info->info_buffer);
95
96 mutex_destroy(&info->info_lock);
97 vfree(info->info_buffer);
98 kfree(info);
99
100 return 0;
101 }
102
103 static int
104 splat_buffer_clear(struct file *file, splat_cfg_t *kcfg, unsigned long arg)
105 {
106 splat_info_t *info = (splat_info_t *)file->private_data;
107
108 ASSERT(info);
109 ASSERT(info->info_buffer);
110
111 mutex_enter(&info->info_lock);
112 memset(info->info_buffer, 0, info->info_size);
113 info->info_head = info->info_buffer;
114 mutex_exit(&info->info_lock);
115
116 return 0;
117 }
118
119 static int
120 splat_buffer_size(struct file *file, splat_cfg_t *kcfg, unsigned long arg)
121 {
122 splat_info_t *info = (splat_info_t *)file->private_data;
123 char *buf;
124 int min, size, rc = 0;
125
126 ASSERT(info);
127 ASSERT(info->info_buffer);
128
129 mutex_enter(&info->info_lock);
130 if (kcfg->cfg_arg1 > 0) {
131
132 size = kcfg->cfg_arg1;
133 buf = (char *)vmalloc(size);
134 if (buf == NULL) {
135 rc = -ENOMEM;
136 goto out;
137 }
138
139 /* Zero fill and truncate contents when coping buffer */
140 min = ((size < info->info_size) ? size : info->info_size);
141 memset(buf, 0, size);
142 memcpy(buf, info->info_buffer, min);
143 vfree(info->info_buffer);
144 info->info_size = size;
145 info->info_buffer = buf;
146 info->info_head = info->info_buffer;
147 }
148
149 kcfg->cfg_rc1 = info->info_size;
150
151 if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg)))
152 rc = -EFAULT;
153 out:
154 mutex_exit(&info->info_lock);
155
156 return rc;
157 }
158
159
160 static splat_subsystem_t *
161 splat_subsystem_find(int id) {
162 splat_subsystem_t *sub;
163
164 spin_lock(&splat_module_lock);
165 list_for_each_entry(sub, &splat_module_list, subsystem_list) {
166 if (id == sub->desc.id) {
167 spin_unlock(&splat_module_lock);
168 return sub;
169 }
170 }
171 spin_unlock(&splat_module_lock);
172
173 return NULL;
174 }
175
176 static int
177 splat_subsystem_count(splat_cfg_t *kcfg, unsigned long arg)
178 {
179 splat_subsystem_t *sub;
180 int i = 0;
181
182 spin_lock(&splat_module_lock);
183 list_for_each_entry(sub, &splat_module_list, subsystem_list)
184 i++;
185
186 spin_unlock(&splat_module_lock);
187 kcfg->cfg_rc1 = i;
188
189 if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg)))
190 return -EFAULT;
191
192 return 0;
193 }
194
195 static int
196 splat_subsystem_list(splat_cfg_t *kcfg, unsigned long arg)
197 {
198 splat_subsystem_t *sub;
199 splat_cfg_t *tmp;
200 int size, i = 0;
201
202 /* Structure will be sized large enough for N subsystem entries
203 * which is passed in by the caller. On exit the number of
204 * entries filled in with valid subsystems will be stored in
205 * cfg_rc1. If the caller does not provide enough entries
206 * for all subsystems we will truncate the list to avoid overrun.
207 */
208 size = sizeof(*tmp) + kcfg->cfg_data.splat_subsystems.size *
209 sizeof(splat_user_t);
210 tmp = kmalloc(size, GFP_KERNEL);
211 if (tmp == NULL)
212 return -ENOMEM;
213
214 /* Local 'tmp' is used as the structure copied back to user space */
215 memset(tmp, 0, size);
216 memcpy(tmp, kcfg, sizeof(*kcfg));
217
218 spin_lock(&splat_module_lock);
219 list_for_each_entry(sub, &splat_module_list, subsystem_list) {
220 strncpy(tmp->cfg_data.splat_subsystems.descs[i].name,
221 sub->desc.name, SPLAT_NAME_SIZE);
222 strncpy(tmp->cfg_data.splat_subsystems.descs[i].desc,
223 sub->desc.desc, SPLAT_DESC_SIZE);
224 tmp->cfg_data.splat_subsystems.descs[i].id = sub->desc.id;
225
226 /* Truncate list if we are about to overrun alloc'ed memory */
227 if ((i++) == kcfg->cfg_data.splat_subsystems.size)
228 break;
229 }
230 spin_unlock(&splat_module_lock);
231 tmp->cfg_rc1 = i;
232
233 if (copy_to_user((struct splat_cfg_t __user *)arg, tmp, size)) {
234 kfree(tmp);
235 return -EFAULT;
236 }
237
238 kfree(tmp);
239 return 0;
240 }
241
242 static int
243 splat_test_count(splat_cfg_t *kcfg, unsigned long arg)
244 {
245 splat_subsystem_t *sub;
246 splat_test_t *test;
247 int i = 0;
248
249 /* Subsystem ID passed as arg1 */
250 sub = splat_subsystem_find(kcfg->cfg_arg1);
251 if (sub == NULL)
252 return -EINVAL;
253
254 spin_lock(&(sub->test_lock));
255 list_for_each_entry(test, &(sub->test_list), test_list)
256 i++;
257
258 spin_unlock(&(sub->test_lock));
259 kcfg->cfg_rc1 = i;
260
261 if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg)))
262 return -EFAULT;
263
264 return 0;
265 }
266
267 static int
268 splat_test_list(splat_cfg_t *kcfg, unsigned long arg)
269 {
270 splat_subsystem_t *sub;
271 splat_test_t *test;
272 splat_cfg_t *tmp;
273 int size, i = 0;
274
275 /* Subsystem ID passed as arg1 */
276 sub = splat_subsystem_find(kcfg->cfg_arg1);
277 if (sub == NULL)
278 return -EINVAL;
279
280 /* Structure will be sized large enough for N test entries
281 * which is passed in by the caller. On exit the number of
282 * entries filled in with valid tests will be stored in
283 * cfg_rc1. If the caller does not provide enough entries
284 * for all tests we will truncate the list to avoid overrun.
285 */
286 size = sizeof(*tmp)+kcfg->cfg_data.splat_tests.size*sizeof(splat_user_t);
287 tmp = kmalloc(size, GFP_KERNEL);
288 if (tmp == NULL)
289 return -ENOMEM;
290
291 /* Local 'tmp' is used as the structure copied back to user space */
292 memset(tmp, 0, size);
293 memcpy(tmp, kcfg, sizeof(*kcfg));
294
295 spin_lock(&(sub->test_lock));
296 list_for_each_entry(test, &(sub->test_list), test_list) {
297 strncpy(tmp->cfg_data.splat_tests.descs[i].name,
298 test->desc.name, SPLAT_NAME_SIZE);
299 strncpy(tmp->cfg_data.splat_tests.descs[i].desc,
300 test->desc.desc, SPLAT_DESC_SIZE);
301 tmp->cfg_data.splat_tests.descs[i].id = test->desc.id;
302
303 /* Truncate list if we are about to overrun alloc'ed memory */
304 if ((i++) == kcfg->cfg_data.splat_tests.size)
305 break;
306 }
307 spin_unlock(&(sub->test_lock));
308 tmp->cfg_rc1 = i;
309
310 if (copy_to_user((struct splat_cfg_t __user *)arg, tmp, size)) {
311 kfree(tmp);
312 return -EFAULT;
313 }
314
315 kfree(tmp);
316 return 0;
317 }
318
319 static int
320 splat_validate(struct file *file, splat_subsystem_t *sub, int cmd, void *arg)
321 {
322 splat_test_t *test;
323
324 spin_lock(&(sub->test_lock));
325 list_for_each_entry(test, &(sub->test_list), test_list) {
326 if (test->desc.id == cmd) {
327 spin_unlock(&(sub->test_lock));
328 return test->test(file, arg);
329 }
330 }
331 spin_unlock(&(sub->test_lock));
332
333 return -EINVAL;
334 }
335
336 static int
337 splat_ioctl_cfg(struct file *file, unsigned int cmd, unsigned long arg)
338 {
339 splat_cfg_t kcfg;
340 int rc = 0;
341
342 /* User and kernel space agree about arg size */
343 if (_IOC_SIZE(cmd) != sizeof(kcfg))
344 return -EBADMSG;
345
346 if (copy_from_user(&kcfg, (splat_cfg_t *)arg, sizeof(kcfg)))
347 return -EFAULT;
348
349 if (kcfg.cfg_magic != SPLAT_CFG_MAGIC) {
350 splat_print(file, "Bad config magic 0x%x != 0x%x\n",
351 kcfg.cfg_magic, SPLAT_CFG_MAGIC);
352 return -EINVAL;
353 }
354
355 switch (kcfg.cfg_cmd) {
356 case SPLAT_CFG_BUFFER_CLEAR:
357 /* cfg_arg1 - Unused
358 * cfg_rc1 - Unused
359 */
360 rc = splat_buffer_clear(file, &kcfg, arg);
361 break;
362 case SPLAT_CFG_BUFFER_SIZE:
363 /* cfg_arg1 - 0 - query size; >0 resize
364 * cfg_rc1 - Set to current buffer size
365 */
366 rc = splat_buffer_size(file, &kcfg, arg);
367 break;
368 case SPLAT_CFG_SUBSYSTEM_COUNT:
369 /* cfg_arg1 - Unused
370 * cfg_rc1 - Set to number of subsystems
371 */
372 rc = splat_subsystem_count(&kcfg, arg);
373 break;
374 case SPLAT_CFG_SUBSYSTEM_LIST:
375 /* cfg_arg1 - Unused
376 * cfg_rc1 - Set to number of subsystems
377 * cfg_data.splat_subsystems - Set with subsystems
378 */
379 rc = splat_subsystem_list(&kcfg, arg);
380 break;
381 case SPLAT_CFG_TEST_COUNT:
382 /* cfg_arg1 - Set to a target subsystem
383 * cfg_rc1 - Set to number of tests
384 */
385 rc = splat_test_count(&kcfg, arg);
386 break;
387 case SPLAT_CFG_TEST_LIST:
388 /* cfg_arg1 - Set to a target subsystem
389 * cfg_rc1 - Set to number of tests
390 * cfg_data.splat_subsystems - Populated with tests
391 */
392 rc = splat_test_list(&kcfg, arg);
393 break;
394 default:
395 splat_print(file, "Bad config command %d\n",
396 kcfg.cfg_cmd);
397 rc = -EINVAL;
398 break;
399 }
400
401 return rc;
402 }
403
404 static int
405 splat_ioctl_cmd(struct file *file, unsigned int cmd, unsigned long arg)
406 {
407 splat_subsystem_t *sub;
408 splat_cmd_t kcmd;
409 int rc = -EINVAL;
410 void *data = NULL;
411
412 /* User and kernel space agree about arg size */
413 if (_IOC_SIZE(cmd) != sizeof(kcmd))
414 return -EBADMSG;
415
416 if (copy_from_user(&kcmd, (splat_cfg_t *)arg, sizeof(kcmd)))
417 return -EFAULT;
418
419 if (kcmd.cmd_magic != SPLAT_CMD_MAGIC) {
420 splat_print(file, "Bad command magic 0x%x != 0x%x\n",
421 kcmd.cmd_magic, SPLAT_CFG_MAGIC);
422 return -EINVAL;
423 }
424
425 /* Allocate memory for any opaque data the caller needed to pass on */
426 if (kcmd.cmd_data_size > 0) {
427 data = (void *)kmalloc(kcmd.cmd_data_size, GFP_KERNEL);
428 if (data == NULL)
429 return -ENOMEM;
430
431 if (copy_from_user(data, (void *)(arg + offsetof(splat_cmd_t,
432 cmd_data_str)), kcmd.cmd_data_size)) {
433 kfree(data);
434 return -EFAULT;
435 }
436 }
437
438 sub = splat_subsystem_find(kcmd.cmd_subsystem);
439 if (sub != NULL)
440 rc = splat_validate(file, sub, kcmd.cmd_test, data);
441 else
442 rc = -EINVAL;
443
444 if (data != NULL)
445 kfree(data);
446
447 return rc;
448 }
449
450 static long
451 splat_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
452 {
453 int rc = 0;
454
455 /* Ignore tty ioctls */
456 if ((cmd & 0xffffff00) == ((int)'T') << 8)
457 return -ENOTTY;
458
459 switch (cmd) {
460 case SPLAT_CFG:
461 rc = splat_ioctl_cfg(file, cmd, arg);
462 break;
463 case SPLAT_CMD:
464 rc = splat_ioctl_cmd(file, cmd, arg);
465 break;
466 default:
467 splat_print(file, "Bad ioctl command %d\n", cmd);
468 rc = -EINVAL;
469 break;
470 }
471
472 return rc;
473 }
474
475 #ifdef CONFIG_COMPAT
476 /* Compatibility handler for ioctls from 32-bit ELF binaries */
477 static long
478 splat_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
479 {
480 return splat_unlocked_ioctl(file, cmd, arg);
481 }
482 #endif /* CONFIG_COMPAT */
483
484 /* I'm not sure why you would want to write in to this buffer from
485 * user space since its principle use is to pass test status info
486 * back to the user space, but I don't see any reason to prevent it.
487 */
488 static ssize_t splat_write(struct file *file, const char __user *buf,
489 size_t count, loff_t *ppos)
490 {
491 splat_info_t *info = (splat_info_t *)file->private_data;
492 int rc = 0;
493
494 ASSERT(info);
495 ASSERT(info->info_buffer);
496
497 mutex_enter(&info->info_lock);
498
499 /* Write beyond EOF */
500 if (*ppos >= info->info_size) {
501 rc = -EFBIG;
502 goto out;
503 }
504
505 /* Resize count if beyond EOF */
506 if (*ppos + count > info->info_size)
507 count = info->info_size - *ppos;
508
509 if (copy_from_user(info->info_buffer, buf, count)) {
510 rc = -EFAULT;
511 goto out;
512 }
513
514 *ppos += count;
515 rc = count;
516 out:
517 mutex_exit(&info->info_lock);
518 return rc;
519 }
520
521 static ssize_t splat_read(struct file *file, char __user *buf,
522 size_t count, loff_t *ppos)
523 {
524 splat_info_t *info = (splat_info_t *)file->private_data;
525 int rc = 0;
526
527 ASSERT(info);
528 ASSERT(info->info_buffer);
529
530 mutex_enter(&info->info_lock);
531
532 /* Read beyond EOF */
533 if (*ppos >= info->info_size)
534 goto out;
535
536 /* Resize count if beyond EOF */
537 if (*ppos + count > info->info_size)
538 count = info->info_size - *ppos;
539
540 if (copy_to_user(buf, info->info_buffer + *ppos, count)) {
541 rc = -EFAULT;
542 goto out;
543 }
544
545 *ppos += count;
546 rc = count;
547 out:
548 mutex_exit(&info->info_lock);
549 return rc;
550 }
551
552 static loff_t splat_seek(struct file *file, loff_t offset, int origin)
553 {
554 splat_info_t *info = (splat_info_t *)file->private_data;
555 int rc = -EINVAL;
556
557 ASSERT(info);
558 ASSERT(info->info_buffer);
559
560 mutex_enter(&info->info_lock);
561
562 switch (origin) {
563 case 0: /* SEEK_SET - No-op just do it */
564 break;
565 case 1: /* SEEK_CUR - Seek from current */
566 offset = file->f_pos + offset;
567 break;
568 case 2: /* SEEK_END - Seek from end */
569 offset = info->info_size + offset;
570 break;
571 }
572
573 if (offset >= 0) {
574 file->f_pos = offset;
575 file->f_version = 0;
576 rc = offset;
577 }
578
579 mutex_exit(&info->info_lock);
580
581 return rc;
582 }
583
584 static struct file_operations splat_fops = {
585 .owner = THIS_MODULE,
586 .open = splat_open,
587 .release = splat_release,
588 .unlocked_ioctl = splat_unlocked_ioctl,
589 #ifdef CONFIG_COMPAT
590 .compat_ioctl = splat_compat_ioctl,
591 #endif
592 .read = splat_read,
593 .write = splat_write,
594 .llseek = splat_seek,
595 };
596
597 static struct miscdevice splat_misc = {
598 .minor = MISC_DYNAMIC_MINOR,
599 .name = SPLAT_NAME,
600 .fops = &splat_fops,
601 };
602
603 static int
604 splat_init(void)
605 {
606 int error;
607
608 spin_lock_init(&splat_module_lock);
609 INIT_LIST_HEAD(&splat_module_list);
610
611 SPLAT_SUBSYSTEM_INIT(kmem);
612 SPLAT_SUBSYSTEM_INIT(taskq);
613 SPLAT_SUBSYSTEM_INIT(krng);
614 SPLAT_SUBSYSTEM_INIT(mutex);
615 SPLAT_SUBSYSTEM_INIT(condvar);
616 SPLAT_SUBSYSTEM_INIT(thread);
617 SPLAT_SUBSYSTEM_INIT(rwlock);
618 SPLAT_SUBSYSTEM_INIT(time);
619 SPLAT_SUBSYSTEM_INIT(vnode);
620 SPLAT_SUBSYSTEM_INIT(kobj);
621 SPLAT_SUBSYSTEM_INIT(atomic);
622 SPLAT_SUBSYSTEM_INIT(list);
623 SPLAT_SUBSYSTEM_INIT(generic);
624 SPLAT_SUBSYSTEM_INIT(cred);
625 SPLAT_SUBSYSTEM_INIT(zlib);
626 SPLAT_SUBSYSTEM_INIT(linux);
627
628 error = misc_register(&splat_misc);
629 if (error) {
630 printk(KERN_INFO "SPLAT: misc_register() failed %d\n", error);
631 } else {
632 printk(KERN_INFO "SPLAT: Loaded module v%s-%s%s\n",
633 SPL_META_VERSION, SPL_META_RELEASE, SPL_DEBUG_STR);
634 }
635
636 return (error);
637 }
638
639 static int
640 splat_fini(void)
641 {
642 int error;
643
644 error = misc_deregister(&splat_misc);
645 if (error)
646 printk(KERN_INFO "SPLAT: misc_deregister() failed %d\n", error);
647
648 SPLAT_SUBSYSTEM_FINI(linux);
649 SPLAT_SUBSYSTEM_FINI(zlib);
650 SPLAT_SUBSYSTEM_FINI(cred);
651 SPLAT_SUBSYSTEM_FINI(generic);
652 SPLAT_SUBSYSTEM_FINI(list);
653 SPLAT_SUBSYSTEM_FINI(atomic);
654 SPLAT_SUBSYSTEM_FINI(kobj);
655 SPLAT_SUBSYSTEM_FINI(vnode);
656 SPLAT_SUBSYSTEM_FINI(time);
657 SPLAT_SUBSYSTEM_FINI(rwlock);
658 SPLAT_SUBSYSTEM_FINI(thread);
659 SPLAT_SUBSYSTEM_FINI(condvar);
660 SPLAT_SUBSYSTEM_FINI(mutex);
661 SPLAT_SUBSYSTEM_FINI(krng);
662 SPLAT_SUBSYSTEM_FINI(taskq);
663 SPLAT_SUBSYSTEM_FINI(kmem);
664
665 ASSERT(list_empty(&splat_module_list));
666 printk(KERN_INFO "SPLAT: Unloaded module v%s-%s%s\n",
667 SPL_META_VERSION, SPL_META_RELEASE, SPL_DEBUG_STR);
668
669 return (0);
670 }
671
672 spl_module_init(splat_init);
673 spl_module_exit(splat_fini);
674
675 MODULE_DESCRIPTION("Solaris Porting LAyer Tests");
676 MODULE_AUTHOR(SPL_META_AUTHOR);
677 MODULE_LICENSE(SPL_META_LICENSE);
678 MODULE_VERSION(SPL_META_VERSION "-" SPL_META_RELEASE);