int ldlm_resource_put(struct ldlm_resource *res);
void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head,
struct ldlm_lock *lock);
-void ldlm_resource_del_lock(struct ldlm_lock *lock);
+int ldlm_resource_del_lock(struct ldlm_lock *lock);
void ldlm_res2desc(struct ldlm_resource *res, struct ldlm_resource_desc *desc);
void ldlm_resource_dump(struct ldlm_resource *res);
/* The server returned a blocked lock, but it was granted before
* we got a chance to actually enqueue it. We don't need to do
* anything else. */
- GOTO(out, ELDLM_OK);
+ GOTO(out_noput, ELDLM_OK);
}
/* If this is a local resource, put it on the appropriate list. */
ldlm_grant_lock(res, lock);
EXIT;
out:
+ /* We're called with a lock that has a referenced resource and is not on
+ * any resource list. When we added it to a list, we incurred an extra
+ * reference. */
+ ldlm_resource_put(lock->l_resource);
+ out_noput:
/* Don't set 'completion_ast' until here so that if the lock is granted
* immediately we don't do an unnecessary completion call. */
lock->l_completion_ast = completion;
CDEBUG(D_INFO, "lock still has references (%d readers, %d "
"writers)\n", lock->l_readers, lock->l_writers);
- ldlm_resource_del_lock(lock);
- if (ldlm_resource_put(res))
+ if (ldlm_resource_del_lock(lock))
res = NULL; /* res was freed, nothing else to do. */
else
spin_unlock(&res->lr_lock);
if (!new) {
CDEBUG(D_INFO, "Got local completion AST for lock %p.\n", lock);
lock->l_req_mode = mode;
- list_del_init(&lock->l_res_link);
+
+ /* FIXME: the API is flawed if I have to do these refcount
+ * acrobatics (along with the _put() below). */
+ lock->l_resource->lr_refcount++;
+
+ /* _del_lock is safe for half-created locks that are not yet on
+ * a list. */
+ ldlm_resource_del_lock(lock);
ldlm_grant_lock(lock->l_resource, lock);
+
+ ldlm_resource_put(lock->l_resource);
+
wake_up(&lock->l_waitq);
spin_unlock(&lock->l_lock);
spin_unlock(&lock->l_resource->lr_lock);
common_callback(lock1, lock2, dlm_req->lock_desc.l_granted_mode, NULL,
0, NULL);
- LDLM_DEBUG_NOLOCK("client %s callback handler END",
- lock2 == NULL ? "completion" : "blocked");
+ LDLM_DEBUG_NOLOCK("client %s callback handler END (lock: %p)",
+ lock2 == NULL ? "completion" : "blocked", lock1);
RETURN(0);
}
}
/* Must be called with resource->lr_lock taken */
-void ldlm_resource_del_lock(struct ldlm_lock *lock)
+int ldlm_resource_del_lock(struct ldlm_lock *lock)
{
if (!list_empty(&lock->l_res_link)) {
list_del_init(&lock->l_res_link);
- lock->l_resource->lr_refcount--;
+ return ldlm_resource_put(lock->l_resource);
}
+ return 0;
}
int ldlm_get_resource_handle(struct ldlm_resource *res, struct lustre_handle *h)
if (!rc) {
lock = lustre_handle2object(&lockh);
ldlm_lock_decref(lock, LCK_EX);
- if (ldlm_cli_cancel(lock->l_client, lock))
- CERROR("failed to get child inode lock ino %Ld\n",
- res_id[0]);
+ rc = ldlm_cli_cancel(lock->l_client, lock);
+ if (rc < 0)
+ CERROR("failed to cancel child inode lock ino "
+ "%Ld: %d\n", res_id[0], rc);
}
out_unlink: