Whamcloud - gitweb
8cd970a155213aa84630da345068db9108297c67
[fs/lustre-release.git] / lustre / ldlm / ldlm_test.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  *
6  * This code is issued under the GNU General Public License.
7  * See the file COPYING in this distribution
8  *
9  * by Cluster File Systems, Inc.
10  */
11
12 #define DEBUG_SUBSYSTEM S_LDLM
13
14 #include <linux/types.h>
15 #include <linux/random.h>
16
17 #include <linux/lustre_dlm.h>
18
19 struct ldlm_test_thread {
20         struct ldlm_namespace *t_ns;
21         struct list_head t_link;
22         __u32 t_flags; 
23         wait_queue_head_t t_ctl_waitq;
24 };
25
26 static spinlock_t ctl_lock = SPIN_LOCK_UNLOCKED;
27 static struct list_head ctl_threads;
28 static int regression_running = 0;
29 static struct ptlrpc_client ctl_client;
30 static struct ptlrpc_connection *ctl_conn;
31
32 static int ldlm_test_callback(struct lustre_handle *lockh,
33                               struct ldlm_lock_desc *new,
34                               void *data, __u32 data_len)
35 {
36         struct ldlm_lock *lock;
37         ENTRY;
38
39         lock = ldlm_handle2lock(lockh);
40         if (lock == NULL) {
41                 CERROR("invalid handle in callback\n");
42                 RETURN(0);
43         }
44
45         printk("ldlm_test_callback: lock=%Lu, new=%p\n", lockh->addr, new);
46         return 0;
47 }
48
49 int ldlm_test_basics(struct obd_device *obddev)
50 {
51         struct ldlm_namespace *ns;
52         struct ldlm_resource *res;
53         __u64 res_id[RES_NAME_SIZE] = {1, 2, 3};
54         ldlm_error_t err;
55         struct ldlm_lock *lock1, *lock;
56         int flags;
57
58         ns = ldlm_namespace_new("test_server", LDLM_NAMESPACE_SERVER);
59         if (ns == NULL)
60                 LBUG();
61
62         lock1 = ldlm_lock_create(ns, NULL, res_id, LDLM_PLAIN, LCK_CR, NULL, 0);
63         if (lock1 == NULL)
64                 LBUG();
65         err = ldlm_lock_enqueue(lock1, NULL, 0, &flags,
66                                 ldlm_test_callback, ldlm_test_callback);
67         if (err != ELDLM_OK)
68                 LBUG();
69
70         lock = ldlm_lock_create(ns, NULL, res_id, LDLM_PLAIN, LCK_EX, NULL, 0);
71         if (lock == NULL)
72                 LBUG();
73         err = ldlm_lock_enqueue(lock, NULL, 0, &flags,
74                                 ldlm_test_callback, ldlm_test_callback);
75         if (err != ELDLM_OK)
76                 LBUG();
77         if (!(flags & LDLM_FL_BLOCK_GRANTED))
78                 LBUG();
79
80         res = ldlm_resource_get(ns, NULL, res_id, LDLM_PLAIN, 1);
81         if (res == NULL)
82                 LBUG();
83         ldlm_resource_dump(res);
84
85         res = ldlm_lock_convert(lock1, LCK_NL, &flags);
86         if (res != NULL)
87                 ldlm_reprocess_all(res);
88
89         ldlm_resource_dump(res);
90         ldlm_namespace_free(ns);
91
92         return 0;
93 }
94
95 int ldlm_test_extents(struct obd_device *obddev)
96 {
97         struct ldlm_namespace *ns;
98         struct ldlm_resource *res;
99         struct ldlm_lock *lock, *lock1, *lock2;
100         __u64 res_id[RES_NAME_SIZE] = {0, 0, 0};
101         struct ldlm_extent ext1 = {4, 6}, ext2 = {6, 9}, ext3 = {10, 11};
102         ldlm_error_t err;
103         int flags;
104
105         ns = ldlm_namespace_new("test_server", LDLM_NAMESPACE_SERVER);
106         if (ns == NULL)
107                 LBUG();
108
109         flags = 0;
110         lock1 = ldlm_lock_create(ns, NULL, res_id, LDLM_EXTENT, LCK_PR, NULL,
111                                  0);
112         if (lock1 == NULL)
113                 LBUG();
114         err = ldlm_lock_enqueue(lock1, &ext1, sizeof(ext1), &flags, NULL, NULL);
115         if (err != ELDLM_OK)
116                 LBUG();
117         if (!(flags & LDLM_FL_LOCK_CHANGED))
118                 LBUG();
119
120         flags = 0;
121         lock2 = ldlm_lock_create(ns, NULL, res_id, LDLM_EXTENT, LCK_PR,
122                                 NULL, 0);
123         err = ldlm_lock_enqueue(lock2, &ext2, sizeof(ext2), &flags, NULL, NULL);
124         if (err != ELDLM_OK)
125                 LBUG();
126         if (!(flags & LDLM_FL_LOCK_CHANGED))
127                 LBUG();
128
129         flags = 0;
130         lock = ldlm_lock_create(ns, NULL, res_id, LDLM_EXTENT, LCK_EX, NULL, 0);
131         if (lock == NULL)
132                 LBUG();
133         err = ldlm_lock_enqueue(lock, &ext3, sizeof(ext3), &flags,
134                                 NULL, NULL);
135         if (err != ELDLM_OK)
136                 LBUG();
137         if (!(flags & LDLM_FL_BLOCK_GRANTED))
138                 LBUG();
139         if (flags & LDLM_FL_LOCK_CHANGED)
140                 LBUG();
141
142         /* Convert/cancel blocking locks */
143         flags = 0;
144         res = ldlm_lock_convert(lock1, LCK_NL, &flags);
145         if (res != NULL)
146                 ldlm_reprocess_all(res);
147
148         ldlm_lock_cancel(lock2);
149         if (res != NULL)
150                 ldlm_reprocess_all(res);
151
152         /* Dump the results */
153         res = ldlm_resource_get(ns, NULL, res_id, LDLM_EXTENT, 0);
154         if (res == NULL)
155                 LBUG();
156         ldlm_resource_dump(res);
157         ldlm_namespace_free(ns);
158
159         return 0;
160 }
161
162 static int ldlm_test_network(struct obd_device *obddev,
163                              struct ptlrpc_connection *conn)
164 {
165         struct ldlm_obd *ldlm = &obddev->u.ldlm;
166
167         __u64 res_id[RES_NAME_SIZE] = {1, 2, 3};
168         struct ldlm_extent ext = {4, 6};
169         struct lustre_handle lockh1;
170         int flags = 0;
171         ldlm_error_t err;
172
173         /* FIXME: this needs a connh as 3rd paramter, before it will work */
174
175         err = ldlm_cli_enqueue(ldlm->ldlm_client, conn, NULL, NULL,
176                                obddev->obd_namespace, NULL, res_id, LDLM_EXTENT,
177                                &ext, sizeof(ext), LCK_PR, &flags, NULL, NULL, 0,
178                                &lockh1);
179         CERROR("ldlm_cli_enqueue: %d\n", err);
180         if (err == ELDLM_OK)
181                 ldlm_lock_decref(&lockh1, LCK_PR);
182
183         RETURN(err);
184 }
185
186 static int ldlm_test_main(void *data)
187 {
188         struct ldlm_test_thread *thread = data;
189         struct ldlm_namespace *ns;
190         ENTRY;
191
192         lock_kernel();
193         daemonize();
194         spin_lock_irq(&current->sigmask_lock);
195         sigfillset(&current->blocked);
196         recalc_sigpending(current);
197         spin_unlock_irq(&current->sigmask_lock);
198
199         sprintf(current->comm, "ldlm_test");
200
201         ns = ldlm_namespace_new("ldlm_test", LDLM_NAMESPACE_CLIENT);
202         if (ns == NULL) {
203                 LBUG();
204                 GOTO(out, -ENOMEM);
205         }
206
207         /* Record that the thread is running */
208         thread->t_flags |= SVC_RUNNING;
209         wake_up(&thread->t_ctl_waitq);
210
211         while (1) {
212                 struct lustre_handle lockh;
213                 __u64 res_id[3] = {0};
214                 __u32 lock_mode;
215                 char random;
216                 int flags = 0, rc;
217
218                 /* Pick a random resource from 1 to 10 */
219                 get_random_bytes(&random, sizeof(random));
220                 res_id[0] = random % 10 + 1;
221
222                 /* Pick a random lock mode */
223                 get_random_bytes(&random, sizeof(random));
224                 lock_mode = random % LCK_NL + 1;
225
226                 rc = ldlm_cli_enqueue(&ctl_client, ctl_conn, NULL, NULL, ns, NULL,
227                                       res_id, LDLM_PLAIN, NULL, 0, lock_mode,
228                                       &flags, ldlm_test_callback, NULL, 0,
229                                       &lockh);
230                 if (rc < 0) {
231                         CERROR("ldlm_cli_enqueue: %d\n", rc);
232                         LBUG();
233                 }
234         }
235
236  out:
237         thread->t_flags |= SVC_STOPPED;
238         wake_up(&thread->t_ctl_waitq);
239
240         RETURN(0);
241 }
242
243 static int ldlm_start_thread(void)
244 {
245         struct ldlm_test_thread *test;
246         int rc;
247         ENTRY;
248
249         OBD_ALLOC(test, sizeof(*test));
250         if (test == NULL) {
251                 LBUG();
252                 RETURN(-ENOMEM);
253         }
254         init_waitqueue_head(&test->t_ctl_waitq);
255
256         spin_lock(&ctl_lock);
257         list_add(&test->t_link, &ctl_threads);
258         spin_unlock(&ctl_lock);
259
260         rc = kernel_thread(ldlm_test_main, (void *)test,
261                            CLONE_VM | CLONE_FS | CLONE_FILES);
262         if (rc < 0) {
263                 CERROR("cannot start thread\n");
264                 RETURN(-EINVAL);
265         }
266         wait_event(test->t_ctl_waitq, test->t_flags & SVC_RUNNING);
267
268         RETURN(0);
269 }
270
271 int ldlm_regression_start(struct obd_device *obddev,
272                           struct ptlrpc_connection *conn, int count)
273 {
274         int i, rc = 0;
275         ENTRY;
276
277         spin_lock(&ctl_lock);
278         if (regression_running) {
279                 CERROR("You can't start the ldlm regression twice.\n");
280                 spin_unlock(&ctl_lock);
281                 RETURN(-EINVAL);
282         }
283         regression_running = 1;
284         spin_unlock(&ctl_lock);
285
286         for (i = 0; i < count; i++) {
287                 rc = ldlm_start_thread();
288                 if (rc < 0)
289                         GOTO(cleanup, rc);
290         }
291
292  cleanup:
293         RETURN(rc);
294 }
295
296 int ldlm_regression_stop(void)
297 {
298         ENTRY;
299
300         spin_lock(&ctl_lock);
301         if (!regression_running) {
302                 CERROR("The ldlm regression isn't started.\n");
303                 spin_unlock(&ctl_lock);
304                 RETURN(-EINVAL);
305         }
306
307         while (!list_empty(&ctl_threads)) {
308                 struct ldlm_test_thread *thread;
309                 thread = list_entry(ctl_threads.next, struct ldlm_test_thread,
310                                     t_link);
311
312                 thread->t_flags |= SVC_STOPPING;
313                 spin_unlock(&ctl_lock);
314
315                 wake_up(&thread->t_ctl_waitq);
316                 wait_event(thread->t_ctl_waitq, thread->t_flags & SVC_STOPPED);
317
318                 spin_lock(&ctl_lock);
319                 list_del(&thread->t_link);
320                 OBD_FREE(thread, sizeof(*thread));
321         }
322
323         regression_running = 0;
324         spin_unlock(&ctl_lock);
325
326         RETURN(0);
327 }
328
329 int ldlm_test(struct obd_device *obddev, struct ptlrpc_connection *conn)
330 {
331         int rc;
332         rc = ldlm_test_basics(obddev);
333         if (rc)
334                 RETURN(rc);
335
336         rc = ldlm_test_extents(obddev);
337         if (rc)
338                 RETURN(rc);
339
340         rc = ldlm_test_network(obddev, conn);
341         RETURN(rc);
342 }