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.
12 #define DEBUG_SUBSYSTEM S_LDLM
14 #include <linux/lustre_dlm.h>
16 kmem_cache_t *ldlm_resource_slab, *ldlm_lock_slab;
18 struct ldlm_namespace *ldlm_namespace_new(__u32 local)
20 struct ldlm_namespace *ns = NULL;
21 struct list_head *bucket;
23 OBD_ALLOC(ns, sizeof(*ns));
29 ns->ns_hash = vmalloc(sizeof(*ns->ns_hash) * RES_HASH_SIZE);
35 ptlrpc_init_client(NULL, NULL,
36 LDLM_REQUEST_PORTAL, LDLM_REPLY_PORTAL,
39 INIT_LIST_HEAD(&ns->ns_root_list);
40 ns->ns_lock = SPIN_LOCK_UNLOCKED;
44 for (bucket = ns->ns_hash + RES_HASH_SIZE - 1; bucket >= ns->ns_hash;
46 INIT_LIST_HEAD(bucket);
50 if (ns && ns->ns_hash)
53 OBD_FREE(ns, sizeof(*ns));
57 static int cleanup_resource(struct ldlm_resource *res, struct list_head *q)
59 struct list_head *tmp, *pos;
60 int rc = 0, client = res->lr_namespace->ns_local;
63 list_for_each_safe(tmp, pos, q) {
64 struct ldlm_lock *lock;
65 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
68 rc = ldlm_cli_cancel(lock->l_client, lock);
70 CERROR("ldlm_cli_cancel: %d\n", rc);
73 if (rc == ELDLM_RESOURCE_FREED)
76 CERROR("Freeing a lock still held by a client node.\n");
78 spin_lock(&lock->l_lock);
79 ldlm_resource_del_lock(lock);
82 rc = ldlm_resource_put(res);
89 int ldlm_namespace_free(struct ldlm_namespace *ns)
91 struct list_head *tmp, *pos;
96 /* We should probably take the ns_lock, but then ldlm_resource_put
97 * couldn't take it. Hmm. */
98 for (i = 0; i < RES_HASH_SIZE; i++) {
99 list_for_each_safe(tmp, pos, &(ns->ns_hash[i])) {
100 struct ldlm_resource *res;
101 res = list_entry(tmp, struct ldlm_resource, lr_hash);
103 spin_lock(&res->lr_lock);
104 rc = cleanup_resource(res, &res->lr_granted);
106 rc = cleanup_resource(res, &res->lr_converting);
108 rc = cleanup_resource(res, &res->lr_waiting);
111 CERROR("Resource refcount nonzero after lock "
112 "cleanup; forcing cleanup.\n");
113 res->lr_refcount = 1;
114 rc = ldlm_resource_put(res);
119 vfree(ns->ns_hash /* , sizeof(struct list_head) * RES_HASH_SIZE */);
120 ptlrpc_cleanup_client(&ns->ns_client);
121 OBD_FREE(ns, sizeof(*ns));
126 static __u32 ldlm_hash_fn(struct ldlm_resource *parent, __u64 *name)
131 for (i = 0; i < RES_NAME_SIZE; i++)
134 hash += (__u32)((unsigned long)parent >> 4);
136 return (hash & RES_HASH_MASK);
139 static struct ldlm_resource *ldlm_resource_new(void)
141 struct ldlm_resource *res;
143 res = kmem_cache_alloc(ldlm_resource_slab, SLAB_KERNEL);
148 memset(res, 0, sizeof(*res));
150 INIT_LIST_HEAD(&res->lr_children);
151 INIT_LIST_HEAD(&res->lr_childof);
152 INIT_LIST_HEAD(&res->lr_granted);
153 INIT_LIST_HEAD(&res->lr_converting);
154 INIT_LIST_HEAD(&res->lr_waiting);
156 res->lr_lock = SPIN_LOCK_UNLOCKED;
157 res->lr_refcount = 1;
162 /* Args: locked namespace
163 * Returns: newly-allocated, referenced, unlocked resource */
164 static struct ldlm_resource *ldlm_resource_add(struct ldlm_namespace *ns,
165 struct ldlm_resource *parent,
166 __u64 *name, __u32 type)
168 struct list_head *bucket;
169 struct ldlm_resource *res;
172 if (type < LDLM_MIN_TYPE || type > LDLM_MAX_TYPE) {
177 res = ldlm_resource_new();
183 memcpy(res->lr_name, name, sizeof(res->lr_name));
184 res->lr_namespace = ns;
188 res->lr_most_restr = LCK_NL;
190 bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
191 list_add(&res->lr_hash, bucket);
193 if (parent == NULL) {
194 res->lr_parent = res;
195 list_add(&res->lr_rootlink, &ns->ns_root_list);
197 res->lr_parent = parent;
198 list_add(&res->lr_childof, &parent->lr_children);
204 /* Args: unlocked namespace
205 * Locks: takes and releases ns->ns_lock and res->lr_lock
206 * Returns: referenced, unlocked ldlm_resource or NULL */
207 struct ldlm_resource *ldlm_resource_get(struct ldlm_namespace *ns,
208 struct ldlm_resource *parent,
209 __u64 *name, __u32 type, int create)
211 struct list_head *bucket;
212 struct list_head *tmp = bucket;
213 struct ldlm_resource *res = NULL;
216 if (ns == NULL || ns->ns_hash == NULL) {
221 spin_lock(&ns->ns_lock);
222 bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
224 list_for_each(tmp, bucket) {
225 struct ldlm_resource *chk;
226 chk = list_entry(tmp, struct ldlm_resource, lr_hash);
228 if (memcmp(chk->lr_name, name, sizeof(chk->lr_name)) == 0) {
230 spin_lock(&res->lr_lock);
232 spin_unlock(&res->lr_lock);
238 if (res == NULL && create)
239 res = ldlm_resource_add(ns, parent, name, type);
240 spin_unlock(&ns->ns_lock);
245 /* Args: locked resource
246 * Locks: takes and releases res->lr_lock
247 * takes and releases ns->ns_lock iff res->lr_refcount falls to 0
249 int ldlm_resource_put(struct ldlm_resource *res)
253 if (res->lr_refcount == 1) {
254 struct ldlm_namespace *ns = res->lr_namespace;
257 spin_unlock(&res->lr_lock);
258 spin_lock(&ns->ns_lock);
259 spin_lock(&res->lr_lock);
261 if (res->lr_refcount != 1) {
262 spin_unlock(&ns->ns_lock);
266 if (!list_empty(&res->lr_granted))
269 if (!list_empty(&res->lr_converting))
272 if (!list_empty(&res->lr_waiting))
275 if (!list_empty(&res->lr_children))
279 list_del(&res->lr_hash);
280 list_del(&res->lr_rootlink);
281 list_del(&res->lr_childof);
283 kmem_cache_free(ldlm_resource_slab, res);
284 spin_unlock(&ns->ns_lock);
290 if (res->lr_refcount < 0)
297 /* Must be called with resource->lr_lock taken */
298 void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head,
299 struct ldlm_lock *lock)
301 ldlm_resource_dump(res);
302 ldlm_lock_dump(lock);
303 if (!list_empty(&lock->l_res_link))
306 list_add(&lock->l_res_link, head);
310 /* Must be called with resource->lr_lock taken */
311 void ldlm_resource_del_lock(struct ldlm_lock *lock)
313 list_del_init(&lock->l_res_link);
314 lock->l_resource->lr_refcount--;
317 int ldlm_get_resource_handle(struct ldlm_resource *res, struct lustre_handle *h)
323 void ldlm_res2desc(struct ldlm_resource *res, struct ldlm_resource_desc *desc)
325 desc->lr_type = res->lr_type;
326 memcpy(desc->lr_name, res->lr_name, sizeof(desc->lr_name));
327 memcpy(desc->lr_version, res->lr_version, sizeof(desc->lr_version));
330 void ldlm_resource_dump(struct ldlm_resource *res)
332 struct list_head *tmp;
335 if (RES_NAME_SIZE != 3)
338 snprintf(name, sizeof(name), "%Lx %Lx %Lx",
339 (unsigned long long)res->lr_name[0],
340 (unsigned long long)res->lr_name[1],
341 (unsigned long long)res->lr_name[2]);
343 CDEBUG(D_OTHER, "--- Resource: %p (%s)\n", res, name);
344 CDEBUG(D_OTHER, "Namespace: %p\n", res->lr_namespace);
345 CDEBUG(D_OTHER, "Parent: %p, root: %p\n", res->lr_parent, res->lr_root);
347 CDEBUG(D_OTHER, "Granted locks:\n");
348 list_for_each(tmp, &res->lr_granted) {
349 struct ldlm_lock *lock;
350 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
351 ldlm_lock_dump(lock);
354 CDEBUG(D_OTHER, "Converting locks:\n");
355 list_for_each(tmp, &res->lr_converting) {
356 struct ldlm_lock *lock;
357 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
358 ldlm_lock_dump(lock);
361 CDEBUG(D_OTHER, "Waiting locks:\n");
362 list_for_each(tmp, &res->lr_waiting) {
363 struct ldlm_lock *lock;
364 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
365 ldlm_lock_dump(lock);