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 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;
35 list_for_each(tmp, &obddev->u.ldlm.ldlm_namespaces) {
36 struct ldlm_namespace *chk;
37 chk = list_entry(tmp, struct ldlm_namespace, ns_link);
39 if ( chk->ns_id == id ) {
48 /* this must be called with ldlm_lock(obddev) held */
49 static void res_hash_init(struct ldlm_namespace *ns)
51 struct list_head *res_hash;
52 struct list_head *bucket;
54 if (ns->ns_hash != NULL)
57 OBD_ALLOC(res_hash, sizeof(struct list_head) * RES_HASH_SIZE);
61 for (bucket = res_hash + RES_HASH_SIZE - 1; bucket >= res_hash;
63 INIT_LIST_HEAD(bucket);
65 ns->ns_hash = res_hash;
68 struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obddev, __u32 id)
70 struct ldlm_namespace *ns;
72 if (ldlm_namespace_find(obddev, id))
75 OBD_ALLOC(ns, sizeof(*ns));
80 INIT_LIST_HEAD(&ns->ns_root_list);
82 list_add(&ns->ns_link, &obddev->u.ldlm.ldlm_namespaces);
85 atomic_set(&ns->ns_refcount, 0);
90 int ldlm_namespace_free(struct ldlm_namespace *ns)
92 if (atomic_read(&ns->ns_refcount))
95 list_del(&ns->ns_link);
96 OBD_FREE(ns->ns_hash, sizeof(struct list_head) * RES_HASH_SIZE);
97 OBD_FREE(ns, sizeof(*ns));
102 static __u32 ldlm_hash_fn(struct ldlm_resource *parent, __u64 *name)
107 for (i = 0; i < RES_NAME_SIZE; i++)
110 hash += (__u32)((unsigned long)parent >> 4);
112 return (hash & RES_HASH_MASK);
115 static struct ldlm_resource *ldlm_resource_new(void)
117 struct ldlm_resource *res;
119 res = kmem_cache_alloc(ldlm_resource_slab, SLAB_KERNEL);
122 memset(res, 0, sizeof(*res));
124 INIT_LIST_HEAD(&res->lr_children);
125 INIT_LIST_HEAD(&res->lr_childof);
126 INIT_LIST_HEAD(&res->lr_granted);
127 INIT_LIST_HEAD(&res->lr_converting);
128 INIT_LIST_HEAD(&res->lr_waiting);
130 res->lr_lock = SPIN_LOCK_UNLOCKED;
132 atomic_set(&res->lr_refcount, 1);
137 /* ldlm_lock(obddev) must be taken before calling resource_add */
138 static struct ldlm_resource *ldlm_resource_add(struct ldlm_namespace *ns,
139 struct ldlm_resource *parent,
140 __u64 *name, __u32 type)
142 struct list_head *bucket;
143 struct ldlm_resource *res;
145 bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
147 res = ldlm_resource_new();
151 memcpy(res->lr_name, name, RES_NAME_SIZE * sizeof(__u32));
152 res->lr_namespace = ns;
153 if (type < 0 || type > LDLM_MAX_TYPE)
157 res->lr_most_restr = LCK_NL;
158 list_add(&res->lr_hash, bucket);
159 atomic_inc(&ns->ns_refcount);
160 if (parent == NULL) {
161 res->lr_parent = res;
162 list_add(&res->lr_rootlink, &ns->ns_root_list);
164 res->lr_parent = parent;
165 list_add(&res->lr_childof, &parent->lr_children);
171 struct ldlm_resource *ldlm_resource_get(struct ldlm_namespace *ns,
172 struct ldlm_resource *parent,
173 __u64 *name, __u32 type, int create)
175 struct list_head *bucket;
176 struct list_head *tmp = bucket;
177 struct ldlm_resource *res;
181 if (ns->ns_hash == NULL)
183 bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
186 list_for_each(tmp, bucket) {
187 struct ldlm_resource *chk;
188 chk = list_entry(tmp, struct ldlm_resource, lr_hash);
190 if (memcmp(chk->lr_name, name,
191 RES_NAME_SIZE * sizeof(__u32)) == 0) {
193 atomic_inc(&res->lr_refcount);
198 if (res == NULL && create)
199 res = ldlm_resource_add(ns, parent, name, type);
204 int ldlm_resource_put(struct ldlm_resource *res)
208 if (atomic_read(&res->lr_refcount) <= 0)
211 if (atomic_dec_and_test(&res->lr_refcount)) {
212 if (!list_empty(&res->lr_granted))
215 if (!list_empty(&res->lr_converting))
218 if (!list_empty(&res->lr_waiting))
221 atomic_dec(&res->lr_namespace->ns_refcount);
222 list_del(&res->lr_hash);
223 list_del(&res->lr_rootlink);
224 list_del(&res->lr_childof);
226 kmem_cache_free(ldlm_resource_slab, res);
233 void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head,
234 struct ldlm_lock *lock)
236 list_add(&lock->l_res_link, head);
237 atomic_inc(&res->lr_refcount);
240 void ldlm_resource_del_lock(struct ldlm_lock *lock)
242 list_del(&lock->l_res_link);
243 atomic_dec(&lock->l_resource->lr_refcount);
246 int ldlm_get_resource_handle(struct ldlm_resource *res, struct ldlm_handle *h)
252 void ldlm_resource_dump(struct ldlm_resource *res)
254 struct list_head *tmp;
257 if (RES_NAME_SIZE != 3)
260 snprintf(name, sizeof(name), "%Lx %Lx %Lx",
261 res->lr_name[0], res->lr_name[1], res->lr_name[2]);
263 CDEBUG(D_OTHER, "--- Resource: %p (%s)\n", res, name);
264 CDEBUG(D_OTHER, "Namespace: %p (%u)\n", res->lr_namespace,
265 res->lr_namespace->ns_id);
266 CDEBUG(D_OTHER, "Parent: %p, root: %p\n", res->lr_parent, res->lr_root);
268 CDEBUG(D_OTHER, "Granted locks:\n");
269 list_for_each(tmp, &res->lr_granted) {
270 struct ldlm_lock *lock;
271 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
272 ldlm_lock_dump(lock);
275 CDEBUG(D_OTHER, "Converting locks:\n");
276 list_for_each(tmp, &res->lr_converting) {
277 struct ldlm_lock *lock;
278 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
279 ldlm_lock_dump(lock);
282 CDEBUG(D_OTHER, "Waiting locks:\n");
283 list_for_each(tmp, &res->lr_waiting) {
284 struct ldlm_lock *lock;
285 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
286 ldlm_lock_dump(lock);