Skip to content

Commit

Permalink
Workaround for Linux PowerPC GPL-only cpu_has_feature()
Browse files Browse the repository at this point in the history
Linux since 4.7 makes interface 'cpu_has_feature' to use jump labels on
powerpc if CONFIG_JUMP_LABEL_FEATURE_CHECKS is enabled, in this case however
this inline function references GPL-only symbol 'cpu_feature_keys'.

ZFS currently uses 'cpu_has_feature' either directly or indirectly from
several places; while it is unknown how this issue didn't break ZFS on 64-bit
little-endian powerpc, it is known to break ZFS with many Linux versions on
both 32-bit and 64-bit big-endian powerpc.

Until this issue is fixed in Linux, we have to workaround it by providing our
own version of the inline function without using jump labels.

Signed-off-by: WHR <msl0000023508@gmail.com>
  • Loading branch information
Low-power committed Mar 7, 2023
1 parent 620a977 commit aa96b32
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 0 deletions.
29 changes: 29 additions & 0 deletions config/kernel-cpu_has_feature.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
dnl #
dnl # cpu_has_feature() may referencing GPL-only cpu_feature_keys on powerpc
dnl #

dnl #
dnl # Checking if cpu_has_feature is exported GPL-only
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE], [
ZFS_LINUX_TEST_SRC([cpu_has_feature], [
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
#include <asm/cpu_has_feature.h>
#else
#include <asm/cputable.h>
#endif
], [
return cpu_has_feature(CPU_FTR_ALTIVEC) ? 0 : 1;
], [], [ZFS_META_LICENSE])
])
AC_DEFUN([ZFS_AC_KERNEL_CPU_HAS_FEATURE], [
AC_MSG_CHECKING([whether cpu_has_feature() is GPL-only])
ZFS_LINUX_TEST_RESULT([cpu_has_feature_license], [
AC_MSG_RESULT(no)
], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_CPU_HAS_FEATURE_GPL_ONLY, 1,
[cpu_has_feature() is GPL-only])
])
])
10 changes: 10 additions & 0 deletions config/kernel.m4
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_IDMAP_MNT_API
ZFS_AC_KERNEL_SRC_IATTR_VFSID
ZFS_AC_KERNEL_SRC_FILEMAP
case "$host_cpu" in
powerpc*)
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
;;
esac
AC_MSG_CHECKING([for available kernel interfaces])
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
Expand Down Expand Up @@ -275,6 +280,11 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_IDMAP_MNT_API
ZFS_AC_KERNEL_IATTR_VFSID
ZFS_AC_KERNEL_FILEMAP
case "$host_cpu" in
powerpc*)
ZFS_AC_KERNEL_CPU_HAS_FEATURE
;;
esac
])

dnl #
Expand Down
34 changes: 34 additions & 0 deletions include/os/linux/kernel/linux/powerpc_cpu_has_feature_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0 */

#if defined __powerpc__ && defined CONFIG_JUMP_LABEL_FEATURE_CHECKS && \
defined HAVE_CPU_HAS_FEATURE_GPL_ONLY
/*
* Linux 4.7 makes cpu_has_feature to use jump labels on powerpc if
* CONFIG_JUMP_LABEL_FEATURE_CHECKS is enabled, in this case however it
* references GPL-only symbol cpu_feature_keys. Therefore we overrides this
* interface when it is detected being GPL-only.
*/

#ifndef __ASM_POWERPC_CPU_HAS_FEATURE_H
#define __ASM_POWERPC_CPU_HAS_FEATURE_H

#ifndef __ASSEMBLY__

#include <asm/cputable.h>

static __always_inline bool early_cpu_has_feature(unsigned long feature)
{
return (!!((CPU_FTRS_ALWAYS & feature) ||
(CPU_FTRS_POSSIBLE & cur_cpu_spec->cpu_features & feature)));
}

static __always_inline bool cpu_has_feature(unsigned long feature)
{
return (early_cpu_has_feature(feature));
}

#endif /* __ASSEMBLY__ */

#endif /* __ASM_POWERPC_CPU_HAS_FEATURE_H */

#endif
4 changes: 4 additions & 0 deletions module/icp/algs/sha2/sha256_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
* Copyright (c) 2022 Tino Reichardt <milky-zfs@mcmilk.de>
*/

#if defined(__linux__) && defined(__powerpc__)
#include <linux/powerpc_cpu_has_feature_compat.h>
#endif

#include <sys/zfs_context.h>
#include <sys/zfs_impl.h>
#include <sys/sha2.h>
Expand Down
4 changes: 4 additions & 0 deletions module/icp/algs/sha2/sha512_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
* Copyright (c) 2022 Tino Reichardt <milky-zfs@mcmilk.de>
*/

#if defined(__linux__) && defined(__powerpc__)
#include <linux/powerpc_cpu_has_feature_compat.h>
#endif

#include <sys/zfs_context.h>
#include <sys/zfs_impl.h>
#include <sys/sha2.h>
Expand Down
3 changes: 3 additions & 0 deletions module/os/linux/zfs/zfs_vnops_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
/* Portions Copyright 2007 Jeremy Teo */
/* Portions Copyright 2010 Robert Milkowski */

#ifdef __powerpc__
#include <linux/powerpc_cpu_has_feature_compat.h>
#endif

#include <sys/types.h>
#include <sys/param.h>
Expand Down
3 changes: 3 additions & 0 deletions module/os/linux/zfs/zfs_znode.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
/* Portions Copyright 2007 Jeremy Teo */

#ifdef _KERNEL
#ifdef __powerpc__
#include <linux/powerpc_cpu_has_feature_compat.h>
#endif
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
Expand Down
4 changes: 4 additions & 0 deletions module/zfs/vdev_raidz_math_powerpc_altivec.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
#if defined(__powerpc__)
#pragma GCC target("altivec")

#ifdef __linux__
#include <linux/powerpc_cpu_has_feature_compat.h>
#endif

#include "vdev_raidz_math_powerpc_altivec_common.h"

#define SYN_STRIDE 4
Expand Down

0 comments on commit aa96b32

Please sign in to comment.