diff options
Diffstat (limited to 'modules/spl/spl-generic.c')
-rw-r--r-- | modules/spl/spl-generic.c | 356 |
1 files changed, 48 insertions, 308 deletions
diff --git a/modules/spl/spl-generic.c b/modules/spl/spl-generic.c index 8cd217cf1..252e9788d 100644 --- a/modules/spl/spl-generic.c +++ b/modules/spl/spl-generic.c @@ -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 -unsigned long spl_debug_mask = 0; -unsigned long spl_debug_subsys = 0xff; -unsigned long spl_hostid = 0; -char hw_serial[11] = "<none>"; +#define DEBUG_SUBSYSTEM S_GENERIC -EXPORT_SYMBOL(spl_debug_mask); -EXPORT_SYMBOL(spl_debug_subsys); +unsigned long spl_hostid = 0; 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) -{ - *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) +set_hostid(void) { - 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; - } - - 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; - } - - 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; - } + /* 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_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; - } +static int __init spl_init(void) +{ + int rc = 0; + ENTRY; - 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; - - /* 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; + GOTO(out2, rc); - printk("spl: Loaded Solaris Porting Layer v%s\n", VERSION); + if ((rc = proc_init())) + GOTO(out3, rc); - 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); |