diff --git a/acinclude.m4 b/acinclude.m4 index adc2b5ef12..36df23026c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -697,6 +697,7 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*) LINUX_EXPORTS_SYS_CLOSE LINUX_EXPORTS_SYS_OPEN LINUX_EXPORTS_SYS_WAIT4 + LINUX_EXPORTS_RCU_READ_LOCK LINUX_WHICH_MODULES if test "x$ac_cv_linux_config_modversions" = "xno" -o $AFS_SYSKVERS -ge 26; then AC_MSG_WARN([Cannot determine sys_call_table status. assuming it isn't exported]) diff --git a/src/afs/LINUX/osi_groups.c b/src/afs/LINUX/osi_groups.c index 9f1e618dcf..752057de56 100644 --- a/src/afs/LINUX/osi_groups.c +++ b/src/afs/LINUX/osi_groups.c @@ -51,12 +51,14 @@ afs_setgroups(cred_t **cr, struct group_info *group_info, int change_parent) crset(*cr); +#ifdef STRUCT_TASK_STRUCT_HAS_PARENT if (change_parent) { old_info = current->parent->group_info; get_group_info(group_info); current->parent->group_info = group_info; put_group_info(old_info); } +#endif return (0); } @@ -625,32 +627,40 @@ extern rwlock_t tasklist_lock __attribute__((weak)); void osi_keyring_init(void) { struct task_struct *p; + + /* If we can't lock the tasklist, either with its explicit lock, + * or by using the RCU lock, then we can't safely work out the + * type of a keyring. So, we have to rely on the weak reference. + * If that's not available, then keyring based PAGs won't work. + */ +#if defined(EXPORTED_TASKLIST_LOCK) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) && defined(EXPORTED_RCU_READ_LOCK)) if (__key_type_keyring == NULL) { -#ifdef EXPORTED_TASKLIST_LOCK +# ifdef EXPORTED_TASKLIST_LOCK if (&tasklist_lock) read_lock(&tasklist_lock); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) -# ifdef EXPORTED_TASKLIST_LOCK - else # endif +# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) && defined(EXPORTED_RCU_READ_LOCK)) +# ifdef EXPORTED_TASKLIST_LOCK + else +# endif rcu_read_lock(); -#endif +# endif p = find_task_by_pid(1); if (p && p->user->session_keyring) __key_type_keyring = p->user->session_keyring->type; -#ifdef EXPORTED_TASKLIST_LOCK +# ifdef EXPORTED_TASKLIST_LOCK if (&tasklist_lock) read_unlock(&tasklist_lock); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) -# ifdef EXPORTED_TASKLIST_LOCK - else # endif +# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) && defined(EXPORTED_RCU_READ_LOCK)) +# ifdef EXPORTED_TASKLIST_LOCK + else +# endif rcu_read_unlock(); -#endif +# endif } +#endif register_key_type(&key_type_afs_pag); } diff --git a/src/cf/linux-test4.m4 b/src/cf/linux-test4.m4 index 09e713dde1..448d55143b 100644 --- a/src/cf/linux-test4.m4 +++ b/src/cf/linux-test4.m4 @@ -999,3 +999,16 @@ printk("%x\n", _nd.path);], ac_cv_linux_struct_nameidata_has_path=no)]) AC_MSG_RESULT($ac_cv_linux_struct_nameidata_has_path)]) +AC_DEFUN([LINUX_EXPORTS_RCU_READ_LOCK], [ + AC_MSG_CHECKING([if rcu_read_lock is usable]) + AC_CACHE_VAL([ac_cv_linux_exports_rcu_read_lock], [ + AC_TRY_KBUILD( +[#include ], +[rcu_read_lock();], + ac_cv_linux_exports_rcu_read_lock=yes, + ac_cv_linux_exports_rcu_read_lock=no)]) + AC_MSG_RESULT($ac_cv_linux_exports_rcu_read_lock) + if test "x$ac_cv_linux_exports_rcu_read_lock" = "xyes"; then + AC_DEFINE([EXPORTED_RCU_READ_LOCK], 1, [define if rcu_read_lock() is usable]) + fi]) +