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   	 */
14   	#include "lockdep.h"
15   	#include "common/ceph_context.h"
16   	#include "common/dout.h"
17   	#include "common/valgrind.h"
18   	
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 **********/
25   	bool g_lockdep;
26   	struct lockdep_stopper_t {
27   	  // disable lockdep when this module destructs.
28   	  ~lockdep_stopper_t() {
29   	    g_lockdep = 0;
30   	  }
31   	};
32   	static pthread_mutex_t lockdep_mutex = PTHREAD_MUTEX_INITIALIZER;
33   	static CephContext *g_lockdep_ceph_ctx = NULL;
34   	static lockdep_stopper_t lockdep_stopper;
35   	static ceph::unordered_map<std::string, int> lock_ids;
36   	static map<int, std::string> lock_names;
37   	static map<int, int> lock_refs;
38   	static char free_ids[MAX_LOCKS/8]; // bit set = free
39   	static ceph::unordered_map<pthread_t, map<int,BackTrace*> > held;
40   	static char follows[MAX_LOCKS][MAX_LOCKS/8]; // follows[a][b] means b taken after a
41   	static BackTrace *follows_bt[MAX_LOCKS][MAX_LOCKS];
42   	unsigned current_maxid;
43   	int last_freed_id = -1;
44   	static bool free_ids_inited;
45   	
46   	static 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 **********/
53   	void 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;
66   	    if (!free_ids_inited) {
67   	      free_ids_inited = true;
68   	      memset((void*) &free_ids[0], 255, sizeof(free_ids));
69   	    }
70   	  }
71   	  pthread_mutex_unlock(&lockdep_mutex);
72   	}
73   	
74   	void 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();
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);
95   	  }
96   	  pthread_mutex_unlock(&lockdep_mutex);
97   	}
98   	
99   	int lockdep_dump_locks()
100  	{
101  	  pthread_mutex_lock(&lockdep_mutex);
102  	  if (!g_lockdep)
103  	    goto out;
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  	  }
118  	out:
119  	  pthread_mutex_unlock(&lockdep_mutex);
120  	  return 0;
121  	}
122  	
123  	int 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  	
154  	static int _lockdep_register(const char *name)
155  	{
(1) Event assign_neg_constant: Assigning: "id" = "-1", which is negative.
Also see events: [return_negative_variable]
156  	  int id = -1;
157  	
(2) Event cond_true: Condition "!g_lockdep", taking true branch.
158  	  if (!g_lockdep)
(3) Event return_negative_variable: Explicitly returning negative variable "id".
Also see events: [assign_neg_constant]
159  	    return id;
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  	      }
169  	      ceph_abort();
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];
183  	
184  	  return id;
185  	}
186  	
187  	int 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  	
197  	void lockdep_unregister(int id)
198  	{
199  	  if (id < 0) {
200  	    return;
201  	  }
202  	
203  	  pthread_mutex_lock(&lockdep_mutex);
204  	
205  	  std::string name;
206  	  map<int, std::string>::iterator p = lock_names.find(id);
207  	  if (p == lock_names.end())
208  	    name = "unknown" ;
209  	  else
210  	    name = p->second;
211  	
212  	  int &refs = lock_refs[id];
213  	  if (--refs == 0) {
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  	      }
225  	
226  	      lockdep_dout(10) << "unregistered '" << name << "' from " << id << dendl;
227  	      lock_ids.erase(p->second);
228  	      lock_names.erase(id);
229  	    }
230  	    lock_refs.erase(id);
231  	    free_ids[id/8] |= (1 << (id % 8));
232  	    last_freed_id = id;
233  	  } else if (g_lockdep) {
234  	    lockdep_dout(20) << "have " << refs << " of '" << name << "' " <<
235  				"from " << id << dendl;
236  	  }
237  	  pthread_mutex_unlock(&lockdep_mutex);
238  	}
239  	
240  	
241  	// does b follow a?
242  	static bool does_follow(int a, int b)
243  	{
(1) Event index: Indexing "follows" with "a".
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  	
272  	int lockdep_will_lock(const char *name, int id, bool force_backtrace,
273  			      bool recursive)
274  	{
275  	  pthread_t p = pthread_self();
276  	
277  	  pthread_mutex_lock(&lockdep_mutex);
(1) Event cond_false: Condition "!g_lockdep", taking false branch.
278  	  if (!g_lockdep) {
279  	    pthread_mutex_unlock(&lockdep_mutex);
280  	    return id;
(2) Event if_end: End of if statement.
281  	  }
282  	
(3) Event cond_true: Condition "id < 0", taking true branch.
283  	  if (id < 0)
(4) Event negative_return_fn: Function "_lockdep_register(name)" returns a negative number. [details]
(5) Event assign: Assigning: "id" = "_lockdep_register(name)".
Also see events: [negative_returns]
284  	    id = _lockdep_register(name);
285  	
(6) Event cond_true: Condition "should_gather", taking true branch.
286  	  lockdep_dout(20) << "_will_lock " << name << " (" << id << ")" << dendl;
287  	
288  	  // check dependency graph
289  	  map<int, BackTrace *> &m = held[p];
(7) Event cond_true: Condition "p != m->end()", taking true branch.
290  	  for (map<int, BackTrace *>::iterator p = m.begin();
291  	       p != m.end();
292  	       ++p) {
(8) Event cond_false: Condition "p->first == id", taking false branch.
293  	    if (p->first == id) {
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();
306  	      }
307  	    }
(9) Event else_branch: Reached else branch.
(10) Event cond_true: Condition "!(follows[p->first][id / 8] & (1 << id % 8))", taking true branch.
308  	    else if (!(follows[p->first][id/8] & (1 << (id % 8)))) {
309  	      // new dependency
310  	
311  	      // did we just create a cycle?
(11) Event negative_returns: "id" is passed to a parameter that cannot be negative. [details]
Also see events: [negative_return_fn][assign]
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  	  }
350  	  pthread_mutex_unlock(&lockdep_mutex);
351  	  return id;
352  	}
353  	
354  	int lockdep_locked(const char *name, int id, bool force_backtrace)
355  	{
356  	  pthread_t p = pthread_self();
357  	
358  	  pthread_mutex_lock(&lockdep_mutex);
359  	  if (!g_lockdep)
360  	    goto out;
361  	  if (id < 0)
362  	    id = _lockdep_register(name);
363  	
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;
369  	out:
370  	  pthread_mutex_unlock(&lockdep_mutex);
371  	  return id;
372  	}
373  	
374  	int 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);
380  	    ceph_assert(id == -1);
381  	    return id;
382  	  }
383  	
384  	  pthread_mutex_lock(&lockdep_mutex);
385  	  if (!g_lockdep)
386  	    goto out;
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);
395  	out:
396  	  pthread_mutex_unlock(&lockdep_mutex);
397  	  return id;
398  	}
399  	
400  	
401