First commit of lustre style internal debug support. These

changes bring over everything lustre had for debugging with
two exceptions.  I dropped by the debug daemon and upcalls
just because it made things a little easier.  They can be
readded easily enough if we feel they are needed.

Everything compiles and seems to work on first inspection
but I suspect there are a handful of issues still lingering
which I'll be sorting out right away.  I just wanted to get
all these changes commited and safe.  I'm getting a little
paranoid about losing them.



git-svn-id: https://outreach.scidac.gov/svn/spl/trunk@75 7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c
This commit is contained in:
behlendo
2008-04-18 23:39:58 +00:00
parent 55152ebbb4
commit 57d1b18858
10 changed files with 2464 additions and 337 deletions
+2
View File
@@ -9,6 +9,8 @@ CPPFLAGS += @KERNELCPPFLAGS@
# Solaris porting layer module
obj-m := spl.o
spl-objs += spl-debug.o
spl-objs += spl-proc.o
spl-objs += spl-kmem.o
spl-objs += spl-thread.o
spl-objs += spl-taskq.o
File diff suppressed because it is too large Load Diff
+48 -308
View File
@@ -3,32 +3,21 @@
#include <sys/vnode.h>
#include <sys/kmem.h>
#include <sys/debug.h>
#include <linux/proc_fs.h>
#include <sys/proc.h>
#include <linux/kmod.h>
#include "config.h"
/*
* Generic support
*/
static char spl_debug_buffer1[1024];
static char spl_debug_buffer2[1024];
static spinlock_t spl_debug_lock = SPIN_LOCK_UNLOCKED;
#ifdef DEBUG_SUBSYSTEM
#undef DEBUG_SUBSYSTEM
#endif
#define DEBUG_SUBSYSTEM S_GENERIC
unsigned long spl_debug_mask = 0;
unsigned long spl_debug_subsys = 0xff;
unsigned long spl_hostid = 0;
char hw_serial[11] = "<none>";
EXPORT_SYMBOL(spl_debug_mask);
EXPORT_SYMBOL(spl_debug_subsys);
EXPORT_SYMBOL(spl_hostid);
EXPORT_SYMBOL(hw_serial);
static struct proc_dir_entry *spl_proc_root = NULL;
static struct proc_dir_entry *spl_proc_debug_mask = NULL;
static struct proc_dir_entry *spl_proc_debug_subsys = NULL;
static struct proc_dir_entry *spl_proc_hostid = NULL;
static struct proc_dir_entry *spl_proc_hw_serial = NULL;
char spl_hw_serial[11] = "<none>";
EXPORT_SYMBOL(spl_hw_serial);
int p0 = 0;
EXPORT_SYMBOL(p0);
@@ -36,14 +25,14 @@ EXPORT_SYMBOL(p0);
vmem_t *zio_alloc_arena = NULL;
EXPORT_SYMBOL(zio_alloc_arena);
int
highbit(unsigned long i)
{
register int h = 1;
ENTRY;
if (i == 0)
return (0);
RETURN(0);
#if BITS_PER_LONG == 64
if (i & 0xffffffff00000000ul) {
h += 32; i >>= 32;
@@ -64,7 +53,7 @@ highbit(unsigned long i)
if (i & 0x2) {
h += 1;
}
return (h);
RETURN(h);
}
EXPORT_SYMBOL(highbit);
@@ -76,324 +65,75 @@ ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
}
EXPORT_SYMBOL(ddi_strtoul);
/* XXX: Not the most efficient debug function ever. This should be re-done
* as an internal per-cpu in-memory debug log accessable via /proc/. Not as
* a shared global buffer everything gets serialize though. That said I'll
* worry about performance considerations once I've dealt with correctness.
*/
void
__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
{
char *sfp;
struct timeval tv;
unsigned long flags;
va_list ap;
sfp = strrchr(file, '/');
do_gettimeofday(&tv);
/* XXX: This is particularly bad for performance, but we need to
* disable irqs here or two __dprintf()'s may deadlock on each
* other if one if called from an irq handler. This is yet another
* reason why we really, really, need an internal debug log.
*/
spin_lock_irqsave(&spl_debug_lock, flags);
memset(spl_debug_buffer1, 0, 1024);
memset(spl_debug_buffer2, 0, 1024);
snprintf(spl_debug_buffer1, 1023,
"spl: %lu.%06lu:%d:%u:%s:%d:%s(): ",
tv.tv_sec, tv.tv_usec, current->pid,
smp_processor_id(),
sfp == NULL ? file : sfp + 1,
line, func);
va_start(ap, fmt);
vsnprintf(spl_debug_buffer2, 1023, fmt, ap);
va_end(ap);
printk("%s%s", spl_debug_buffer1, spl_debug_buffer2);
spin_unlock_irqrestore(&spl_debug_lock, flags);
}
EXPORT_SYMBOL(__dprintf);
static int
spl_proc_rd_generic_ul(char *page, char **start, off_t off,
int count, int *eof, unsigned long val)
set_hostid(void)
{
*start = page;
*eof = 1;
if (off || count > PAGE_SIZE)
return 0;
return snprintf(page, PAGE_SIZE, "0x%lx\n", val & 0xffffffff);
}
static int
spl_proc_rd_debug_mask(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int rc;
spin_lock(&spl_debug_lock);
rc = spl_proc_rd_generic_ul(page, start, off, count,
eof, spl_debug_mask);
spin_unlock(&spl_debug_lock);
return rc;
}
static int
spl_proc_rd_debug_subsys(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int rc;
spin_lock(&spl_debug_lock);
rc = spl_proc_rd_generic_ul(page, start, off, count,
eof, spl_debug_subsys);
spin_unlock(&spl_debug_lock);
return rc;
}
static int
spl_proc_rd_hostid(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
*start = page;
*eof = 1;
if (off || count > PAGE_SIZE)
return 0;
return snprintf(page, PAGE_SIZE, "%lx\n", spl_hostid & 0xffffffff);
}
static int
spl_proc_rd_hw_serial(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
*start = page;
*eof = 1;
if (off || count > PAGE_SIZE)
return 0;
strncpy(page, hw_serial, 11);
return strlen(page);
}
static int
spl_proc_wr_generic_ul(const char *ubuf, unsigned long count,
unsigned long *val, int base)
{
char *end, kbuf[32];
if (count >= sizeof(kbuf))
return -EOVERFLOW;
if (copy_from_user(kbuf, ubuf, count))
return -EFAULT;
kbuf[count] = '\0';
*val = (int)simple_strtoul(kbuf, &end, base);
if (kbuf == end)
return -EINVAL;
return 0;
}
static int
spl_proc_wr_debug_mask(struct file *file, const char *ubuf,
unsigned long count, void *data, int mode)
{
unsigned long val;
int rc;
rc = spl_proc_wr_generic_ul(ubuf, count, &val, 16);
if (rc)
return rc;
spin_lock(&spl_debug_lock);
spl_debug_mask = val;
spin_unlock(&spl_debug_lock);
return count;
}
static int
spl_proc_wr_debug_subsys(struct file *file, const char *ubuf,
unsigned long count, void *data, int mode)
{
unsigned long val;
int rc;
rc = spl_proc_wr_generic_ul(ubuf, count, &val, 16);
if (rc)
return rc;
spin_lock(&spl_debug_lock);
spl_debug_subsys = val;
spin_unlock(&spl_debug_lock);
return count;
}
static int
spl_proc_wr_hostid(struct file *file, const char *ubuf,
unsigned long count, void *data, int mode)
{
unsigned long val;
int rc;
rc = spl_proc_wr_generic_ul(ubuf, count, &val, 16);
if (rc)
return rc;
spl_hostid = val;
sprintf(hw_serial, "%lu\n", ((long)val >= 0) ? val : -val);
return count;
}
static struct proc_dir_entry *
spl_register_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent, void *data,
void *read_proc, void *write_proc)
{
struct proc_dir_entry *entry;
entry = create_proc_entry(name, mode, parent);
if (!entry)
return ERR_PTR(-EINVAL);
entry->data = data;
entry->read_proc = read_proc;
entry->write_proc = write_proc;
return entry;
} /* register_proc_entry() */
void spl_set_debug_mask(unsigned long mask) {
spin_lock(&spl_debug_lock);
spl_debug_mask = mask;
spin_unlock(&spl_debug_lock);
}
EXPORT_SYMBOL(spl_set_debug_mask);
void spl_set_debug_subsys(unsigned long mask) {
spin_lock(&spl_debug_lock);
spl_debug_subsys = mask;
spin_unlock(&spl_debug_lock);
}
EXPORT_SYMBOL(spl_set_debug_subsys);
static int __init spl_init(void)
{
int rc = 0;
char sh_path[] = "/bin/sh";
char *argv[] = { sh_path,
"-c",
"/usr/bin/hostid >/proc/spl/hostid",
"/usr/bin/hostid >/proc/sys/spl/hostid",
NULL };
char *envp[] = { "HOME=/",
"TERM=linux",
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL };
spl_proc_root = proc_mkdir("spl", NULL);
if (!spl_proc_root) {
printk("spl: Error unable to create /proc/spl/ directory\n");
return -EINVAL;
}
/* Doing address resolution in the kernel is tricky and just
* not a good idea in general. So to set the proper 'spl_hw_serial'
* use the usermodehelper support to ask '/bin/sh' to run
* '/usr/bin/hostid' and redirect the result to /proc/sys/spl/hostid
* for us to use. It's a horific solution but it will do for now.
*/
return call_usermodehelper(sh_path, argv, envp, 1);
}
spl_proc_debug_mask = spl_register_proc_entry("debug_mask", 0644,
spl_proc_root, NULL,
spl_proc_rd_debug_mask,
spl_proc_wr_debug_mask);
if (IS_ERR(spl_proc_debug_mask)) {
rc = PTR_ERR(spl_proc_debug_mask);
goto out;
}
static int __init spl_init(void)
{
int rc = 0;
ENTRY;
spl_proc_debug_subsys = spl_register_proc_entry("debug_subsys", 0644,
spl_proc_root, NULL,
spl_proc_rd_debug_subsys,
spl_proc_wr_debug_subsys);
if (IS_ERR(spl_proc_debug_subsys)) {
rc = PTR_ERR(spl_proc_debug_subsys);
goto out2;
}
spl_proc_hostid = spl_register_proc_entry("hostid", 0644,
spl_proc_root, NULL,
spl_proc_rd_hostid,
spl_proc_wr_hostid);
if (IS_ERR(spl_proc_hostid)) {
rc = PTR_ERR(spl_proc_hostid);
goto out3;
}
spl_proc_hw_serial = spl_register_proc_entry("hw_serial", 0444,
spl_proc_root, NULL,
spl_proc_rd_hw_serial,
NULL);
if (IS_ERR(spl_proc_hw_serial)) {
rc = PTR_ERR(spl_proc_hw_serial);
goto out4;
}
if ((rc = debug_init()))
RETURN(rc);
if ((rc = kmem_init()))
goto out4;
GOTO(out , rc);
if ((rc = vn_init()))
goto out4;
GOTO(out2, rc);
/* Doing address resolution in the kernel is tricky and just
* not a good idea in general. So to set the proper 'hw_serial'
* use the usermodehelper support to ask '/bin/sh' to run
* '/usr/bin/hostid' and redirect the result to /proc/spl/hostid
* for us to use. It's a horific solution but it will do.
*/
if ((rc = call_usermodehelper(sh_path, argv, envp, 1)))
goto out4;
if ((rc = proc_init()))
GOTO(out3, rc);
printk("spl: Loaded Solaris Porting Layer v%s\n", VERSION);
return 0;
if ((rc = set_hostid()))
GOTO(out4, rc = -EADDRNOTAVAIL);
CWARN("Loaded Solaris Porting Layer v%s\n", VERSION);
RETURN(rc);
out4:
if (spl_proc_hw_serial)
remove_proc_entry("hw_serial", spl_proc_root);
proc_fini();
out3:
if (spl_proc_hostid)
remove_proc_entry("hostid", spl_proc_root);
vn_fini();
out2:
if (spl_proc_debug_mask)
remove_proc_entry("debug_mask", spl_proc_root);
if (spl_proc_debug_subsys)
remove_proc_entry("debug_subsys", spl_proc_root);
kmem_fini();
out:
remove_proc_entry("spl", NULL);
debug_fini();
return rc;
printk("SPL: Failed to Load Solaris Porting Layer v%s, "
"rc = %d\n", VERSION, rc);
RETURN(rc);
}
static void spl_fini(void)
{
ENTRY;
CWARN("Unloaded Solaris Porting Layer v%s\n", VERSION);
proc_fini();
vn_fini();
kmem_fini();
debug_fini();
remove_proc_entry("hw_serial", spl_proc_root);
remove_proc_entry("hostid", spl_proc_root);
remove_proc_entry("debug_subsys", spl_proc_root);
remove_proc_entry("debug_mask", spl_proc_root);
remove_proc_entry("spl", NULL);
return;
EXIT;
}
module_init(spl_init);
+574
View File
@@ -0,0 +1,574 @@
#include <linux/proc_fs.h>
#include <linux/kmod.h>
#include <linux/uaccess.h>
#include <linux/ctype.h>
#include <linux/sysctl.h>
#include <sys/sysmacros.h>
#include <sys/kmem.h>
#include <sys/debug.h>
#include "config.h"
#ifdef DEBUG_SUBSYSTEM
#undef DEBUG_SUBSYSTEM
#endif
#define DEBUG_SUBSYSTEM S_PROC
static struct ctl_table_header *spl_header = NULL;
static unsigned long table_min = 0;
static unsigned long table_max = ~0;
#define CTL_SPL 0x87
enum {
CTL_DEBUG_SUBSYS = 1, /* Debug subsystem */
CTL_DEBUG_MASK, /* Debug mask */
CTL_DEBUG_PRINTK, /* Force all messages to console */
CTL_DEBUG_MB, /* Debug buffer size */
CTL_DEBUG_BINARY, /* Include binary data in buffer */
CTL_DEBUG_CATASTROPHE, /* Set if we have BUG'd or panic'd */
CTL_DEBUG_PANIC_ON_BUG, /* Set if we should panic on BUG */
CTL_DEBUG_PATH, /* Dump log location */
CTL_DEBUG_DUMP, /* Dump debug buffer to file */
CTL_DEBUG_FORCE_BUG, /* Hook to force a BUG */
CTL_CONSOLE_RATELIMIT, /* Ratelimit console messages */
CTL_CONSOLE_MAX_DELAY_CS, /* Max delay at which we skip messages */
CTL_CONSOLE_MIN_DELAY_CS, /* Init delay at which we skip messages */
CTL_CONSOLE_BACKOFF, /* Delay increase factor */
CTL_STACK_SIZE, /* Max observed stack size */
#ifdef DEBUG_KMEM
CTL_KMEM_KMEMUSED, /* Crrently alloc'd kmem bytes */
CTL_KMEM_KMEMMAX, /* Max alloc'd by kmem bytes */
CTL_KMEM_VMEMUSED, /* Currently alloc'd vmem bytes */
CTL_KMEM_VMEMMAX, /* Max alloc'd by vmem bytes */
#endif
CTL_HOSTID, /* Host id reported by /usr/bin/hostid */
CTL_HW_SERIAL, /* Hardware serial number from hostid */
};
static int
proc_copyin_string(char *kbuffer, int kbuffer_size,
const char *ubuffer, int ubuffer_size)
{
int size;
if (ubuffer_size > kbuffer_size)
return -EOVERFLOW;
if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
return -EFAULT;
/* strip trailing whitespace */
size = strnlen(kbuffer, ubuffer_size);
while (size-- >= 0)
if (!isspace(kbuffer[size]))
break;
/* empty string */
if (size < 0)
return -EINVAL;
/* no space to terminate */
if (size == kbuffer_size)
return -EOVERFLOW;
kbuffer[size + 1] = 0;
return 0;
}
static int
proc_copyout_string(char *ubuffer, int ubuffer_size,
const char *kbuffer, char *append)
{
/* NB if 'append' != NULL, it's a single character to append to the
* copied out string - usually "\n", for /proc entries and
* (i.e. a terminating zero byte) for sysctl entries
*/
int size = MIN(strlen(kbuffer), ubuffer_size);
if (copy_to_user(ubuffer, kbuffer, size))
return -EFAULT;
if (append != NULL && size < ubuffer_size) {
if (copy_to_user(ubuffer + size, append, 1))
return -EFAULT;
size++;
}
return size;
}
static int
proc_dobitmasks(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
unsigned long *mask = table->data;
int is_subsys = (mask == &spl_debug_subsys) ? 1 : 0;
int is_printk = (mask == &spl_debug_printk) ? 1 : 0;
int size = 512, rc;
char *str;
ENTRY;
str = kmem_alloc(size, KM_SLEEP);
if (str == NULL)
RETURN(-ENOMEM);
if (write) {
rc = proc_copyin_string(str, size, buffer, *lenp);
if (rc < 0)
RETURN(rc);
rc = spl_debug_str2mask(mask, str, is_subsys);
/* Always print BUG/ASSERT to console, so keep this mask */
if (is_printk)
*mask |= D_EMERG;
*ppos += *lenp;
} else {
rc = spl_debug_mask2str(str, size, *mask, is_subsys);
if (*ppos >= rc)
rc = 0;
else
rc = proc_copyout_string(buffer, *lenp,
str + *ppos, "\n");
if (rc >= 0) {
*lenp = rc;
*ppos += rc;
}
}
kmem_free(str, size);
RETURN(rc);
}
static int
proc_debug_mb(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
char str[32];
int rc, len;
ENTRY;
if (write) {
rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
if (rc < 0)
RETURN(rc);
rc = spl_debug_set_mb(simple_strtoul(str, NULL, 0));
*ppos += *lenp;
} else {
len = snprintf(str, sizeof(str), "%d", spl_debug_get_mb());
if (*ppos >= len)
rc = 0;
else
rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
if (rc >= 0) {
*lenp = rc;
*ppos += rc;
}
}
RETURN(rc);
}
static int
proc_dump_kernel(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
ENTRY;
if (write) {
spl_debug_dumplog();
*ppos += *lenp;
} else {
*lenp = 0;
}
RETURN(0);
}
static int
proc_force_bug(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
ENTRY;
if (write) {
CERROR("Crashing due to forced BUG\n");
BUG();
/* Unreachable */
} else {
*lenp = 0;
}
RETURN(0);
}
static int
proc_console_max_delay_cs(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int rc, max_delay_cs;
struct ctl_table dummy = *table;
long d;
ENTRY;
dummy.data = &max_delay_cs;
dummy.proc_handler = &proc_dointvec;
if (write) {
max_delay_cs = 0;
rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
if (rc < 0)
RETURN(rc);
if (max_delay_cs <= 0)
RETURN(-EINVAL);
d = (max_delay_cs * HZ) / 100;
if (d == 0 || d < spl_console_min_delay)
RETURN(-EINVAL);
spl_console_max_delay = d;
} else {
max_delay_cs = (spl_console_max_delay * 100) / HZ;
rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
}
RETURN(rc);
}
static int
proc_console_min_delay_cs(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int rc, min_delay_cs;
struct ctl_table dummy = *table;
long d;
ENTRY;
dummy.data = &min_delay_cs;
dummy.proc_handler = &proc_dointvec;
if (write) {
min_delay_cs = 0;
rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
if (rc < 0)
RETURN(rc);
if (min_delay_cs <= 0)
RETURN(-EINVAL);
d = (min_delay_cs * HZ) / 100;
if (d == 0 || d > spl_console_max_delay)
RETURN(-EINVAL);
spl_console_min_delay = d;
} else {
min_delay_cs = (spl_console_min_delay * 100) / HZ;
rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
}
RETURN(rc);
}
static int
proc_console_backoff(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int rc, backoff;
struct ctl_table dummy = *table;
ENTRY;
dummy.data = &backoff;
dummy.proc_handler = &proc_dointvec;
if (write) {
backoff = 0;
rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
if (rc < 0)
RETURN(rc);
if (backoff <= 0)
RETURN(-EINVAL);
spl_console_backoff = backoff;
} else {
backoff = spl_console_backoff;
rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
}
RETURN(rc);
}
static int
proc_doatomic64(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int rc = 0;
unsigned long min = 0, max = ~0, val;
struct ctl_table dummy = *table;
ENTRY;
dummy.data = &val;
dummy.proc_handler = &proc_dointvec;
dummy.extra1 = &min;
dummy.extra2 = &max;
if (write) {
*ppos += *lenp;
} else {
val = atomic_read((atomic64_t *)table->data);
rc = proc_doulongvec_minmax(&dummy, write, filp,
buffer, lenp, ppos);
}
RETURN(rc);
}
static int
proc_dohostid(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int len, rc = 0;
unsigned long val;
char *end, str[32];
ENTRY;
if (write) {
/* We can't use proc_doulongvec_minmax() in the write
* case hear because hostid while a hex value has no
* leading 0x which confuses the helper function. */
rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
if (rc < 0)
RETURN(rc);
val = simple_strtoul(str, &end, 16);
if (str == end)
RETURN(-EINVAL);
spl_hostid = val;
sprintf(spl_hw_serial, "%lu", ((long)val >= 0) ? val : -val);
*ppos += *lenp;
} else {
len = snprintf(str, sizeof(str), "%lx", spl_hostid);
if (*ppos >= len)
rc = 0;
else
rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
if (rc >= 0) {
*lenp = rc;
*ppos += rc;
}
}
RETURN(rc);
}
static struct ctl_table spl_table[] = {
/* NB No .strategy entries have been provided since
* sysctl(8) prefers to go via /proc for portability.
*/
{
.ctl_name = CTL_DEBUG_SUBSYS,
.procname = "debug_subsystem",
.data = &spl_debug_subsys,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = &proc_dobitmasks
},
{
.ctl_name = CTL_DEBUG_MASK,
.procname = "debug_mask",
.data = &spl_debug_mask,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = &proc_dobitmasks
},
{
.ctl_name = CTL_DEBUG_PRINTK,
.procname = "debug_printk",
.data = &spl_debug_printk,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = &proc_dobitmasks
},
{
.ctl_name = CTL_DEBUG_MB,
.procname = "debug_mb",
.mode = 0644,
.proc_handler = &proc_debug_mb,
},
{
.ctl_name = CTL_DEBUG_BINARY,
.procname = "debug_binary",
.data = &spl_debug_binary,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = CTL_DEBUG_CATASTROPHE,
.procname = "catastrophe",
.data = &spl_debug_catastrophe,
.maxlen = sizeof(int),
.mode = 0444,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = CTL_DEBUG_PANIC_ON_BUG,
.procname = "panic_on_bug",
.data = &spl_debug_panic_on_bug,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
},
{
.ctl_name = CTL_DEBUG_PATH,
.procname = "debug_path",
.data = spl_debug_file_path,
.maxlen = sizeof(spl_debug_file_path),
.mode = 0644,
.proc_handler = &proc_dostring,
},
{
.ctl_name = CTL_DEBUG_DUMP,
.procname = "debug_dump",
.mode = 0200,
.proc_handler = &proc_dump_kernel,
},
{ .ctl_name = CTL_DEBUG_FORCE_BUG,
.procname = "force_bug",
.mode = 0200,
.proc_handler = &proc_force_bug,
},
{
.ctl_name = CTL_CONSOLE_RATELIMIT,
.procname = "console_ratelimit",
.data = &spl_console_ratelimit,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = CTL_CONSOLE_MAX_DELAY_CS,
.procname = "console_max_delay_centisecs",
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_console_max_delay_cs,
},
{
.ctl_name = CTL_CONSOLE_MIN_DELAY_CS,
.procname = "console_min_delay_centisecs",
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_console_min_delay_cs,
},
{
.ctl_name = CTL_CONSOLE_BACKOFF,
.procname = "console_backoff",
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_console_backoff,
},
{
.ctl_name = CTL_STACK_SIZE,
.procname = "stack_max",
.data = &spl_debug_stack,
.maxlen = sizeof(int),
.mode = 0444,
.proc_handler = &proc_dointvec,
},
#ifdef DEBUG_KMEM
{
.ctl_name = CTL_KMEM_KMEMUSED,
.procname = "kmem_used",
.data = &kmem_alloc_used,
.maxlen = sizeof(atomic64_t),
.mode = 0444,
.proc_handler = &proc_doatomic64,
},
{
.ctl_name = CTL_KMEM_KMEMMAX,
.procname = "kmem_max",
.data = &kmem_alloc_max,
.maxlen = sizeof(unsigned long),
.extra1 = &table_min,
.extra2 = &table_max,
.mode = 0444,
.proc_handler = &proc_doulongvec_minmax,
},
{
.ctl_name = CTL_KMEM_VMEMUSED,
.procname = "vmem_used",
.data = &vmem_alloc_used,
.maxlen = sizeof(atomic64_t),
.mode = 0444,
.proc_handler = &proc_doatomic64,
},
{
.ctl_name = CTL_KMEM_VMEMMAX,
.procname = "vmem_max",
.data = &vmem_alloc_max,
.maxlen = sizeof(unsigned long),
.extra1 = &table_min,
.extra2 = &table_max,
.mode = 0444,
.proc_handler = &proc_doulongvec_minmax,
},
#endif
{
.ctl_name = CTL_HOSTID,
.procname = "hostid",
.data = &spl_hostid,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = &proc_dohostid,
},
{
.ctl_name = CTL_HW_SERIAL,
.procname = "hw_serial",
.data = spl_hw_serial,
.maxlen = sizeof(spl_hw_serial),
.mode = 0444,
.proc_handler = &proc_dostring,
},
{ 0 },
};
static struct ctl_table spl_dir_table[] = {
{
.ctl_name = CTL_SPL,
.procname = "spl",
.mode = 0555,
.child = spl_table,
},
{0}
};
int
proc_init(void)
{
ENTRY;
#ifdef CONFIG_SYSCTL
spl_header = register_sysctl_table(spl_dir_table, 0);
if (spl_header == NULL)
RETURN(-EUNATCH);
#endif
RETURN(0);
}
void
proc_fini(void)
{
ENTRY;
#ifdef CONFIG_SYSCTL
ASSERT(spl_header != NULL);
unregister_sysctl_table(spl_header);
#endif
EXIT;
}
+2 -2
View File
@@ -588,7 +588,7 @@ vn_fini(void)
rc = kmem_cache_destroy(vn_file_cache);
if (rc)
printk("spl: Warning leaked vn_file_cache objects\n");
printk("spl: Warning leaked vn_file_cache objects, %d\n", rc);
vn_file_cache = NULL;
spin_unlock(&vn_file_lock);
@@ -598,7 +598,7 @@ vn_fini(void)
rc = kmem_cache_destroy(vn_cache);
if (rc)
printk("spl: Warning leaked vn_cache objects\n");
printk("spl: Warning leaked vn_cache objects, %d\n", rc);
return;
} /* vn_fini() */