#include #include #include #include #include #include #include "config.h" /* * Generic support */ static char spl_debug_buffer[MAXMSGLEN]; static spinlock_t spl_debug_lock = SPIN_LOCK_UNLOCKED; unsigned long spl_debug_mask = 0; unsigned long spl_debug_subsys = 0xff; EXPORT_SYMBOL(spl_debug_mask); EXPORT_SYMBOL(spl_debug_subsys); 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; int p0 = 0; EXPORT_SYMBOL(p0); char hw_serial[11]; EXPORT_SYMBOL(hw_serial); vmem_t *zio_alloc_arena = NULL; EXPORT_SYMBOL(zio_alloc_arena); int highbit(unsigned long i) { register int h = 1; if (i == 0) return (0); #if BITS_PER_LONG == 64 if (i & 0xffffffff00000000ul) { h += 32; i >>= 32; } #endif if (i & 0xffff0000) { h += 16; i >>= 16; } if (i & 0xff00) { h += 8; i >>= 8; } if (i & 0xf0) { h += 4; i >>= 4; } if (i & 0xc) { h += 2; i >>= 2; } if (i & 0x2) { h += 1; } return (h); } EXPORT_SYMBOL(highbit); int ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result) { char *end; return (*result = simple_strtoul(str, &end, base)); } 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, *start, *ptr; struct timeval tv; unsigned long flags; va_list ap; start = ptr = spl_debug_buffer; 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); ptr += snprintf(ptr, MAXMSGLEN - 1, "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); ptr += vsnprintf(ptr, MAXMSGLEN - (ptr - start) - 1, fmt, ap); va_end(ap); printk("%s", start); 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) { int rc; *start = page; *eof = 1; if (off || count > PAGE_SIZE) return 0; spin_lock(&spl_debug_lock); rc = snprintf(page, PAGE_SIZE, "0x%lx\n", val); spin_unlock(&spl_debug_lock); return rc; } static int spl_proc_rd_debug_mask(char *page, char **start, off_t off, int count, int *eof, void *data) { return spl_proc_rd_generic_ul(page, start, off, count, eof, spl_debug_mask); } static int spl_proc_rd_debug_subsys(char *page, char **start, off_t off, int count, int *eof, void *data) { return spl_proc_rd_generic_ul(page, start, off, count, eof, spl_debug_subsys); } 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 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; 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; } if ((rc = kmem_init())) goto out2; if ((rc = vn_init())) goto out2; strcpy(hw_serial, "007f0100"); /* loopback */ printk("spl: Loaded Solaris Porting Layer v%s\n", VERSION); return 0; 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); out: remove_proc_entry("spl", NULL); return rc; } static void spl_fini(void) { vn_fini(); kmem_fini(); remove_proc_entry("debug_subsys", spl_proc_root); remove_proc_entry("debug_mask", spl_proc_root); remove_proc_entry("spl", NULL); return; } module_init(spl_init); module_exit(spl_fini); MODULE_AUTHOR("Lawrence Livermore National Labs"); MODULE_DESCRIPTION("Solaris Porting Layer"); MODULE_LICENSE("GPL");