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>
15 #define DEBUG_SUBSYSTEM S_LDLM
17 #include <linux/slab.h>
18 #include <linux/lustre_dlm.h>
20 extern kmem_cache_t *ldlm_lock_slab;
22 static int ldlm_plain_compat(struct ldlm_lock *a, struct ldlm_lock *b);
23 static int ldlm_intent_compat(struct ldlm_lock *a, struct ldlm_lock *b);
25 ldlm_res_compat ldlm_res_compat_table [] = {
26 [LDLM_PLAIN] ldlm_plain_compat,
27 [LDLM_EXTENT] ldlm_extent_compat,
28 [LDLM_MDSINTENT] ldlm_intent_compat
31 ldlm_res_policy ldlm_res_policy_table [] = {
33 [LDLM_EXTENT] ldlm_extent_policy,
37 static int ldlm_plain_compat(struct ldlm_lock *a, struct ldlm_lock *b)
39 return lockmode_compat(a->l_req_mode, b->l_req_mode);
42 static int ldlm_intent_compat(struct ldlm_lock *a, struct ldlm_lock *b)
48 /* Caller should do ldlm_resource_get() on this resource first. */
49 static struct ldlm_lock *ldlm_lock_new(struct ldlm_lock *parent,
50 struct ldlm_resource *resource)
52 struct ldlm_lock *lock;
57 lock = kmem_cache_alloc(ldlm_lock_slab, SLAB_KERNEL);
61 memset(lock, 0, sizeof(*lock));
62 lock->l_resource = resource;
63 INIT_LIST_HEAD(&lock->l_children);
64 init_waitqueue_head(&lock->l_waitq);
67 lock->l_parent = parent;
68 list_add(&lock->l_childof, &parent->l_children);
74 /* Caller must do its own ldlm_resource_put() on lock->l_resource */
75 void ldlm_lock_free(struct ldlm_lock *lock)
77 if (!list_empty(&lock->l_children)) {
78 CERROR("lock still has children!\n");
81 kmem_cache_free(ldlm_lock_slab, lock);
84 void ldlm_lock2desc(struct ldlm_lock *lock, struct ldlm_lock_desc *desc)
86 ldlm_res2desc(lock->l_resource, &desc->l_resource);
87 desc->l_req_mode = lock->l_req_mode;
88 desc->l_granted_mode = lock->l_granted_mode;
89 memcpy(&desc->l_extent, &lock->l_extent, sizeof(desc->l_extent));
90 memcpy(desc->l_version, lock->l_version, sizeof(desc->l_version));
93 static int ldlm_lock_compat(struct ldlm_lock *lock)
95 struct list_head *tmp;
98 list_for_each(tmp, &lock->l_resource->lr_granted) {
99 struct ldlm_lock *child;
100 ldlm_res_compat compat;
102 child = list_entry(tmp, struct ldlm_lock, l_res_link);
104 compat = ldlm_res_compat_table[child->l_resource->lr_type];
105 if (compat(child, lock) ||
106 lockmode_compat(child->l_req_mode, lock->l_req_mode))
111 if (child->l_blocking_ast != NULL)
112 child->l_blocking_ast(child, lock, child->l_data,
119 static void ldlm_grant_lock(struct ldlm_resource *res, struct ldlm_lock *lock)
121 ldlm_resource_add_lock(res, &res->lr_granted, lock);
122 lock->l_granted_mode = lock->l_req_mode;
124 if (lock->l_granted_mode < res->lr_most_restr)
125 res->lr_most_restr = lock->l_granted_mode;
127 if (lock->l_completion_ast)
128 lock->l_completion_ast(lock, NULL,
129 lock->l_data, lock->l_data_len);
132 ldlm_error_t ldlm_local_lock_create(__u32 ns_id,
133 struct ldlm_handle *parent_lock_handle,
134 __u64 *res_id, __u32 type,
135 struct ldlm_handle *lockh)
137 struct ldlm_namespace *ns;
138 struct ldlm_resource *res, *parent_res = NULL;
139 struct ldlm_lock *lock, *parent_lock;
141 ns = ldlm_namespace_find(ns_id);
142 if (ns == NULL || ns->ns_hash == NULL)
143 RETURN(-ELDLM_BAD_NAMESPACE);
145 parent_lock = ldlm_handle2object(parent_lock_handle);
147 parent_res = parent_lock->l_resource;
149 res = ldlm_resource_get(ns, parent_res, res_id, type, 1);
153 lock = ldlm_lock_new(parent_lock, res);
157 ldlm_object2handle(lock, lockh);
162 /* XXX: Revisit the error handling; we do not, for example, do
163 * ldlm_resource_put()s in our error cases, and we probably leak any allocated
165 ldlm_error_t ldlm_local_lock_enqueue(struct ldlm_handle *lockh,
167 struct ldlm_extent *req_ex,
169 ldlm_lock_callback completion,
170 ldlm_lock_callback blocking,
174 struct ldlm_lock *lock;
175 struct ldlm_extent new_ex;
176 int incompat = 0, rc;
177 ldlm_res_policy policy;
180 lock = ldlm_handle2object(lockh);
181 if ((policy = ldlm_res_policy_table[lock->l_resource->lr_type])) {
182 rc = policy(lock->l_resource, req_ex, &new_ex, mode, NULL);
183 if (rc == ELDLM_LOCK_CHANGED) {
184 *flags |= LDLM_FL_LOCK_CHANGED;
185 memcpy(req_ex, &new_ex, sizeof(new_ex));
189 if ((lock->l_resource->lr_type == LDLM_EXTENT && !req_ex) ||
190 (lock->l_resource->lr_type != LDLM_EXTENT && req_ex))
193 memcpy(&lock->l_extent, req_ex, sizeof(*req_ex));
194 lock->l_req_mode = mode;
196 lock->l_data_len = data_len;
197 lock->l_blocking_ast = blocking;
198 spin_lock(&lock->l_resource->lr_lock);
200 /* FIXME: We may want to optimize by checking lr_most_restr */
202 if (!list_empty(&lock->l_resource->lr_converting)) {
203 ldlm_resource_add_lock(lock->l_resource,
204 lock->l_resource->lr_waiting.prev, lock);
205 *flags |= LDLM_FL_BLOCK_CONV;
208 if (!list_empty(&lock->l_resource->lr_waiting)) {
209 ldlm_resource_add_lock(lock->l_resource,
210 lock->l_resource->lr_waiting.prev, lock);
211 *flags |= LDLM_FL_BLOCK_WAIT;
215 incompat = ldlm_lock_compat(lock);
217 ldlm_resource_add_lock(lock->l_resource,
218 lock->l_resource->lr_waiting.prev, lock);
219 *flags |= LDLM_FL_BLOCK_GRANTED;
223 ldlm_grant_lock(lock->l_resource, lock);
226 /* Don't set 'completion_ast' until here so that if the lock is granted
227 * immediately we don't do an unnecessary completion call. */
228 lock->l_completion_ast = completion;
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);