checked carefully in case some malformed flags cause fake
join_file req on client.
+Severity : normal
+Bugzilla : 14225
+Description: LDLM_ENQUEUE races with LDLM_CP_CALLBACK
+Details : ldlm_completion_ast() assumes that a lock is granted when the req
+ mode is equal to the granted mode. However, it should also check
+ that LDLM_FL_CP_REQD is not set.
+
--------------------------------------------------------------------------------
2007-08-10 Cluster File Systems, Inc. <info@clusterfs.com>
list_for_each_safe(tmp, pos, rpc_list) {
struct ldlm_lock *lock =
list_entry(tmp, struct ldlm_lock, l_cp_ast);
+ ldlm_completion_callback completion_callback;
/* nobody should touch l_cp_ast */
lock_res_and_lock(lock);
list_del_init(&lock->l_cp_ast);
LASSERT(lock->l_flags & LDLM_FL_CP_REQD);
+ /* save l_completion_ast since it can be changed by
+ * mds_intent_policy(), see bug 14225 */
+ completion_callback = lock->l_completion_ast;
lock->l_flags &= ~LDLM_FL_CP_REQD;
unlock_res_and_lock(lock);
- if (lock->l_completion_ast != NULL) {
- rc = lock->l_completion_ast(lock, 0, (void *)&arg);
+ if (completion_callback != NULL) {
+ rc = completion_callback(lock, 0, (void *)&arg);
ast_count++;
}
LDLM_LOCK_PUT(lock);
RETURN(0);
}
+static int is_granted_or_cancelled(struct ldlm_lock *lock)
+{
+ int ret = 0;
+
+ lock_res_and_lock(lock);
+ if (((lock->l_req_mode == lock->l_granted_mode) &&
+ !(lock->l_flags & LDLM_FL_CP_REQD)) ||
+ (lock->l_flags & LDLM_FL_FAILED))
+ ret = 1;
+ unlock_res_and_lock(lock);
+
+ return ret;
+}
+
int ldlm_completion_ast(struct ldlm_lock *lock, int flags, void *data)
{
/* XXX ALLOCATE - 160 bytes */
}
/* Go to sleep until the lock is granted or cancelled. */
- rc = l_wait_event(lock->l_waitq,
- ((lock->l_req_mode == lock->l_granted_mode) ||
- (lock->l_flags & LDLM_FL_FAILED)), &lwi);
+ rc = l_wait_event(lock->l_waitq, is_granted_or_cancelled(lock), &lwi);
if (lock->l_destroyed || lock->l_flags & LDLM_FL_FAILED) {
LDLM_DEBUG(lock, "client-side enqueue waking up: destroyed");