From 9a02674a149077dcfd0323ebd689b4cd05ddec95 Mon Sep 17 00:00:00 2001 From: nikita Date: Sat, 18 Oct 2008 15:38:15 +0000 Subject: [PATCH] Use spin_lock_nested() in (the only) situation where more than one ldlm_lock is locked simultaneously. Also, fix possible dead-lock in ldlm_lock_change_resource() by enforcing particular lock ordering. b=16450 --- lustre/ChangeLog | 8 ++++++++ lustre/include/lustre_dlm.h | 16 ++++++++++++++++ lustre/ldlm/ldlm_lock.c | 20 ++++++++++++++++---- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lustre/ChangeLog b/lustre/ChangeLog index 894ae0c..bee80a7 100644 --- a/lustre/ChangeLog +++ b/lustre/ChangeLog @@ -1499,6 +1499,14 @@ Description: Zap lock->l_granted_mode with explicit LCK_MINMODE. Details : Use LCK_MINMODE rather than 0 to reset lock->l_granted_mode to its initial state. +Severity : normal +Bugzilla : 16450 +Description: Add lockdep support for ldlm_lock and ldlm_resource. +Details : Use spin_lock_nested() in (the only) situation where more than + one ldlm_lock is locked simultaneously. Also, fix possible + dead-lock in ldlm_lock_change_resource() by enforcing particular + lock ordering. + -------------------------------------------------------------------------------- 2007-08-10 Cluster File Systems, Inc. diff --git a/lustre/include/lustre_dlm.h b/lustre/include/lustre_dlm.h index 10384f1..468e0c3 100644 --- a/lustre/include/lustre_dlm.h +++ b/lustre/include/lustre_dlm.h @@ -1053,11 +1053,27 @@ void intent_set_disposition(struct ldlm_reply *rep, int flag); #define IOC_LDLM_REGRESS_STOP _IOWR('f', 43, long) #define IOC_LDLM_MAX_NR 43 +/** + * "Modes" of acquiring lock_res, necessary to tell lockdep that taking more + * than one lock_res is dead-lock safe. + */ +enum lock_res_type { + LRT_NORMAL, + LRT_NEW +}; + static inline void lock_res(struct ldlm_resource *res) { spin_lock(&res->lr_lock); } +static inline void lock_res_nested(struct ldlm_resource *res, + enum lock_res_type mode) +{ + spin_lock_nested(&res->lr_lock, mode); +} + + static inline void unlock_res(struct ldlm_resource *res) { spin_unlock(&res->lr_lock); diff --git a/lustre/ldlm/ldlm_lock.c b/lustre/ldlm/ldlm_lock.c index 7c9b3a6..191cf10 100644 --- a/lustre/ldlm/ldlm_lock.c +++ b/lustre/ldlm/ldlm_lock.c @@ -391,11 +391,23 @@ int ldlm_lock_change_resource(struct ldlm_namespace *ns, struct ldlm_lock *lock, newres = ldlm_resource_get(ns, NULL, new_resid, type, 1); if (newres == NULL) RETURN(-ENOMEM); - - lock_res_and_lock(lock); - LASSERT(memcmp(new_resid, &lock->l_resource->lr_name, - sizeof(lock->l_resource->lr_name)) != 0); + /* + * To flip the lock from the old to the new resource, lock, oldres and + * newres have to be locked. Resource spin-locks are nested within + * lock->l_lock, and are taken in the memory address order to avoid + * dead-locks. + */ + spin_lock(&lock->l_lock); + oldres = lock->l_resource; + if (oldres < newres) { + lock_res(oldres); + lock_res_nested(newres, LRT_NEW); + } else { lock_res(newres); + lock_res_nested(oldres, LRT_NEW); + } + LASSERT(memcmp(new_resid, &oldres->lr_name, + sizeof oldres->lr_name) != 0); lock->l_resource = newres; unlock_res(oldres); unlock_res_and_lock(lock); -- 1.8.3.1