]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/lockdep.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / common / lockdep.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2008-2011 New Dream Network
7 *
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.
12 *
13 */
31f18b77 14#include "lockdep.h"
11fdf7f2 15#include "common/ceph_context.h"
7c673cae 16#include "common/dout.h"
7c673cae 17#include "common/valgrind.h"
7c673cae 18
7c673cae
FG
19/******* Constants **********/
20#define lockdep_dout(v) lsubdout(g_lockdep_ceph_ctx, lockdep, v)
21#define MAX_LOCKS 4096 // increase me as needed
22#define BACKTRACE_SKIP 2
23
24/******* Globals **********/
b32b8144 25bool g_lockdep;
7c673cae
FG
26struct lockdep_stopper_t {
27 // disable lockdep when this module destructs.
28 ~lockdep_stopper_t() {
29 g_lockdep = 0;
30 }
31};
32static pthread_mutex_t lockdep_mutex = PTHREAD_MUTEX_INITIALIZER;
33static CephContext *g_lockdep_ceph_ctx = NULL;
34static lockdep_stopper_t lockdep_stopper;
35static ceph::unordered_map<std::string, int> lock_ids;
36static map<int, std::string> lock_names;
37static map<int, int> lock_refs;
38static char free_ids[MAX_LOCKS/8]; // bit set = free
39static ceph::unordered_map<pthread_t, map<int,BackTrace*> > held;
40static char follows[MAX_LOCKS][MAX_LOCKS/8]; // follows[a][b] means b taken after a
41static BackTrace *follows_bt[MAX_LOCKS][MAX_LOCKS];
42unsigned current_maxid;
b32b8144
FG
43int last_freed_id = -1;
44static bool free_ids_inited;
7c673cae
FG
45
46static bool lockdep_force_backtrace()
47{
48 return (g_lockdep_ceph_ctx != NULL &&
49 g_lockdep_ceph_ctx->_conf->lockdep_force_backtrace);
50}
51
52/******* Functions **********/
53void lockdep_register_ceph_context(CephContext *cct)
54{
55 static_assert((MAX_LOCKS > 0) && (MAX_LOCKS % 8 == 0),
56 "lockdep's MAX_LOCKS needs to be divisible by 8 to operate correctly.");
57 pthread_mutex_lock(&lockdep_mutex);
58 if (g_lockdep_ceph_ctx == NULL) {
59 ANNOTATE_BENIGN_RACE_SIZED(&g_lockdep_ceph_ctx, sizeof(g_lockdep_ceph_ctx),
60 "lockdep cct");
61 ANNOTATE_BENIGN_RACE_SIZED(&g_lockdep, sizeof(g_lockdep),
62 "lockdep enabled");
63 g_lockdep = true;
64 g_lockdep_ceph_ctx = cct;
65 lockdep_dout(1) << "lockdep start" << dendl;
b32b8144
FG
66 if (!free_ids_inited) {
67 free_ids_inited = true;
68 memset((void*) &free_ids[0], 255, sizeof(free_ids));
69 }
7c673cae
FG
70 }
71 pthread_mutex_unlock(&lockdep_mutex);
72}
73
74void lockdep_unregister_ceph_context(CephContext *cct)
75{
76 pthread_mutex_lock(&lockdep_mutex);
77 if (cct == g_lockdep_ceph_ctx) {
78 lockdep_dout(1) << "lockdep stop" << dendl;
79 // this cct is going away; shut it down!
80 g_lockdep = false;
81 g_lockdep_ceph_ctx = NULL;
82
83 // blow away all of our state, too, in case it starts up again.
84 for (unsigned i = 0; i < current_maxid; ++i) {
85 for (unsigned j = 0; j < current_maxid; ++j) {
86 delete follows_bt[i][j];
87 }
88 }
89
90 held.clear();
91 lock_names.clear();
92 lock_ids.clear();
7c673cae
FG
93 memset((void*)&follows[0][0], 0, current_maxid * MAX_LOCKS/8);
94 memset((void*)&follows_bt[0][0], 0, sizeof(BackTrace*) * current_maxid * MAX_LOCKS);
7c673cae
FG
95 }
96 pthread_mutex_unlock(&lockdep_mutex);
97}
98
99int lockdep_dump_locks()
100{
101 pthread_mutex_lock(&lockdep_mutex);
b32b8144
FG
102 if (!g_lockdep)
103 goto out;
7c673cae
FG
104
105 for (ceph::unordered_map<pthread_t, map<int,BackTrace*> >::iterator p = held.begin();
106 p != held.end();
107 ++p) {
108 lockdep_dout(0) << "--- thread " << p->first << " ---" << dendl;
109 for (map<int,BackTrace*>::iterator q = p->second.begin();
110 q != p->second.end();
111 ++q) {
112 lockdep_dout(0) << " * " << lock_names[q->first] << "\n";
113 if (q->second)
114 *_dout << *(q->second);
115 *_dout << dendl;
116 }
117 }
b32b8144 118out:
7c673cae
FG
119 pthread_mutex_unlock(&lockdep_mutex);
120 return 0;
121}
122
123int lockdep_get_free_id(void)
124{
125 // if there's id known to be freed lately, reuse it
126 if ((last_freed_id >= 0) &&
127 (free_ids[last_freed_id/8] & (1 << (last_freed_id % 8)))) {
128 int tmp = last_freed_id;
129 last_freed_id = -1;
130 free_ids[tmp/8] &= 255 - (1 << (tmp % 8));
131 lockdep_dout(1) << "lockdep reusing last freed id " << tmp << dendl;
132 return tmp;
133 }
134
135 // walk through entire array and locate nonzero char, then find
136 // actual bit.
137 for (int i = 0; i < MAX_LOCKS / 8; ++i) {
138 if (free_ids[i] != 0) {
139 for (int j = 0; j < 8; ++j) {
140 if (free_ids[i] & (1 << j)) {
141 free_ids[i] &= 255 - (1 << j);
142 lockdep_dout(1) << "lockdep using id " << i * 8 + j << dendl;
143 return i * 8 + j;
144 }
145 }
146 }
147 }
148
149 // not found
150 lockdep_dout(0) << "failing miserably..." << dendl;
151 return -1;
152}
153
b32b8144 154static int _lockdep_register(const char *name)
7c673cae 155{
b32b8144 156 int id = -1;
7c673cae 157
b32b8144
FG
158 if (!g_lockdep)
159 return id;
7c673cae
FG
160 ceph::unordered_map<std::string, int>::iterator p = lock_ids.find(name);
161 if (p == lock_ids.end()) {
162 id = lockdep_get_free_id();
163 if (id < 0) {
164 lockdep_dout(0) << "ERROR OUT OF IDS .. have 0"
165 << " max " << MAX_LOCKS << dendl;
166 for (auto& p : lock_names) {
167 lockdep_dout(0) << " lock " << p.first << " " << p.second << dendl;
168 }
11fdf7f2 169 ceph_abort();
7c673cae
FG
170 }
171 if (current_maxid <= (unsigned)id) {
172 current_maxid = (unsigned)id + 1;
173 }
174 lock_ids[name] = id;
175 lock_names[id] = name;
176 lockdep_dout(10) << "registered '" << name << "' as " << id << dendl;
177 } else {
178 id = p->second;
179 lockdep_dout(20) << "had '" << name << "' as " << id << dendl;
180 }
181
182 ++lock_refs[id];
7c673cae
FG
183
184 return id;
185}
186
b32b8144
FG
187int lockdep_register(const char *name)
188{
189 int id;
190
191 pthread_mutex_lock(&lockdep_mutex);
192 id = _lockdep_register(name);
193 pthread_mutex_unlock(&lockdep_mutex);
194 return id;
195}
196
7c673cae
FG
197void lockdep_unregister(int id)
198{
199 if (id < 0) {
200 return;
201 }
202
203 pthread_mutex_lock(&lockdep_mutex);
204
b32b8144 205 std::string name;
7c673cae 206 map<int, std::string>::iterator p = lock_names.find(id);
b32b8144 207 if (p == lock_names.end())
11fdf7f2 208 name = "unknown" ;
b32b8144
FG
209 else
210 name = p->second;
7c673cae
FG
211
212 int &refs = lock_refs[id];
213 if (--refs == 0) {
b32b8144
FG
214 if (p != lock_names.end()) {
215 // reset dependency ordering
216 memset((void*)&follows[id][0], 0, MAX_LOCKS/8);
217 for (unsigned i=0; i<current_maxid; ++i) {
218 delete follows_bt[id][i];
219 follows_bt[id][i] = NULL;
220
221 delete follows_bt[i][id];
222 follows_bt[i][id] = NULL;
223 follows[i][id / 8] &= 255 - (1 << (id % 8));
224 }
7c673cae 225
b32b8144
FG
226 lockdep_dout(10) << "unregistered '" << name << "' from " << id << dendl;
227 lock_ids.erase(p->second);
228 lock_names.erase(id);
229 }
7c673cae
FG
230 lock_refs.erase(id);
231 free_ids[id/8] |= (1 << (id % 8));
b32b8144
FG
232 last_freed_id = id;
233 } else if (g_lockdep) {
234 lockdep_dout(20) << "have " << refs << " of '" << name << "' " <<
235 "from " << id << dendl;
7c673cae
FG
236 }
237 pthread_mutex_unlock(&lockdep_mutex);
238}
239
240
241// does b follow a?
242static bool does_follow(int a, int b)
243{
244 if (follows[a][b/8] & (1 << (b % 8))) {
245 lockdep_dout(0) << "\n";
246 *_dout << "------------------------------------" << "\n";
247 *_dout << "existing dependency " << lock_names[a] << " (" << a << ") -> "
248 << lock_names[b] << " (" << b << ") at:\n";
249 if (follows_bt[a][b]) {
250 follows_bt[a][b]->print(*_dout);
251 }
252 *_dout << dendl;
253 return true;
254 }
255
256 for (unsigned i=0; i<current_maxid; i++) {
257 if ((follows[a][i/8] & (1 << (i % 8))) &&
258 does_follow(i, b)) {
259 lockdep_dout(0) << "existing intermediate dependency " << lock_names[a]
260 << " (" << a << ") -> " << lock_names[i] << " (" << i << ") at:\n";
261 if (follows_bt[a][i]) {
262 follows_bt[a][i]->print(*_dout);
263 }
264 *_dout << dendl;
265 return true;
266 }
267 }
268
269 return false;
270}
271
11fdf7f2
TL
272int lockdep_will_lock(const char *name, int id, bool force_backtrace,
273 bool recursive)
7c673cae
FG
274{
275 pthread_t p = pthread_self();
7c673cae
FG
276
277 pthread_mutex_lock(&lockdep_mutex);
b32b8144
FG
278 if (!g_lockdep) {
279 pthread_mutex_unlock(&lockdep_mutex);
280 return id;
281 }
282
283 if (id < 0)
284 id = _lockdep_register(name);
285
7c673cae
FG
286 lockdep_dout(20) << "_will_lock " << name << " (" << id << ")" << dendl;
287
288 // check dependency graph
289 map<int, BackTrace *> &m = held[p];
290 for (map<int, BackTrace *>::iterator p = m.begin();
291 p != m.end();
292 ++p) {
293 if (p->first == id) {
11fdf7f2
TL
294 if (!recursive) {
295 lockdep_dout(0) << "\n";
296 *_dout << "recursive lock of " << name << " (" << id << ")\n";
297 BackTrace *bt = new BackTrace(BACKTRACE_SKIP);
298 bt->print(*_dout);
299 if (p->second) {
300 *_dout << "\npreviously locked at\n";
301 p->second->print(*_dout);
302 }
303 delete bt;
304 *_dout << dendl;
305 ceph_abort();
7c673cae 306 }
7c673cae
FG
307 }
308 else if (!(follows[p->first][id/8] & (1 << (id % 8)))) {
309 // new dependency
310
311 // did we just create a cycle?
312 if (does_follow(id, p->first)) {
313 BackTrace *bt = new BackTrace(BACKTRACE_SKIP);
314 lockdep_dout(0) << "new dependency " << lock_names[p->first]
315 << " (" << p->first << ") -> " << name << " (" << id << ")"
316 << " creates a cycle at\n";
317 bt->print(*_dout);
318 *_dout << dendl;
319
320 lockdep_dout(0) << "btw, i am holding these locks:" << dendl;
321 for (map<int, BackTrace *>::iterator q = m.begin();
322 q != m.end();
323 ++q) {
324 lockdep_dout(0) << " " << lock_names[q->first] << " (" << q->first << ")" << dendl;
325 if (q->second) {
326 lockdep_dout(0) << " ";
327 q->second->print(*_dout);
328 *_dout << dendl;
329 }
330 }
331
332 lockdep_dout(0) << "\n" << dendl;
333
334 // don't add this dependency, or we'll get aMutex. cycle in the graph, and
335 // does_follow() won't terminate.
336
337 ceph_abort(); // actually, we should just die here.
338 } else {
339 BackTrace *bt = NULL;
340 if (force_backtrace || lockdep_force_backtrace()) {
341 bt = new BackTrace(BACKTRACE_SKIP);
342 }
343 follows[p->first][id/8] |= 1 << (id % 8);
344 follows_bt[p->first][id] = bt;
345 lockdep_dout(10) << lock_names[p->first] << " -> " << name << " at" << dendl;
346 //bt->print(*_dout);
347 }
348 }
349 }
7c673cae
FG
350 pthread_mutex_unlock(&lockdep_mutex);
351 return id;
352}
353
354int lockdep_locked(const char *name, int id, bool force_backtrace)
355{
356 pthread_t p = pthread_self();
357
7c673cae 358 pthread_mutex_lock(&lockdep_mutex);
b32b8144
FG
359 if (!g_lockdep)
360 goto out;
361 if (id < 0)
362 id = _lockdep_register(name);
363
7c673cae
FG
364 lockdep_dout(20) << "_locked " << name << dendl;
365 if (force_backtrace || lockdep_force_backtrace())
366 held[p][id] = new BackTrace(BACKTRACE_SKIP);
367 else
368 held[p][id] = 0;
b32b8144 369out:
7c673cae
FG
370 pthread_mutex_unlock(&lockdep_mutex);
371 return id;
372}
373
374int lockdep_will_unlock(const char *name, int id)
375{
376 pthread_t p = pthread_self();
377
378 if (id < 0) {
379 //id = lockdep_register(name);
11fdf7f2 380 ceph_assert(id == -1);
7c673cae
FG
381 return id;
382 }
383
384 pthread_mutex_lock(&lockdep_mutex);
b32b8144
FG
385 if (!g_lockdep)
386 goto out;
7c673cae
FG
387 lockdep_dout(20) << "_will_unlock " << name << dendl;
388
389 // don't assert.. lockdep may be enabled at any point in time
390 //assert(held.count(p));
391 //assert(held[p].count(id));
392
393 delete held[p][id];
394 held[p].erase(id);
b32b8144 395out:
7c673cae
FG
396 pthread_mutex_unlock(&lockdep_mutex);
397 return id;
398}
399
400