]> git.proxmox.com Git - mirror_spl-debian.git/blame - modules/spl/spl-generic.c
* modules/spl/spl-kmem.c : Make sure to disable interrupts
[mirror_spl-debian.git] / modules / spl / spl-generic.c
CommitLineData
14c5326c 1#include <sys/sysmacros.h>
af828292 2#include <sys/vmsystm.h>
3#include <sys/vnode.h>
c19c06f3 4#include <sys/kmem.h>
8d0f1ee9 5#include <sys/debug.h>
6#include <linux/proc_fs.h>
f23e92fa 7#include <linux/kmod.h>
70eadc19 8#include "config.h"
f1b59d26 9
10/*
11 * Generic support
12 */
d61e12af 13static char spl_debug_buffer1[1024];
14static char spl_debug_buffer2[1024];
8d0f1ee9 15static spinlock_t spl_debug_lock = SPIN_LOCK_UNLOCKED;
16
17unsigned long spl_debug_mask = 0;
18unsigned long spl_debug_subsys = 0xff;
f23e92fa 19unsigned long spl_hostid = 0;
20char hw_serial[11] = "<none>";
21
8d0f1ee9 22EXPORT_SYMBOL(spl_debug_mask);
23EXPORT_SYMBOL(spl_debug_subsys);
f23e92fa 24EXPORT_SYMBOL(spl_hostid);
25EXPORT_SYMBOL(hw_serial);
8d0f1ee9 26
27static struct proc_dir_entry *spl_proc_root = NULL;
28static struct proc_dir_entry *spl_proc_debug_mask = NULL;
29static struct proc_dir_entry *spl_proc_debug_subsys = NULL;
f23e92fa 30static struct proc_dir_entry *spl_proc_hostid = NULL;
31static struct proc_dir_entry *spl_proc_hw_serial = NULL;
f1b59d26 32
33int p0 = 0;
34EXPORT_SYMBOL(p0);
70eadc19 35
af828292 36vmem_t *zio_alloc_arena = NULL;
37EXPORT_SYMBOL(zio_alloc_arena);
38
8d0f1ee9 39
77b1fe8f 40int
41highbit(unsigned long i)
42{
43 register int h = 1;
44
45 if (i == 0)
46 return (0);
47#if BITS_PER_LONG == 64
48 if (i & 0xffffffff00000000ul) {
49 h += 32; i >>= 32;
50 }
51#endif
52 if (i & 0xffff0000) {
53 h += 16; i >>= 16;
54 }
55 if (i & 0xff00) {
56 h += 8; i >>= 8;
57 }
58 if (i & 0xf0) {
59 h += 4; i >>= 4;
60 }
61 if (i & 0xc) {
62 h += 2; i >>= 2;
63 }
64 if (i & 0x2) {
65 h += 1;
66 }
67 return (h);
68}
69EXPORT_SYMBOL(highbit);
70
2f5d55aa 71int
72ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
73{
74 char *end;
75 return (*result = simple_strtoul(str, &end, base));
76}
77EXPORT_SYMBOL(ddi_strtoul);
78
8d0f1ee9 79/* XXX: Not the most efficient debug function ever. This should be re-done
80 * as an internal per-cpu in-memory debug log accessable via /proc/. Not as
81 * a shared global buffer everything gets serialize though. That said I'll
82 * worry about performance considerations once I've dealt with correctness.
83 */
84void
85__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
86{
d61e12af 87 char *sfp;
8d0f1ee9 88 struct timeval tv;
0a6fd143 89 unsigned long flags;
8d0f1ee9 90 va_list ap;
91
8d0f1ee9 92 sfp = strrchr(file, '/');
93 do_gettimeofday(&tv);
94
0a6fd143 95 /* XXX: This is particularly bad for performance, but we need to
96 * disable irqs here or two __dprintf()'s may deadlock on each
97 * other if one if called from an irq handler. This is yet another
98 * reason why we really, really, need an internal debug log.
99 */
100 spin_lock_irqsave(&spl_debug_lock, flags);
d61e12af 101 memset(spl_debug_buffer1, 0, 1024);
102 memset(spl_debug_buffer2, 0, 1024);
103
104 snprintf(spl_debug_buffer1, 1023,
105 "spl: %lu.%06lu:%d:%u:%s:%d:%s(): ",
106 tv.tv_sec, tv.tv_usec, current->pid,
107 smp_processor_id(),
108 sfp == NULL ? file : sfp + 1,
109 line, func);
8d0f1ee9 110
111 va_start(ap, fmt);
d61e12af 112 vsnprintf(spl_debug_buffer2, 1023, fmt, ap);
8d0f1ee9 113 va_end(ap);
114
d61e12af 115 printk("%s%s", spl_debug_buffer1, spl_debug_buffer2);
0a6fd143 116 spin_unlock_irqrestore(&spl_debug_lock, flags);
8d0f1ee9 117}
118EXPORT_SYMBOL(__dprintf);
119
120static int
121spl_proc_rd_generic_ul(char *page, char **start, off_t off,
122 int count, int *eof, unsigned long val)
70eadc19 123{
8d0f1ee9 124 *start = page;
125 *eof = 1;
126
127 if (off || count > PAGE_SIZE)
128 return 0;
129
f23e92fa 130 return snprintf(page, PAGE_SIZE, "0x%lx\n", val & 0xffffffff);
8d0f1ee9 131}
132
133static int
134spl_proc_rd_debug_mask(char *page, char **start, off_t off,
135 int count, int *eof, void *data)
136{
f23e92fa 137 int rc;
138
139 spin_lock(&spl_debug_lock);
140 rc = spl_proc_rd_generic_ul(page, start, off, count,
141 eof, spl_debug_mask);
142 spin_unlock(&spl_debug_lock);
143
144 return rc;
8d0f1ee9 145}
146
147static int
148spl_proc_rd_debug_subsys(char *page, char **start, off_t off,
149 int count, int *eof, void *data)
150{
f23e92fa 151 int rc;
152
153 spin_lock(&spl_debug_lock);
154 rc = spl_proc_rd_generic_ul(page, start, off, count,
155 eof, spl_debug_subsys);
156 spin_unlock(&spl_debug_lock);
157
158 return rc;
159}
160
161static int
162spl_proc_rd_hostid(char *page, char **start, off_t off,
163 int count, int *eof, void *data)
164{
165 *start = page;
166 *eof = 1;
167
168 if (off || count > PAGE_SIZE)
169 return 0;
170
171 return snprintf(page, PAGE_SIZE, "%lx\n", spl_hostid & 0xffffffff);
172}
173
174static int
175spl_proc_rd_hw_serial(char *page, char **start, off_t off,
176 int count, int *eof, void *data)
177{
178 *start = page;
179 *eof = 1;
180
181 if (off || count > PAGE_SIZE)
182 return 0;
183
184 strncpy(page, hw_serial, 11);
185 return strlen(page);
8d0f1ee9 186}
187
188static int
189spl_proc_wr_generic_ul(const char *ubuf, unsigned long count,
190 unsigned long *val, int base)
191{
192 char *end, kbuf[32];
193
194 if (count >= sizeof(kbuf))
195 return -EOVERFLOW;
196
197 if (copy_from_user(kbuf, ubuf, count))
198 return -EFAULT;
199
200 kbuf[count] = '\0';
201 *val = (int)simple_strtoul(kbuf, &end, base);
202 if (kbuf == end)
203 return -EINVAL;
204
205 return 0;
206}
207
208static int
209spl_proc_wr_debug_mask(struct file *file, const char *ubuf,
210 unsigned long count, void *data, int mode)
211{
212 unsigned long val;
213 int rc;
214
215 rc = spl_proc_wr_generic_ul(ubuf, count, &val, 16);
216 if (rc)
5d86345d 217 return rc;
218
8d0f1ee9 219 spin_lock(&spl_debug_lock);
220 spl_debug_mask = val;
221 spin_unlock(&spl_debug_lock);
222
223 return count;
224}
225
226static int
227spl_proc_wr_debug_subsys(struct file *file, const char *ubuf,
228 unsigned long count, void *data, int mode)
229{
230 unsigned long val;
231 int rc;
232
233 rc = spl_proc_wr_generic_ul(ubuf, count, &val, 16);
234 if (rc)
af828292 235 return rc;
236
8d0f1ee9 237 spin_lock(&spl_debug_lock);
238 spl_debug_subsys = val;
239 spin_unlock(&spl_debug_lock);
240
241 return count;
242}
243
f23e92fa 244static int
245spl_proc_wr_hostid(struct file *file, const char *ubuf,
246 unsigned long count, void *data, int mode)
247{
248 unsigned long val;
249 int rc;
250
251 rc = spl_proc_wr_generic_ul(ubuf, count, &val, 16);
252 if (rc)
253 return rc;
254
255 spl_hostid = val;
256 sprintf(hw_serial, "%lu\n", ((long)val >= 0) ? val : -val);
257
258 return count;
259}
260
8d0f1ee9 261static struct proc_dir_entry *
262spl_register_proc_entry(const char *name, mode_t mode,
263 struct proc_dir_entry *parent, void *data,
264 void *read_proc, void *write_proc)
265{
266 struct proc_dir_entry *entry;
267
268 entry = create_proc_entry(name, mode, parent);
269 if (!entry)
270 return ERR_PTR(-EINVAL);
271
272 entry->data = data;
273 entry->read_proc = read_proc;
274 entry->write_proc = write_proc;
275
276 return entry;
277} /* register_proc_entry() */
278
279void spl_set_debug_mask(unsigned long mask) {
280 spin_lock(&spl_debug_lock);
281 spl_debug_mask = mask;
282 spin_unlock(&spl_debug_lock);
283}
284EXPORT_SYMBOL(spl_set_debug_mask);
285
286void spl_set_debug_subsys(unsigned long mask) {
287 spin_lock(&spl_debug_lock);
288 spl_debug_subsys = mask;
289 spin_unlock(&spl_debug_lock);
290}
291EXPORT_SYMBOL(spl_set_debug_subsys);
292
293static int __init spl_init(void)
294{
295 int rc = 0;
f23e92fa 296 char sh_path[] = "/bin/sh";
297 char *argv[] = { sh_path,
298 "-c",
299 "/usr/bin/hostid >/proc/spl/hostid",
300 NULL };
301 char *envp[] = { "HOME=/",
302 "TERM=linux",
303 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
304 NULL };
8d0f1ee9 305
306 spl_proc_root = proc_mkdir("spl", NULL);
307 if (!spl_proc_root) {
308 printk("spl: Error unable to create /proc/spl/ directory\n");
309 return -EINVAL;
310 }
311
312 spl_proc_debug_mask = spl_register_proc_entry("debug_mask", 0644,
313 spl_proc_root, NULL,
314 spl_proc_rd_debug_mask,
315 spl_proc_wr_debug_mask);
316 if (IS_ERR(spl_proc_debug_mask)) {
317 rc = PTR_ERR(spl_proc_debug_mask);
318 goto out;
319 }
320
321 spl_proc_debug_subsys = spl_register_proc_entry("debug_subsys", 0644,
322 spl_proc_root, NULL,
323 spl_proc_rd_debug_subsys,
324 spl_proc_wr_debug_subsys);
325 if (IS_ERR(spl_proc_debug_subsys)) {
326 rc = PTR_ERR(spl_proc_debug_subsys);
327 goto out2;
328 }
329
f23e92fa 330 spl_proc_hostid = spl_register_proc_entry("hostid", 0644,
331 spl_proc_root, NULL,
332 spl_proc_rd_hostid,
333 spl_proc_wr_hostid);
334 if (IS_ERR(spl_proc_hostid)) {
335 rc = PTR_ERR(spl_proc_hostid);
336 goto out3;
337 }
338
339 spl_proc_hw_serial = spl_register_proc_entry("hw_serial", 0444,
340 spl_proc_root, NULL,
341 spl_proc_rd_hw_serial,
342 NULL);
343 if (IS_ERR(spl_proc_hw_serial)) {
344 rc = PTR_ERR(spl_proc_hw_serial);
345 goto out4;
346 }
347
8d0f1ee9 348 if ((rc = kmem_init()))
f23e92fa 349 goto out4;
8d0f1ee9 350
351 if ((rc = vn_init()))
f23e92fa 352 goto out4;
353
354 /* Doing address resolution in the kernel is tricky and just
355 * not a good idea in general. So to set the proper 'hw_serial'
356 * use the usermodehelper support to ask '/bin/sh' to run
357 * '/usr/bin/hostid' and redirect the result to /proc/spl/hostid
358 * for us to use. It's a horific solution but it will do.
359 */
360 if ((rc = call_usermodehelper(sh_path, argv, envp, 1)))
361 goto out4;
8d0f1ee9 362
8d0f1ee9 363 printk("spl: Loaded Solaris Porting Layer v%s\n", VERSION);
af828292 364
70eadc19 365 return 0;
f23e92fa 366
367out4:
368 if (spl_proc_hw_serial)
369 remove_proc_entry("hw_serial", spl_proc_root);
370out3:
371 if (spl_proc_hostid)
372 remove_proc_entry("hostid", spl_proc_root);
8d0f1ee9 373out2:
374 if (spl_proc_debug_mask)
375 remove_proc_entry("debug_mask", spl_proc_root);
376
377 if (spl_proc_debug_subsys)
378 remove_proc_entry("debug_subsys", spl_proc_root);
379out:
380 remove_proc_entry("spl", NULL);
381
382 return rc;
70eadc19 383}
384
385static void spl_fini(void)
386{
af828292 387 vn_fini();
e4f1d29f 388 kmem_fini();
c19c06f3 389
f23e92fa 390 remove_proc_entry("hw_serial", spl_proc_root);
391 remove_proc_entry("hostid", spl_proc_root);
8d0f1ee9 392 remove_proc_entry("debug_subsys", spl_proc_root);
393 remove_proc_entry("debug_mask", spl_proc_root);
394 remove_proc_entry("spl", NULL);
395
70eadc19 396 return;
397}
398
399module_init(spl_init);
400module_exit(spl_fini);
401
402MODULE_AUTHOR("Lawrence Livermore National Labs");
403MODULE_DESCRIPTION("Solaris Porting Layer");
404MODULE_LICENSE("GPL");