From: Jason Dillaman Date: Thu, 30 Apr 2015 17:29:12 +0000 (-0400) Subject: common: lockdep now support unregistering once destructed X-Git-Tag: v0.94.4~77^2~26 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=2fa35b1c5ca8e33959fff8c84eaa4feca0f67df3;p=ceph.git common: lockdep now support unregistering once destructed librbd use of an image hierarchy resulted in lock names being re-used and incorrectly analyzed. librbd now uses unique lock names per instance, but to prevent an unbounded growth of tracked locks, we now remove lock tracking once a lock is destructed. Signed-off-by: Jason Dillaman (cherry picked from commit 7c7df2ce9f837628535d21df61ae4f13d809c4fa) --- diff --git a/src/common/Mutex.cc b/src/common/Mutex.cc index a0c1202183dc..011b6af09d65 100644 --- a/src/common/Mutex.cc +++ b/src/common/Mutex.cc @@ -17,14 +17,15 @@ #include "common/perf_counters.h" #include "common/ceph_context.h" #include "common/config.h" +#include "include/stringify.h" #include "include/utime.h" #include "common/Clock.h" -Mutex::Mutex(const char *n, bool r, bool ld, +Mutex::Mutex(const std::string &n, bool r, bool ld, bool bt, CephContext *cct) : - name(n), id(-1), recursive(r), lockdep(ld), backtrace(bt), - nlock(0), locked_by(0), cct(cct), logger(0) + name(n), id(-1), recursive(r), lockdep(ld), backtrace(bt), nlock(0), + locked_by(0), cct(cct), logger(0) { if (cct) { PerfCountersBuilder b(cct, string("mutex-") + name, @@ -74,6 +75,9 @@ Mutex::~Mutex() { cct->get_perfcounters_collection()->remove(logger); delete logger; } + if (g_lockdep) { + lockdep_unregister(id); + } } void Mutex::Lock(bool no_lockdep) { diff --git a/src/common/Mutex.h b/src/common/Mutex.h index 758157536b70..fb91d612a8b9 100644 --- a/src/common/Mutex.h +++ b/src/common/Mutex.h @@ -33,7 +33,7 @@ enum { class Mutex { private: - const char *name; + std::string name; int id; bool recursive; bool lockdep; @@ -50,20 +50,20 @@ private: Mutex(const Mutex &M); void _register() { - id = lockdep_register(name); + id = lockdep_register(name.c_str()); } void _will_lock() { // about to lock - id = lockdep_will_lock(name, id); + id = lockdep_will_lock(name.c_str(), id); } void _locked() { // just locked - id = lockdep_locked(name, id, backtrace); + id = lockdep_locked(name.c_str(), id, backtrace); } void _will_unlock() { // about to unlock - id = lockdep_will_unlock(name, id); + id = lockdep_will_unlock(name.c_str(), id); } public: - Mutex(const char *n, bool r = false, bool ld=true, bool bt=false, + Mutex(const std::string &n, bool r = false, bool ld=true, bool bt=false, CephContext *cct = 0); ~Mutex(); bool is_locked() const { diff --git a/src/common/RWLock.h b/src/common/RWLock.h index 6f0ab8ed0943..c82a23cccc60 100644 --- a/src/common/RWLock.h +++ b/src/common/RWLock.h @@ -18,6 +18,7 @@ #define CEPH_RWLock_Posix__H #include +#include #include #include "lockdep.h" #include "include/atomic.h" @@ -25,17 +26,19 @@ class RWLock { mutable pthread_rwlock_t L; - const char *name; + std::string name; mutable int id; mutable atomic_t nrlock, nwlock; + std::string unique_name(const char* name) const; + public: RWLock(const RWLock& other); const RWLock& operator=(const RWLock& other); - RWLock(const char *n) : name(n), id(-1), nrlock(0), nwlock(0) { + RWLock(const std::string &n) : name(n), id(-1), nrlock(0), nwlock(0) { pthread_rwlock_init(&L, NULL); - if (g_lockdep) id = lockdep_register(name); + if (g_lockdep) id = lockdep_register(name.c_str()); } bool is_locked() const { @@ -50,6 +53,9 @@ public: // the object and we assume that there are no other users. assert(!is_locked()); pthread_rwlock_destroy(&L); + if (g_lockdep) { + lockdep_unregister(id); + } } void unlock(bool lockdep=true) const { @@ -59,23 +65,23 @@ public: assert(nrlock.read() > 0); nrlock.dec(); } - if (lockdep && g_lockdep) id = lockdep_will_unlock(name, id); + if (lockdep && g_lockdep) id = lockdep_will_unlock(name.c_str(), id); int r = pthread_rwlock_unlock(&L); assert(r == 0); } // read void get_read() const { - if (g_lockdep) id = lockdep_will_lock(name, id); + if (g_lockdep) id = lockdep_will_lock(name.c_str(), id); int r = pthread_rwlock_rdlock(&L); assert(r == 0); - if (g_lockdep) id = lockdep_locked(name, id); + if (g_lockdep) id = lockdep_locked(name.c_str(), id); nrlock.inc(); } bool try_get_read() const { if (pthread_rwlock_tryrdlock(&L) == 0) { nrlock.inc(); - if (g_lockdep) id = lockdep_locked(name, id); + if (g_lockdep) id = lockdep_locked(name.c_str(), id); return true; } return false; @@ -86,16 +92,16 @@ public: // write void get_write(bool lockdep=true) { - if (lockdep && g_lockdep) id = lockdep_will_lock(name, id); + if (lockdep && g_lockdep) id = lockdep_will_lock(name.c_str(), id); int r = pthread_rwlock_wrlock(&L); assert(r == 0); - if (g_lockdep) id = lockdep_locked(name, id); + if (g_lockdep) id = lockdep_locked(name.c_str(), id); nwlock.inc(); } bool try_get_write(bool lockdep=true) { if (pthread_rwlock_trywrlock(&L) == 0) { - if (lockdep && g_lockdep) id = lockdep_locked(name, id); + if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id); nwlock.inc(); return true; } diff --git a/src/common/lockdep.cc b/src/common/lockdep.cc index 6639d8ad731b..e0b69e137249 100644 --- a/src/common/lockdep.cc +++ b/src/common/lockdep.cc @@ -49,9 +49,10 @@ struct lockdep_stopper_t { static pthread_mutex_t lockdep_mutex = PTHREAD_MUTEX_INITIALIZER; static CephContext *g_lockdep_ceph_ctx = NULL; static lockdep_stopper_t lockdep_stopper; -static ceph::unordered_map lock_ids; -static map lock_names; -static int last_id = 0; +static ceph::unordered_map lock_ids; +static map lock_names; +static map lock_refs; +static list free_ids; static ceph::unordered_map > held; static BackTrace *follows[MAX_LOCKS][MAX_LOCKS]; // follows[a][b] means b taken after a @@ -62,6 +63,10 @@ void lockdep_register_ceph_context(CephContext *cct) if (g_lockdep_ceph_ctx == NULL) { g_lockdep_ceph_ctx = cct; lockdep_dout(0) << "lockdep start" << dendl; + + for (int i=0; i::iterator p = lock_ids.find(name); + ceph::unordered_map::iterator p = lock_ids.find(name); if (p == lock_ids.end()) { - assert(last_id < MAX_LOCKS); - id = last_id++; + assert(!free_ids.empty()); + id = free_ids.front(); + free_ids.pop_front(); + lock_ids[name] = id; lock_names[id] = name; lockdep_dout(10) << "registered '" << name << "' as " << id << dendl; @@ -132,11 +135,47 @@ int lockdep_register(const char *name) lockdep_dout(20) << "had '" << name << "' as " << id << dendl; } + ++lock_refs[id]; pthread_mutex_unlock(&lockdep_mutex); return id; } +void lockdep_unregister(int id) +{ + if (id < 0) { + return; + } + + pthread_mutex_lock(&lockdep_mutex); + + map::iterator p = lock_names.find(id); + assert(p != lock_names.end()); + + int &refs = lock_refs[id]; + if (--refs == 0) { + // reset dependency ordering + for (int i=0; isecond << "' from " << id + << dendl; + lock_ids.erase(p->second); + lock_names.erase(id); + lock_refs.erase(id); + free_ids.push_back(id); + } else { + lockdep_dout(20) << "have " << refs << " of '" << p->second << "' " + << "from " << id << dendl; + } + pthread_mutex_unlock(&lockdep_mutex); +} + // does b follow a? static bool does_follow(int a, int b) diff --git a/src/common/lockdep.h b/src/common/lockdep.h index 1dcf05378ee9..e9949fd76fa1 100644 --- a/src/common/lockdep.h +++ b/src/common/lockdep.h @@ -22,6 +22,7 @@ extern int g_lockdep; extern void lockdep_register_ceph_context(CephContext *cct); extern void lockdep_unregister_ceph_context(CephContext *cct); extern int lockdep_register(const char *n); +extern void lockdep_unregister(int id); extern int lockdep_will_lock(const char *n, int id); extern int lockdep_locked(const char *n, int id, bool force_backtrace=false); extern int lockdep_will_unlock(const char *n, int id);