aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/cluster/masklog.h
blob: 75cd877f6d42e17d3687674158a37764826e0633 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * Copyright (C) 2005 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#ifndef O2CLUSTER_MASKLOG_H
#define O2CLUSTER_MASKLOG_H

/*
 * For now this is a trivial wrapper around printk() that gives the critical
 * ability to enable sets of debugging output at run-time.  In the future this
 * will almost certainly be redirected to relayfs so that it can pay a
 * substantially lower heisenberg tax.
 *
 * Callers associate the message with a bitmask and a global bitmask is
 * maintained with help from /proc.  If any of the bits match the message is
 * output.
 *
 * We must have efficient bit tests on i386 and it seems gcc still emits crazy
 * code for the 64bit compare.  It emits very good code for the dual unsigned
 * long tests, though, completely avoiding tests that can never pass if the
 * caller gives a constant bitmask that fills one of the longs with all 0s.  So
 * the desire is to have almost all of the calls decided on by comparing just
 * one of the longs.  This leads to having infrequently given bits that are
 * frequently matched in the high bits.
 *
 * _ERROR and _NOTICE are used for messages that always go to the console and
 * have appropriate KERN_ prefixes.  We wrap these in our function instead of
 * just calling printk() so that this can eventually make its way through
 * relayfs along with the debugging messages.  Everything else gets KERN_DEBUG.
 * The inline tests and macro dance give GCC the opportunity to quite cleverly
 * only emit the appropriage printk() when the caller passes in a constant
 * mask, as is almost always the case.
 *
 * All this bitmask nonsense is hidden from the /proc interface so that Joel
 * doesn't have an aneurism.  Reading the file gives a straight forward
 * indication of which bits are on or off:
 * 	ENTRY off
 * 	EXIT off
 * 	TCP off
 * 	MSG off
 * 	SOCKET off
 * 	ERROR off
 * 	NOTICE on
 *
 * Writing changes the state of a given bit and requires a strictly formatted
 * single write() call:
 *
 * 	write(fd, "ENTRY on", 8);
 *
 * would turn the entry bit on.  "1" is also accepted in the place of "on", and
 * "off" and "0" behave as expected.
 *
 * Some trivial shell can flip all the bits on or off:
 *
 * log_mask="/proc/fs/ocfs2_nodemanager/log_mask"
 * cat $log_mask | (
 * 	while read bit status; do
 * 		# $1 is "on" or "off", say
 * 		echo "$bit $1" > $log_mask
 * 	done
 * )
 */

/* for task_struct */
#include <linux/sched.h>

/* bits that are frequently given and infrequently matched in the low word */
/* NOTE: If you add a flag, you need to also update mlog.c! */
#define ML_ENTRY	0x0000000000000001ULL /* func call entry */
#define ML_EXIT		0x0000000000000002ULL /* func call exit */
#define ML_TCP		0x0000000000000004ULL /* net cluster/tcp.c */
#define ML_MSG		0x0000000000000008ULL /* net network messages */
#define ML_SOCKET	0x0000000000000010ULL /* net socket lifetime */
#define ML_HEARTBEAT	0x0000000000000020ULL /* hb all heartbeat tracking */
#define ML_HB_BIO	0x0000000000000040ULL /* hb io tracing */
#define ML_DLMFS	0x0000000000000080ULL /* dlm user dlmfs */
#define ML_DLM		0x0000000000000100ULL /* dlm general debugging */
#define ML_DLM_DOMAIN	0x0000000000000200ULL /* dlm domain debugging */
#define ML_DLM_THREAD	0x0000000000000400ULL /* dlm domain thread */
#define ML_DLM_MASTER	0x0000000000000800ULL /* dlm master functions */
#define ML_DLM_RECOVERY	0x0000000000001000ULL /* dlm master functions */
#define ML_AIO		0x0000000000002000ULL /* ocfs2 aio read and write */
#define ML_JOURNAL	0x0000000000004000ULL /* ocfs2 journalling functions */
#define ML_DISK_ALLOC	0x0000000000008000ULL /* ocfs2 disk allocation */
#define ML_SUPER	0x0000000000010000ULL /* ocfs2 mount / umount */
#define ML_FILE_IO	0x0000000000020000ULL /* ocfs2 file I/O */
#define ML_EXTENT_MAP	0x0000000000040000ULL /* ocfs2 extent map caching */
#define ML_DLM_GLUE	0x0000000000080000ULL /* ocfs2 dlm glue layer */
#define ML_BH_IO	0x0000000000100000ULL /* ocfs2 buffer I/O */
#define ML_UPTODATE	0x0000000000200000ULL /* ocfs2 caching sequence #'s */
#define ML_NAMEI	0x0000000000400000ULL /* ocfs2 directory / namespace */
#define ML_INODE	0x0000000000800000ULL /* ocfs2 inode manipulation */
#define ML_VOTE		0x0000000001000000ULL /* ocfs2 node messaging  */
#define ML_DCACHE	0x0000000002000000ULL /* ocfs2 dcache operations */
#define ML_CONN		0x0000000004000000ULL /* net connection management */
#define ML_QUORUM	0x0000000008000000ULL /* net connection quorum */
#define ML_EXPORT	0x0000000010000000ULL /* ocfs2 export operations */
/* bits that are infrequently given and frequently matched in the high word */
#define ML_ERROR	0x0000000100000000ULL /* sent to KERN_ERR */
#define ML_NOTICE	0x0000000200000000ULL /* setn to KERN_NOTICE */
#define ML_KTHREAD	0x0000000400000000ULL /* kernel thread activity */

