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.
6 * This code is issued under the GNU General Public License.
7 * See the file COPYING in this distribution
9 * by Cluster File Systems, Inc.
14 #include <linux/version.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include <asm/unistd.h>
19 #define DEBUG_SUBSYSTEM S_LDLM
21 #include <linux/obd_support.h>
22 #include <linux/obd_class.h>
24 #include <linux/lustre_dlm.h>
26 static kmem_cache_t *ldlm_resource_slab;
27 kmem_cache_t *ldlm_lock_slab;
29 struct ldlm_namespace *ldlm_namespace_find(struct obd_device *obddev, __u32 id)
31 struct list_head *tmp;
32 struct ldlm_namespace *res;
37 list_for_each(tmp, &obddev->u.ldlm.ldlm_namespaces) {
38 struct ldlm_namespace *chk;
39 chk = list_entry(tmp, struct ldlm_namespace, ns_link);
41 if ( chk->ns_id == id ) {
52 /* this must be called with ldlm_lock(obddev) held */
53 static void res_hash_init(struct ldlm_namespace *ns)
55 struct list_head *res_hash;
56 struct list_head *bucket;
58 if (ns->ns_hash != NULL)
61 OBD_ALLOC(res_hash, sizeof(struct list_head) * RES_HASH_SIZE);
65 for (bucket = res_hash + RES_HASH_SIZE-1 ; bucket >= res_hash ;
67 INIT_LIST_HEAD(bucket);
70 ns->ns_hash = res_hash;
73 struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obddev, __u32 id)
75 struct ldlm_namespace *ns;
79 if (ldlm_namespace_find(obddev, id))
82 OBD_ALLOC(ns, sizeof(*ns));
87 INIT_LIST_HEAD(&ns->ns_root_list);
89 list_add(&ns->ns_link, &obddev->u.ldlm.ldlm_namespaces);
98 static __u32 ldlm_hash_fn(struct ldlm_resource *parent, __u32 *name)
103 for (i = 0; i < RES_NAME_SIZE; i++) {
107 hash += (__u32)((unsigned long)parent >> 4);
109 return (hash & RES_HASH_MASK);
112 static struct ldlm_resource *ldlm_resource_new(void)
114 struct ldlm_resource *res;
116 res = kmem_cache_alloc(ldlm_resource_slab, SLAB_KERNEL);
119 memset(res, 0, sizeof(*res));
121 INIT_LIST_HEAD(&res->lr_children);
122 INIT_LIST_HEAD(&res->lr_granted);
123 INIT_LIST_HEAD(&res->lr_converting);
124 INIT_LIST_HEAD(&res->lr_waiting);
126 res->lr_lock = SPIN_LOCK_UNLOCKED;
128 atomic_set(&res->lr_refcount, 1);
133 /* ldlm_lock(obddev) must be taken before calling resource_add */
134 static struct ldlm_resource *ldlm_resource_add(struct ldlm_namespace *ns,
135 struct ldlm_resource *parent,
138 struct list_head *bucket;
139 struct ldlm_resource *res;
141 bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
143 res = ldlm_resource_new();
147 memcpy(res->lr_name, name, RES_NAME_SIZE * sizeof(__u32));
148 res->lr_namespace = ns;
149 list_add(&res->lr_hash, bucket);
150 if (parent == NULL) {
151 res->lr_parent = res;
152 list_add(&res->lr_rootlink, &ns->ns_root_list);
154 res->lr_parent = parent;
155 list_add(&res->lr_childof, &parent->lr_children);
161 struct ldlm_resource *ldlm_resource_get(struct ldlm_namespace *ns,
162 struct ldlm_resource *parent,
163 __u32 *name, int create)
165 struct list_head *bucket;
166 struct list_head *tmp = bucket;
167 struct ldlm_resource *res;
169 if (ns->ns_hash == NULL)
171 bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
173 ldlm_lock(ns->ns_obddev);
176 list_for_each(tmp, bucket) {
177 struct ldlm_resource *chk;
178 chk = list_entry(tmp, struct ldlm_resource, lr_hash);
180 if (memcmp(chk->lr_name, name,
181 RES_NAME_SIZE * sizeof(__u32)) == 0) {
183 atomic_inc(&res->lr_refcount);
188 if (res == NULL && create)
189 res = ldlm_resource_add(ns, parent, name);
191 ldlm_unlock(ns->ns_obddev);
196 int ldlm_resource_put(struct ldlm_resource *res)
199 ldlm_lock(res->lr_namespace->ns_obddev);
201 if (atomic_dec_and_test(&res->lr_refcount)) {
202 if (!list_empty(&res->lr_granted))
205 if (!list_empty(&res->lr_converting))
208 if (!list_empty(&res->lr_waiting))
211 list_del(&res->lr_hash);
212 list_del(&res->lr_rootlink);
213 list_del(&res->lr_childof);
215 kmem_cache_free(ldlm_resource_slab, res);
218 ldlm_unlock(res->lr_namespace->ns_obddev);
222 int ldlm_get_resource_handle(struct ldlm_resource *res, struct ldlm_handle *h)
228 void ldlm_resource_dump(struct ldlm_resource *res)
230 struct list_head *tmp;
233 if (RES_NAME_SIZE != 6)
236 snprintf(name, sizeof(name), "%x %x %x %x %x %x",
237 res->lr_name[0], res->lr_name[1], res->lr_name[2],
238 res->lr_name[3], res->lr_name[4], res->lr_name[5]);
240 CDEBUG(D_OTHER, "--- Resource: %p (%s)\n", res, name);
241 CDEBUG(D_OTHER, "Namespace: %p (%u)\n", res->lr_namespace,
242 res->lr_namespace->ns_id);
243 CDEBUG(D_OTHER, "Parent: %p, root: %p\n", res->lr_parent, res->lr_root);
245 CDEBUG(D_OTHER, "Granted locks:\n");
246 list_for_each(tmp, &res->lr_granted) {
247 struct ldlm_lock *lock;
248 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
249 ldlm_lock_dump(lock);
252 CDEBUG(D_OTHER, "Converting locks:\n");
253 list_for_each(tmp, &res->lr_converting) {
254 struct ldlm_lock *lock;
255 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
256 ldlm_lock_dump(lock);
259 CDEBUG(D_OTHER, "Waiting locks:\n");
260 list_for_each(tmp, &res->lr_waiting) {
261 struct ldlm_lock *lock;
262 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
263 ldlm_lock_dump(lock);
267 static int ldlm_obd_setup(struct obd_device *obddev, obd_count len, void *data)
269 INIT_LIST_HEAD(&obddev->u.ldlm.ldlm_namespaces);
270 obddev->u.ldlm.ldlm_lock = SPIN_LOCK_UNLOCKED;
275 static int ldlm_iocontrol(int cmd, struct obd_conn *conn, int len, void *karg,
278 struct obd_device *obddev = conn->oc_dev;
283 if ( _IOC_TYPE(cmd) != IOC_LDLM_TYPE ||
284 _IOC_NR(cmd) < IOC_LDLM_MIN_NR ||
285 _IOC_NR(cmd) > IOC_LDLM_MAX_NR ) {
286 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
287 _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
293 case IOC_LDLM_TEST: {
294 err = ldlm_test(obddev);
295 CERROR("-- done err %d\n", err);
308 struct obd_ops ldlm_obd_ops = {
309 o_iocontrol: ldlm_iocontrol,
310 o_setup: ldlm_obd_setup,
311 o_connect: gen_connect,
312 o_disconnect: gen_disconnect
315 static int __init ldlm_init(void)
317 int rc = obd_register_type(&ldlm_obd_ops, OBD_LDLM_DEVICENAME);
321 ldlm_resource_slab = kmem_cache_create("ldlm_resources",
322 sizeof(struct ldlm_resource), 0,
323 SLAB_HWCACHE_ALIGN, NULL, NULL);
324 if (ldlm_resource_slab == NULL)
327 ldlm_lock_slab = kmem_cache_create("ldlm_locks",
328 sizeof(struct ldlm_lock), 0,
329 SLAB_HWCACHE_ALIGN, NULL, NULL);
330 if (ldlm_lock_slab == NULL) {
331 kmem_cache_destroy(ldlm_resource_slab);
338 static void __exit ldlm_exit(void)
340 obd_unregister_type(OBD_LDLM_DEVICENAME);
341 kmem_cache_destroy(ldlm_resource_slab);
342 kmem_cache_destroy(ldlm_lock_slab);
345 MODULE_AUTHOR("Cluster File Systems, Inc. <braam@clusterfs.com>");
346 MODULE_DESCRIPTION("Lustre Lock Management Module v0.1");
347 MODULE_LICENSE("GPL");
349 module_init(ldlm_init);
350 module_exit(ldlm_exit);