From 96dded38442684319305082aa2ac7e25f7f414da Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Wed, 20 May 2009 10:08:37 -0700 Subject: [PATCH] SLES10 Fixes (part 2): - Configure check, the div64_64() function was renamed to div64_u64() as of 2.6.26. - Configure check, the global_page_state() fuction was introduced in 2.6.18 kernels. The earlier 2.6.16 based SLES10 must not try and use it, thankfully get_zone_counts() is still available. - To simplify debugging poison all symbols aquired dynamically using spl_kallsyms_lookup_name() with SYMBOL_POISON. - Add console messages when the user mode helpers fail. - spl_kmem_init_globals() use bit shifts instead of division. - When the monotonic clock is unavailable __gethrtime() must perform the HZ division as an 'unsigned long long' because the SPL only implements __udivdi3(), and not __divdi3() for 'long long' division on 32-bit arches. --- config/spl-build.m4 | 57 ++++++++--- configure | 166 +++++++++++++++++++++++--------- configure.ac | 2 + include/linux/kallsyms_compat.h | 2 + include/sys/vmsystm.h | 4 +- module/spl/spl-generic.c | 42 +++++--- module/spl/spl-kmem.c | 24 ++--- module/spl/spl-proc.c | 2 +- module/spl/spl-time.c | 4 +- module/splat/splat-list.c | 2 +- spl_config.h.in | 6 ++ 11 files changed, 217 insertions(+), 94 deletions(-) diff --git a/config/spl-build.m4 b/config/spl-build.m4 index 76fa96ff9..ebc2721f5 100644 --- a/config/spl-build.m4 +++ b/config/spl-build.m4 @@ -706,22 +706,29 @@ AC_DEFUN([SPL_AC_INODE_I_MUTEX], [ ]) dnl # -dnl # 2.6.14 API change, -dnl # check whether 'div64_64()' is available -dnl # +dnl # 2.6.22 API change, +dnl # First introduced 'div64_64()' in lib/div64.c +dnl AC_DEFUN([SPL_AC_DIV64_64], [ - AC_MSG_CHECKING([whether div64_64() is available]) - SPL_LINUX_TRY_COMPILE([ - #include - #include - ],[ - uint64_t i = div64_64(1ULL, 1ULL); - ],[ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_DIV64_64, 1, [div64_64() is available]) - ],[ - AC_MSG_RESULT(no) - ]) + SPL_CHECK_SYMBOL_EXPORT( + [div64_64], + [], + [AC_DEFINE(HAVE_DIV64_64, 1, + [div64_64() is available])], + []) +]) + +dnl # +dnl # 2.6.26 API change, +dnl # Renamed 'div64_64()' to 'div64_u64' in lib/div64.c +dnl # +AC_DEFUN([SPL_AC_DIV64_U64], [ + SPL_CHECK_SYMBOL_EXPORT( + [div64_u64], + [], + [AC_DEFINE(HAVE_DIV64_U64, 1, + [div64_u64() is available])], + []) ]) dnl # @@ -836,6 +843,26 @@ AC_DEFUN([SPL_AC_GET_ZONE_COUNTS], [ []) ]) +dnl # +dnl # 2.6.18 API change, +dnl # First introduced global_page_state() support as an inline. +dnl # +AC_DEFUN([SPL_AC_GLOBAL_PAGE_STATE], [ + AC_MSG_CHECKING([whether global_page_state() is available]) + SPL_LINUX_TRY_COMPILE([ + #include + ],[ + unsigned long state; + state = global_page_state(NR_FREE_PAGES); + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GLOBAL_PAGE_STATE, 1, + [global_page_state() is available]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + dnl # dnl # 2.6.21 API change, dnl # Public global zone stats now include free/inactive/active page diff --git a/configure b/configure index f6f164dca..96d9d886f 100755 --- a/configure +++ b/configure @@ -20510,48 +20510,34 @@ fi - echo "$as_me:$LINENO: checking whether div64_64() is available" >&5 -echo $ECHO_N "checking whether div64_64() is available... $ECHO_C" >&6 + echo "$as_me:$LINENO: checking whether symbol div64_64 is exported" >&5 +echo $ECHO_N "checking whether symbol div64_64 is exported... $ECHO_C" >&6 + grep -q -E '[[:space:]]div64_64[[:space:]]' $LINUX_OBJ/Module.symvers 2>/dev/null + rc=$? + if test $rc -ne 0; then + export=0 + for file in ; do + grep -q -E "EXPORT_SYMBOL.*(div64_64)" "$LINUX_OBJ/$file" 2>/dev/null + rc=$? + if test $rc -eq 0; then + export=1 + break; + fi + done + if test $export -eq 0; then + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + else + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 -cat >conftest.c <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - - - #include - #include - -int -main (void) -{ - - uint64_t i = div64_64(1ULL, 1ULL); - - ; - return 0; -} - +cat >>confdefs.h <<\_ACEOF +#define HAVE_DIV64_64 1 _ACEOF - - rm -Rf build && mkdir -p build - echo "obj-m := conftest.o" >build/Makefile - if { ac_try='cp conftest.c build && make modules LINUXINCLUDE="-Iinclude -Iinclude2 -I$LINUX/include -include include/linux/autoconf.h" -o tmp_include_depends -o scripts -o include/config/MARKER -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - + fi + else echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 @@ -20559,20 +20545,46 @@ cat >>confdefs.h <<\_ACEOF #define HAVE_DIV64_64 1 _ACEOF + fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - echo "$as_me:$LINENO: result: no" >&5 + + echo "$as_me:$LINENO: checking whether symbol div64_u64 is exported" >&5 +echo $ECHO_N "checking whether symbol div64_u64 is exported... $ECHO_C" >&6 + grep -q -E '[[:space:]]div64_u64[[:space:]]' $LINUX_OBJ/Module.symvers 2>/dev/null + rc=$? + if test $rc -ne 0; then + export=0 + for file in ; do + grep -q -E "EXPORT_SYMBOL.*(div64_u64)" "$LINUX_OBJ/$file" 2>/dev/null + rc=$? + if test $rc -eq 0; then + export=1 + break; + fi + done + if test $export -eq 0; then + echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 + else + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +cat >>confdefs.h <<\_ACEOF +#define HAVE_DIV64_U64 1 +_ACEOF -fi + fi + else + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 - rm -Rf build +cat >>confdefs.h <<\_ACEOF +#define HAVE_DIV64_U64 1 +_ACEOF + fi @@ -20875,6 +20887,72 @@ _ACEOF + echo "$as_me:$LINENO: checking whether global_page_state() is available" >&5 +echo $ECHO_N "checking whether global_page_state() is available... $ECHO_C" >&6 + + +cat >conftest.c <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + + #include + +int +main (void) +{ + + unsigned long state; + state = global_page_state(NR_FREE_PAGES); + + ; + return 0; +} + +_ACEOF + + + rm -Rf build && mkdir -p build + echo "obj-m := conftest.o" >build/Makefile + if { ac_try='cp conftest.c build && make modules LINUXINCLUDE="-Iinclude -Iinclude2 -I$LINUX/include -include include/linux/autoconf.h" -o tmp_include_depends -o scripts -o include/config/MARKER -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GLOBAL_PAGE_STATE 1 +_ACEOF + + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + + + +fi + + rm -Rf build + + + + echo "$as_me:$LINENO: checking whether free/inactive/active page state is available" >&5 echo $ECHO_N "checking whether free/inactive/active page state is available... $ECHO_C" >&6 diff --git a/configure.ac b/configure.ac index b6abe7a8c..179dbc1d7 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,7 @@ SPL_AC_KMALLOC_NODE SPL_AC_MONOTONIC_CLOCK SPL_AC_INODE_I_MUTEX SPL_AC_DIV64_64 +SPL_AC_DIV64_U64 SPL_AC_3ARGS_ON_EACH_CPU SPL_AC_KALLSYMS_LOOKUP_NAME SPL_AC_GET_VMALLOC_INFO @@ -75,6 +76,7 @@ SPL_AC_FIRST_ONLINE_PGDAT SPL_AC_NEXT_ONLINE_PGDAT SPL_AC_NEXT_ZONE SPL_AC_GET_ZONE_COUNTS +SPL_AC_GLOBAL_PAGE_STATE SPL_AC_ZONE_STAT_ITEM_FIA AC_CONFIG_FILES([ diff --git a/include/linux/kallsyms_compat.h b/include/linux/kallsyms_compat.h index 82abed41d..6cd0a18de 100644 --- a/include/linux/kallsyms_compat.h +++ b/include/linux/kallsyms_compat.h @@ -1,6 +1,8 @@ #ifndef _SPL_KALLSYMS_COMPAT_H #define _SPL_KALLSYMS_COMPAT_H +#define SYMBOL_POISON ((void*)0xabcddcba) + #ifdef HAVE_KALLSYMS_LOOKUP_NAME #include diff --git a/include/sys/vmsystm.h b/include/sys/vmsystm.h index 123005e5e..71058eef8 100644 --- a/include/sys/vmsystm.h +++ b/include/sys/vmsystm.h @@ -121,15 +121,13 @@ typedef void (*get_zone_counts_t)(unsigned long *, unsigned long *, unsigned long *); extern get_zone_counts_t get_zone_counts_fn; # define get_zone_counts(a,i,f) get_zone_counts_fn(a,i,f) +# endif /* HAVE_GET_ZONE_COUNTS */ extern unsigned long spl_global_page_state(int); /* Defines designed to simulate enum but large enough to ensure no overlap */ # define NR_FREE_PAGES 0x8001 # define NR_INACTIVE 0x8002 # define NR_ACTIVE 0x8003 -# else -# error "HAVE_ZONE_STAT_ITEM_FIA and HAVE_GET_ZONE_COUNTS unavailable" -# endif /* HAVE_GET_ZONE_COUNTS */ #else #define spl_global_page_state(item) global_page_state(item) #endif /* HAVE_ZONE_STAT_ITEM_FIA */ diff --git a/module/spl/spl-generic.c b/module/spl/spl-generic.c index 76a8de472..fe6350079 100644 --- a/module/spl/spl-generic.c +++ b/module/spl/spl-generic.c @@ -55,7 +55,7 @@ int p0 = 0; EXPORT_SYMBOL(p0); #ifndef HAVE_KALLSYMS_LOOKUP_NAME -kallsyms_lookup_name_t spl_kallsyms_lookup_name_fn = NULL; +kallsyms_lookup_name_t spl_kallsyms_lookup_name_fn = SYMBOL_POISON; #endif int @@ -96,10 +96,12 @@ EXPORT_SYMBOL(highbit); #if BITS_PER_LONG == 32 uint64_t __udivdi3(uint64_t dividend, uint64_t divisor) { -#ifdef HAVE_DIV64_64 +#if defined(HAVE_DIV64_64) /* 2.6.22 - 2.6.25 API */ return div64_64(dividend, divisor); +#elif defined(HAVE_DIV64_U64) /* 2.6.26 - 2.6.x API */ + return div64_u64(dividend, divisor); #else - /* Taken from a 2.6.24 kernel. */ + /* Implementation from 2.6.30 kernel */ uint32_t high, d; high = divisor >> 32; @@ -111,10 +113,8 @@ uint64_t __udivdi3(uint64_t dividend, uint64_t divisor) } else d = divisor; - do_div(dividend, d); - - return dividend; -#endif + return do_div64(dividend, d); +#endif /* HAVE_DIV64_64, HAVE_DIV64_U64 */ } EXPORT_SYMBOL(__udivdi3); @@ -126,12 +126,12 @@ uint64_t __umoddi3(uint64_t dividend, uint64_t divisor) return dividend - divisor * (dividend / divisor); } EXPORT_SYMBOL(__umoddi3); -#endif +#endif /* BITS_PER_LONG */ /* NOTE: The strtoxx behavior is solely based on my reading of the Solaris * ddi_strtol(9F) man page. I have not verified the behavior of these * functions against their Solaris counterparts. It is possible that I - * may have misinterpretted the man page or the man page is incorrect. + * may have misinterpreted the man page or the man page is incorrect. */ int ddi_strtoul(const char *, char **, int, unsigned long *); int ddi_strtol(const char *, char **, int, long *); @@ -248,14 +248,20 @@ set_hostid(void) "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + int 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/sys/spl/hostid - * for us to use. It's a horific solution but it will do for now. + * for us to use. It's a horrific solution but it will do for now. */ - return call_usermodehelper(sh_path, argv, envp, 1); + rc = call_usermodehelper(sh_path, argv, envp, 1); + if (rc) + printk("SPL: Failed user helper '%s %s %s', rc = %d\n", + argv[0], argv[1], argv[2], rc); + + return rc; } uint32_t @@ -273,9 +279,7 @@ zone_get_hostid(void *zone) } EXPORT_SYMBOL(zone_get_hostid); -#ifdef HAVE_KALLSYMS_LOOKUP_NAME -#define set_kallsyms_lookup_name() (0) -#else +#ifndef HAVE_KALLSYMS_LOOKUP_NAME /* * Because kallsyms_lookup_name() is no longer exported in the * mainline kernel we are forced to resort to somewhat drastic @@ -303,9 +307,10 @@ set_kallsyms_lookup_name(void) rc = call_usermodehelper(sh_path, argv, envp, 1); if (rc) - return rc; + printk("SPL: Failed user helper '%s %s %s', rc = %d\n", + argv[0], argv[1], argv[2], rc); - return spl_kmem_init_kallsyms_lookup(); + return rc; } #endif @@ -337,8 +342,13 @@ static int __init spl_init(void) if ((rc = set_hostid())) GOTO(out7, rc = -EADDRNOTAVAIL); +#ifndef HAVE_KALLSYMS_LOOKUP_NAME if ((rc = set_kallsyms_lookup_name())) GOTO(out7, rc = -EADDRNOTAVAIL); +#endif /* HAVE_KALLSYMS_LOOKUP_NAME */ + + if ((rc = spl_kmem_init_kallsyms_lookup())) + GOTO(out7, rc); printk("SPL: Loaded Solaris Porting Layer v%s\n", SPL_META_VERSION); RETURN(rc); diff --git a/module/spl/spl-kmem.c b/module/spl/spl-kmem.c index 6723dcd08..706691929 100644 --- a/module/spl/spl-kmem.c +++ b/module/spl/spl-kmem.c @@ -80,29 +80,30 @@ vmem_t *zio_arena = NULL; EXPORT_SYMBOL(zio_arena); #ifndef HAVE_GET_VMALLOC_INFO -get_vmalloc_info_t get_vmalloc_info_fn = NULL; +get_vmalloc_info_t get_vmalloc_info_fn = SYMBOL_POISON; EXPORT_SYMBOL(get_vmalloc_info_fn); #endif /* HAVE_GET_VMALLOC_INFO */ #ifndef HAVE_FIRST_ONLINE_PGDAT -first_online_pgdat_t first_online_pgdat_fn = NULL; +first_online_pgdat_t first_online_pgdat_fn = SYMBOL_POISON; EXPORT_SYMBOL(first_online_pgdat_fn); #endif /* HAVE_FIRST_ONLINE_PGDAT */ #ifndef HAVE_NEXT_ONLINE_PGDAT -next_online_pgdat_t next_online_pgdat_fn = NULL; +next_online_pgdat_t next_online_pgdat_fn = SYMBOL_POISON; EXPORT_SYMBOL(next_online_pgdat_fn); #endif /* HAVE_NEXT_ONLINE_PGDAT */ #ifndef HAVE_NEXT_ZONE -next_zone_t next_zone_fn = NULL; +next_zone_t next_zone_fn = SYMBOL_POISON; EXPORT_SYMBOL(next_zone_fn); #endif /* HAVE_NEXT_ZONE */ #ifndef HAVE_ZONE_STAT_ITEM_FIA # ifndef HAVE_GET_ZONE_COUNTS -get_zone_counts_t get_zone_counts_fn = NULL; +get_zone_counts_t get_zone_counts_fn = SYMBOL_POISON; EXPORT_SYMBOL(get_zone_counts_fn); +# endif /* HAVE_GET_ZONE_COUNTS */ unsigned long spl_global_page_state(int item) @@ -126,12 +127,13 @@ spl_global_page_state(int item) return active; } +# ifdef HAVE_GLOBAL_PAGE_STATE return global_page_state((enum zone_stat_item)item); +# else + return 0; /* Unsupported */ +# endif /* HAVE_GLOBAL_PAGE_STATE */ } EXPORT_SYMBOL(spl_global_page_state); -# else -# error "HAVE_ZONE_STAT_ITEM_FIA and HAVE_GET_ZONE_COUNTS unavailable" -# endif /* HAVE_GET_ZONE_COUNTS */ #endif /* HAVE_ZONE_STAT_ITEM_FIA */ pgcnt_t @@ -1785,8 +1787,8 @@ spl_kmem_init_globals(void) } /* Solaris default values */ - swapfs_minfree = MAX(2*1024*1024 / PAGE_SIZE, physmem / 8); - swapfs_reserve = MIN(4*1024*1024 / PAGE_SIZE, physmem / 16); + swapfs_minfree = MAX(2*1024*1024 >> PAGE_SHIFT, physmem >> 3); + swapfs_reserve = MIN(4*1024*1024 >> PAGE_SHIFT, physmem >> 4); } /* @@ -1839,8 +1841,6 @@ spl_kmem_init_kallsyms_lookup(void) printk(KERN_ERR "Error: Unknown symbol get_zone_counts\n"); return -EFAULT; } -# else -# error "HAVE_ZONE_STAT_ITEM_FIA and HAVE_GET_ZONE_COUNTS unavailable" # endif /* HAVE_GET_ZONE_COUNTS */ #endif /* HAVE_ZONE_STAT_ITEM_FIA */ diff --git a/module/spl/spl-proc.c b/module/spl/spl-proc.c index 294948d81..5dd7884f6 100644 --- a/module/spl/spl-proc.c +++ b/module/spl/spl-proc.c @@ -503,7 +503,7 @@ proc_dokallsyms_lookup_name(struct ctl_table *table, int write, if (write) { /* This may only be set once at module load time */ - if (spl_kallsyms_lookup_name_fn) + if (spl_kallsyms_lookup_name_fn != SYMBOL_POISON) RETURN(-EEXIST); /* We can't use proc_doulongvec_minmax() in the write diff --git a/module/spl/spl-time.c b/module/spl/spl-time.c index 88722afe1..1e9671e83 100644 --- a/module/spl/spl-time.c +++ b/module/spl/spl-time.c @@ -60,9 +60,9 @@ __gethrtime(void) { /* Deal with signed/unsigned mismatch */ return (hrtime_t)(res & ~(1ULL << 63)); #else - int64_t j = get_jiffies_64(); + uint64_t j = get_jiffies_64(); - return j * NSEC_PER_SEC / HZ; + return (hrtime_t)(j * NSEC_PER_SEC / HZ); #endif } EXPORT_SYMBOL(__gethrtime); diff --git a/module/splat/splat-list.c b/module/splat/splat-list.c index 5a610cee4..224eaa63a 100644 --- a/module/splat/splat-list.c +++ b/module/splat/splat-list.c @@ -327,7 +327,7 @@ splat_list_test6(struct file *file, void *arg) /* Remove all odd items from the queue */ splat_vprint(file, SPLAT_LIST_TEST6_NAME, - "Removing %d odd items from the list\n", list_size / 2); + "Removing %d odd items from the list\n", list_size >> 1); for (li = list_head(&list); li != NULL; li = list_next(&list, li)) { if (li->li_data % 2 == 1) { li_prev = list_prev(&list, li); diff --git a/spl_config.h.in b/spl_config.h.in index 8cfcff5c6..4369f85b7 100644 --- a/spl_config.h.in +++ b/spl_config.h.in @@ -39,6 +39,9 @@ /* div64_64() is available */ #undef HAVE_DIV64_64 +/* div64_u64() is available */ +#undef HAVE_DIV64_U64 + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H @@ -60,6 +63,9 @@ /* get_zone_counts() is available */ #undef HAVE_GET_ZONE_COUNTS +/* global_page_state() is available */ +#undef HAVE_GLOBAL_PAGE_STATE + /* init_utsname() is available */ #undef HAVE_INIT_UTSNAME