1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2008-2011 New Dream Network
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
16 #include "common/ceph_context.h"
17 #include "common/dout.h"
18 #include "common/valgrind.h"
20 /******* Constants **********/
21 #define lockdep_dout(v) lsubdout(g_lockdep_ceph_ctx, lockdep, v)
22 #define BACKTRACE_SKIP 2
24 /******* Globals **********/
26 struct lockdep_stopper_t
{
27 // disable lockdep when this module destructs.
28 ~lockdep_stopper_t() {
34 static pthread_mutex_t lockdep_mutex
= PTHREAD_MUTEX_INITIALIZER
;
35 static CephContext
*g_lockdep_ceph_ctx
= NULL
;
36 static lockdep_stopper_t lockdep_stopper
;
37 static ceph::unordered_map
<std::string
, int> lock_ids
;
38 static std::map
<int, std::string
> lock_names
;
39 static std::map
<int, int> lock_refs
;
40 static constexpr size_t MAX_LOCKS
= 128 * 1024; // increase me as needed
41 static std::bitset
<MAX_LOCKS
> free_ids
; // bit set = free
42 static ceph::unordered_map
<pthread_t
, std::map
<int,ceph::BackTrace
*> > held
;
43 static constexpr size_t NR_LOCKS
= 4096; // the initial number of locks
44 static std::vector
<std::bitset
<MAX_LOCKS
>> follows(NR_LOCKS
); // follows[a][b] means b taken after a
45 static std::vector
<std::map
<int,ceph::BackTrace
*>> follows_bt(NR_LOCKS
);
46 // upper bound of lock id
47 unsigned current_maxid
;
48 int last_freed_id
= -1;
49 static bool free_ids_inited
;
51 static bool lockdep_force_backtrace()
53 return (g_lockdep_ceph_ctx
!= NULL
&&
54 g_lockdep_ceph_ctx
->_conf
->lockdep_force_backtrace
);
57 /******* Functions **********/
58 void lockdep_register_ceph_context(CephContext
*cct
)
60 static_assert((MAX_LOCKS
> 0) && (MAX_LOCKS
% 8 == 0),
61 "lockdep's MAX_LOCKS needs to be divisible by 8 to operate correctly.");
62 pthread_mutex_lock(&lockdep_mutex
);
63 if (g_lockdep_ceph_ctx
== NULL
) {
64 ANNOTATE_BENIGN_RACE_SIZED(&g_lockdep_ceph_ctx
, sizeof(g_lockdep_ceph_ctx
),
66 ANNOTATE_BENIGN_RACE_SIZED(&g_lockdep
, sizeof(g_lockdep
),
69 g_lockdep_ceph_ctx
= cct
;
70 lockdep_dout(1) << "lockdep start" << dendl
;
71 if (!free_ids_inited
) {
72 free_ids_inited
= true;
73 // FIPS zeroization audit 20191115: this memset is not security related.
77 pthread_mutex_unlock(&lockdep_mutex
);
80 void lockdep_unregister_ceph_context(CephContext
*cct
)
82 pthread_mutex_lock(&lockdep_mutex
);
83 if (cct
== g_lockdep_ceph_ctx
) {
84 lockdep_dout(1) << "lockdep stop" << dendl
;
85 // this cct is going away; shut it down!
87 g_lockdep_ceph_ctx
= NULL
;
89 // blow away all of our state, too, in case it starts up again.
90 for (unsigned i
= 0; i
< current_maxid
; ++i
) {
91 for (unsigned j
= 0; j
< current_maxid
; ++j
) {
92 delete follows_bt
[i
][j
];
99 std::for_each(follows
.begin(), std::next(follows
.begin(), current_maxid
),
100 [](auto& follow
) { follow
.reset(); });
101 std::for_each(follows_bt
.begin(), std::next(follows_bt
.begin(), current_maxid
),
102 [](auto& follow_bt
) { follow_bt
= {}; });
104 pthread_mutex_unlock(&lockdep_mutex
);
107 int lockdep_dump_locks()
109 pthread_mutex_lock(&lockdep_mutex
);
113 for (auto p
= held
.begin(); p
!= held
.end(); ++p
) {
114 lockdep_dout(0) << "--- thread " << p
->first
<< " ---" << dendl
;
115 for (auto q
= p
->second
.begin();
116 q
!= p
->second
.end();
118 lockdep_dout(0) << " * " << lock_names
[q
->first
] << "\n";
120 *_dout
<< *(q
->second
);
125 pthread_mutex_unlock(&lockdep_mutex
);
129 int lockdep_get_free_id(void)
131 // if there's id known to be freed lately, reuse it
132 if (last_freed_id
>= 0 &&
133 free_ids
.test(last_freed_id
)) {
134 int tmp
= last_freed_id
;
137 lockdep_dout(1) << "lockdep reusing last freed id " << tmp
<< dendl
;
141 // walk through entire array and locate nonzero char, then find
143 for (size_t i
= 0; i
< free_ids
.size(); ++i
) {
144 if (free_ids
.test(i
)) {
151 lockdep_dout(0) << "failing miserably..." << dendl
;
155 static int _lockdep_register(const char *name
)
161 ceph::unordered_map
<std::string
, int>::iterator p
= lock_ids
.find(name
);
162 if (p
== lock_ids
.end()) {
163 id
= lockdep_get_free_id();
165 lockdep_dout(0) << "ERROR OUT OF IDS .. have 0"
166 << " max " << MAX_LOCKS
<< dendl
;
167 for (auto& p
: lock_names
) {
168 lockdep_dout(0) << " lock " << p
.first
<< " " << p
.second
<< dendl
;
172 if (current_maxid
<= (unsigned)id
) {
173 current_maxid
= (unsigned)id
+ 1;
174 if (current_maxid
== follows
.size()) {
175 follows
.resize(current_maxid
+ 1);
176 follows_bt
.resize(current_maxid
+ 1);
180 lock_names
[id
] = name
;
181 lockdep_dout(10) << "registered '" << name
<< "' as " << id
<< dendl
;
184 lockdep_dout(20) << "had '" << name
<< "' as " << id
<< dendl
;
192 int lockdep_register(const char *name
)
196 pthread_mutex_lock(&lockdep_mutex
);
197 id
= _lockdep_register(name
);
198 pthread_mutex_unlock(&lockdep_mutex
);
202 void lockdep_unregister(int id
)
208 pthread_mutex_lock(&lockdep_mutex
);
211 auto p
= lock_names
.find(id
);
212 if (p
== lock_names
.end())
217 int &refs
= lock_refs
[id
];
219 if (p
!= lock_names
.end()) {
220 // reset dependency ordering
222 for (unsigned i
=0; i
<current_maxid
; ++i
) {
223 delete follows_bt
[id
][i
];
224 follows_bt
[id
][i
] = NULL
;
226 delete follows_bt
[i
][id
];
227 follows_bt
[i
][id
] = NULL
;
228 follows
[i
].reset(id
);
231 lockdep_dout(10) << "unregistered '" << name
<< "' from " << id
<< dendl
;
232 lock_ids
.erase(p
->second
);
233 lock_names
.erase(id
);
238 } else if (g_lockdep
) {
239 lockdep_dout(20) << "have " << refs
<< " of '" << name
<< "' " <<
240 "from " << id
<< dendl
;
242 pthread_mutex_unlock(&lockdep_mutex
);
247 static bool does_follow(int a
, int b
)
249 if (follows
[a
].test(b
)) {
250 lockdep_dout(0) << "\n";
251 *_dout
<< "------------------------------------" << "\n";
252 *_dout
<< "existing dependency " << lock_names
[a
] << " (" << a
<< ") -> "
253 << lock_names
[b
] << " (" << b
<< ") at:\n";
254 if (follows_bt
[a
][b
]) {
255 follows_bt
[a
][b
]->print(*_dout
);
261 for (unsigned i
=0; i
<current_maxid
; i
++) {
262 if (follows
[a
].test(i
) &&
264 lockdep_dout(0) << "existing intermediate dependency " << lock_names
[a
]
265 << " (" << a
<< ") -> " << lock_names
[i
] << " (" << i
<< ") at:\n";
266 if (follows_bt
[a
][i
]) {
267 follows_bt
[a
][i
]->print(*_dout
);
277 int lockdep_will_lock(const char *name
, int id
, bool force_backtrace
,
280 pthread_t p
= pthread_self();
282 pthread_mutex_lock(&lockdep_mutex
);
284 pthread_mutex_unlock(&lockdep_mutex
);
289 id
= _lockdep_register(name
);
291 lockdep_dout(20) << "_will_lock " << name
<< " (" << id
<< ")" << dendl
;
293 // check dependency graph
295 for (auto p
= m
.begin(); p
!= m
.end(); ++p
) {
296 if (p
->first
== id
) {
298 lockdep_dout(0) << "\n";
299 *_dout
<< "recursive lock of " << name
<< " (" << id
<< ")\n";
300 auto bt
= new ceph::ClibBackTrace(BACKTRACE_SKIP
);
303 *_dout
<< "\npreviously locked at\n";
304 p
->second
->print(*_dout
);
310 } else if (!follows
[p
->first
].test(id
)) {
313 // did we just create a cycle?
314 if (does_follow(id
, p
->first
)) {
315 auto bt
= new ceph::ClibBackTrace(BACKTRACE_SKIP
);
316 lockdep_dout(0) << "new dependency " << lock_names
[p
->first
]
317 << " (" << p
->first
<< ") -> " << name
<< " (" << id
<< ")"
318 << " creates a cycle at\n";
322 lockdep_dout(0) << "btw, i am holding these locks:" << dendl
;
323 for (auto q
= m
.begin(); q
!= m
.end(); ++q
) {
324 lockdep_dout(0) << " " << lock_names
[q
->first
] << " (" << q
->first
<< ")" << dendl
;
326 lockdep_dout(0) << " ";
327 q
->second
->print(*_dout
);
332 lockdep_dout(0) << "\n" << dendl
;
334 // don't add this dependency, or we'll get aMutex. cycle in the graph, and
335 // does_follow() won't terminate.
337 ceph_abort(); // actually, we should just die here.
339 ceph::BackTrace
* bt
= NULL
;
340 if (force_backtrace
|| lockdep_force_backtrace()) {
341 bt
= new ceph::ClibBackTrace(BACKTRACE_SKIP
);
343 follows
[p
->first
].set(id
);
344 follows_bt
[p
->first
][id
] = bt
;
345 lockdep_dout(10) << lock_names
[p
->first
] << " -> " << name
<< " at" << dendl
;
350 pthread_mutex_unlock(&lockdep_mutex
);
354 int lockdep_locked(const char *name
, int id
, bool force_backtrace
)
356 pthread_t p
= pthread_self();
358 pthread_mutex_lock(&lockdep_mutex
);
362 id
= _lockdep_register(name
);
364 lockdep_dout(20) << "_locked " << name
<< dendl
;
365 if (force_backtrace
|| lockdep_force_backtrace())
366 held
[p
][id
] = new ceph::ClibBackTrace(BACKTRACE_SKIP
);
370 pthread_mutex_unlock(&lockdep_mutex
);
374 int lockdep_will_unlock(const char *name
, int id
)
376 pthread_t p
= pthread_self();
379 //id = lockdep_register(name);
380 ceph_assert(id
== -1);
384 pthread_mutex_lock(&lockdep_mutex
);
387 lockdep_dout(20) << "_will_unlock " << name
<< dendl
;
389 // don't assert.. lockdep may be enabled at any point in time
390 //assert(held.count(p));
391 //assert(held[p].count(id));
396 pthread_mutex_unlock(&lockdep_mutex
);