+ LDLM_DEBUG(lock, "client %s callback handler START",
+ is_blocking_ast ? "blocked" : "completion");
+
+ if (descp) {
+ int do_ast;
+ l_lock(&lock->l_resource->lr_namespace->ns_lock);
+ lock->l_flags |= LDLM_FL_CBPENDING;
+ do_ast = (!lock->l_readers && !lock->l_writers);
+ l_unlock(&lock->l_resource->lr_namespace->ns_lock);
+
+ if (do_ast) {
+ LDLM_DEBUG(lock, "already unused, calling "
+ "callback (%p)", lock->l_blocking_ast);
+ if (lock->l_blocking_ast != NULL) {
+ struct lustre_handle lockh;
+ ldlm_lock2handle(lock, &lockh);
+ lock->l_blocking_ast(&lockh, descp,
+ lock->l_data,
+ lock->l_data_len);
+ }
+ } else {
+ LDLM_DEBUG(lock, "Lock still has references, will be"
+ " cancelled later");
+ }
+ LDLM_LOCK_PUT(lock);
+ } else {
+ struct list_head rpc_list = LIST_HEAD_INIT(rpc_list);
+
+ l_lock(&lock->l_resource->lr_namespace->ns_lock);
+ lock->l_req_mode = dlm_req->lock_desc.l_granted_mode;
+
+ /* If we receive the completion AST before the actual enqueue
+ * returned, then we might need to switch resources. */
+ if (memcmp(dlm_req->lock_desc.l_resource.lr_name,
+ lock->l_resource->lr_name,
+ sizeof(__u64) * RES_NAME_SIZE) != 0) {
+ ldlm_lock_change_resource(lock, dlm_req->lock_desc.l_resource.lr_name);
+ LDLM_DEBUG(lock, "completion AST, new resource");
+ }
+ lock->l_resource->lr_tmp = &rpc_list;
+ ldlm_resource_unlink_lock(lock);
+ ldlm_grant_lock(lock);
+ /* FIXME: we want any completion function, not just wake_up */
+ wake_up(&lock->l_waitq);
+ lock->l_resource->lr_tmp = NULL;
+ l_unlock(&lock->l_resource->lr_namespace->ns_lock);
+ LDLM_LOCK_PUT(lock);
+
+ ldlm_run_ast_work(&rpc_list);
+ }
+
+ LDLM_DEBUG_NOLOCK("client %s callback handler END (lock %p)",
+ is_blocking_ast ? "blocked" : "completion", lock);