]> granicus.if.org Git - zfs/blob - module/spl/spl-generic.c
Cleanly split Linux proc.h (fs) from conflicting Solaris proc.h (process)
[zfs] / module / spl / spl-generic.c
1 /*****************************************************************************\
2  *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3  *  Copyright (C) 2007 The Regents of the University of California.
4  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5  *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
6  *  UCRL-CODE-235197
7  *
8  *  This file is part of the SPL, Solaris Porting Layer.
9  *  For details, see <http://github.com/behlendorf/spl/>.
10  *
11  *  The SPL is free software; you can redistribute it and/or modify it
12  *  under the terms of the GNU General Public License as published by the
13  *  Free Software Foundation; either version 2 of the License, or (at your
14  *  option) any later version.
15  *
16  *  The SPL is distributed in the hope that it will be useful, but WITHOUT
17  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19  *  for more details.
20  *
21  *  You should have received a copy of the GNU General Public License along
22  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
23  *****************************************************************************
24  *  Solaris Porting Layer (SPL) Generic Implementation.
25 \*****************************************************************************/
26
27 #include <sys/sysmacros.h>
28 #include <sys/systeminfo.h>
29 #include <sys/vmsystm.h>
30 #include <sys/vnode.h>
31 #include <sys/kmem.h>
32 #include <sys/mutex.h>
33 #include <sys/rwlock.h>
34 #include <sys/taskq.h>
35 #include <sys/debug.h>
36 #include <sys/proc.h>
37 #include <sys/kstat.h>
38 #include <sys/utsname.h>
39 #include <sys/file.h>
40 #include <linux/kmod.h>
41 #include <linux/proc_compat.h>
42
43 #ifdef DEBUG_SUBSYSTEM
44 #undef DEBUG_SUBSYSTEM
45 #endif
46
47 #define DEBUG_SUBSYSTEM S_GENERIC
48
49 char spl_version[16] = "SPL v" SPL_META_VERSION;
50
51 long spl_hostid = 0;
52 EXPORT_SYMBOL(spl_hostid);
53
54 char hw_serial[HW_HOSTID_LEN] = "<none>";
55 EXPORT_SYMBOL(hw_serial);
56
57 proc_t p0 = { 0 };
58 EXPORT_SYMBOL(p0);
59
60 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
61 kallsyms_lookup_name_t spl_kallsyms_lookup_name_fn = SYMBOL_POISON;
62 #endif
63
64 int
65 highbit(unsigned long i)
66 {
67         register int h = 1;
68         ENTRY;
69
70         if (i == 0)
71                 RETURN(0);
72 #if BITS_PER_LONG == 64
73         if (i & 0xffffffff00000000ul) {
74                 h += 32; i >>= 32;
75         }
76 #endif
77         if (i & 0xffff0000) {
78                 h += 16; i >>= 16;
79         }
80         if (i & 0xff00) {
81                 h += 8; i >>= 8;
82         }
83         if (i & 0xf0) {
84                 h += 4; i >>= 4;
85         }
86         if (i & 0xc) {
87                 h += 2; i >>= 2;
88         }
89         if (i & 0x2) {
90                 h += 1;
91         }
92         RETURN(h);
93 }
94 EXPORT_SYMBOL(highbit);
95
96 /*
97  * Implementation of 64 bit division for 32-bit machines.
98  */
99 #if BITS_PER_LONG == 32
100 uint64_t
101 __udivdi3(uint64_t dividend, uint64_t divisor)
102 {
103 #if defined(HAVE_DIV64_64) /* 2.6.22 - 2.6.25 API */
104         return div64_64(dividend, divisor);
105 #elif defined(HAVE_DIV64_U64) /* 2.6.26 - 2.6.x API */
106         return div64_u64(dividend, divisor);
107 #else
108         /* Implementation from 2.6.30 kernel */
109         uint32_t high, d;
110
111         high = divisor >> 32;
112         if (high) {
113                 unsigned int shift = fls(high);
114
115                 d = divisor >> shift;
116                 dividend >>= shift;
117         } else
118                 d = divisor;
119
120         do_div(dividend, d);
121
122         return dividend;
123 #endif /* HAVE_DIV64_64, HAVE_DIV64_U64 */
124 }
125 EXPORT_SYMBOL(__udivdi3);
126
127 /*
128  * Implementation of 64 bit modulo for 32-bit machines.
129  */
130 uint64_t
131 __umoddi3(uint64_t dividend, uint64_t divisor)
132 {
133         return (dividend - (divisor * __udivdi3(dividend, divisor)));
134 }
135 EXPORT_SYMBOL(__umoddi3);
136 #endif /* BITS_PER_LONG */
137
138 /* NOTE: The strtoxx behavior is solely based on my reading of the Solaris
139  * ddi_strtol(9F) man page.  I have not verified the behavior of these
140  * functions against their Solaris counterparts.  It is possible that I
141  * may have misinterpreted the man page or the man page is incorrect.
142  */
143 int ddi_strtoul(const char *, char **, int, unsigned long *);
144 int ddi_strtol(const char *, char **, int, long *);
145 int ddi_strtoull(const char *, char **, int, unsigned long long *);
146 int ddi_strtoll(const char *, char **, int, long long *);
147
148 #define define_ddi_strtoux(type, valtype)                               \
149 int ddi_strtou##type(const char *str, char **endptr,                    \
150                      int base, valtype *result)                         \
151 {                                                                       \
152         valtype last_value, value = 0;                                  \
153         char *ptr = (char *)str;                                        \
154         int flag = 1, digit;                                            \
155                                                                         \
156         if (strlen(ptr) == 0)                                           \
157                 return EINVAL;                                          \
158                                                                         \
159         /* Auto-detect base based on prefix */                          \
160         if (!base) {                                                    \
161                 if (str[0] == '0') {                                    \
162                         if (tolower(str[1])=='x' && isxdigit(str[2])) { \
163                                 base = 16; /* hex */                    \
164                                 ptr += 2;                               \
165                         } else if (str[1] >= '0' && str[1] < 8) {       \
166                                 base = 8; /* octal */                   \
167                                 ptr += 1;                               \
168                         } else {                                        \
169                                 return EINVAL;                          \
170                         }                                               \
171                 } else {                                                \
172                         base = 10; /* decimal */                        \
173                 }                                                       \
174         }                                                               \
175                                                                         \
176         while (1) {                                                     \
177                 if (isdigit(*ptr))                                      \
178                         digit = *ptr - '0';                             \
179                 else if (isalpha(*ptr))                                 \
180                         digit = tolower(*ptr) - 'a' + 10;               \
181                 else                                                    \
182                         break;                                          \
183                                                                         \
184                 if (digit >= base)                                      \
185                         break;                                          \
186                                                                         \
187                 last_value = value;                                     \
188                 value = value * base + digit;                           \
189                 if (last_value > value) /* Overflow */                  \
190                         return ERANGE;                                  \
191                                                                         \
192                 flag = 1;                                               \
193                 ptr++;                                                  \
194         }                                                               \
195                                                                         \
196         if (flag)                                                       \
197                 *result = value;                                        \
198                                                                         \
199         if (endptr)                                                     \
200                 *endptr = (char *)(flag ? ptr : str);                   \
201                                                                         \
202         return 0;                                                       \
203 }                                                                       \
204
205 #define define_ddi_strtox(type, valtype)                                \
206 int ddi_strto##type(const char *str, char **endptr,                     \
207                        int base, valtype *result)                       \
208 {                                                                       \
209         int rc;                                                         \
210                                                                         \
211         if (*str == '-') {                                              \
212                 rc = ddi_strtou##type(str + 1, endptr, base, result);   \
213                 if (!rc) {                                              \
214                         if (*endptr == str + 1)                         \
215                                 *endptr = (char *)str;                  \
216                         else                                            \
217                                 *result = -*result;                     \
218                 }                                                       \
219         } else {                                                        \
220                 rc = ddi_strtou##type(str, endptr, base, result);       \
221         }                                                               \
222                                                                         \
223         return rc;                                                      \
224 }
225
226 define_ddi_strtoux(l, unsigned long)
227 define_ddi_strtox(l, long)
228 define_ddi_strtoux(ll, unsigned long long)
229 define_ddi_strtox(ll, long long)
230
231 EXPORT_SYMBOL(ddi_strtoul);
232 EXPORT_SYMBOL(ddi_strtol);
233 EXPORT_SYMBOL(ddi_strtoll);
234 EXPORT_SYMBOL(ddi_strtoull);
235
236 int
237 ddi_copyin(const void *from, void *to, size_t len, int flags)
238 {
239         /* Fake ioctl() issued by kernel, 'from' is a kernel address */
240         if (flags & FKIOCTL) {
241                 memcpy(to, from, len);
242                 return 0;
243         }
244
245         return copyin(from, to, len);
246 }
247 EXPORT_SYMBOL(ddi_copyin);
248
249 int
250 ddi_copyout(const void *from, void *to, size_t len, int flags)
251 {
252         /* Fake ioctl() issued by kernel, 'from' is a kernel address */
253         if (flags & FKIOCTL) {
254                 memcpy(to, from, len);
255                 return 0;
256         }
257
258         return copyout(from, to, len);
259 }
260 EXPORT_SYMBOL(ddi_copyout);
261
262 #ifndef HAVE_PUT_TASK_STRUCT
263 /*
264  * This is only a stub function which should never be used.  The SPL should
265  * never be putting away the last reference on a task structure so this will
266  * not be called.  However, we still need to define it so the module does not
267  * have undefined symbol at load time.  That all said if this impossible
268  * thing does somehow happen SBUG() immediately so we know about it.
269  */
270 void
271 __put_task_struct(struct task_struct *t)
272 {
273         SBUG();
274 }
275 EXPORT_SYMBOL(__put_task_struct);
276 #endif /* HAVE_PUT_TASK_STRUCT */
277
278 struct new_utsname *__utsname(void)
279 {
280 #ifdef HAVE_INIT_UTSNAME
281         return init_utsname();
282 #else
283         return &system_utsname;
284 #endif
285 }
286 EXPORT_SYMBOL(__utsname);
287
288 static int
289 set_hostid(void)
290 {
291         char sh_path[] = "/bin/sh";
292         char *argv[] = { sh_path,
293                          "-c",
294                          "/usr/bin/hostid >/proc/sys/kernel/spl/hostid",
295                          NULL };
296         char *envp[] = { "HOME=/",
297                          "TERM=linux",
298                          "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
299                          NULL };
300         int rc;
301
302         /* Doing address resolution in the kernel is tricky and just
303          * not a good idea in general.  So to set the proper 'hw_serial'
304          * use the usermodehelper support to ask '/bin/sh' to run
305          * '/usr/bin/hostid' and redirect the result to /proc/sys/spl/hostid
306          * for us to use.  It's a horrific solution but it will do for now.
307          */
308         rc = call_usermodehelper(sh_path, argv, envp, 1);
309         if (rc)
310                 printk("SPL: Failed user helper '%s %s %s', rc = %d\n",
311                        argv[0], argv[1], argv[2], rc);
312
313         return rc;
314 }
315
316 uint32_t
317 zone_get_hostid(void *zone)
318 {
319         unsigned long hostid;
320
321         /* Only the global zone is supported */
322         ASSERT(zone == NULL);
323
324         if (ddi_strtoul(hw_serial, NULL, HW_HOSTID_LEN-1, &hostid) != 0)
325                 return HW_INVALID_HOSTID;
326
327         return (uint32_t)hostid;
328 }
329 EXPORT_SYMBOL(zone_get_hostid);
330
331 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
332 /*
333  * Because kallsyms_lookup_name() is no longer exported in the
334  * mainline kernel we are forced to resort to somewhat drastic
335  * measures.  This function replaces the functionality by performing
336  * an upcall to user space where /proc/kallsyms is consulted for
337  * the requested address.
338  */
339 #define GET_KALLSYMS_ADDR_CMD                                           \
340         "awk '{ if ( $3 == \"kallsyms_lookup_name\") { print $1 } }' "  \
341         "/proc/kallsyms >/proc/sys/kernel/spl/kallsyms_lookup_name"
342
343 static int
344 set_kallsyms_lookup_name(void)
345 {
346         char sh_path[] = "/bin/sh";
347         char *argv[] = { sh_path,
348                          "-c",
349                          GET_KALLSYMS_ADDR_CMD,
350                          NULL };
351         char *envp[] = { "HOME=/",
352                          "TERM=linux",
353                          "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
354                          NULL };
355         int rc;
356
357         rc = call_usermodehelper(sh_path, argv, envp, 1);
358         if (rc)
359                 printk("SPL: Failed user helper '%s %s %s', rc = %d\n",
360                        argv[0], argv[1], argv[2], rc);
361
362         return rc;
363 }
364 #endif
365
366 static int
367 __init spl_init(void)
368 {
369         int rc = 0;
370
371         if ((rc = debug_init()))
372                 return rc;
373
374         if ((rc = spl_kmem_init()))
375                 GOTO(out1, rc);
376
377         if ((rc = spl_mutex_init()))
378                 GOTO(out2, rc);
379
380         if ((rc = spl_rw_init()))
381                 GOTO(out3, rc);
382
383         if ((rc = spl_taskq_init()))
384                 GOTO(out4, rc);
385
386         if ((rc = vn_init()))
387                 GOTO(out5, rc);
388
389         if ((rc = proc_init()))
390                 GOTO(out6, rc);
391
392         if ((rc = kstat_init()))
393                 GOTO(out7, rc);
394
395         if ((rc = set_hostid()))
396                 GOTO(out8, rc = -EADDRNOTAVAIL);
397
398 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
399         if ((rc = set_kallsyms_lookup_name()))
400                 GOTO(out8, rc = -EADDRNOTAVAIL);
401 #endif /* HAVE_KALLSYMS_LOOKUP_NAME */
402
403         if ((rc = spl_kmem_init_kallsyms_lookup()))
404                 GOTO(out8, rc);
405
406         printk("SPL: Loaded Solaris Porting Layer v%s\n", SPL_META_VERSION);
407         RETURN(rc);
408 out8:
409         kstat_fini();
410 out7:
411         proc_fini();
412 out6:
413         vn_fini();
414 out5:
415         spl_taskq_fini();
416 out4:
417         spl_rw_fini();
418 out3:
419         spl_mutex_fini();
420 out2:
421         spl_kmem_fini();
422 out1:
423         debug_fini();
424
425         printk("SPL: Failed to Load Solaris Porting Layer v%s, "
426                "rc = %d\n", SPL_META_VERSION, rc);
427         return rc;
428 }
429
430 static void
431 spl_fini(void)
432 {
433         ENTRY;
434
435         printk("SPL: Unloaded Solaris Porting Layer v%s\n", SPL_META_VERSION);
436         kstat_fini();
437         proc_fini();
438         vn_fini();
439         spl_taskq_fini();
440         spl_rw_fini();
441         spl_mutex_fini();
442         spl_kmem_fini();
443         debug_fini();
444 }
445
446 /* Called when a dependent module is loaded */
447 void
448 spl_setup(void)
449 {
450         int rc;
451
452         /*
453          * At module load time the pwd is set to '/' on a Solaris system.
454          * On a Linux system will be set to whatever directory the caller
455          * was in when executing insmod/modprobe.
456          */
457         rc = vn_set_pwd("/");
458         if (rc)
459                 printk("SPL: Warning unable to set pwd to '/': %d\n", rc);
460 }
461 EXPORT_SYMBOL(spl_setup);
462
463 /* Called when a dependent module is unloaded */
464 void
465 spl_cleanup(void)
466 {
467 }
468 EXPORT_SYMBOL(spl_cleanup);
469
470 module_init(spl_init);
471 module_exit(spl_fini);
472
473 MODULE_AUTHOR("Lawrence Livermore National Labs");
474 MODULE_DESCRIPTION("Solaris Porting Layer");
475 MODULE_LICENSE("GPL");