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.
13 #define DEBUG_SUBSYSTEM S_LDLM
15 #include <linux/slab.h>
16 #include <linux/lustre_dlm.h>
18 kmem_cache_t *ldlm_resource_slab, *ldlm_lock_slab;
20 LIST_HEAD(ldlm_namespaces);
21 spinlock_t ldlm_spinlock;
23 struct ldlm_namespace *ldlm_namespace_find(__u32 id)
25 struct list_head *tmp;
26 struct ldlm_namespace *res;
29 list_for_each(tmp, &ldlm_namespaces) {
30 struct ldlm_namespace *chk;
31 chk = list_entry(tmp, struct ldlm_namespace, ns_link);
33 if ( chk->ns_id == id ) {
42 /* this must be called with ldlm_lock() held */
43 static int res_hash_init(struct ldlm_namespace *ns)
45 struct list_head *res_hash;
46 struct list_head *bucket;
48 if (ns->ns_hash != NULL)
51 /* FIXME: this memory appears to be leaked */
52 OBD_ALLOC(res_hash, sizeof(*res_hash) * RES_HASH_SIZE);
58 for (bucket = res_hash + RES_HASH_SIZE - 1; bucket >= res_hash;
60 INIT_LIST_HEAD(bucket);
62 ns->ns_hash = res_hash;
67 ldlm_error_t ldlm_namespace_new(struct obd_device *obddev, __u32 id,
68 struct ldlm_namespace **ns_out)
70 struct ldlm_namespace *ns;
73 if (ldlm_namespace_find(id))
74 RETURN(-ELDLM_NAMESPACE_EXISTS);
76 OBD_ALLOC(ns, sizeof(*ns));
83 ns->ns_obddev = obddev;
84 INIT_LIST_HEAD(&ns->ns_root_list);
86 rc = res_hash_init(ns);
88 OBD_FREE(ns, sizeof(*ns));
91 list_add(&ns->ns_link, &ldlm_namespaces);
92 atomic_set(&ns->ns_refcount, 0);
98 int ldlm_namespace_free(struct ldlm_namespace *ns)
100 if (atomic_read(&ns->ns_refcount))
103 list_del(&ns->ns_link);
104 OBD_FREE(ns->ns_hash, sizeof(struct list_head) * RES_HASH_SIZE);
105 OBD_FREE(ns, sizeof(*ns));
110 static __u32 ldlm_hash_fn(struct ldlm_resource *parent, __u64 *name)
115 for (i = 0; i < RES_NAME_SIZE; i++)
118 hash += (__u32)((unsigned long)parent >> 4);
120 return (hash & RES_HASH_MASK);
123 static struct ldlm_resource *ldlm_resource_new(void)
125 struct ldlm_resource *res;
127 res = kmem_cache_alloc(ldlm_resource_slab, SLAB_KERNEL);
130 memset(res, 0, sizeof(*res));
132 INIT_LIST_HEAD(&res->lr_children);
133 INIT_LIST_HEAD(&res->lr_childof);
134 INIT_LIST_HEAD(&res->lr_granted);
135 INIT_LIST_HEAD(&res->lr_converting);
136 INIT_LIST_HEAD(&res->lr_waiting);
138 res->lr_lock = SPIN_LOCK_UNLOCKED;
140 atomic_set(&res->lr_refcount, 1);
145 /* ldlm_lock() must be taken before calling resource_add */
146 static struct ldlm_resource *ldlm_resource_add(struct ldlm_namespace *ns,
147 struct ldlm_resource *parent,
148 __u64 *name, __u32 type)
150 struct list_head *bucket;
151 struct ldlm_resource *res;
153 bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
155 res = ldlm_resource_new();
159 memcpy(res->lr_name, name, sizeof(res->lr_name));
160 res->lr_namespace = ns;
161 if (type < 0 || type > LDLM_MAX_TYPE)
165 res->lr_most_restr = LCK_NL;
166 list_add(&res->lr_hash, bucket);
167 atomic_inc(&ns->ns_refcount);
168 if (parent == NULL) {
169 res->lr_parent = res;
170 list_add(&res->lr_rootlink, &ns->ns_root_list);
172 res->lr_parent = parent;
173 list_add(&res->lr_childof, &parent->lr_children);
179 struct ldlm_resource *ldlm_resource_get(struct ldlm_namespace *ns,
180 struct ldlm_resource *parent,
181 __u64 *name, __u32 type, int create)
183 struct list_head *bucket;
184 struct list_head *tmp = bucket;
185 struct ldlm_resource *res;
189 if (ns->ns_hash == NULL)
191 bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
194 list_for_each(tmp, bucket) {
195 struct ldlm_resource *chk;
196 chk = list_entry(tmp, struct ldlm_resource, lr_hash);
198 if (memcmp(chk->lr_name, name, sizeof(chk->lr_name)) == 0) {
200 atomic_inc(&res->lr_refcount);
205 if (res == NULL && create)
206 res = ldlm_resource_add(ns, parent, name, type);
211 int ldlm_resource_put(struct ldlm_resource *res)
215 if (atomic_read(&res->lr_refcount) <= 0)
218 if (atomic_dec_and_test(&res->lr_refcount)) {
219 if (!list_empty(&res->lr_granted))
222 if (!list_empty(&res->lr_converting))
225 if (!list_empty(&res->lr_waiting))
228 atomic_dec(&res->lr_namespace->ns_refcount);
229 list_del(&res->lr_hash);
230 list_del(&res->lr_rootlink);
231 list_del(&res->lr_childof);
233 kmem_cache_free(ldlm_resource_slab, res);
240 void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head,
241 struct ldlm_lock *lock)
243 list_add(&lock->l_res_link, head);
244 atomic_inc(&res->lr_refcount);
247 void ldlm_resource_del_lock(struct ldlm_lock *lock)
249 list_del(&lock->l_res_link);
250 atomic_dec(&lock->l_resource->lr_refcount);
253 int ldlm_get_resource_handle(struct ldlm_resource *res, struct ldlm_handle *h)
259 void ldlm_res2desc(struct ldlm_resource *res, struct ldlm_resource_desc *desc)
261 desc->lr_ns_id = res->lr_namespace->ns_id;
262 desc->lr_type = res->lr_type;
263 memcpy(desc->lr_name, res->lr_name, sizeof(desc->lr_name));
264 memcpy(desc->lr_version, res->lr_version, sizeof(desc->lr_version));
267 void ldlm_resource_dump(struct ldlm_resource *res)
269 struct list_head *tmp;
272 if (RES_NAME_SIZE != 3)
275 snprintf(name, sizeof(name), "%Lx %Lx %Lx",
276 (unsigned long long)res->lr_name[0],
277 (unsigned long long)res->lr_name[1],
278 (unsigned long long)res->lr_name[2]);
280 CDEBUG(D_OTHER, "--- Resource: %p (%s)\n", res, name);
281 CDEBUG(D_OTHER, "Namespace: %p (%u)\n", res->lr_namespace,
282 res->lr_namespace->ns_id);
283 CDEBUG(D_OTHER, "Parent: %p, root: %p\n", res->lr_parent, res->lr_root);
285 CDEBUG(D_OTHER, "Granted locks:\n");
286 list_for_each(tmp, &res->lr_granted) {
287 struct ldlm_lock *lock;
288 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
289 ldlm_lock_dump(lock);
292 CDEBUG(D_OTHER, "Converting locks:\n");
293 list_for_each(tmp, &res->lr_converting) {
294 struct ldlm_lock *lock;
295 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
296 ldlm_lock_dump(lock);
299 CDEBUG(D_OTHER, "Waiting locks:\n");
300 list_for_each(tmp, &res->lr_waiting) {
301 struct ldlm_lock *lock;
302 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
303 ldlm_lock_dump(lock);