]> git.proxmox.com Git - mirror_spl.git/blob - modules/splat/splat-thread.c
3cea573ed5bda7d62a3a0a01eca4963d4f698330
[mirror_spl.git] / modules / splat / splat-thread.c
1 #include "splat-internal.h"
2
3 #define SPLAT_SUBSYSTEM_THREAD 0x0600
4 #define SPLAT_THREAD_NAME "thread"
5 #define SPLAT_THREAD_DESC "Kernel Thread Tests"
6
7 #define SPLAT_THREAD_TEST1_ID 0x0601
8 #define SPLAT_THREAD_TEST1_NAME "create"
9 #define SPLAT_THREAD_TEST1_DESC "Validate thread creation"
10
11 #define SPLAT_THREAD_TEST2_ID 0x0602
12 #define SPLAT_THREAD_TEST2_NAME "exit"
13 #define SPLAT_THREAD_TEST2_DESC "Validate thread exit"
14
15 #define SPLAT_THREAD_TEST_MAGIC 0x4488CC00UL
16
17 typedef struct thread_priv {
18 unsigned long tp_magic;
19 struct file *tp_file;
20 spinlock_t tp_lock;
21 wait_queue_head_t tp_waitq;
22 int tp_rc;
23 } thread_priv_t;
24
25 static int
26 splat_thread_rc(thread_priv_t *tp, int rc)
27 {
28 int ret;
29
30 spin_lock(&tp->tp_lock);
31 ret = (tp->tp_rc == rc);
32 spin_unlock(&tp->tp_lock);
33
34 return ret;
35 }
36
37 static void
38 splat_thread_work1(void *priv)
39 {
40 thread_priv_t *tp = (thread_priv_t *)priv;
41
42 spin_lock(&tp->tp_lock);
43 ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
44 tp->tp_rc = 1;
45 spin_unlock(&tp->tp_lock);
46
47 wake_up(&tp->tp_waitq);
48 thread_exit();
49 }
50
51 static int
52 splat_thread_test1(struct file *file, void *arg)
53 {
54 thread_priv_t tp;
55 DEFINE_WAIT(wait);
56 kthread_t *thr;
57
58 tp.tp_magic = SPLAT_THREAD_TEST_MAGIC;
59 tp.tp_file = file;
60 spin_lock_init(&tp.tp_lock);
61 init_waitqueue_head(&tp.tp_waitq);
62 tp.tp_rc = 0;
63
64 thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work1, &tp, 0,
65 &p0, TS_RUN, minclsyspri);
66 /* Must never fail under Solaris, but we check anyway since this
67 * can happen in the linux SPL, we may want to change this behavior */
68 if (thr == NULL)
69 return -ESRCH;
70
71 /* Sleep until the thread sets tp.tp_rc == 1 */
72 wait_event(tp.tp_waitq, splat_thread_rc(&tp, 1));
73
74 splat_vprint(file, SPLAT_THREAD_TEST1_NAME, "%s",
75 "Thread successfully started properly\n");
76 return 0;
77 }
78
79 static void
80 splat_thread_work2(void *priv)
81 {
82 thread_priv_t *tp = (thread_priv_t *)priv;
83
84 spin_lock(&tp->tp_lock);
85 ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
86 tp->tp_rc = 1;
87 spin_unlock(&tp->tp_lock);
88
89 wake_up(&tp->tp_waitq);
90 thread_exit();
91
92 /* The following code is unreachable when thread_exit() is
93 * working properly, which is exactly what we're testing */
94 spin_lock(&tp->tp_lock);
95 tp->tp_rc = 2;
96 spin_unlock(&tp->tp_lock);
97
98 wake_up(&tp->tp_waitq);
99 }
100
101 static int
102 splat_thread_test2(struct file *file, void *arg)
103 {
104 thread_priv_t tp;
105 DEFINE_WAIT(wait);
106 kthread_t *thr;
107 int rc = 0;
108
109 tp.tp_magic = SPLAT_THREAD_TEST_MAGIC;
110 tp.tp_file = file;
111 spin_lock_init(&tp.tp_lock);
112 init_waitqueue_head(&tp.tp_waitq);
113 tp.tp_rc = 0;
114
115 thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work2, &tp, 0,
116 &p0, TS_RUN, minclsyspri);
117 /* Must never fail under Solaris, but we check anyway since this
118 * can happen in the linux SPL, we may want to change this behavior */
119 if (thr == NULL)
120 return -ESRCH;
121
122 /* Sleep until the thread sets tp.tp_rc == 1 */
123 wait_event(tp.tp_waitq, splat_thread_rc(&tp, 1));
124
125 /* Sleep until the thread sets tp.tp_rc == 2, or until we hit
126 * the timeout. If thread exit is working properly we should
127 * hit the timeout and never see to.tp_rc == 2. */
128 rc = wait_event_timeout(tp.tp_waitq, splat_thread_rc(&tp, 2), HZ / 10);
129 if (rc > 0) {
130 rc = -EINVAL;
131 splat_vprint(file, SPLAT_THREAD_TEST2_NAME, "%s",
132 "Thread did not exit properly at thread_exit()\n");
133 } else {
134 splat_vprint(file, SPLAT_THREAD_TEST2_NAME, "%s",
135 "Thread successfully exited at thread_exit()\n");
136 }
137
138 return rc;
139 }
140
141 splat_subsystem_t *
142 splat_thread_init(void)
143 {
144 splat_subsystem_t *sub;
145
146 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
147 if (sub == NULL)
148 return NULL;
149
150 memset(sub, 0, sizeof(*sub));
151 strncpy(sub->desc.name, SPLAT_THREAD_NAME, SPLAT_NAME_SIZE);
152 strncpy(sub->desc.desc, SPLAT_THREAD_DESC, SPLAT_DESC_SIZE);
153 INIT_LIST_HEAD(&sub->subsystem_list);
154 INIT_LIST_HEAD(&sub->test_list);
155 spin_lock_init(&sub->test_lock);
156 sub->desc.id = SPLAT_SUBSYSTEM_THREAD;
157
158 SPLAT_TEST_INIT(sub, SPLAT_THREAD_TEST1_NAME, SPLAT_THREAD_TEST1_DESC,
159 SPLAT_THREAD_TEST1_ID, splat_thread_test1);
160 SPLAT_TEST_INIT(sub, SPLAT_THREAD_TEST2_NAME, SPLAT_THREAD_TEST2_DESC,
161 SPLAT_THREAD_TEST2_ID, splat_thread_test2);
162
163 return sub;
164 }
165
166 void
167 splat_thread_fini(splat_subsystem_t *sub)
168 {
169 ASSERT(sub);
170 SPLAT_TEST_FINI(sub, SPLAT_THREAD_TEST2_ID);
171 SPLAT_TEST_FINI(sub, SPLAT_THREAD_TEST1_ID);
172
173 kfree(sub);
174 }
175
176 int
177 splat_thread_id(void) {
178 return SPLAT_SUBSYSTEM_THREAD;
179 }