#define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE)
#define MLOG_INITIAL_NOT_MASK (ML_ENTRY|ML_EXIT)
#ifndef MLOG_MASK_PREFIX
#define MLOG_MASK_PREFIX 0
#endif

/*
 * When logging is disabled, force the bit test to 0 for anything other
 * than errors and notices, allowing gcc to remove the code completely.
 * When enabled, allow all masks.
 */
#if defined(CONFIG_OCFS2_DEBUG_MASKLOG)
#define ML_ALLOWED_BITS ~0
#else
#define ML_ALLOWED_BITS (ML_ERROR|ML_NOTICE)
#endif

#define MLOG_MAX_BITS 64

struct mlog_bits {
	unsigned long words[MLOG_MAX_BITS / BITS_PER_LONG];
};

extern struct mlog_bits mlog_and_bits, mlog_not_bits;

#if BITS_PER_LONG == 32

#define __mlog_test_u64(mask, bits)			\
	( (u32)(mask & 0xffffffff) & bits.words[0] || 	\
	  ((u64)(mask) >> 32) & bits.words[1] )
#define __mlog_set_u64(mask, bits) do {			\
	bits.words[0] |= (u32)(mask & 0xffffffff);	\
       	bits.words[1] |= (u64)(mask) >> 32;		\
} while (0)
#define __mlog_clear_u64(mask, bits) do {		\
	bits.words[0] &= ~((u32)(mask & 0xffffffff));	\
       	bits.words[1] &= ~((u64)(mask) >> 32);		\
} while (0)
#define MLOG_BITS_RHS(mask) {				\
	{						\
		[0] = (u32)(mask & 0xffffffff),		\
		[1] = (u64)(mask) >> 32,		\
	}						\
}

#else /* 32bit long above, 64bit long below */

#define __mlog_test_u64(mask, bits)	((mask) & bits.words[0])
#define __mlog_set_u64(mask, bits) do {		\
	bits.words[0] |= (mask);		\
} while (0)
#define __mlog_clear_u64(mask, bits) do {	\
	bits.words[0] &= ~(mask);		\
} while (0)
#define MLOG_BITS_RHS(mask) { { (mask) } }

#endif

/*
 * smp_processor_id() "helpfully" screams when called outside preemptible
 * regions in current kernels.  sles doesn't have the variants that don't
 * scream.  just do this instead of trying to guess which we're building
 * against.. *sigh*.
 */
#define __mlog_cpu_guess ({		\
	unsigned long _cpu = get_cpu();	\
	put_cpu();			\
	_cpu;				\
})

/* In the following two macros, the whitespace after the ',' just
 * before ##args is intentional. Otherwise, gcc 2.95 will eat the
 * previous token if args expands to nothing.
 */
