usability: added /proc/sys/mars/{errors,warnings}

This commit is contained in:
Thomas Schoebel-Theuer 2012-02-02 11:16:06 +01:00 committed by Thomas Schoebel-Theuer
parent ff37572045
commit 7ee39d8dfa
8 changed files with 207 additions and 44 deletions

16
brick.h
View File

@ -28,22 +28,22 @@ extern int brick_msleep(int msecs, bool shorten);
#define BRICK_INFO "BRICK_INFO "
#define BRICK_DEBUG "BRICK_DEBUG "
#define _BRICK_MSG(_dump, PREFIX, _fmt, _args...) \
brick_say(_dump, PREFIX, __BASE_FILE__, __LINE__, __FUNCTION__, _fmt, ##_args)
#define _BRICK_MSG(_class, _dump, PREFIX, _fmt, _args...) \
brick_say(_class, _dump, PREFIX, __BASE_FILE__, __LINE__, __FUNCTION__, _fmt, ##_args)
#define BRICK_FAT(_fmt, _args...) _BRICK_MSG(true, BRICK_FATAL, _fmt, ##_args)
#define BRICK_ERR(_fmt, _args...) _BRICK_MSG(true, BRICK_ERROR, _fmt, ##_args)
#define BRICK_WRN(_fmt, _args...) _BRICK_MSG(false, BRICK_WARNING, _fmt, ##_args)
#define BRICK_INF(_fmt, _args...) _BRICK_MSG(false, BRICK_INFO, _fmt, ##_args)
#define BRICK_FAT(_fmt, _args...) _BRICK_MSG(1, true, BRICK_FATAL, _fmt, ##_args)
#define BRICK_ERR(_fmt, _args...) _BRICK_MSG(1, true, BRICK_ERROR, _fmt, ##_args)
#define BRICK_WRN(_fmt, _args...) _BRICK_MSG(0, false, BRICK_WARNING, _fmt, ##_args)
#define BRICK_INF(_fmt, _args...) _BRICK_MSG(-1, false, BRICK_INFO, _fmt, ##_args)
#ifdef BRICK_DEBUGGING
#define BRICK_DBG(_fmt, _args...) _BRICK_MSG(false, BRICK_DEBUG, _fmt, ##_args)
#define BRICK_DBG(_fmt, _args...) _BRICK_MSG(-1, false, BRICK_DEBUG, _fmt, ##_args)
#else
#define BRICK_DBG(_args...) /**/
#endif
#ifdef IO_DEBUGGING
#define BRICK_IO(_fmt, _args...) _BRICK_MSG(false, BRICK_DEBUG, _fmt, ##_args)
#define BRICK_IO(_fmt, _args...) _BRICK_MSG(-1, false, BRICK_DEBUG, _fmt, ##_args)
#else
#define BRICK_IO(_args...) /*empty*/
#endif

View File

@ -30,13 +30,13 @@
#define INT_ACCESS(ptr,offset) (*(int*)(((char*)(ptr)) + (offset)))
#define _BRICK_FMT(_fmt) __BASE_FILE__ " %d %s(): " _fmt, __LINE__, __FUNCTION__
#define _BRICK_MSG(_dump, PREFIX, _fmt, _args...) do { say(PREFIX _BRICK_FMT(_fmt), ##_args); if (_dump) dump_stack(); } while (0)
#define _BRICK_MSG(_class, _dump, PREFIX, _fmt, _args...) do { say(_class, PREFIX _BRICK_FMT(_fmt), ##_args); if (_dump) dump_stack(); } while (0)
#define BRICK_ERROR "MEM_ERROR "
#define BRICK_WARNING "MEM_WARN "
#define BRICK_INFO "MEM_INFO "
#define BRICK_ERR(_fmt, _args...) _BRICK_MSG(true, BRICK_ERROR, _fmt, ##_args)
#define BRICK_WRN(_fmt, _args...) _BRICK_MSG(false, BRICK_WARNING, _fmt, ##_args)
#define BRICK_INF(_fmt, _args...) _BRICK_MSG(false, BRICK_INFO, _fmt, ##_args)
#define BRICK_ERR(_fmt, _args...) _BRICK_MSG(1, true, BRICK_ERROR, _fmt, ##_args)
#define BRICK_WRN(_fmt, _args...) _BRICK_MSG(0, false, BRICK_WARNING, _fmt, ##_args)
#define BRICK_INF(_fmt, _args...) _BRICK_MSG(-1, false, BRICK_INFO, _fmt, ##_args)
/////////////////////////////////////////////////////////////////////////

View File

@ -31,8 +31,48 @@ static int say_index[NR_CPUS] = {};
static int dump_max = 5;
static atomic_t overflow = ATOMIC_INIT(0);
static spinlock_t proc_lock = SPIN_LOCK_UNLOCKED;
static char *proc_buf1[MAX_SAY_CLASS] = {};
static char *proc_buf2[MAX_SAY_CLASS] = {};
static int proc_index1[MAX_SAY_CLASS] = {};
static int proc_index2[MAX_SAY_CLASS] = {};
static long long proc_stamp[MAX_SAY_CLASS] = {};
static struct file *log_file = NULL;
const char *proc_say_get(int class, int *len)
{
*len = 0;
if (class >= 0 && class < MAX_SAY_CLASS) {
*len = proc_index2[class];
return proc_buf2[class];
}
return NULL;
}
EXPORT_SYMBOL_GPL(proc_say_get);
void proc_say_commit(void)
{
unsigned long flags;
int class;
spin_lock_irqsave(&proc_lock, flags);
for (class = 0; class < MAX_SAY_CLASS; class++) {
char *tmp = proc_buf1[class];
if (!tmp || (!proc_index1[class] && proc_stamp[class] - (long long)jiffies < 60 * HZ))
continue;
proc_buf1[class] = proc_buf2[class];
proc_buf2[class] = tmp;
proc_index2[class] = proc_index1[class];
proc_index1[class] = 0;
proc_stamp[class] = jiffies;
}
spin_unlock_irqrestore(&proc_lock, flags);
}
EXPORT_SYMBOL_GPL(proc_say_commit);
static inline
void say_alloc(unsigned long cpu, bool use_atomic)
{
@ -119,11 +159,13 @@ void say_mark(void)
EXPORT_SYMBOL_GPL(say_mark);
static
void _say(unsigned long cpu, va_list args, bool use_args, const char *fmt, ...)
void _say(int class, unsigned long cpu, va_list args, bool use_args, const char *fmt, ...) __attribute__ ((format (printf, 5, 6)));
static
void _say(int class, unsigned long cpu, va_list args, bool use_args, const char *fmt, ...)
{
char *start;
char *start = NULL;
int rest;
int written;
int written = 0;
if (!say_buf[cpu])
goto done;
@ -151,9 +193,33 @@ void _say(unsigned long cpu, va_list args, bool use_args, const char *fmt, ...)
} else {
// indicate overflow
start[0] = '\0';
written = 0;
atomic_inc(&overflow);
}
done: ;
done:
if (class >= 0 && class < MAX_SAY_CLASS && start && written > 0) {
char *pstart;
unsigned long flags;
spin_lock_irqsave(&proc_lock, flags);
if (!proc_buf1[class])
goto proc_done;
rest = SAY_BUFMAX - proc_index1[class];
if (rest <= 0)
goto proc_done;
if (likely(rest > written)) {
pstart = proc_buf1[class] + proc_index1[class];
memcpy(pstart, start, written);
pstart[written] = '\0';
proc_index1[class] += written;
}
proc_done:
spin_unlock_irqrestore(&proc_lock, flags);
}
}
static inline
@ -163,12 +229,12 @@ void _check_overflow(unsigned long cpu)
atomic_xchg(&overflow, count);
if (unlikely(count > 0)) {
if (likely(say_index[cpu] < SAY_BUFMAX - 8)) {
_say(cpu, NULL, true, "#%d#\n", count);
_say(0, cpu, NULL, true, "#%d#\n", count);
}
}
}
void say(const char *fmt, ...)
void say(int class, const char *fmt, ...)
{
unsigned long cpu = get_cpu();
va_list args;
@ -179,7 +245,7 @@ void say(const char *fmt, ...)
_check_overflow(cpu);
va_start(args, fmt);
_say(cpu, args, false, fmt);
_say(class, cpu, args, false, fmt);
va_end(args);
_say_mark(cpu);
@ -188,7 +254,7 @@ done:
}
EXPORT_SYMBOL_GPL(say);
void brick_say(bool dump, const char *prefix, const char *file, int line, const char *func, const char *fmt, ...)
void brick_say(int class, bool dump, const char *prefix, const char *file, int line, const char *func, const char *fmt, ...)
{
struct timespec now = CURRENT_TIME;
unsigned long cpu = get_cpu();
@ -205,9 +271,9 @@ void brick_say(bool dump, const char *prefix, const char *file, int line, const
if (filelen > MAX_FILELEN)
file += filelen - MAX_FILELEN;
_say(cpu, NULL, true, "%ld.%09ld %s %s[%d] %s %d %s(): ", now.tv_sec, now.tv_nsec, prefix, current->comm, (int)cpu, file, line, func);
_say(class, cpu, NULL, true, "%ld.%09ld %s %s[%d] %s %d %s(): ", now.tv_sec, now.tv_nsec, prefix, current->comm, (int)cpu, file, line, func);
va_start(args, fmt);
_say(cpu, args, false, fmt);
_say(class, cpu, args, false, fmt);
va_end(args);
_say_mark(cpu);
@ -239,9 +305,9 @@ void check_open(const char *filename, bool must_exist)
if (unlikely(IS_ERR(log_file))) {
int status = PTR_ERR(log_file);
log_file = NULL;
say("cannot open logfile '%s', status = %d\n", filename, status);
say(1, "cannot open logfile '%s', status = %d\n", filename, status);
} else {
say("opened logfile '%s' %p\n", filename, log_file);
say(0, "opened logfile '%s' %p\n", filename, log_file);
}
}
@ -262,12 +328,12 @@ void check_close(const char *filename, bool force, bool re_open)
if (force) {
if (log_file) {
struct file *old;
say("closing logfile....\n");
say(0, "closing logfile....\n");
old = log_file;
log_file = NULL;
// FIXME: this may race against vfs_write(). Use rcu here.
filp_close(old, NULL);
say("closed logfile.\n");
say(0, "closed logfile.\n");
}
if (re_open)
check_open(filename, true);
@ -276,6 +342,11 @@ void check_close(const char *filename, bool force, bool re_open)
void init_say(void)
{
int i;
for (i = 0; i < MAX_SAY_CLASS; i++) {
proc_buf1[i] = (void*)__get_free_pages(GFP_KERNEL, SAY_ORDER);
proc_buf2[i] = (void*)__get_free_pages(GFP_KERNEL, SAY_ORDER);
}
check_open(CONFIG_MARS_LOGFILE, true);
}
EXPORT_SYMBOL_GPL(init_say);
@ -290,6 +361,14 @@ void exit_say(void)
say_buf[i] = NULL;
}
check_close(CONFIG_MARS_LOGFILE, true, false);
for (i = 0; i < MAX_SAY_CLASS; i++) {
if (proc_buf1[i])
__free_pages(virt_to_page((unsigned long)proc_buf1[i]), SAY_ORDER);
if (proc_buf2[i])
__free_pages(virt_to_page((unsigned long)proc_buf2[i]), SAY_ORDER);
proc_buf1[i] = NULL;
proc_buf2[i] = NULL;
}
}
EXPORT_SYMBOL_GPL(exit_say);

View File

@ -6,13 +6,18 @@
// printk() replacements
#define MAX_SAY_CLASS 2
extern const char *proc_say_get(int class, int *len);
extern void proc_say_commit(void);
extern void check_open(const char *filename, bool must_exist);
extern void check_close(const char *filename, bool force, bool re_open);
extern void say(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
extern void say(int class, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
extern void say_mark(void);
extern void brick_say(bool dump, const char *prefix, const char *file, int line, const char *func, const char *fmt, ...) __attribute__ ((format (printf, 6, 7)));
extern void brick_say(int class, bool dump, const char *prefix, const char *file, int line, const char *func, const char *fmt, ...) __attribute__ ((format (printf, 7, 8)));
extern void init_say(void);
extern void exit_say(void);

16
mars.h
View File

@ -29,22 +29,22 @@
#define MARS_INFO "MARS_INFO "
#define MARS_DEBUG "MARS_DEBUG "
#define _MARS_MSG(_dump, PREFIX, _fmt, _args...) \
brick_say(_dump, PREFIX, __BASE_FILE__, __LINE__, __FUNCTION__, _fmt, ##_args)
#define _MARS_MSG(_class, _dump, PREFIX, _fmt, _args...) \
brick_say(_class, _dump, PREFIX, __BASE_FILE__, __LINE__, __FUNCTION__, _fmt, ##_args)
#define MARS_FAT(_fmt, _args...) _MARS_MSG(true, MARS_FATAL, _fmt, ##_args)
#define MARS_ERR(_fmt, _args...) _MARS_MSG(true, MARS_ERROR, _fmt, ##_args)
#define MARS_WRN(_fmt, _args...) _MARS_MSG(false, MARS_WARNING, _fmt, ##_args)
#define MARS_INF(_fmt, _args...) _MARS_MSG(false, MARS_INFO, _fmt, ##_args)
#define MARS_FAT(_fmt, _args...) _MARS_MSG(1, true, MARS_FATAL, _fmt, ##_args)
#define MARS_ERR(_fmt, _args...) _MARS_MSG(1, true, MARS_ERROR, _fmt, ##_args)
#define MARS_WRN(_fmt, _args...) _MARS_MSG(0, false, MARS_WARNING, _fmt, ##_args)
#define MARS_INF(_fmt, _args...) _MARS_MSG(-1, false, MARS_INFO, _fmt, ##_args)
#ifdef MARS_DEBUGGING
#define MARS_DBG(_fmt, _args...) _MARS_MSG(false, MARS_DEBUG, _fmt, ##_args)
#define MARS_DBG(_fmt, _args...) _MARS_MSG(-1, false, MARS_DEBUG, _fmt, ##_args)
#else
#define MARS_DBG(_args...) /**/
#endif
#ifdef IO_DEBUGGING
#define MARS_IO(_fmt, _args...) _MARS_MSG(false, MARS_DEBUG, _fmt, ##_args)
#define MARS_IO(_fmt, _args...) _MARS_MSG(-1, false, MARS_DEBUG, _fmt, ##_args)
#else
#define MARS_IO(_args...) /*empty*/
#endif

View File

@ -111,14 +111,14 @@ static void dump_mem(void *data, int len)
unsigned char byte = ((unsigned char*)data)[i];
if (!(i % 8)) {
if (tmp != buf) {
say("%4d: %s\n", i, buf);
say(-1, "%4d: %s\n", i, buf);
}
tmp = buf;
}
tmp += snprintf(tmp, 1024 - i * 3, " %02x", byte);
}
if (tmp != buf) {
say("%4d: %s\n", i, buf);
say(-1, "%4d: %s\n", i, buf);
}
brick_string_free(buf);
}

View File

@ -1555,7 +1555,7 @@ int _check_versionlink(struct mars_global *global, const char *parent_path, int
MARS_DBG("VERSION OK '%s'\n", my_data);
status = 1;
} else {
MARS_DBG("VERSION MISMATCH '%s' != '%s'\n", my_data, other_data);
MARS_WRN("VERSION MISMATCH '%s' != '%s' => check for SPLIT BRAIN!\n", my_data, other_data);
status = 0;
}
@ -3541,6 +3541,8 @@ static int light_thread(void *data)
status = mars_kill_brick_when_possible(&_global, &_global.brick_anchor, false, (void*)&sio_brick_type, false);
MARS_DBG("kill sio bricks (when possible) = %d\n", status);
proc_say_commit();
_show_status_all(&_global);
#ifdef STAT_DEBUGGING
_show_statist(&_global);

View File

@ -17,11 +17,12 @@
mars_info_fn mars_info = NULL;
static
int trigger_sysctl_handler(ctl_table *table,
int write,
void __user *buffer,
size_t *length,
loff_t *ppos)
int trigger_sysctl_handler(
ctl_table *table,
int write,
void __user *buffer,
size_t *length,
loff_t *ppos)
{
ssize_t res = 0;
size_t len = *length;
@ -80,6 +81,70 @@ done:
return res;
}
static
int _proc_sysctl_handler(
int class,
int write,
void __user *buffer,
size_t *length,
loff_t *ppos)
{
ssize_t res = 0;
size_t len = *length;
MARS_DBG("write = %d len = %ld pos = %lld\n", write, len, *ppos);
if (!len || *ppos > 0) {
goto done;
}
if (write) {
res = len; // fake consumption of all data
} else {
int len;
const char *answer = proc_say_get(class, &len);
if (answer) {
res = len;
if (copy_to_user(buffer, answer, len)) {
MARS_ERR("write %d bytes at %p failed\n", len, answer);
res = -EFAULT;
}
}
}
done:
MARS_DBG("res = %ld\n", res);
*length = res;
if (res >= 0) {
*ppos += res;
return 0;
}
return res;
}
static
int warnings_sysctl_handler(
ctl_table *table,
int write,
void __user *buffer,
size_t *length,
loff_t *ppos)
{
return _proc_sysctl_handler(0, write, buffer, length, ppos);
}
static
int errors_sysctl_handler(
ctl_table *table,
int write,
void __user *buffer,
size_t *length,
loff_t *ppos)
{
return _proc_sysctl_handler(1, write, buffer, length, ppos);
}
static
ctl_table mars_table[] = {
{
@ -88,6 +153,18 @@ ctl_table mars_table[] = {
.mode = 0200,
.proc_handler = &trigger_sysctl_handler,
},
{
.ctl_name = CTL_UNNUMBERED,
.procname = "warnings",
.mode = 0400,
.proc_handler = &warnings_sysctl_handler,
},
{
.ctl_name = CTL_UNNUMBERED,
.procname = "errors",
.mode = 0400,
.proc_handler = &errors_sysctl_handler,
},
{}
};