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.
10 * authors, Peter Braam <braam@clusterfs.com> &
11 * Phil Schwan <phil@clusterfs.com>
16 #include <linux/version.h>
17 #include <linux/module.h>
18 #include <linux/slab.h>
19 #include <asm/unistd.h>
21 #define DEBUG_SUBSYSTEM S_LDLM
23 #include <linux/obd_support.h>
24 #include <linux/obd_class.h>
26 #include <linux/lustre_dlm.h>
28 extern kmem_cache_t *ldlm_lock_slab;
30 static int ldlm_plain_compat(struct ldlm_lock *a, struct ldlm_lock *b);
31 static int ldlm_intent_compat(struct ldlm_lock *a, struct ldlm_lock *b);
33 ldlm_res_compat ldlm_res_compat_table [] = {
34 [LDLM_PLAIN] ldlm_plain_compat,
35 [LDLM_EXTENT] ldlm_extent_compat,
36 [LDLM_MDSINTENT] ldlm_intent_compat
39 ldlm_res_policy ldlm_res_policy_table [] = {
41 [LDLM_EXTENT] ldlm_extent_policy,
45 static int ldlm_plain_compat(struct ldlm_lock *a, struct ldlm_lock *b)
47 return lockmode_compat(a->l_req_mode, b->l_req_mode);
50 static int ldlm_intent_compat(struct ldlm_lock *a, struct ldlm_lock *b)
56 static struct ldlm_lock *ldlm_lock_new(struct ldlm_lock *parent,
57 struct ldlm_resource *resource)
59 struct ldlm_lock *lock;
64 lock = kmem_cache_alloc(ldlm_lock_slab, SLAB_KERNEL);
68 memset(lock, 0, sizeof(*lock));
69 lock->l_resource = resource;
70 INIT_LIST_HEAD(&lock->l_children);
73 lock->l_parent = parent;
74 list_add(&lock->l_childof, &parent->l_children);
80 void ldlm_lock_free(struct ldlm_lock *lock)
82 kmem_cache_free(ldlm_lock_slab, lock);
85 void ldlm_lock2desc(struct ldlm_lock *lock, struct ldlm_lock_desc *desc)
87 ldlm_res2desc(lock->l_resource, &desc->l_resource);
88 desc->l_req_mode = lock->l_req_mode;
89 desc->l_granted_mode = lock->l_granted_mode;
90 memcpy(&desc->l_extent, &lock->l_extent, sizeof(desc->l_extent));
91 memcpy(desc->l_version, lock->l_version, sizeof(desc->l_version));
94 static int ldlm_lock_compat(struct ldlm_lock *lock)
96 struct list_head *tmp;
99 list_for_each(tmp, &lock->l_resource->lr_granted) {
100 struct ldlm_lock *child;
101 ldlm_res_compat compat;
103 child = list_entry(tmp, struct ldlm_lock, l_res_link);
105 compat = ldlm_res_compat_table[child->l_resource->lr_type];
106 if (compat(child, lock) ||
107 lockmode_compat(child->l_req_mode, lock->l_req_mode))
112 if (child->l_blocking_ast != NULL)
113 child->l_blocking_ast(child, lock, child->l_data,
120 static void ldlm_grant_lock(struct ldlm_resource *res, struct ldlm_lock *lock)
122 ldlm_resource_add_lock(res, &res->lr_granted, lock);
123 lock->l_granted_mode = lock->l_req_mode;
125 if (lock->l_granted_mode < res->lr_most_restr)
126 res->lr_most_restr = lock->l_granted_mode;
128 if (lock->l_completion_ast)
129 lock->l_completion_ast(lock, NULL,
130 lock->l_data, lock->l_data_len);
133 ldlm_error_t ldlm_local_lock_create(__u32 ns_id,
134 struct ldlm_handle *parent_lock_handle,
137 struct ldlm_handle *lockh)
139 struct ldlm_namespace *ns;
140 struct ldlm_resource *res, *parent_res = NULL;
141 struct ldlm_lock *lock, *parent_lock;
143 ns = ldlm_namespace_find(ns_id);
144 if (ns == NULL || ns->ns_hash == NULL)
145 RETURN(-ELDLM_BAD_NAMESPACE);
147 parent_lock = ldlm_handle2object(parent_lock_handle);
149 parent_res = parent_lock->l_resource;
151 res = ldlm_resource_get(ns, parent_res, res_id, type, 1);
155 lock = ldlm_lock_new(parent_lock, res);
159 ldlm_object2handle(lock, lockh);
164 /* XXX: Revisit the error handling; we do not, for example, do
165 * ldlm_resource_put()s in our error cases, and we probably leak any allocated
167 ldlm_error_t ldlm_local_lock_enqueue(struct ldlm_handle *lockh,
169 struct ldlm_extent *req_ex,
171 ldlm_lock_callback completion,
172 ldlm_lock_callback blocking,
176 struct ldlm_lock *lock;
177 struct ldlm_extent new_ex;
178 int incompat = 0, rc;
179 ldlm_res_policy policy;
182 lock = ldlm_handle2object(lockh);
183 if ((policy = ldlm_res_policy_table[lock->l_resource->lr_type])) {
184 rc = policy(lock->l_resource, req_ex, &new_ex, mode, NULL);
185 if (rc == ELDLM_LOCK_CHANGED) {
186 *flags |= LDLM_FL_LOCK_CHANGED;
187 memcpy(req_ex, &new_ex, sizeof(new_ex));
191 if ((lock->l_resource->lr_type == LDLM_EXTENT && !req_ex) ||
192 (lock->l_resource->lr_type != LDLM_EXTENT && req_ex))
195 memcpy(&lock->l_extent, req_ex, sizeof(*req_ex));
196 lock->l_req_mode = mode;
198 lock->l_data_len = data_len;
199 lock->l_completion_ast = completion;
200 lock->l_blocking_ast = blocking;
201 spin_lock(&lock->l_resource->lr_lock);
203 /* FIXME: We may want to optimize by checking lr_most_restr */
205 if (!list_empty(&lock->l_resource->lr_converting)) {
206 ldlm_resource_add_lock(lock->l_resource,
207 lock->l_resource->lr_waiting.prev, lock);
208 *flags |= LDLM_FL_BLOCK_CONV;
211 if (!list_empty(&lock->l_resource->lr_waiting)) {
212 ldlm_resource_add_lock(lock->l_resource,
213 lock->l_resource->lr_waiting.prev, lock);
214 *flags |= LDLM_FL_BLOCK_WAIT;
218 incompat = ldlm_lock_compat(lock);
220 ldlm_resource_add_lock(lock->l_resource,
221 lock->l_resource->lr_waiting.prev, lock);
222 *flags |= LDLM_FL_BLOCK_GRANTED;
226 ldlm_grant_lock(lock->l_resource, lock);
229 spin_unlock(&lock->l_resource->lr_lock);
233 static int ldlm_reprocess_queue(struct ldlm_resource *res,
234 struct list_head *converting)
236 struct list_head *tmp, *pos;
239 list_for_each_safe(tmp, pos, converting) {
240 struct ldlm_lock *pending;
241 pending = list_entry(tmp, struct ldlm_lock, l_res_link);
243 incompat = ldlm_lock_compat(pending);
247 list_del(&pending->l_res_link);
248 ldlm_grant_lock(res, pending);
254 static void ldlm_reprocess_all(struct ldlm_resource *res)
256 ldlm_reprocess_queue(res, &res->lr_converting);
257 if (list_empty(&res->lr_converting))
258 ldlm_reprocess_queue(res, &res->lr_waiting);
261 ldlm_error_t ldlm_local_lock_cancel(struct ldlm_handle *lockh)
263 struct ldlm_lock *lock;
264 struct ldlm_resource *res;
267 lock = ldlm_handle2object(lockh);
268 res = lock->l_resource;
270 ldlm_resource_del_lock(lock);
272 ldlm_lock_free(lock);
273 if (ldlm_resource_put(res))
275 ldlm_reprocess_all(res);
280 ldlm_error_t ldlm_local_lock_convert(struct ldlm_handle *lockh,
281 int new_mode, int *flags)
283 struct ldlm_lock *lock;
284 struct ldlm_resource *res;
287 lock = ldlm_handle2object(lockh);
288 res = lock->l_resource;
289 list_del(&lock->l_res_link);
290 lock->l_req_mode = new_mode;
292 list_add(&lock->l_res_link, res->lr_converting.prev);
294 ldlm_reprocess_all(res);
299 void ldlm_lock_dump(struct ldlm_lock *lock)
303 if (RES_VERSION_SIZE != 4)
306 snprintf(ver, sizeof(ver), "%x %x %x %x",
307 lock->l_version[0], lock->l_version[1],
308 lock->l_version[2], lock->l_version[3]);
310 CDEBUG(D_OTHER, " -- Lock dump: %p (%s)\n", lock, ver);
311 CDEBUG(D_OTHER, " Parent: %p\n", lock->l_parent);
312 CDEBUG(D_OTHER, " Resource: %p\n", lock->l_resource);
313 CDEBUG(D_OTHER, " Requested mode: %d, granted mode: %d\n",
314 (int)lock->l_req_mode, (int)lock->l_granted_mode);
315 if (lock->l_resource->lr_type == LDLM_EXTENT)
316 CDEBUG(D_OTHER, " Extent: %Lu -> %Lu\n",
317 lock->l_extent.start, lock->l_extent.end);