#define __mlog_printk(level, fmt, args...)				\
	printk(level "(%u,%lu):%s:%d " fmt, current->pid,		\
	       __mlog_cpu_guess, __PRETTY_FUNCTION__, __LINE__ ,	\
	       ##args)

#define mlog(mask, fmt, args...) do {					\
	u64 __m = MLOG_MASK_PREFIX | (mask);				\
	if ((__m & ML_ALLOWED_BITS) &&					\
	    __mlog_test_u64(__m, mlog_and_bits) &&			\
	    !__mlog_test_u64(__m, mlog_not_bits)) {			\
		if (__m & ML_ERROR)					\
			__mlog_printk(KERN_ERR, "ERROR: "fmt , ##args);	\
		else if (__m & ML_NOTICE)				\
			__mlog_printk(KERN_NOTICE, fmt , ##args);	\
		else __mlog_printk(KERN_INFO, fmt , ##args);		\
	}								\
} while (0)

#define mlog_errno(st) do {						\
	int _st = (st);							\
	if (_st != -ERESTARTSYS && _st != -EINTR &&			\
	    _st != AOP_TRUNCATED_PAGE)					\
		mlog(ML_ERROR, "status = %lld\n", (long long)_st);	\
} while (0)

#if defined(CONFIG_OCFS2_DEBUG_MASKLOG)
#define mlog_entry(fmt, args...) do {					\
	mlog(ML_ENTRY, "ENTRY:" fmt , ##args);				\
} while (0)

#define mlog_entry_void() do {						\
	mlog(ML_ENTRY, "ENTRY:\n");					\
} while (0)

/*
 * We disable this for sparse.
 */
#if !defined(__CHECKER__)
#define mlog_exit(st) do {						     \
	if (__builtin_types_compatible_p(typeof(st), unsigned long))	     \
		mlog(ML_EXIT, "EXIT: %lu\n", (unsigned long) (st));	     \
	else if (__builtin_types_compatible_p(typeof(st), signed long))      \
		mlog(ML_EXIT, "EXIT: %ld\n", (signed long) (st));	     \
	else if (__builtin_types_compatible_p(typeof(st), unsigned int)	     \
		 || __builtin_types_compatible_p(typeof(st), unsigned short) \
		 || __builtin_types_compatible_p(typeof(st), unsigned char)) \
		mlog(ML_EXIT, "EXIT: %u\n", (unsigned int) (st));	     \
	else if (__builtin_types_compatible_p(typeof(st), signed int)	     \
		 || __builtin_types_compatible_p(typeof(st), signed short)   \
		 || __builtin_types_compatible_p(typeof(st), signed char))   \
		mlog(ML_EXIT, "EXIT: %d\n", (signed int) (st));		     \
	else if (__builtin_types_compatible_p(typeof(st), long long))	     \
		mlog(ML_EXIT, "EXIT: %lld\n", (long long) (st));	     \
	else								     \
		mlog(ML_EXIT, "EXIT: %llu\n", (unsigned long long) (st));    \
} while (0)
#else
#define mlog_exit(st) do {						     \
	mlog(ML_EXIT, "EXIT: %lld\n", (long long) (st));		     \
} while (0)
#endif

#define mlog_exit_ptr(ptr) do {						\
	mlog(ML_EXIT, "EXIT: %p\n", ptr);				\
} while (0)

#define mlog_exit_void() do {						\
	mlog(ML_EXIT, "EXIT\n");					\
} while (0)
#else
#define mlog_entry(...)  do { } while (0)
#define mlog_entry_void(...)  do { } while (0)
#define mlog_exit(...)  do { } while (0)
#define mlog_exit_ptr(...)  do { } while (0)
#define mlog_exit_void(...)  do { } while (0)
#endif  /* defined(CONFIG_OCFS2_DEBUG_MASKLOG) */

#define mlog_bug_on_msg(cond, fmt, args...) do {			\
	if (cond) {							\
		mlog(ML_ERROR, "bug expression: " #cond "\n");		\
		mlog(ML_ERROR, fmt, ##args);				\
		BUG();							\
	}								\
} while (0)

#include <linux/kobject.h>
#include <linux/sysfs.h>
int mlog_sys_init(struct kset *o2cb_subsys);
void mlog_sys_shutdown(void);

#endif /* O2CLUSTER_MASKLOG_H */