1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (c) 2002 Cluster File Systems, Inc. <info@clusterfs.com>
5 * Copyright (c) 2002 Lawrence Livermore National Laboratory
6 * Author: James Newsome <newsome2@llnl.gov>
8 * This file is part of Lustre, http://www.lustre.org.
10 * Lustre is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
14 * Lustre is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Lustre; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #define DEBUG_SUBSYSTEM S_LDLM
26 #include <asm/atomic.h>
27 #include <linux/types.h>
28 #include <linux/random.h>
30 #include <linux/lustre_dlm.h>
32 struct ldlm_test_thread {
33 struct lustre_handle *connh;
34 struct obd_device *obddev;
35 struct ldlm_namespace *t_ns;
36 struct list_head t_link;
38 wait_queue_head_t t_ctl_waitq;
41 struct ldlm_test_lock {
42 struct list_head l_link;
43 struct lustre_handle l_lockh;
47 static const int max_locks = 10;
49 static spinlock_t ctl_lock = SPIN_LOCK_UNLOCKED;
50 /* protect these with the ctl_lock */
51 static LIST_HEAD(ctl_threads);
52 static int regression_running = 0;
53 static LIST_HEAD(lock_list);
54 static int num_locks = 0;
56 /* cumulative stats for regression test */
57 static atomic_t locks_requested = ATOMIC_INIT(0);
58 static atomic_t locks_granted = ATOMIC_INIT(0);
59 static atomic_t locks_matched = ATOMIC_INIT(0);
62 * blocking ast for regression test.
65 static int ldlm_test_blocking_ast(struct ldlm_lock *lock,
66 struct ldlm_lock_desc *new,
67 void *data, __u32 data_len)
70 struct lustre_handle lockh;
73 LDLM_DEBUG_NOLOCK("We're blocking. Cancelling lock");
74 ldlm_lock2handle(lock, &lockh);
75 rc = ldlm_cli_cancel(&lockh);
77 CERROR("ldlm_cli_cancel: %d\n", rc);
84 /* blocking ast for basic tests. noop */
85 static int ldlm_blocking_ast(struct ldlm_lock *lock,
86 struct ldlm_lock_desc *new,
87 void *data, __u32 data_len)
90 CERROR("ldlm_blocking_ast: lock=%p, new=%p\n", lock, new);
94 /* Completion ast for regression test.
95 * Does not sleep when blocked.
97 static int ldlm_test_completion_ast(struct ldlm_lock *lock, int flags)
102 if (flags & (LDLM_FL_BLOCK_WAIT | LDLM_FL_BLOCK_GRANTED |
103 LDLM_FL_BLOCK_CONV)) {
105 LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock");
106 ldlm_lock_dump(lock);
108 /* add to list of granted locks */
109 struct ldlm_test_lock *lock_info;
111 if (flags == LDLM_FL_WAIT_NOREPROC) {
112 atomic_inc(&locks_matched);
113 LDLM_DEBUG(lock, "lock matched");
114 } else if (flags == LDLM_FL_LOCK_CHANGED) {
115 atomic_inc(&locks_granted);
116 LDLM_DEBUG(lock, "lock changed and granted");
118 atomic_inc(&locks_granted);
119 LDLM_DEBUG(lock, "lock granted");
122 OBD_ALLOC(lock_info, sizeof(*lock_info));
123 if (lock_info == NULL) {
128 ldlm_lock2handle(lock, &lock_info->l_lockh);
129 lock_info->l_mode = lock->l_granted_mode;
131 spin_lock(&ctl_lock);
132 list_add_tail(&lock_info->l_link, &lock_list);
135 /* if we're over the max of granted locks, decref some */
136 if (num_locks > max_locks) {
137 /* delete from list */
138 lock_info = list_entry(lock_list.next,
139 struct ldlm_test_lock, l_link);
140 list_del(lock_list.next);
142 spin_unlock(&ctl_lock);
144 /* decrement and free the info
145 * Don't hold ctl_lock here. The decref
146 * may result in another lock being granted
147 * and hence this function being called again.
149 LDLM_DEBUG_NOLOCK("Decrementing lock");
150 ldlm_lock_decref(&lock_info->l_lockh,
152 OBD_FREE(lock_info, sizeof(*lock_info));
154 spin_lock(&ctl_lock);
156 spin_unlock(&ctl_lock);
162 int ldlm_test_basics(struct obd_device *obddev)
164 struct ldlm_namespace *ns;
165 struct ldlm_resource *res;
166 __u64 res_id[RES_NAME_SIZE] = {1, 2, 3};
168 struct ldlm_lock *lock1, *lock;
171 ns = ldlm_namespace_new("test_server", LDLM_NAMESPACE_SERVER);
175 lock1 = ldlm_lock_create(ns, NULL, res_id, LDLM_PLAIN, LCK_CR, NULL, 0);
178 err = ldlm_lock_enqueue(lock1, NULL, 0, &flags,
179 ldlm_completion_ast, ldlm_blocking_ast);
183 lock = ldlm_lock_create(ns, NULL, res_id, LDLM_PLAIN, LCK_EX, NULL, 0);
186 err = ldlm_lock_enqueue(lock, NULL, 0, &flags,
187 ldlm_completion_ast, ldlm_blocking_ast);
190 if (!(flags & LDLM_FL_BLOCK_GRANTED))
193 res = ldlm_resource_get(ns, NULL, res_id, LDLM_PLAIN, 1);
196 ldlm_resource_dump(res);
198 res = ldlm_lock_convert(lock1, LCK_NL, &flags);
200 ldlm_reprocess_all(res);
202 ldlm_resource_dump(res);
203 ldlm_namespace_free(ns);
208 int ldlm_test_extents(struct obd_device *obddev)
210 struct ldlm_namespace *ns;
211 struct ldlm_resource *res;
212 struct ldlm_lock *lock, *lock1, *lock2;
213 __u64 res_id[RES_NAME_SIZE] = {0, 0, 0};
214 struct ldlm_extent ext1 = {4, 6}, ext2 = {6, 9}, ext3 = {10, 11};
218 ns = ldlm_namespace_new("test_server", LDLM_NAMESPACE_SERVER);
223 lock1 = ldlm_lock_create(ns, NULL, res_id, LDLM_EXTENT, LCK_PR, NULL,
227 err = ldlm_lock_enqueue(lock1, &ext1, sizeof(ext1), &flags, NULL, NULL);
230 if (!(flags & LDLM_FL_LOCK_CHANGED))
234 lock2 = ldlm_lock_create(ns, NULL, res_id, LDLM_EXTENT, LCK_PR,
236 err = ldlm_lock_enqueue(lock2, &ext2, sizeof(ext2), &flags, NULL, NULL);
239 if (!(flags & LDLM_FL_LOCK_CHANGED))
243 lock = ldlm_lock_create(ns, NULL, res_id, LDLM_EXTENT, LCK_EX, NULL, 0);
246 err = ldlm_lock_enqueue(lock, &ext3, sizeof(ext3), &flags,
250 if (!(flags & LDLM_FL_BLOCK_GRANTED))
252 if (flags & LDLM_FL_LOCK_CHANGED)
255 /* Convert/cancel blocking locks */
257 res = ldlm_lock_convert(lock1, LCK_NL, &flags);
259 ldlm_reprocess_all(res);
261 ldlm_lock_cancel(lock2);
263 ldlm_reprocess_all(res);
265 /* Dump the results */
266 res = ldlm_resource_get(ns, NULL, res_id, LDLM_EXTENT, 0);
269 ldlm_resource_dump(res);
270 ldlm_namespace_free(ns);
275 static int ldlm_test_network(struct obd_device *obddev,
276 struct lustre_handle *connh)
279 __u64 res_id[RES_NAME_SIZE] = {1, 2, 3};
280 struct ldlm_extent ext = {4, 6};
281 struct lustre_handle lockh1;
285 err = ldlm_cli_enqueue(connh, NULL, obddev->obd_namespace, NULL, res_id,
286 LDLM_EXTENT, &ext, sizeof(ext), LCK_PR, &flags,
287 ldlm_completion_ast, NULL, NULL, 0, &lockh1);
289 CERROR("ldlm_cli_enqueue: %d\n", err);
292 err = ldlm_cli_convert(&lockh1, LCK_EX, &flags);
293 CERROR("ldlm_cli_convert: %d\n", err);
296 ldlm_lock_decref(&lockh1, LCK_EX);
301 static int ldlm_test_main(void *data)
303 struct ldlm_test_thread *thread = data;
304 const unsigned int num_resources = 10;
305 const unsigned int num_extent = 10;
310 spin_lock_irq(¤t->sigmask_lock);
311 sigfillset(¤t->blocked);
312 recalc_sigpending(current);
313 spin_unlock_irq(¤t->sigmask_lock);
315 sprintf(current->comm, "ldlm_test");
317 /* Record that the thread is running */
318 thread->t_flags |= SVC_RUNNING;
319 wake_up(&thread->t_ctl_waitq);
321 while (!(thread->t_flags & SVC_STOPPING)) {
322 struct lustre_handle lockh;
323 __u64 res_id[3] = {0};
325 struct ldlm_extent ext;
327 int flags = 0, rc = 0;
329 /* Pick a random resource from 1 to num_resources */
330 get_random_bytes(&random, sizeof(random));
331 res_id[0] = (unsigned char)random % num_resources;
333 /* Pick a random lock mode */
334 get_random_bytes(&random, sizeof(random));
335 lock_mode = (unsigned char)random % LCK_NL + 1;
337 /* Pick a random extent */
338 get_random_bytes(&random, sizeof(random));
339 ext.start = (unsigned int)random % num_extent;
340 get_random_bytes(&random, sizeof(random));
341 ext.end = (unsigned int)random %
342 (num_extent - (int)ext.start) + ext.start;
344 LDLM_DEBUG_NOLOCK("about to enqueue with resource %d, mode %d,"
345 " extent %d -> %d", (int)res_id[0], lock_mode,
346 (int)ext.start, (int)ext.end);
348 rc = ldlm_match_or_enqueue(thread->connh, NULL,
349 thread->obddev->obd_namespace, NULL,
350 res_id, LDLM_EXTENT, &ext,
351 sizeof(ext), lock_mode, &flags,
352 ldlm_test_completion_ast,
353 ldlm_test_blocking_ast, NULL, 0,
356 atomic_inc(&locks_requested);
358 CERROR("ldlm_cli_enqueue: %d\n", rc);
362 LDLM_DEBUG_NOLOCK("locks requested: %d, granted: %d, "
364 atomic_read(&locks_requested),
365 atomic_read(&locks_granted),
366 atomic_read(&locks_matched));
368 /* I think this may be necessary since we don't sleep
369 * after a lock being blocked
374 thread->t_flags |= SVC_STOPPED;
375 wake_up(&thread->t_ctl_waitq);
380 static int ldlm_start_thread(struct obd_device *obddev,
381 struct lustre_handle *connh)
383 struct ldlm_test_thread *test;
387 OBD_ALLOC(test, sizeof(*test));
392 init_waitqueue_head(&test->t_ctl_waitq);
395 test->obddev = obddev;
397 spin_lock(&ctl_lock);
398 list_add(&test->t_link, &ctl_threads);
399 spin_unlock(&ctl_lock);
401 rc = kernel_thread(ldlm_test_main, (void *)test,
402 CLONE_VM | CLONE_FS | CLONE_FILES);
404 CERROR("cannot start thread\n");
407 wait_event(test->t_ctl_waitq, test->t_flags & SVC_RUNNING);
412 int ldlm_regression_start(struct obd_device *obddev,
413 struct lustre_handle *connh, int count)
418 spin_lock(&ctl_lock);
419 if (regression_running) {
420 CERROR("You can't start the ldlm regression twice.\n");
421 spin_unlock(&ctl_lock);
424 regression_running = 1;
425 spin_unlock(&ctl_lock);
427 for (i = 0; i < count; i++) {
428 rc = ldlm_start_thread(obddev, connh);
437 int ldlm_regression_stop(void)
441 spin_lock(&ctl_lock);
442 if (!regression_running) {
443 CERROR("The ldlm regression isn't started.\n");
444 spin_unlock(&ctl_lock);
448 while (!list_empty(&ctl_threads)) {
449 struct ldlm_test_thread *thread;
450 thread = list_entry(ctl_threads.next, struct ldlm_test_thread,
453 thread->t_flags |= SVC_STOPPING;
454 spin_unlock(&ctl_lock);
456 wake_up(&thread->t_ctl_waitq);
457 wait_event(thread->t_ctl_waitq, thread->t_flags & SVC_STOPPED);
459 spin_lock(&ctl_lock);
460 list_del(&thread->t_link);
461 OBD_FREE(thread, sizeof(*thread));
464 regression_running = 0;
465 spin_unlock(&ctl_lock);
470 int ldlm_test(struct obd_device *obddev, struct lustre_handle *connh)
473 /* rc = ldlm_test_basics(obddev);
477 rc = ldlm_test_extents(obddev);
482 rc = ldlm_test_network(obddev, connh);