1#ifndef _LOCKHELP_H
2#define _LOCKHELP_H
3#include <linux/config.h>
4
5#include <linux/spinlock.h>
6#include <asm/atomic.h>
7#include <linux/interrupt.h>
8#include <linux/smp.h>
9
10/* Header to do help in lock debugging. */
11
12#ifdef CONFIG_NETFILTER_DEBUG
13struct spinlock_debug
14{
15	spinlock_t l;
16	atomic_t locked_by;
17};
18
19struct rwlock_debug
20{
21	rwlock_t l;
22	long read_locked_map;
23	long write_locked_map;
24};
25
26#define DECLARE_LOCK(l) 						\
27struct spinlock_debug l = { SPIN_LOCK_UNLOCKED, ATOMIC_INIT(-1) }
28#define DECLARE_LOCK_EXTERN(l) 			\
29extern struct spinlock_debug l
30#define DECLARE_RWLOCK(l)				\
31struct rwlock_debug l = { RW_LOCK_UNLOCKED, 0, 0 }
32#define DECLARE_RWLOCK_EXTERN(l)		\
33extern struct rwlock_debug l
34
35#define MUST_BE_LOCKED(l)						\
36do { if (atomic_read(&(l)->locked_by) != smp_processor_id())		\
37	printk("ASSERT %s:%u %s unlocked\n", __FILE__, __LINE__, #l);	\
38} while(0)
39
40#define MUST_BE_UNLOCKED(l)						\
41do { if (atomic_read(&(l)->locked_by) == smp_processor_id())		\
42	printk("ASSERT %s:%u %s locked\n", __FILE__, __LINE__, #l);	\
43} while(0)
44
45/* Write locked OK as well. */						    \
46#define MUST_BE_READ_LOCKED(l)						    \
47do { if (!((l)->read_locked_map & (1 << smp_processor_id()))		    \
48	 && !((l)->write_locked_map & (1 << smp_processor_id())))	    \
49	printk("ASSERT %s:%u %s not readlocked\n", __FILE__, __LINE__, #l); \
50} while(0)
51
52#define MUST_BE_WRITE_LOCKED(l)						     \
53do { if (!((l)->write_locked_map & (1 << smp_processor_id())))		     \
54	printk("ASSERT %s:%u %s not writelocked\n", __FILE__, __LINE__, #l); \
55} while(0)
56
57#define MUST_BE_READ_WRITE_UNLOCKED(l)					  \
58do { if ((l)->read_locked_map & (1 << smp_processor_id()))		  \
59	printk("ASSERT %s:%u %s readlocked\n", __FILE__, __LINE__, #l);	  \
60 else if ((l)->write_locked_map & (1 << smp_processor_id()))		  \
61	 printk("ASSERT %s:%u %s writelocked\n", __FILE__, __LINE__, #l); \
62} while(0)
63
64#define LOCK_BH(lk)						\
65do {								\
66	MUST_BE_UNLOCKED(lk);					\
67	spin_lock_bh(&(lk)->l);					\
68	atomic_set(&(lk)->locked_by, smp_processor_id());	\
69} while(0)
70
71#define UNLOCK_BH(lk)				\
72do {						\
73	MUST_BE_LOCKED(lk);			\
74	atomic_set(&(lk)->locked_by, -1);	\
75	spin_unlock_bh(&(lk)->l);		\
76} while(0)
77
78#define READ_LOCK(lk) 						\
79do {								\
80	MUST_BE_READ_WRITE_UNLOCKED(lk);			\
81	read_lock_bh(&(lk)->l);					\
82	set_bit(smp_processor_id(), &(lk)->read_locked_map);	\
83} while(0)
84
85#define WRITE_LOCK(lk)							  \
86do {									  \
87	MUST_BE_READ_WRITE_UNLOCKED(lk);				  \
88	write_lock_bh(&(lk)->l);					  \
89	set_bit(smp_processor_id(), &(lk)->write_locked_map);		  \
90} while(0)
91
92#define READ_UNLOCK(lk)							\
93do {									\
94	if (!((lk)->read_locked_map & (1 << smp_processor_id())))	\
95		printk("ASSERT: %s:%u %s not readlocked\n", 		\
96		       __FILE__, __LINE__, #lk);			\
97	clear_bit(smp_processor_id(), &(lk)->read_locked_map);		\
98	read_unlock_bh(&(lk)->l);					\
99} while(0)
100
101#define WRITE_UNLOCK(lk)					\
102do {								\
103	MUST_BE_WRITE_LOCKED(lk);				\
104	clear_bit(smp_processor_id(), &(lk)->write_locked_map);	\
105	write_unlock_bh(&(lk)->l);				\
106} while(0)
107
108#else
109#define DECLARE_LOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED
110#define DECLARE_LOCK_EXTERN(l) extern spinlock_t l
111#define DECLARE_RWLOCK(l) rwlock_t l = RW_LOCK_UNLOCKED
112#define DECLARE_RWLOCK_EXTERN(l) extern rwlock_t l
113
114#define MUST_BE_LOCKED(l)
115#define MUST_BE_UNLOCKED(l)
116#define MUST_BE_READ_LOCKED(l)
117#define MUST_BE_WRITE_LOCKED(l)
118#define MUST_BE_READ_WRITE_UNLOCKED(l)
119
120#define LOCK_BH(l) spin_lock_bh(l)
121#define UNLOCK_BH(l) spin_unlock_bh(l)
122
123#define READ_LOCK(l) read_lock_bh(l)
124#define WRITE_LOCK(l) write_lock_bh(l)
125#define READ_UNLOCK(l) read_unlock_bh(l)
126#define WRITE_UNLOCK(l) write_unlock_bh(l)
127#endif /*CONFIG_NETFILTER_DEBUG*/
128
129#endif /* _LOCKHELP_H */
130