Merge tag 'mm-nonmm-stable-2026-04-15-04-20' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull non-MM updates from Andrew Morton:

 - "pid: make sub-init creation retryable" (Oleg Nesterov)

   Make creation of init in a new namespace more robust by clearing away
   some historical cruft which is no longer needed. Also some
   documentation fixups

 - "selftests/fchmodat2: Error handling and general" (Mark Brown)

   Fix and a cleanup for the fchmodat2() syscall selftest

 - "lib: polynomial: Move to math/ and clean up" (Andy Shevchenko)

 - "hung_task: Provide runtime reset interface for hung task detector"
   (Aaron Tomlin)

   Give administrators the ability to zero out
   /proc/sys/kernel/hung_task_detect_count

 - "tools/getdelays: use the static UAPI headers from
   tools/include/uapi" (Thomas Weißschuh)

   Teach getdelays to use the in-kernel UAPI headers rather than the
   system-provided ones

 - "watchdog/hardlockup: Improvements to hardlockup" (Mayank Rungta)

   Several cleanups and fixups to the hardlockup detector code and its
   documentation

 - "lib/bch: fix undefined behavior from signed left-shifts" (Josh Law)

   A couple of small/theoretical fixes in the bch code

 - "ocfs2/dlm: fix two bugs in dlm_match_regions()" (Junrui Luo)

 - "cleanup the RAID5 XOR library" (Christoph Hellwig)

   A quite far-reaching cleanup to this code. I can't do better than to
   quote Christoph:

     "The XOR library used for the RAID5 parity is a bit of a mess right
      now. The main file sits in crypto/ despite not being cryptography
      and not using the crypto API, with the generic implementations
      sitting in include/asm-generic and the arch implementations
      sitting in an asm/ header in theory. The latter doesn't work for
      many cases, so architectures often build the code directly into
      the core kernel, or create another module for the architecture
      code.

      Change this to a single module in lib/ that also contains the
      architecture optimizations, similar to the library work Eric
      Biggers has done for the CRC and crypto libraries later. After
      that it changes to better calling conventions that allow for
      smarter architecture implementations (although none is contained
      here yet), and uses static_call to avoid indirection function call
      overhead"

 - "lib/list_sort: Clean up list_sort() scheduling workarounds"
   (Kuan-Wei Chiu)

   Clean up this library code by removing a hacky thing which was added
   for UBIFS, which UBIFS doesn't actually need

 - "Fix bugs in extract_iter_to_sg()" (Christian Ehrhardt)

   Fix a few bugs in the scatterlist code, add in-kernel tests for the
   now-fixed bugs and fix a leak in the test itself

 - "kdump: Enable LUKS-encrypted dump target support in ARM64 and
   PowerPC" (Coiby Xu)

   Enable support of the LUKS-encrypted device dump target on arm64 and
   powerpc

 - "ocfs2: consolidate extent list validation into block read callbacks"
   (Joseph Qi)

   Cleanup, simplify, and make more robust ocfs2's validation of extent
   list fields (Kernel test robot loves mounting corrupted fs images!)

* tag 'mm-nonmm-stable-2026-04-15-04-20' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (127 commits)
  ocfs2: validate group add input before caching
  ocfs2: validate bg_bits during freefrag scan
  ocfs2: fix listxattr handling when the buffer is full
  doc: watchdog: fix typos etc
  update Sean's email address
  ocfs2: use get_random_u32() where appropriate
  ocfs2: split transactions in dio completion to avoid credit exhaustion
  ocfs2: remove redundant l_next_free_rec check in __ocfs2_find_path()
  ocfs2: validate extent block list fields during block read
  ocfs2: remove empty extent list check in ocfs2_dx_dir_lookup_rec()
  ocfs2: validate dx_root extent list fields during block read
  ocfs2: fix use-after-free in ocfs2_fault() when VM_FAULT_RETRY
  ocfs2: handle invalid dinode in ocfs2_group_extend
  .get_maintainer.ignore: add Askar
  ocfs2: validate bg_list extent bounds in discontig groups
  checkpatch: exclude forward declarations of const structs
  tools/accounting: handle truncated taskstats netlink messages
  taskstats: set version in TGID exit notifications
  ocfs2/heartbeat: fix slot mapping rollback leaks on error paths
  arm64,ppc64le/kdump: pass dm-crypt keys to kdump kernel
  ...
This commit is contained in:
Linus Torvalds
2026-04-16 20:11:56 -07:00
155 changed files with 3528 additions and 2708 deletions

View File

@@ -309,7 +309,10 @@ Gokul Sriram Palanisamy <quic_gokulsri@quicinc.com> <gokulsri@codeaurora.org>
Govindaraj Saminathan <quic_gsamin@quicinc.com> <gsamin@codeaurora.org> Govindaraj Saminathan <quic_gsamin@quicinc.com> <gsamin@codeaurora.org>
Guo Ren <guoren@kernel.org> <guoren@linux.alibaba.com> Guo Ren <guoren@kernel.org> <guoren@linux.alibaba.com>
Guo Ren <guoren@kernel.org> <ren_guo@c-sky.com> Guo Ren <guoren@kernel.org> <ren_guo@c-sky.com>
Guru Das Srinagesh <quic_gurus@quicinc.com> <gurus@codeaurora.org> Guru Das Srinagesh <linux@gurudas.dev>
Guru Das Srinagesh <linux@gurudas.dev> <quic_gurus@quicinc.com>
Guru Das Srinagesh <linux@gurudas.dev> <gurus@codeaurora.org>
Guru Das Srinagesh <linux@gurudas.dev> <gurooodas@gmail.com>
Gustavo Padovan <gustavo@las.ic.unicamp.br> Gustavo Padovan <gustavo@las.ic.unicamp.br>
Gustavo Padovan <padovan@profusion.mobi> Gustavo Padovan <padovan@profusion.mobi>
Hamza Mahfooz <hamzamahfooz@linux.microsoft.com> <hamza.mahfooz@amd.com> Hamza Mahfooz <hamzamahfooz@linux.microsoft.com> <hamza.mahfooz@amd.com>
@@ -743,6 +746,7 @@ Sathishkumar Muruganandam <quic_murugana@quicinc.com> <murugana@codeaurora.org>
Satya Priya <quic_skakitap@quicinc.com> <quic_c_skakit@quicinc.com> <skakit@codeaurora.org> Satya Priya <quic_skakitap@quicinc.com> <quic_c_skakit@quicinc.com> <skakit@codeaurora.org>
S.Çağlar Onur <caglar@pardus.org.tr> S.Çağlar Onur <caglar@pardus.org.tr>
Sayali Lokhande <quic_sayalil@quicinc.com> <sayalil@codeaurora.org> Sayali Lokhande <quic_sayalil@quicinc.com> <sayalil@codeaurora.org>
Sean Anderson <sean.anderson@linux.dev> <sean.anderson@seco.com>
Sean Christopherson <seanjc@google.com> <sean.j.christopherson@intel.com> Sean Christopherson <seanjc@google.com> <sean.j.christopherson@intel.com>
Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk> Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
Sean Tranchetti <quic_stranche@quicinc.com> <stranche@codeaurora.org> Sean Tranchetti <quic_stranche@quicinc.com> <stranche@codeaurora.org>

View File

@@ -4570,8 +4570,5 @@ D: MD driver
D: EISA/sysfs subsystem D: EISA/sysfs subsystem
S: France S: France
# Don't add your name here, unless you really _are_ after Marc # Don't add your name here unless you really are last alphabetically.
# alphabetically. Leonard used to be very proud of being the # (This file is supposed to be kept in alphabetical order by last name.)
# last entry, and he'll get positively pissed if he can't even
# be second-to-last. (and this file really _is_ supposed to be
# in alphabetic order)

View File

@@ -16,7 +16,7 @@ details), and a compile option, "BOOTPARAM_SOFTLOCKUP_PANIC", are
provided for this. provided for this.
A 'hardlockup' is defined as a bug that causes the CPU to loop in A 'hardlockup' is defined as a bug that causes the CPU to loop in
kernel mode for more than 10 seconds (see "Implementation" below for kernel mode for several seconds (see "Implementation" below for
details), without letting other interrupts have a chance to run. details), without letting other interrupts have a chance to run.
Similarly to the softlockup case, the current stack trace is displayed Similarly to the softlockup case, the current stack trace is displayed
upon detection and the system will stay locked up unless the default upon detection and the system will stay locked up unless the default
@@ -30,39 +30,135 @@ timeout is set through the confusingly named "kernel.panic" sysctl),
to cause the system to reboot automatically after a specified amount to cause the system to reboot automatically after a specified amount
of time. of time.
Configuration
=============
A kernel knob is provided that allows administrators to configure
this period. The "watchdog_thresh" parameter (default 10 seconds)
controls the threshold. The right value for a particular environment
is a trade-off between fast response to lockups and detection overhead.
Implementation Implementation
============== ==============
The soft and hard lockup detectors are built on top of the hrtimer and The soft and hard lockup detectors are built around an hrtimer.
perf subsystems, respectively. A direct consequence of this is that, In addition, the softlockup detector regularly schedules a job, and
in principle, they should work in any architecture where these the hard lockup detector might use Perf/NMI events on architectures
subsystems are present. that support it.
A periodic hrtimer runs to generate interrupts and kick the watchdog Frequency and Heartbeats
job. An NMI perf event is generated every "watchdog_thresh" ------------------------
(compile-time initialized to 10 and configurable through sysctl of the
same name) seconds to check for hardlockups. If any CPU in the system
does not receive any hrtimer interrupt during that time the
'hardlockup detector' (the handler for the NMI perf event) will
generate a kernel warning or call panic, depending on the
configuration.
The watchdog job runs in a stop scheduling thread that updates a The core of the detectors is an hrtimer. It serves multiple purposes:
timestamp every time it is scheduled. If that timestamp is not updated
for 2*watchdog_thresh seconds (the softlockup threshold) the - schedules watchdog job for the softlockup detector
- bumps the interrupt counter for hardlockup detectors (heartbeat)
- detects softlockups
- detects hardlockups in Buddy mode
The period of this hrtimer is 2*watchdog_thresh/5, which is 4 seconds
by default. The hrtimer has two or three chances to generate an interrupt
(heartbeat) before the hardlockup detector kicks in.
Softlockup Detector
-------------------
The watchdog job is scheduled by the hrtimer and runs in a stop scheduling
thread. It updates a timestamp every time it is scheduled. If that timestamp
is not updated for 2*watchdog_thresh seconds (the softlockup threshold) the
'softlockup detector' (coded inside the hrtimer callback function) 'softlockup detector' (coded inside the hrtimer callback function)
will dump useful debug information to the system log, after which it will dump useful debug information to the system log, after which it
will call panic if it was instructed to do so or resume execution of will call panic if it was instructed to do so or resume execution of
other kernel code. other kernel code.
The period of the hrtimer is 2*watchdog_thresh/5, which means it has Hardlockup Detector (NMI/Perf)
two or three chances to generate an interrupt before the hardlockup ------------------------------
detector kicks in.
As explained above, a kernel knob is provided that allows On architectures that support NMI (Non-Maskable Interrupt) perf events,
administrators to configure the period of the hrtimer and the perf a periodic NMI is generated every "watchdog_thresh" seconds.
event. The right value for a particular environment is a trade-off
between fast response to lockups and detection overhead. If any CPU in the system does not receive any hrtimer interrupt
(heartbeat) during the "watchdog_thresh" window, the 'hardlockup
detector' (the handler for the NMI perf event) will generate a kernel
warning or call panic.
**Detection Overhead (NMI):**
The time to detect a lockup can vary depending on when the lockup
occurs relative to the NMI check window. Examples below assume a watchdog_thresh of 10.
* **Best Case:** The lockup occurs just before the first heartbeat is
due. The detector will notice the missing hrtimer interrupt almost
immediately during the next check.
::
Time 100.0: cpu 1 heartbeat
Time 100.1: hardlockup_check, cpu1 stores its state
Time 103.9: Hard Lockup on cpu1
Time 104.0: cpu 1 heartbeat never comes
Time 110.1: hardlockup_check, cpu1 checks the state again, should be the same, declares lockup
Time to detection: ~6 seconds
* **Worst Case:** The lockup occurs shortly after a valid interrupt
(heartbeat) which itself happened just after the NMI check. The next
NMI check sees that the interrupt count has changed (due to that one
heartbeat), assumes the CPU is healthy, and resets the baseline. The
lockup is only detected at the subsequent check.
::
Time 100.0: hardlockup_check, cpu1 stores its state
Time 100.1: cpu 1 heartbeat
Time 100.2: Hard Lockup on cpu1
Time 110.0: hardlockup_check, cpu1 stores its state (misses lockup as state changed)
Time 120.0: hardlockup_check, cpu1 checks the state again, should be the same, declares lockup
Time to detection: ~20 seconds
Hardlockup Detector (Buddy)
---------------------------
On architectures or configurations where NMI perf events are not
available (or disabled), the kernel may use the "buddy" hardlockup
detector. This mechanism requires SMP (Symmetric Multi-Processing).
In this mode, each CPU is assigned a "buddy" CPU to monitor. The
monitoring CPU runs its own hrtimer (the same one used for softlockup
detection) and checks if the buddy CPU's hrtimer interrupt count has
increased.
To ensure timeliness and avoid false positives, the buddy system performs
checks at every hrtimer interval (2*watchdog_thresh/5, which is 4 seconds
by default). It uses a missed-interrupt threshold of 3. If the buddy's
interrupt count has not changed for 3 consecutive checks, it is assumed
that the buddy CPU is hardlocked (interrupts disabled). The monitoring
CPU will then trigger the hardlockup response (warning or panic).
**Detection Overhead (Buddy):**
With a default check interval of 4 seconds (watchdog_thresh = 10):
* **Best case:** Lockup occurs just before a check.
Detected in ~8s (0s till 1st check + 4s till 2nd + 4s till 3rd).
* **Worst case:** Lockup occurs just after a check.
Detected in ~12s (4s till 1st check + 4s till 2nd + 4s till 3rd).
**Limitations of the Buddy Detector:**
1. **All-CPU Lockup:** If all CPUs lock up simultaneously, the buddy
detector cannot detect the condition because the monitoring CPUs
are also frozen.
2. **Stack Traces:** Unlike the NMI detector, the buddy detector
cannot directly interrupt the locked CPU to grab a stack trace.
It relies on architecture-specific mechanisms (like NMI backtrace
support) to try and retrieve the status of the locked CPU. If
such support is missing, the log may only show that a lockup
occurred without providing the locked CPU's stack.
Watchdog Core Exclusion
=======================
By default, the watchdog runs on all online cores. However, on a By default, the watchdog runs on all online cores. However, on a
kernel configured with NO_HZ_FULL, by default the watchdog runs only kernel configured with NO_HZ_FULL, by default the watchdog runs only

View File

@@ -418,7 +418,8 @@ hung_task_detect_count
====================== ======================
Indicates the total number of tasks that have been detected as hung since Indicates the total number of tasks that have been detected as hung since
the system boot. the system boot or since the counter was reset. The counter is zeroed when
a value of 0 is written.
This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled. This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.

View File

@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Xilinx LogiCORE IP AXI Timer title: Xilinx LogiCORE IP AXI Timer
maintainers: maintainers:
- Sean Anderson <sean.anderson@seco.com> - Sean Anderson <sean.anderson@linux.dev>
properties: properties:
compatible: compatible:

View File

@@ -35,6 +35,7 @@ Descriptions of section entries and preferred order
F: drivers/net/ all files in and below drivers/net F: drivers/net/ all files in and below drivers/net
F: drivers/net/* all files in drivers/net, but not below F: drivers/net/* all files in drivers/net, but not below
F: */net/* all files in "any top level directory"/net F: */net/* all files in "any top level directory"/net
F: fs/**/*foo*.c all *foo*.c files in any subdirectory of fs
One pattern per line. Multiple F: lines acceptable. One pattern per line. Multiple F: lines acceptable.
X: *Excluded* files and directories that are NOT maintained, same X: *Excluded* files and directories that are NOT maintained, same
rules as F:. Files exclusions are tested before file matches. rules as F:. Files exclusions are tested before file matches.
@@ -10308,7 +10309,7 @@ F: drivers/net/ethernet/freescale/dpaa
FREESCALE QORIQ DPAA FMAN DRIVER FREESCALE QORIQ DPAA FMAN DRIVER
M: Madalin Bucur <madalin.bucur@nxp.com> M: Madalin Bucur <madalin.bucur@nxp.com>
R: Sean Anderson <sean.anderson@seco.com> R: Sean Anderson <sean.anderson@linux.dev>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/net/fsl,fman*.yaml F: Documentation/devicetree/bindings/net/fsl,fman*.yaml
@@ -29109,7 +29110,7 @@ S: Orphan
F: drivers/net/ethernet/xilinx/ll_temac* F: drivers/net/ethernet/xilinx/ll_temac*
XILINX PWM DRIVER XILINX PWM DRIVER
M: Sean Anderson <sean.anderson@seco.com> M: Sean Anderson <sean.anderson@linux.dev>
S: Maintained S: Maintained
F: drivers/pwm/pwm-xilinx.c F: drivers/pwm/pwm-xilinx.c
F: include/clocksource/timer-xilinx.h F: include/clocksource/timer-xilinx.h

View File

@@ -39,9 +39,4 @@ endif
$(obj)/csumpartialcopy.o: $(obj)/csumpartialcopygeneric.S $(obj)/csumpartialcopy.o: $(obj)/csumpartialcopygeneric.S
$(obj)/csumpartialcopyuser.o: $(obj)/csumpartialcopygeneric.S $(obj)/csumpartialcopyuser.o: $(obj)/csumpartialcopygeneric.S
ifeq ($(CONFIG_KERNEL_MODE_NEON),y)
CFLAGS_xor-neon.o += $(CC_FLAGS_FPU)
obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o
endif
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o

View File

@@ -1,73 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* arch/arm64/include/asm/xor.h
*
* Authors: Jackie Liu <liuyun01@kylinos.cn>
* Copyright (C) 2018,Tianjin KYLIN Information Technology Co., Ltd.
*/
#include <linux/hardirq.h>
#include <asm-generic/xor.h>
#include <asm/hwcap.h>
#include <asm/simd.h>
#ifdef CONFIG_KERNEL_MODE_NEON
extern struct xor_block_template const xor_block_inner_neon;
static void
xor_neon_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2)
{
scoped_ksimd()
xor_block_inner_neon.do_2(bytes, p1, p2);
}
static void
xor_neon_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3)
{
scoped_ksimd()
xor_block_inner_neon.do_3(bytes, p1, p2, p3);
}
static void
xor_neon_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4)
{
scoped_ksimd()
xor_block_inner_neon.do_4(bytes, p1, p2, p3, p4);
}
static void
xor_neon_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5)
{
scoped_ksimd()
xor_block_inner_neon.do_5(bytes, p1, p2, p3, p4, p5);
}
static struct xor_block_template xor_block_arm64 = {
.name = "arm64_neon",
.do_2 = xor_neon_2,
.do_3 = xor_neon_3,
.do_4 = xor_neon_4,
.do_5 = xor_neon_5
};
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_32regs); \
if (cpu_has_neon()) { \
xor_speed(&xor_block_arm64);\
} \
} while (0)
#endif /* ! CONFIG_KERNEL_MODE_NEON */

View File

@@ -134,6 +134,10 @@ int load_other_segments(struct kimage *image,
kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
image->elf_load_addr, kbuf.bufsz, kbuf.memsz); image->elf_load_addr, kbuf.bufsz, kbuf.memsz);
ret = crash_load_dm_crypt_keys(image);
if (ret)
goto out_err;
} }
#endif #endif

View File

@@ -5,12 +5,6 @@ lib-y := clear_user.o delay.o copy_from_user.o \
memset.o memcmp.o strcmp.o strncmp.o strlen.o \ memset.o memcmp.o strcmp.o strncmp.o strlen.o \
strnlen.o strchr.o strrchr.o tishift.o strnlen.o strchr.o strrchr.o tishift.o
ifeq ($(CONFIG_KERNEL_MODE_NEON), y)
obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o
CFLAGS_xor-neon.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_xor-neon.o += $(CC_FLAGS_NO_FPU)
endif
lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o

View File

@@ -1,68 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2023 WANG Xuerui <git@xen0n.name>
*/
#ifndef _ASM_LOONGARCH_XOR_H
#define _ASM_LOONGARCH_XOR_H
#include <asm/cpu-features.h>
#include <asm/xor_simd.h>
#ifdef CONFIG_CPU_HAS_LSX
static struct xor_block_template xor_block_lsx = {
.name = "lsx",
.do_2 = xor_lsx_2,
.do_3 = xor_lsx_3,
.do_4 = xor_lsx_4,
.do_5 = xor_lsx_5,
};
#define XOR_SPEED_LSX() \
do { \
if (cpu_has_lsx) \
xor_speed(&xor_block_lsx); \
} while (0)
#else /* CONFIG_CPU_HAS_LSX */
#define XOR_SPEED_LSX()
#endif /* CONFIG_CPU_HAS_LSX */
#ifdef CONFIG_CPU_HAS_LASX
static struct xor_block_template xor_block_lasx = {
.name = "lasx",
.do_2 = xor_lasx_2,
.do_3 = xor_lasx_3,
.do_4 = xor_lasx_4,
.do_5 = xor_lasx_5,
};
#define XOR_SPEED_LASX() \
do { \
if (cpu_has_lasx) \
xor_speed(&xor_block_lasx); \
} while (0)
#else /* CONFIG_CPU_HAS_LASX */
#define XOR_SPEED_LASX()
#endif /* CONFIG_CPU_HAS_LASX */
/*
* For grins, also test the generic routines.
*
* More importantly: it cannot be ruled out at this point of time, that some
* future (maybe reduced) models could run the vector algorithms slower than
* the scalar ones, maybe for errata or micro-op reasons. It may be
* appropriate to revisit this after one or two more uarch generations.
*/
#include <asm-generic/xor.h>
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_8regs_p); \
xor_speed(&xor_block_32regs); \
xor_speed(&xor_block_32regs_p); \
XOR_SPEED_LSX(); \
XOR_SPEED_LASX(); \
} while (0)
#endif /* _ASM_LOONGARCH_XOR_H */

View File

@@ -1,34 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2023 WANG Xuerui <git@xen0n.name>
*/
#ifndef _ASM_LOONGARCH_XOR_SIMD_H
#define _ASM_LOONGARCH_XOR_SIMD_H
#ifdef CONFIG_CPU_HAS_LSX
void xor_lsx_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2);
void xor_lsx_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p3);
void xor_lsx_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p3,
const unsigned long * __restrict p4);
void xor_lsx_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p3,
const unsigned long * __restrict p4, const unsigned long * __restrict p5);
#endif /* CONFIG_CPU_HAS_LSX */
#ifdef CONFIG_CPU_HAS_LASX
void xor_lasx_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2);
void xor_lasx_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p3);
void xor_lasx_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p3,
const unsigned long * __restrict p4);
void xor_lasx_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p3,
const unsigned long * __restrict p4, const unsigned long * __restrict p5);
#endif /* CONFIG_CPU_HAS_LASX */
#endif /* _ASM_LOONGARCH_XOR_SIMD_H */

View File

@@ -8,6 +8,4 @@ lib-y += delay.o memset.o memcpy.o memmove.o \
obj-$(CONFIG_ARCH_SUPPORTS_INT128) += tishift.o obj-$(CONFIG_ARCH_SUPPORTS_INT128) += tishift.o
obj-$(CONFIG_CPU_HAS_LSX) += xor_simd.o xor_simd_glue.o
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o

View File

@@ -1,72 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LoongArch SIMD XOR operations
*
* Copyright (C) 2023 WANG Xuerui <git@xen0n.name>
*/
#include <linux/export.h>
#include <linux/sched.h>
#include <asm/fpu.h>
#include <asm/xor_simd.h>
#include "xor_simd.h"
#define MAKE_XOR_GLUE_2(flavor) \
void xor_##flavor##_2(unsigned long bytes, unsigned long * __restrict p1, \
const unsigned long * __restrict p2) \
{ \
kernel_fpu_begin(); \
__xor_##flavor##_2(bytes, p1, p2); \
kernel_fpu_end(); \
} \
EXPORT_SYMBOL_GPL(xor_##flavor##_2)
#define MAKE_XOR_GLUE_3(flavor) \
void xor_##flavor##_3(unsigned long bytes, unsigned long * __restrict p1, \
const unsigned long * __restrict p2, \
const unsigned long * __restrict p3) \
{ \
kernel_fpu_begin(); \
__xor_##flavor##_3(bytes, p1, p2, p3); \
kernel_fpu_end(); \
} \
EXPORT_SYMBOL_GPL(xor_##flavor##_3)
#define MAKE_XOR_GLUE_4(flavor) \
void xor_##flavor##_4(unsigned long bytes, unsigned long * __restrict p1, \
const unsigned long * __restrict p2, \
const unsigned long * __restrict p3, \
const unsigned long * __restrict p4) \
{ \
kernel_fpu_begin(); \
__xor_##flavor##_4(bytes, p1, p2, p3, p4); \
kernel_fpu_end(); \
} \
EXPORT_SYMBOL_GPL(xor_##flavor##_4)
#define MAKE_XOR_GLUE_5(flavor) \
void xor_##flavor##_5(unsigned long bytes, unsigned long * __restrict p1, \
const unsigned long * __restrict p2, \
const unsigned long * __restrict p3, \
const unsigned long * __restrict p4, \
const unsigned long * __restrict p5) \
{ \
kernel_fpu_begin(); \
__xor_##flavor##_5(bytes, p1, p2, p3, p4, p5); \
kernel_fpu_end(); \
} \
EXPORT_SYMBOL_GPL(xor_##flavor##_5)
#define MAKE_XOR_GLUES(flavor) \
MAKE_XOR_GLUE_2(flavor); \
MAKE_XOR_GLUE_3(flavor); \
MAKE_XOR_GLUE_4(flavor); \
MAKE_XOR_GLUE_5(flavor)
#ifdef CONFIG_CPU_HAS_LSX
MAKE_XOR_GLUES(lsx);
#endif
#ifdef CONFIG_CPU_HAS_LASX
MAKE_XOR_GLUES(lasx);
#endif

View File

@@ -1,47 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
*
* Copyright (C) IBM Corporation, 2012
*
* Author: Anton Blanchard <anton@au.ibm.com>
*/
#ifndef _ASM_POWERPC_XOR_H
#define _ASM_POWERPC_XOR_H
#ifdef CONFIG_ALTIVEC
#include <asm/cputable.h>
#include <asm/cpu_has_feature.h>
#include <asm/xor_altivec.h>
static struct xor_block_template xor_block_altivec = {
.name = "altivec",
.do_2 = xor_altivec_2,
.do_3 = xor_altivec_3,
.do_4 = xor_altivec_4,
.do_5 = xor_altivec_5,
};
#define XOR_SPEED_ALTIVEC() \
do { \
if (cpu_has_feature(CPU_FTR_ALTIVEC)) \
xor_speed(&xor_block_altivec); \
} while (0)
#else
#define XOR_SPEED_ALTIVEC()
#endif
/* Also try the generic routines. */
#include <asm-generic/xor.h>
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_8regs_p); \
xor_speed(&xor_block_32regs); \
xor_speed(&xor_block_32regs_p); \
XOR_SPEED_ALTIVEC(); \
} while (0)
#endif /* _ASM_POWERPC_XOR_H */

View File

@@ -1,22 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_POWERPC_XOR_ALTIVEC_H
#define _ASM_POWERPC_XOR_ALTIVEC_H
#ifdef CONFIG_ALTIVEC
void xor_altivec_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2);
void xor_altivec_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3);
void xor_altivec_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4);
void xor_altivec_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5);
#endif
#endif /* _ASM_POWERPC_XOR_ALTIVEC_H */

View File

@@ -79,6 +79,10 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
goto out; goto out;
} }
ret = crash_load_dm_crypt_keys(image);
if (ret)
goto out;
/* Setup cmdline for kdump kernel case */ /* Setup cmdline for kdump kernel case */
modified_cmdline = setup_kdump_cmdline(image, cmdline, modified_cmdline = setup_kdump_cmdline(image, cmdline,
cmdline_len); cmdline_len);

View File

@@ -72,9 +72,4 @@ obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o
obj-$(CONFIG_FTR_FIXUP_SELFTEST) += feature-fixups-test.o obj-$(CONFIG_FTR_FIXUP_SELFTEST) += feature-fixups-test.o
obj-$(CONFIG_ALTIVEC) += xor_vmx.o xor_vmx_glue.o
CFLAGS_xor_vmx.o += -mhard-float -maltivec $(call cc-option,-mabi=altivec)
# Enable <altivec.h>
CFLAGS_xor_vmx.o += -isystem $(shell $(CC) -print-file-name=include)
obj-$(CONFIG_PPC64) += $(obj64-y) obj-$(CONFIG_PPC64) += $(obj64-y)

View File

@@ -1,22 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Simple interface to link xor_vmx.c and xor_vmx_glue.c
*
* Separating these file ensures that no altivec instructions are run
* outside of the enable/disable altivec block.
*/
void __xor_altivec_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2);
void __xor_altivec_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3);
void __xor_altivec_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4);
void __xor_altivec_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5);

View File

@@ -1,63 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Altivec XOR operations
*
* Copyright 2017 IBM Corp.
*/
#include <linux/preempt.h>
#include <linux/export.h>
#include <linux/sched.h>
#include <asm/switch_to.h>
#include <asm/xor_altivec.h>
#include "xor_vmx.h"
void xor_altivec_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2)
{
preempt_disable();
enable_kernel_altivec();
__xor_altivec_2(bytes, p1, p2);
disable_kernel_altivec();
preempt_enable();
}
EXPORT_SYMBOL(xor_altivec_2);
void xor_altivec_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3)
{
preempt_disable();
enable_kernel_altivec();
__xor_altivec_3(bytes, p1, p2, p3);
disable_kernel_altivec();
preempt_enable();
}
EXPORT_SYMBOL(xor_altivec_3);
void xor_altivec_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4)
{
preempt_disable();
enable_kernel_altivec();
__xor_altivec_4(bytes, p1, p2, p3, p4);
disable_kernel_altivec();
preempt_enable();
}
EXPORT_SYMBOL(xor_altivec_4);
void xor_altivec_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5)
{
preempt_disable();
enable_kernel_altivec();
__xor_altivec_5(bytes, p1, p2, p3, p4, p5);
disable_kernel_altivec();
preempt_enable();
}
EXPORT_SYMBOL(xor_altivec_5);

View File

@@ -1,68 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2021 SiFive
*/
#include <linux/hardirq.h>
#include <asm-generic/xor.h>
#ifdef CONFIG_RISCV_ISA_V
#include <asm/vector.h>
#include <asm/switch_to.h>
#include <asm/asm-prototypes.h>
static void xor_vector_2(unsigned long bytes, unsigned long *__restrict p1,
const unsigned long *__restrict p2)
{
kernel_vector_begin();
xor_regs_2_(bytes, p1, p2);
kernel_vector_end();
}
static void xor_vector_3(unsigned long bytes, unsigned long *__restrict p1,
const unsigned long *__restrict p2,
const unsigned long *__restrict p3)
{
kernel_vector_begin();
xor_regs_3_(bytes, p1, p2, p3);
kernel_vector_end();
}
static void xor_vector_4(unsigned long bytes, unsigned long *__restrict p1,
const unsigned long *__restrict p2,
const unsigned long *__restrict p3,
const unsigned long *__restrict p4)
{
kernel_vector_begin();
xor_regs_4_(bytes, p1, p2, p3, p4);
kernel_vector_end();
}
static void xor_vector_5(unsigned long bytes, unsigned long *__restrict p1,
const unsigned long *__restrict p2,
const unsigned long *__restrict p3,
const unsigned long *__restrict p4,
const unsigned long *__restrict p5)
{
kernel_vector_begin();
xor_regs_5_(bytes, p1, p2, p3, p4, p5);
kernel_vector_end();
}
static struct xor_block_template xor_block_rvv = {
.name = "rvv",
.do_2 = xor_vector_2,
.do_3 = xor_vector_3,
.do_4 = xor_vector_4,
.do_5 = xor_vector_5
};
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_32regs); \
if (has_vector()) { \
xor_speed(&xor_block_rvv);\
} \
} while (0)
#endif

View File

@@ -16,5 +16,4 @@ lib-$(CONFIG_MMU) += uaccess.o
lib-$(CONFIG_64BIT) += tishift.o lib-$(CONFIG_64BIT) += tishift.o
lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
lib-$(CONFIG_RISCV_ISA_V) += xor.o
lib-$(CONFIG_RISCV_ISA_V) += riscv_v_helpers.o lib-$(CONFIG_RISCV_ISA_V) += riscv_v_helpers.o

View File

@@ -1,21 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Optimited xor routines
*
* Copyright IBM Corp. 2016
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef _ASM_S390_XOR_H
#define _ASM_S390_XOR_H
extern struct xor_block_template xor_block_xc;
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_xc); \
} while (0)
#define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_xc)
#endif /* _ASM_S390_XOR_H */

View File

@@ -5,7 +5,7 @@
lib-y += delay.o string.o uaccess.o find.o spinlock.o tishift.o lib-y += delay.o string.o uaccess.o find.o spinlock.o tishift.o
lib-y += csum-partial.o lib-y += csum-partial.o
obj-y += mem.o xor.o obj-y += mem.o
lib-$(CONFIG_KPROBES) += probes.o lib-$(CONFIG_KPROBES) += probes.o
lib-$(CONFIG_UPROBES) += probes.o lib-$(CONFIG_UPROBES) += probes.o
obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o

View File

@@ -14,7 +14,6 @@
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/trap_block.h> #include <asm/trap_block.h>
#include <asm/xor.h>
void *__memscan_zero(void *, size_t); void *__memscan_zero(void *, size_t);
void *__memscan_generic(void *, int, size_t); void *__memscan_generic(void *, int, size_t);

View File

@@ -1,9 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ___ASM_SPARC_XOR_H
#define ___ASM_SPARC_XOR_H
#if defined(__sparc__) && defined(__arch64__)
#include <asm/xor_64.h>
#else
#include <asm/xor_32.h>
#endif
#endif

View File

@@ -48,7 +48,7 @@ lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o
lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
lib-$(CONFIG_SPARC64) += copy_in_user.o memmove.o lib-$(CONFIG_SPARC64) += copy_in_user.o memmove.o
lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o hweight.o ffs.o
obj-$(CONFIG_SPARC64) += iomap.o obj-$(CONFIG_SPARC64) += iomap.o
obj-$(CONFIG_SPARC32) += atomic32.o obj-$(CONFIG_SPARC32) += atomic32.o

View File

@@ -1,24 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_UM_XOR_H
#define _ASM_UM_XOR_H
#ifdef CONFIG_64BIT
#undef CONFIG_X86_32
#define TT_CPU_INF_XOR_DEFAULT (AVX_SELECT(&xor_block_sse_pf64))
#else
#define CONFIG_X86_32 1
#define TT_CPU_INF_XOR_DEFAULT (AVX_SELECT(&xor_block_8regs))
#endif
#include <asm/cpufeature.h>
#include <../../x86/include/asm/xor.h>
#include <linux/time-internal.h>
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
#undef XOR_SELECT_TEMPLATE
/* pick an arbitrary one - measuring isn't possible with inf-cpu */
#define XOR_SELECT_TEMPLATE(x) \
(time_travel_mode == TT_MODE_INFCPU ? TT_CPU_INF_XOR_DEFAULT : x)
#endif
#endif

View File

@@ -1,28 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_X86_XOR_64_H
#define _ASM_X86_XOR_64_H
static struct xor_block_template xor_block_sse = {
.name = "generic_sse",
.do_2 = xor_sse_2,
.do_3 = xor_sse_3,
.do_4 = xor_sse_4,
.do_5 = xor_sse_5,
};
/* Also try the AVX routines */
#include <asm/xor_avx.h>
/* We force the use of the SSE xor block because it can write around L2.
We may also be able to load into the L1 only depending on how the cpu
deals with a load to a line that is being prefetched. */
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
AVX_XOR_SPEED; \
xor_speed(&xor_block_sse_pf64); \
xor_speed(&xor_block_sse); \
} while (0)
#endif /* _ASM_X86_XOR_64_H */

View File

@@ -525,12 +525,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
ret = crash_load_dm_crypt_keys(image); ret = crash_load_dm_crypt_keys(image);
if (ret == -ENOENT) { if (ret)
kexec_dprintk("No dm crypt key to load\n");
} else if (ret) {
pr_err("Failed to load dm crypt keys\n");
return ERR_PTR(ret); return ERR_PTR(ret);
}
if (image->dm_crypt_keys_addr && if (image->dm_crypt_keys_addr &&
cmdline_len + MAX_ELFCOREHDR_STR_LEN + MAX_DMCRYPTKEYS_STR_LEN > cmdline_len + MAX_ELFCOREHDR_STR_LEN + MAX_DMCRYPTKEYS_STR_LEN >
header->cmdline_size) { header->cmdline_size) {

View File

@@ -2,8 +2,6 @@
# #
# Generic algorithms support # Generic algorithms support
# #
config XOR_BLOCKS
tristate
# #
# async_tx api: hardware offloaded memory transfer/transform support # async_tx api: hardware offloaded memory transfer/transform support

View File

@@ -193,7 +193,6 @@ obj-$(CONFIG_CRYPTO_ECRDSA) += ecrdsa_generic.o
# #
# generic algorithms and the async_tx api # generic algorithms and the async_tx api
# #
obj-$(CONFIG_XOR_BLOCKS) += xor.o
obj-$(CONFIG_ASYNC_CORE) += async_tx/ obj-$(CONFIG_ASYNC_CORE) += async_tx/
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
crypto_simd-y := simd.o crypto_simd-y := simd.o

View File

@@ -103,7 +103,6 @@ do_sync_xor_offs(struct page *dest, unsigned int offset,
{ {
int i; int i;
int xor_src_cnt = 0; int xor_src_cnt = 0;
int src_off = 0;
void *dest_buf; void *dest_buf;
void **srcs; void **srcs;
@@ -117,23 +116,12 @@ do_sync_xor_offs(struct page *dest, unsigned int offset,
if (src_list[i]) if (src_list[i])
srcs[xor_src_cnt++] = page_address(src_list[i]) + srcs[xor_src_cnt++] = page_address(src_list[i]) +
(src_offs ? src_offs[i] : offset); (src_offs ? src_offs[i] : offset);
src_cnt = xor_src_cnt;
/* set destination address */ /* set destination address */
dest_buf = page_address(dest) + offset; dest_buf = page_address(dest) + offset;
if (submit->flags & ASYNC_TX_XOR_ZERO_DST) if (submit->flags & ASYNC_TX_XOR_ZERO_DST)
memset(dest_buf, 0, len); memset(dest_buf, 0, len);
xor_gen(dest_buf, srcs, xor_src_cnt, len);
while (src_cnt > 0) {
/* process up to 'MAX_XOR_BLOCKS' sources */
xor_src_cnt = min(src_cnt, MAX_XOR_BLOCKS);
xor_blocks(xor_src_cnt, len, dest_buf, &srcs[src_off]);
/* drop completed sources */
src_cnt -= xor_src_cnt;
src_off += xor_src_cnt;
}
async_tx_sync_epilog(submit); async_tx_sync_epilog(submit);
} }
@@ -168,11 +156,10 @@ dma_xor_aligned_offsets(struct dma_device *device, unsigned int offset,
* *
* honored flags: ASYNC_TX_ACK, ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DST * honored flags: ASYNC_TX_ACK, ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DST
* *
* xor_blocks always uses the dest as a source so the * xor_gen always uses the dest as a source so the ASYNC_TX_XOR_ZERO_DST flag
* ASYNC_TX_XOR_ZERO_DST flag must be set to not include dest data in * must be set to not include dest data in the calculation. The assumption with
* the calculation. The assumption with dma engines is that they only * dma engines is that they only use the destination buffer as a source when it
* use the destination buffer as a source when it is explicitly specified * is explicitly specified in the source list.
* in the source list.
* *
* src_list note: if the dest is also a source it must be at index zero. * src_list note: if the dest is also a source it must be at index zero.
* The contents of this array will be overwritten if a scribble region * The contents of this array will be overwritten if a scribble region
@@ -259,11 +246,10 @@ EXPORT_SYMBOL_GPL(async_xor_offs);
* *
* honored flags: ASYNC_TX_ACK, ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DST * honored flags: ASYNC_TX_ACK, ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DST
* *
* xor_blocks always uses the dest as a source so the * xor_gen always uses the dest as a source so the ASYNC_TX_XOR_ZERO_DST flag
* ASYNC_TX_XOR_ZERO_DST flag must be set to not include dest data in * must be set to not include dest data in the calculation. The assumption with
* the calculation. The assumption with dma engines is that they only * dma engines is that they only use the destination buffer as a source when it
* use the destination buffer as a source when it is explicitly specified * is explicitly specified in the source list.
* in the source list.
* *
* src_list note: if the dest is also a source it must be at index zero. * src_list note: if the dest is also a source it must be at index zero.
* The contents of this array will be overwritten if a scribble region * The contents of this array will be overwritten if a scribble region

View File

@@ -1,174 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* xor.c : Multiple Devices driver for Linux
*
* Copyright (C) 1996, 1997, 1998, 1999, 2000,
* Ingo Molnar, Matti Aarnio, Jakub Jelinek, Richard Henderson.
*
* Dispatch optimized RAID-5 checksumming functions.
*/
#define BH_TRACE 0
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/raid/xor.h>
#include <linux/jiffies.h>
#include <linux/preempt.h>
#include <asm/xor.h>
#ifndef XOR_SELECT_TEMPLATE
#define XOR_SELECT_TEMPLATE(x) (x)
#endif
/* The xor routines to use. */
static struct xor_block_template *active_template;
void
xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs)
{
unsigned long *p1, *p2, *p3, *p4;
p1 = (unsigned long *) srcs[0];
if (src_count == 1) {
active_template->do_2(bytes, dest, p1);
return;
}
p2 = (unsigned long *) srcs[1];
if (src_count == 2) {
active_template->do_3(bytes, dest, p1, p2);
return;
}
p3 = (unsigned long *) srcs[2];
if (src_count == 3) {
active_template->do_4(bytes, dest, p1, p2, p3);
return;
}
p4 = (unsigned long *) srcs[3];
active_template->do_5(bytes, dest, p1, p2, p3, p4);
}
EXPORT_SYMBOL(xor_blocks);
/* Set of all registered templates. */
static struct xor_block_template *__initdata template_list;
#ifndef MODULE
static void __init do_xor_register(struct xor_block_template *tmpl)
{
tmpl->next = template_list;
template_list = tmpl;
}
static int __init register_xor_blocks(void)
{
active_template = XOR_SELECT_TEMPLATE(NULL);
if (!active_template) {
#define xor_speed do_xor_register
// register all the templates and pick the first as the default
XOR_TRY_TEMPLATES;
#undef xor_speed
active_template = template_list;
}
return 0;
}
#endif
#define BENCH_SIZE 4096
#define REPS 800U
static void __init
do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
{
int speed;
unsigned long reps;
ktime_t min, start, t0;
tmpl->next = template_list;
template_list = tmpl;
preempt_disable();
reps = 0;
t0 = ktime_get();
/* delay start until time has advanced */
while ((start = ktime_get()) == t0)
cpu_relax();
do {
mb(); /* prevent loop optimization */
tmpl->do_2(BENCH_SIZE, b1, b2);
mb();
} while (reps++ < REPS || (t0 = ktime_get()) == start);
min = ktime_sub(t0, start);
preempt_enable();
// bytes/ns == GB/s, multiply by 1000 to get MB/s [not MiB/s]
speed = (1000 * reps * BENCH_SIZE) / (unsigned int)ktime_to_ns(min);
tmpl->speed = speed;
pr_info(" %-16s: %5d MB/sec\n", tmpl->name, speed);
}
static int __init
calibrate_xor_blocks(void)
{
void *b1, *b2;
struct xor_block_template *f, *fastest;
fastest = XOR_SELECT_TEMPLATE(NULL);
if (fastest) {
printk(KERN_INFO "xor: automatically using best "
"checksumming function %-10s\n",
fastest->name);
goto out;
}
b1 = (void *) __get_free_pages(GFP_KERNEL, 2);
if (!b1) {
printk(KERN_WARNING "xor: Yikes! No memory available.\n");
return -ENOMEM;
}
b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE;
/*
* If this arch/cpu has a short-circuited selection, don't loop through
* all the possible functions, just test the best one
*/
#define xor_speed(templ) do_xor_speed((templ), b1, b2)
printk(KERN_INFO "xor: measuring software checksum speed\n");
template_list = NULL;
XOR_TRY_TEMPLATES;
fastest = template_list;
for (f = fastest; f; f = f->next)
if (f->speed > fastest->speed)
fastest = f;
pr_info("xor: using function: %s (%d MB/sec)\n",
fastest->name, fastest->speed);
#undef xor_speed
free_pages((unsigned long)b1, 2);
out:
active_template = fastest;
return 0;
}
static __exit void xor_exit(void) { }
MODULE_DESCRIPTION("RAID-5 checksumming functions");
MODULE_LICENSE("GPL");
#ifndef MODULE
/* when built-in xor.o must initialize before drivers/md/md.o */
core_initcall(register_xor_blocks);
#endif
module_init(calibrate_xor_blocks);
module_exit(xor_exit);

View File

@@ -866,6 +866,26 @@ static void __init early_init_dt_check_for_elfcorehdr(unsigned long node)
elfcorehdr_addr, elfcorehdr_size); elfcorehdr_addr, elfcorehdr_size);
} }
static void __init early_init_dt_check_for_dmcryptkeys(unsigned long node)
{
const char *prop_name = "linux,dmcryptkeys";
const __be32 *prop;
if (!IS_ENABLED(CONFIG_CRASH_DM_CRYPT))
return;
pr_debug("Looking for dmcryptkeys property... ");
prop = of_get_flat_dt_prop(node, prop_name, NULL);
if (!prop)
return;
dm_crypt_keys_addr = dt_mem_next_cell(dt_root_addr_cells, &prop);
/* Property only accessible to crash dump kernel */
fdt_delprop(initial_boot_params, node, prop_name);
}
static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND; static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND;
/* /*
@@ -1097,6 +1117,7 @@ int __init early_init_dt_scan_chosen(char *cmdline)
early_init_dt_check_for_initrd(node); early_init_dt_check_for_initrd(node);
early_init_dt_check_for_elfcorehdr(node); early_init_dt_check_for_elfcorehdr(node);
early_init_dt_check_for_dmcryptkeys(node);
rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l); rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l);
if (rng_seed && l > 0) { if (rng_seed && l > 0) {

View File

@@ -423,6 +423,25 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
if (ret) if (ret)
goto out; goto out;
if (image->dm_crypt_keys_addr != 0) {
ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
"linux,dmcryptkeys",
image->dm_crypt_keys_addr,
image->dm_crypt_keys_sz);
if (ret)
goto out;
/*
* Avoid dmcryptkeys from being stomped on in kdump kernel by
* setting up memory reserve map.
*/
ret = fdt_add_mem_rsv(fdt, image->dm_crypt_keys_addr,
image->dm_crypt_keys_sz);
if (ret)
goto out;
}
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_CRASH_DUMP
/* add linux,usable-memory-range */ /* add linux,usable-memory-range */
ret = fdt_appendprop_addrrange(fdt, 0, chosen_node, ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,

View File

@@ -617,26 +617,6 @@ static void cache_rbio(struct btrfs_raid_bio *rbio)
spin_unlock(&table->cache_lock); spin_unlock(&table->cache_lock);
} }
/*
* helper function to run the xor_blocks api. It is only
* able to do MAX_XOR_BLOCKS at a time, so we need to
* loop through.
*/
static void run_xor(void **pages, int src_cnt, ssize_t len)
{
int src_off = 0;
int xor_src_cnt = 0;
void *dest = pages[src_cnt];
while(src_cnt > 0) {
xor_src_cnt = min(src_cnt, MAX_XOR_BLOCKS);
xor_blocks(xor_src_cnt, len, dest, pages + src_off);
src_cnt -= xor_src_cnt;
src_off += xor_src_cnt;
}
}
/* /*
* Returns true if the bio list inside this rbio covers an entire stripe (no * Returns true if the bio list inside this rbio covers an entire stripe (no
* rmw required). * rmw required).
@@ -1434,7 +1414,8 @@ static void generate_pq_vertical_step(struct btrfs_raid_bio *rbio, unsigned int
} else { } else {
/* raid5 */ /* raid5 */
memcpy(pointers[rbio->nr_data], pointers[0], step); memcpy(pointers[rbio->nr_data], pointers[0], step);
run_xor(pointers + 1, rbio->nr_data - 1, step); xor_gen(pointers[rbio->nr_data], pointers + 1, rbio->nr_data - 1,
step);
} }
for (stripe = stripe - 1; stripe >= 0; stripe--) for (stripe = stripe - 1; stripe >= 0; stripe--)
kunmap_local(pointers[stripe]); kunmap_local(pointers[stripe]);
@@ -2029,7 +2010,7 @@ pstripe:
pointers[rbio->nr_data - 1] = p; pointers[rbio->nr_data - 1] = p;
/* Xor in the rest */ /* Xor in the rest */
run_xor(pointers, rbio->nr_data - 1, step); xor_gen(p, pointers, rbio->nr_data - 1, step);
} }
cleanup: cleanup:
@@ -2667,7 +2648,7 @@ static bool verify_one_parity_step(struct btrfs_raid_bio *rbio,
} else { } else {
/* RAID5. */ /* RAID5. */
memcpy(pointers[nr_data], pointers[0], step); memcpy(pointers[nr_data], pointers[0], step);
run_xor(pointers + 1, nr_data - 1, step); xor_gen(pointers[nr_data], pointers + 1, nr_data - 1, step);
} }
/* Check scrubbing parity and repair it. */ /* Check scrubbing parity and repair it. */

View File

@@ -917,11 +917,32 @@ static int ocfs2_validate_extent_block(struct super_block *sb,
goto bail; goto bail;
} }
if (le32_to_cpu(eb->h_fs_generation) != OCFS2_SB(sb)->fs_generation) if (le32_to_cpu(eb->h_fs_generation) != OCFS2_SB(sb)->fs_generation) {
rc = ocfs2_error(sb, rc = ocfs2_error(sb,
"Extent block #%llu has an invalid h_fs_generation of #%u\n", "Extent block #%llu has an invalid h_fs_generation of #%u\n",
(unsigned long long)bh->b_blocknr, (unsigned long long)bh->b_blocknr,
le32_to_cpu(eb->h_fs_generation)); le32_to_cpu(eb->h_fs_generation));
goto bail;
}
if (le16_to_cpu(eb->h_list.l_count) != ocfs2_extent_recs_per_eb(sb)) {
rc = ocfs2_error(sb,
"Extent block #%llu has invalid l_count %u (expected %u)\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(eb->h_list.l_count),
ocfs2_extent_recs_per_eb(sb));
goto bail;
}
if (le16_to_cpu(eb->h_list.l_next_free_rec) > le16_to_cpu(eb->h_list.l_count)) {
rc = ocfs2_error(sb,
"Extent block #%llu has invalid l_next_free_rec %u (l_count %u)\n",
(unsigned long long)bh->b_blocknr,
le16_to_cpu(eb->h_list.l_next_free_rec),
le16_to_cpu(eb->h_list.l_count));
goto bail;
}
bail: bail:
return rc; return rc;
} }
@@ -1857,18 +1878,6 @@ static int __ocfs2_find_path(struct ocfs2_caching_info *ci,
eb = (struct ocfs2_extent_block *) bh->b_data; eb = (struct ocfs2_extent_block *) bh->b_data;
el = &eb->h_list; el = &eb->h_list;
if (le16_to_cpu(el->l_next_free_rec) >
le16_to_cpu(el->l_count)) {
ocfs2_error(ocfs2_metadata_cache_get_super(ci),
"Owner %llu has bad count in extent list at block %llu (next free=%u, count=%u)\n",
(unsigned long long)ocfs2_metadata_cache_owner(ci),
(unsigned long long)bh->b_blocknr,
le16_to_cpu(el->l_next_free_rec),
le16_to_cpu(el->l_count));
ret = -EROFS;
goto out;
}
if (func) if (func)
func(data, bh); func(data, bh);
} }

View File

@@ -37,6 +37,8 @@
#include "namei.h" #include "namei.h"
#include "sysfile.h" #include "sysfile.h"
#define OCFS2_DIO_MARK_EXTENT_BATCH 200
static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
@@ -2277,7 +2279,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
struct ocfs2_alloc_context *meta_ac = NULL; struct ocfs2_alloc_context *meta_ac = NULL;
handle_t *handle = NULL; handle_t *handle = NULL;
loff_t end = offset + bytes; loff_t end = offset + bytes;
int ret = 0, credits = 0; int ret = 0, credits = 0, batch = 0;
ocfs2_init_dealloc_ctxt(&dealloc); ocfs2_init_dealloc_ctxt(&dealloc);
@@ -2295,19 +2297,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
} }
down_write(&oi->ip_alloc_sem); down_write(&oi->ip_alloc_sem);
/* Delete orphan before acquire i_rwsem. */
if (dwc->dw_orphaned) {
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
end = end > i_size_read(inode) ? end : 0;
ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
!!end, end);
if (ret < 0)
mlog_errno(ret);
}
di = (struct ocfs2_dinode *)di_bh->b_data; di = (struct ocfs2_dinode *)di_bh->b_data;
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh); ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
@@ -2327,24 +2316,25 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
credits = ocfs2_calc_extend_credits(inode->i_sb, &di->id2.i_list); credits = ocfs2_calc_extend_credits(inode->i_sb, &di->id2.i_list);
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
goto unlock;
}
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) {
mlog_errno(ret);
goto commit;
}
list_for_each_entry(ue, &dwc->dw_zero_list, ue_node) { list_for_each_entry(ue, &dwc->dw_zero_list, ue_node) {
if (!handle) {
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
goto unlock;
}
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) {
mlog_errno(ret);
goto commit;
}
}
ret = ocfs2_assure_trans_credits(handle, credits); ret = ocfs2_assure_trans_credits(handle, credits);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
break; goto commit;
} }
ret = ocfs2_mark_extent_written(inode, &et, handle, ret = ocfs2_mark_extent_written(inode, &et, handle,
ue->ue_cpos, 1, ue->ue_cpos, 1,
@@ -2352,19 +2342,44 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
meta_ac, &dealloc); meta_ac, &dealloc);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
break; goto commit;
}
if (++batch == OCFS2_DIO_MARK_EXTENT_BATCH) {
ocfs2_commit_trans(osb, handle);
handle = NULL;
batch = 0;
} }
} }
if (end > i_size_read(inode)) { if (end > i_size_read(inode)) {
if (!handle) {
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
goto unlock;
}
}
ret = ocfs2_set_inode_size(handle, inode, di_bh, end); ret = ocfs2_set_inode_size(handle, inode, di_bh, end);
if (ret < 0) if (ret < 0)
mlog_errno(ret); mlog_errno(ret);
} }
commit: commit:
ocfs2_commit_trans(osb, handle); if (handle)
ocfs2_commit_trans(osb, handle);
unlock: unlock:
up_write(&oi->ip_alloc_sem); up_write(&oi->ip_alloc_sem);
/* everything looks good, let's start the cleanup */
if (!ret && dwc->dw_orphaned) {
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0);
if (ret < 0)
mlog_errno(ret);
}
ocfs2_inode_unlock(inode, 1); ocfs2_inode_unlock(inode, 1);
brelse(di_bh); brelse(di_bh);
out: out:

View File

@@ -1488,33 +1488,45 @@ static struct o2hb_region *to_o2hb_region(struct config_item *item)
return item ? container_of(item, struct o2hb_region, hr_item) : NULL; return item ? container_of(item, struct o2hb_region, hr_item) : NULL;
} }
/* drop_item only drops its ref after killing the thread, nothing should static void o2hb_unmap_slot_data(struct o2hb_region *reg)
* be using the region anymore. this has to clean up any state that
* attributes might have built up. */
static void o2hb_region_release(struct config_item *item)
{ {
int i; int i;
struct page *page; struct page *page;
struct o2hb_region *reg = to_o2hb_region(item);
mlog(ML_HEARTBEAT, "hb region release (%pg)\n", reg_bdev(reg));
kfree(reg->hr_tmp_block);
if (reg->hr_slot_data) { if (reg->hr_slot_data) {
for (i = 0; i < reg->hr_num_pages; i++) { for (i = 0; i < reg->hr_num_pages; i++) {
page = reg->hr_slot_data[i]; page = reg->hr_slot_data[i];
if (page) if (page) {
__free_page(page); __free_page(page);
reg->hr_slot_data[i] = NULL;
}
} }
kfree(reg->hr_slot_data); kfree(reg->hr_slot_data);
reg->hr_slot_data = NULL;
} }
kfree(reg->hr_slots);
reg->hr_slots = NULL;
kfree(reg->hr_tmp_block);
reg->hr_tmp_block = NULL;
}
/* drop_item only drops its ref after killing the thread, nothing should
* be using the region anymore. this has to clean up any state that
* attributes might have built up.
*/
static void o2hb_region_release(struct config_item *item)
{
struct o2hb_region *reg = to_o2hb_region(item);
mlog(ML_HEARTBEAT, "hb region release (%pg)\n", reg_bdev(reg));
o2hb_unmap_slot_data(reg);
if (reg->hr_bdev_file) if (reg->hr_bdev_file)
fput(reg->hr_bdev_file); fput(reg->hr_bdev_file);
kfree(reg->hr_slots);
debugfs_remove_recursive(reg->hr_debug_dir); debugfs_remove_recursive(reg->hr_debug_dir);
kfree(reg->hr_db_livenodes); kfree(reg->hr_db_livenodes);
kfree(reg->hr_db_regnum); kfree(reg->hr_db_regnum);
@@ -1667,6 +1679,7 @@ static void o2hb_init_region_params(struct o2hb_region *reg)
static int o2hb_map_slot_data(struct o2hb_region *reg) static int o2hb_map_slot_data(struct o2hb_region *reg)
{ {
int i, j; int i, j;
int ret = -ENOMEM;
unsigned int last_slot; unsigned int last_slot;
unsigned int spp = reg->hr_slots_per_page; unsigned int spp = reg->hr_slots_per_page;
struct page *page; struct page *page;
@@ -1674,14 +1687,14 @@ static int o2hb_map_slot_data(struct o2hb_region *reg)
struct o2hb_disk_slot *slot; struct o2hb_disk_slot *slot;
reg->hr_tmp_block = kmalloc(reg->hr_block_bytes, GFP_KERNEL); reg->hr_tmp_block = kmalloc(reg->hr_block_bytes, GFP_KERNEL);
if (reg->hr_tmp_block == NULL) if (!reg->hr_tmp_block)
return -ENOMEM; goto out;
reg->hr_slots = kzalloc_objs(struct o2hb_disk_slot, reg->hr_blocks); reg->hr_slots = kzalloc_objs(struct o2hb_disk_slot, reg->hr_blocks);
if (reg->hr_slots == NULL) if (!reg->hr_slots)
return -ENOMEM; goto out;
for(i = 0; i < reg->hr_blocks; i++) { for (i = 0; i < reg->hr_blocks; i++) {
slot = &reg->hr_slots[i]; slot = &reg->hr_slots[i];
slot->ds_node_num = i; slot->ds_node_num = i;
INIT_LIST_HEAD(&slot->ds_live_item); INIT_LIST_HEAD(&slot->ds_live_item);
@@ -1695,12 +1708,12 @@ static int o2hb_map_slot_data(struct o2hb_region *reg)
reg->hr_slot_data = kzalloc_objs(struct page *, reg->hr_num_pages); reg->hr_slot_data = kzalloc_objs(struct page *, reg->hr_num_pages);
if (!reg->hr_slot_data) if (!reg->hr_slot_data)
return -ENOMEM; goto out;
for(i = 0; i < reg->hr_num_pages; i++) { for (i = 0; i < reg->hr_num_pages; i++) {
page = alloc_page(GFP_KERNEL); page = alloc_page(GFP_KERNEL);
if (!page) if (!page)
return -ENOMEM; goto out;
reg->hr_slot_data[i] = page; reg->hr_slot_data[i] = page;
@@ -1720,6 +1733,10 @@ static int o2hb_map_slot_data(struct o2hb_region *reg)
} }
return 0; return 0;
out:
o2hb_unmap_slot_data(reg);
return ret;
} }
/* Read in all the slots available and populate the tracking /* Read in all the slots available and populate the tracking
@@ -1809,9 +1826,11 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
"blocksize %u incorrect for device, expected %d", "blocksize %u incorrect for device, expected %d",
reg->hr_block_bytes, sectsize); reg->hr_block_bytes, sectsize);
ret = -EINVAL; ret = -EINVAL;
goto out3; goto out;
} }
reg->hr_aborted_start = 0;
reg->hr_node_deleted = 0;
o2hb_init_region_params(reg); o2hb_init_region_params(reg);
/* Generation of zero is invalid */ /* Generation of zero is invalid */
@@ -1823,13 +1842,13 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
ret = o2hb_map_slot_data(reg); ret = o2hb_map_slot_data(reg);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out3; goto out;
} }
ret = o2hb_populate_slot_data(reg); ret = o2hb_populate_slot_data(reg);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out3; goto out;
} }
INIT_DELAYED_WORK(&reg->hr_write_timeout_work, o2hb_write_timeout); INIT_DELAYED_WORK(&reg->hr_write_timeout_work, o2hb_write_timeout);
@@ -1860,7 +1879,7 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
if (IS_ERR(hb_task)) { if (IS_ERR(hb_task)) {
ret = PTR_ERR(hb_task); ret = PTR_ERR(hb_task);
mlog_errno(ret); mlog_errno(ret);
goto out3; goto out;
} }
spin_lock(&o2hb_live_lock); spin_lock(&o2hb_live_lock);
@@ -1877,12 +1896,12 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
if (reg->hr_aborted_start) { if (reg->hr_aborted_start) {
ret = -EIO; ret = -EIO;
goto out3; goto out;
} }
if (reg->hr_node_deleted) { if (reg->hr_node_deleted) {
ret = -EINVAL; ret = -EINVAL;
goto out3; goto out;
} }
/* Ok, we were woken. Make sure it wasn't by drop_item() */ /* Ok, we were woken. Make sure it wasn't by drop_item() */
@@ -1901,8 +1920,18 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
printk(KERN_NOTICE "o2hb: Heartbeat started on region %s (%pg)\n", printk(KERN_NOTICE "o2hb: Heartbeat started on region %s (%pg)\n",
config_item_name(&reg->hr_item), reg_bdev(reg)); config_item_name(&reg->hr_item), reg_bdev(reg));
out3: out:
if (ret < 0) { if (ret < 0) {
spin_lock(&o2hb_live_lock);
hb_task = reg->hr_task;
reg->hr_task = NULL;
spin_unlock(&o2hb_live_lock);
if (hb_task)
kthread_stop(hb_task);
o2hb_unmap_slot_data(reg);
fput(reg->hr_bdev_file); fput(reg->hr_bdev_file);
reg->hr_bdev_file = NULL; reg->hr_bdev_file = NULL;
} }

View File

@@ -593,7 +593,7 @@ static int ocfs2_validate_dx_root(struct super_block *sb,
mlog(ML_ERROR, mlog(ML_ERROR,
"Checksum failed for dir index root block %llu\n", "Checksum failed for dir index root block %llu\n",
(unsigned long long)bh->b_blocknr); (unsigned long long)bh->b_blocknr);
return ret; goto bail;
} }
if (!OCFS2_IS_VALID_DX_ROOT(dx_root)) { if (!OCFS2_IS_VALID_DX_ROOT(dx_root)) {
@@ -601,8 +601,32 @@ static int ocfs2_validate_dx_root(struct super_block *sb,
"Dir Index Root # %llu has bad signature %.*s\n", "Dir Index Root # %llu has bad signature %.*s\n",
(unsigned long long)le64_to_cpu(dx_root->dr_blkno), (unsigned long long)le64_to_cpu(dx_root->dr_blkno),
7, dx_root->dr_signature); 7, dx_root->dr_signature);
goto bail;
} }
if (!(dx_root->dr_flags & OCFS2_DX_FLAG_INLINE)) {
struct ocfs2_extent_list *el = &dx_root->dr_list;
if (le16_to_cpu(el->l_count) != ocfs2_extent_recs_per_dx_root(sb)) {
ret = ocfs2_error(sb,
"Dir Index Root # %llu has invalid l_count %u (expected %u)\n",
(unsigned long long)le64_to_cpu(dx_root->dr_blkno),
le16_to_cpu(el->l_count),
ocfs2_extent_recs_per_dx_root(sb));
goto bail;
}
if (le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count)) {
ret = ocfs2_error(sb,
"Dir Index Root # %llu has invalid l_next_free_rec %u (l_count %u)\n",
(unsigned long long)le64_to_cpu(dx_root->dr_blkno),
le16_to_cpu(el->l_next_free_rec),
le16_to_cpu(el->l_count));
goto bail;
}
}
bail:
return ret; return ret;
} }
@@ -791,14 +815,6 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
struct ocfs2_extent_block *eb; struct ocfs2_extent_block *eb;
struct ocfs2_extent_rec *rec = NULL; struct ocfs2_extent_rec *rec = NULL;
if (le16_to_cpu(el->l_count) !=
ocfs2_extent_recs_per_dx_root(inode->i_sb)) {
ret = ocfs2_error(inode->i_sb,
"Inode %llu has invalid extent list length %u\n",
inode->i_ino, le16_to_cpu(el->l_count));
goto out;
}
if (el->l_tree_depth) { if (el->l_tree_depth) {
ret = ocfs2_find_leaf(INODE_CACHE(inode), el, major_hash, ret = ocfs2_find_leaf(INODE_CACHE(inode), el, major_hash,
&eb_bh); &eb_bh);
@@ -819,14 +835,6 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
} }
} }
if (le16_to_cpu(el->l_next_free_rec) == 0) {
ret = ocfs2_error(inode->i_sb,
"Inode %llu has empty extent list at depth %u\n",
inode->i_ino,
le16_to_cpu(el->l_tree_depth));
goto out;
}
found = 0; found = 0;
for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) { for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
rec = &el->l_recs[i]; rec = &el->l_recs[i];
@@ -839,10 +847,9 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
if (!found) { if (!found) {
ret = ocfs2_error(inode->i_sb, ret = ocfs2_error(inode->i_sb,
"Inode %llu has bad extent record (%u, %u, 0) in btree\n", "Inode %llu has no extent record for hash %u in btree (next_free_rec %u)\n",
inode->i_ino, inode->i_ino, major_hash,
le32_to_cpu(rec->e_cpos), le16_to_cpu(el->l_next_free_rec));
ocfs2_rec_clusters(el, rec));
goto out; goto out;
} }

View File

@@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm,
goto bail; goto bail;
} }
if (qr->qr_numregions > O2NM_MAX_REGIONS) {
mlog(ML_ERROR, "Domain %s: Joining node %d has invalid "
"number of heartbeat regions %u\n",
qr->qr_domain, qr->qr_node, qr->qr_numregions);
status = -EINVAL;
goto bail;
}
r = remote; r = remote;
for (i = 0; i < qr->qr_numregions; ++i) { for (i = 0; i < qr->qr_numregions; ++i) {
mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r);
@@ -994,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm,
for (i = 0; i < localnr; ++i) { for (i = 0; i < localnr; ++i) {
foundit = 0; foundit = 0;
r = remote; r = remote;
for (j = 0; j <= qr->qr_numregions; ++j) { for (j = 0; j < qr->qr_numregions; ++j) {
if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) {
foundit = 1; foundit = 1;
break; break;

View File

@@ -930,7 +930,6 @@ redo_request:
if (blocked) if (blocked)
goto wait; goto wait;
ret = -EINVAL;
dlm_node_iter_init(mle->vote_map, &iter); dlm_node_iter_init(mle->vote_map, &iter);
while ((nodenum = dlm_node_iter_next(&iter)) >= 0) { while ((nodenum = dlm_node_iter_next(&iter)) >= 0) {
ret = dlm_do_master_request(res, mle, nodenum); ret = dlm_do_master_request(res, mle, nodenum);

View File

@@ -441,13 +441,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb,
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ocfs2_group_desc *bg = NULL; struct ocfs2_group_desc *bg = NULL;
unsigned int max_bits, num_clusters; unsigned int max_bits, max_bitmap_bits, num_clusters;
unsigned int offset = 0, cluster, chunk; unsigned int offset = 0, cluster, chunk;
unsigned int chunk_free, last_chunksize = 0; unsigned int chunk_free, last_chunksize = 0;
if (!le32_to_cpu(rec->c_free)) if (!le32_to_cpu(rec->c_free))
goto bail; goto bail;
max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0,
osb->s_feature_incompat);
do { do {
if (!bg) if (!bg)
blkno = le64_to_cpu(rec->c_blkno); blkno = le64_to_cpu(rec->c_blkno);
@@ -479,6 +482,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb,
continue; continue;
max_bits = le16_to_cpu(bg->bg_bits); max_bits = le16_to_cpu(bg->bg_bits);
/*
* Non-coherent scans read raw blocks and do not get the
* bg_bits validation from
* ocfs2_read_group_descriptor().
*/
if (max_bits > max_bitmap_bits) {
mlog(ML_ERROR,
"Group desc #%llu has %u bits, max bitmap bits %u\n",
(unsigned long long)blkno, max_bits, max_bitmap_bits);
max_bits = max_bitmap_bits;
}
offset = 0; offset = 0;
for (chunk = 0; chunk < chunks_in_group; chunk++) { for (chunk = 0; chunk < chunks_in_group; chunk++) {

View File

@@ -30,7 +30,8 @@
static vm_fault_t ocfs2_fault(struct vm_fault *vmf) static vm_fault_t ocfs2_fault(struct vm_fault *vmf)
{ {
struct vm_area_struct *vma = vmf->vma; unsigned long long ip_blkno =
OCFS2_I(file_inode(vmf->vma->vm_file))->ip_blkno;
sigset_t oldset; sigset_t oldset;
vm_fault_t ret; vm_fault_t ret;
@@ -38,11 +39,9 @@ static vm_fault_t ocfs2_fault(struct vm_fault *vmf)
ret = filemap_fault(vmf); ret = filemap_fault(vmf);
ocfs2_unblock_signals(&oldset); ocfs2_unblock_signals(&oldset);
trace_ocfs2_fault(OCFS2_I(vma->vm_file->f_mapping->host)->ip_blkno, trace_ocfs2_fault(ip_blkno, vmf->page, vmf->pgoff);
vma, vmf->page, vmf->pgoff);
return ret; return ret;
} }
static vm_fault_t __ocfs2_page_mkwrite(struct file *file, static vm_fault_t __ocfs2_page_mkwrite(struct file *file,
struct buffer_head *di_bh, struct folio *folio) struct buffer_head *di_bh, struct folio *folio)
{ {

View File

@@ -1246,22 +1246,20 @@ TRACE_EVENT(ocfs2_write_end_inline,
TRACE_EVENT(ocfs2_fault, TRACE_EVENT(ocfs2_fault,
TP_PROTO(unsigned long long ino, TP_PROTO(unsigned long long ino,
void *area, void *page, unsigned long pgoff), void *page, unsigned long pgoff),
TP_ARGS(ino, area, page, pgoff), TP_ARGS(ino, page, pgoff),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned long long, ino) __field(unsigned long long, ino)
__field(void *, area)
__field(void *, page) __field(void *, page)
__field(unsigned long, pgoff) __field(unsigned long, pgoff)
), ),
TP_fast_assign( TP_fast_assign(
__entry->ino = ino; __entry->ino = ino;
__entry->area = area;
__entry->page = page; __entry->page = page;
__entry->pgoff = pgoff; __entry->pgoff = pgoff;
), ),
TP_printk("%llu %p %p %lu", TP_printk("%llu %p %lu",
__entry->ino, __entry->area, __entry->page, __entry->pgoff) __entry->ino, __entry->page, __entry->pgoff)
); );
/* End of trace events for fs/ocfs2/mmap.c. */ /* End of trace events for fs/ocfs2/mmap.c. */

View File

@@ -311,11 +311,25 @@ int ocfs2_lock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
spin_unlock(&dq_data_lock); spin_unlock(&dq_data_lock);
if (ex) { if (ex) {
inode_lock(oinfo->dqi_gqinode); inode_lock(oinfo->dqi_gqinode);
down_write(&OCFS2_I(oinfo->dqi_gqinode)->ip_alloc_sem); if (!down_write_trylock(&OCFS2_I(oinfo->dqi_gqinode)->ip_alloc_sem)) {
inode_unlock(oinfo->dqi_gqinode);
status = -EBUSY;
goto bail;
}
} else { } else {
down_read(&OCFS2_I(oinfo->dqi_gqinode)->ip_alloc_sem); down_read(&OCFS2_I(oinfo->dqi_gqinode)->ip_alloc_sem);
} }
return 0; return 0;
bail:
/* does a similar job as ocfs2_unlock_global_qf */
ocfs2_inode_unlock(oinfo->dqi_gqinode, ex);
brelse(oinfo->dqi_gqi_bh);
spin_lock(&dq_data_lock);
if (!--oinfo->dqi_gqi_count)
oinfo->dqi_gqi_bh = NULL;
spin_unlock(&dq_data_lock);
return status;
} }
void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex) void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)

View File

@@ -1224,7 +1224,9 @@ int ocfs2_create_local_dquot(struct dquot *dquot)
int status; int status;
u64 pcount; u64 pcount;
down_write(&OCFS2_I(lqinode)->ip_alloc_sem); if (!down_write_trylock(&OCFS2_I(lqinode)->ip_alloc_sem))
return -EBUSY;
chunk = ocfs2_find_free_entry(sb, type, &offset); chunk = ocfs2_find_free_entry(sb, type, &offset);
if (!chunk) { if (!chunk) {
chunk = ocfs2_extend_local_quota_file(sb, type, &offset); chunk = ocfs2_extend_local_quota_file(sb, type, &offset);

View File

@@ -303,9 +303,13 @@ int ocfs2_group_extend(struct inode * inode, int new_clusters)
fe = (struct ocfs2_dinode *)main_bm_bh->b_data; fe = (struct ocfs2_dinode *)main_bm_bh->b_data;
/* main_bm_bh is validated by inode read inside ocfs2_inode_lock(), /* JBD-managed buffers can bypass validation, so treat this as corruption. */
* so any corruption is a code bug. */ if (!OCFS2_IS_VALID_DINODE(fe)) {
BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); ret = ocfs2_error(main_bm_inode->i_sb,
"Invalid dinode #%llu\n",
(unsigned long long)OCFS2_I(main_bm_inode)->ip_blkno);
goto out_unlock;
}
if (le16_to_cpu(fe->id2.i_chain.cl_cpg) != if (le16_to_cpu(fe->id2.i_chain.cl_cpg) !=
ocfs2_group_bitmap_size(osb->sb, 0, ocfs2_group_bitmap_size(osb->sb, 0,
@@ -504,14 +508,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
goto out_unlock; goto out_unlock;
} }
ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh);
ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out_free_group_bh; goto out_free_group_bh;
} }
ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh);
trace_ocfs2_group_add((unsigned long long)input->group, trace_ocfs2_group_add((unsigned long long)input->group,
input->chain, input->clusters, input->frees); input->chain, input->clusters, input->frees);
@@ -519,7 +523,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
if (IS_ERR(handle)) { if (IS_ERR(handle)) {
mlog_errno(PTR_ERR(handle)); mlog_errno(PTR_ERR(handle));
ret = -EINVAL; ret = -EINVAL;
goto out_free_group_bh; goto out_remove_cache;
} }
cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc);
@@ -573,9 +577,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
out_commit: out_commit:
ocfs2_commit_trans(osb, handle); ocfs2_commit_trans(osb, handle);
out_free_group_bh: out_remove_cache:
if (ret < 0) if (ret < 0)
ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh);
out_free_group_bh:
brelse(group_bh); brelse(group_bh);
out_unlock: out_unlock:

View File

@@ -197,6 +197,31 @@ static int ocfs2_validate_gd_self(struct super_block *sb,
8 * le16_to_cpu(gd->bg_size)); 8 * le16_to_cpu(gd->bg_size));
} }
/*
* For discontiguous block groups, validate the on-disk extent list
* against the maximum number of extent records that can physically
* fit in a single block.
*/
if (ocfs2_gd_is_discontig(gd)) {
u16 max_recs = ocfs2_extent_recs_per_gd(sb);
u16 l_count = le16_to_cpu(gd->bg_list.l_count);
u16 l_next_free_rec = le16_to_cpu(gd->bg_list.l_next_free_rec);
if (l_count != max_recs) {
do_error("Group descriptor #%llu bad discontig l_count %u expected %u\n",
(unsigned long long)bh->b_blocknr,
l_count,
max_recs);
}
if (l_next_free_rec > l_count) {
do_error("Group descriptor #%llu bad discontig l_next_free_rec %u max %u\n",
(unsigned long long)bh->b_blocknr,
l_next_free_rec,
l_count);
}
}
return 0; return 0;
} }

View File

@@ -2124,7 +2124,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
osb->osb_cluster_stack[0] = '\0'; osb->osb_cluster_stack[0] = '\0';
} }
get_random_bytes(&osb->s_next_generation, sizeof(u32)); osb->s_next_generation = get_random_u32();
/* /*
* FIXME * FIXME

View File

@@ -911,8 +911,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb,
total_len = prefix_len + name_len + 1; total_len = prefix_len + name_len + 1;
*result += total_len; *result += total_len;
/* we are just looking for how big our buffer needs to be */ /* No buffer means we are only looking for the required size. */
if (!size) if (!buffer)
return 0; return 0;
if (*result > size) if (*result > size)

View File

@@ -280,7 +280,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
blocked = p->blocked; blocked = p->blocked;
collect_sigign_sigcatch(p, &ignored, &caught); collect_sigign_sigcatch(p, &ignored, &caught);
num_threads = get_nr_threads(p); num_threads = get_nr_threads(p);
rcu_read_lock(); /* FIXME: is this correct? */ rcu_read_lock();
qsize = get_rlimit_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING); qsize = get_rlimit_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING);
rcu_read_unlock(); rcu_read_unlock();
qlim = task_rlimit(p, RLIMIT_SIGPENDING); qlim = task_rlimit(p, RLIMIT_SIGPENDING);

View File

@@ -109,7 +109,6 @@ static int data_nodes_cmp(void *priv, const struct list_head *a,
struct ubifs_info *c = priv; struct ubifs_info *c = priv;
struct ubifs_scan_node *sa, *sb; struct ubifs_scan_node *sa, *sb;
cond_resched();
if (a == b) if (a == b)
return 0; return 0;
@@ -153,7 +152,6 @@ static int nondata_nodes_cmp(void *priv, const struct list_head *a,
struct ubifs_info *c = priv; struct ubifs_info *c = priv;
struct ubifs_scan_node *sa, *sb; struct ubifs_scan_node *sa, *sb;
cond_resched();
if (a == b) if (a == b)
return 0; return 0;

View File

@@ -305,7 +305,6 @@ static int replay_entries_cmp(void *priv, const struct list_head *a,
struct ubifs_info *c = priv; struct ubifs_info *c = priv;
struct replay_entry *ra, *rb; struct replay_entry *ra, *rb;
cond_resched();
if (a == b) if (a == b)
return 0; return 0;

View File

@@ -65,4 +65,3 @@ mandatory-y += vermagic.h
mandatory-y += vga.h mandatory-y += vga.h
mandatory-y += video.h mandatory-y += video.h
mandatory-y += word-at-a-time.h mandatory-y += word-at-a-time.h
mandatory-y += xor.h

View File

@@ -1,738 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* include/asm-generic/xor.h
*
* Generic optimized RAID-5 checksumming functions.
*/
#include <linux/prefetch.h>
static void
xor_8regs_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2)
{
long lines = bytes / (sizeof (long)) / 8;
do {
p1[0] ^= p2[0];
p1[1] ^= p2[1];
p1[2] ^= p2[2];
p1[3] ^= p2[3];
p1[4] ^= p2[4];
p1[5] ^= p2[5];
p1[6] ^= p2[6];
p1[7] ^= p2[7];
p1 += 8;
p2 += 8;
} while (--lines > 0);
}
static void
xor_8regs_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3)
{
long lines = bytes / (sizeof (long)) / 8;
do {
p1[0] ^= p2[0] ^ p3[0];
p1[1] ^= p2[1] ^ p3[1];
p1[2] ^= p2[2] ^ p3[2];
p1[3] ^= p2[3] ^ p3[3];
p1[4] ^= p2[4] ^ p3[4];
p1[5] ^= p2[5] ^ p3[5];
p1[6] ^= p2[6] ^ p3[6];
p1[7] ^= p2[7] ^ p3[7];
p1 += 8;
p2 += 8;
p3 += 8;
} while (--lines > 0);
}
static void
xor_8regs_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4)
{
long lines = bytes / (sizeof (long)) / 8;
do {
p1[0] ^= p2[0] ^ p3[0] ^ p4[0];
p1[1] ^= p2[1] ^ p3[1] ^ p4[1];
p1[2] ^= p2[2] ^ p3[2] ^ p4[2];
p1[3] ^= p2[3] ^ p3[3] ^ p4[3];
p1[4] ^= p2[4] ^ p3[4] ^ p4[4];
p1[5] ^= p2[5] ^ p3[5] ^ p4[5];
p1[6] ^= p2[6] ^ p3[6] ^ p4[6];
p1[7] ^= p2[7] ^ p3[7] ^ p4[7];
p1 += 8;
p2 += 8;
p3 += 8;
p4 += 8;
} while (--lines > 0);
}
static void
xor_8regs_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5)
{
long lines = bytes / (sizeof (long)) / 8;
do {
p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0];
p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1];
p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2];
p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3];
p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4];
p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5];
p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6];
p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7];
p1 += 8;
p2 += 8;
p3 += 8;
p4 += 8;
p5 += 8;
} while (--lines > 0);
}
static void
xor_32regs_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2)
{
long lines = bytes / (sizeof (long)) / 8;
do {
register long d0, d1, d2, d3, d4, d5, d6, d7;
d0 = p1[0]; /* Pull the stuff into registers */
d1 = p1[1]; /* ... in bursts, if possible. */
d2 = p1[2];
d3 = p1[3];
d4 = p1[4];
d5 = p1[5];
d6 = p1[6];
d7 = p1[7];
d0 ^= p2[0];
d1 ^= p2[1];
d2 ^= p2[2];
d3 ^= p2[3];
d4 ^= p2[4];
d5 ^= p2[5];
d6 ^= p2[6];
d7 ^= p2[7];
p1[0] = d0; /* Store the result (in bursts) */
p1[1] = d1;
p1[2] = d2;
p1[3] = d3;
p1[4] = d4;
p1[5] = d5;
p1[6] = d6;
p1[7] = d7;
p1 += 8;
p2 += 8;
} while (--lines > 0);
}
static void
xor_32regs_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3)
{
long lines = bytes / (sizeof (long)) / 8;
do {
register long d0, d1, d2, d3, d4, d5, d6, d7;
d0 = p1[0]; /* Pull the stuff into registers */
d1 = p1[1]; /* ... in bursts, if possible. */
d2 = p1[2];
d3 = p1[3];
d4 = p1[4];
d5 = p1[5];
d6 = p1[6];
d7 = p1[7];
d0 ^= p2[0];
d1 ^= p2[1];
d2 ^= p2[2];
d3 ^= p2[3];
d4 ^= p2[4];
d5 ^= p2[5];
d6 ^= p2[6];
d7 ^= p2[7];
d0 ^= p3[0];
d1 ^= p3[1];
d2 ^= p3[2];
d3 ^= p3[3];
d4 ^= p3[4];
d5 ^= p3[5];
d6 ^= p3[6];
d7 ^= p3[7];
p1[0] = d0; /* Store the result (in bursts) */
p1[1] = d1;
p1[2] = d2;
p1[3] = d3;
p1[4] = d4;
p1[5] = d5;
p1[6] = d6;
p1[7] = d7;
p1 += 8;
p2 += 8;
p3 += 8;
} while (--lines > 0);
}
static void
xor_32regs_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4)
{
long lines = bytes / (sizeof (long)) / 8;
do {
register long d0, d1, d2, d3, d4, d5, d6, d7;
d0 = p1[0]; /* Pull the stuff into registers */
d1 = p1[1]; /* ... in bursts, if possible. */
d2 = p1[2];
d3 = p1[3];
d4 = p1[4];
d5 = p1[5];
d6 = p1[6];
d7 = p1[7];
d0 ^= p2[0];
d1 ^= p2[1];
d2 ^= p2[2];
d3 ^= p2[3];
d4 ^= p2[4];
d5 ^= p2[5];
d6 ^= p2[6];
d7 ^= p2[7];
d0 ^= p3[0];
d1 ^= p3[1];
d2 ^= p3[2];
d3 ^= p3[3];
d4 ^= p3[4];
d5 ^= p3[5];
d6 ^= p3[6];
d7 ^= p3[7];
d0 ^= p4[0];
d1 ^= p4[1];
d2 ^= p4[2];
d3 ^= p4[3];
d4 ^= p4[4];
d5 ^= p4[5];
d6 ^= p4[6];
d7 ^= p4[7];
p1[0] = d0; /* Store the result (in bursts) */
p1[1] = d1;
p1[2] = d2;
p1[3] = d3;
p1[4] = d4;
p1[5] = d5;
p1[6] = d6;
p1[7] = d7;
p1 += 8;
p2 += 8;
p3 += 8;
p4 += 8;
} while (--lines > 0);
}
static void
xor_32regs_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5)
{
long lines = bytes / (sizeof (long)) / 8;
do {
register long d0, d1, d2, d3, d4, d5, d6, d7;
d0 = p1[0]; /* Pull the stuff into registers */
d1 = p1[1]; /* ... in bursts, if possible. */
d2 = p1[2];
d3 = p1[3];
d4 = p1[4];
d5 = p1[5];
d6 = p1[6];
d7 = p1[7];
d0 ^= p2[0];
d1 ^= p2[1];
d2 ^= p2[2];
d3 ^= p2[3];
d4 ^= p2[4];
d5 ^= p2[5];
d6 ^= p2[6];
d7 ^= p2[7];
d0 ^= p3[0];
d1 ^= p3[1];
d2 ^= p3[2];
d3 ^= p3[3];
d4 ^= p3[4];
d5 ^= p3[5];
d6 ^= p3[6];
d7 ^= p3[7];
d0 ^= p4[0];
d1 ^= p4[1];
d2 ^= p4[2];
d3 ^= p4[3];
d4 ^= p4[4];
d5 ^= p4[5];
d6 ^= p4[6];
d7 ^= p4[7];
d0 ^= p5[0];
d1 ^= p5[1];
d2 ^= p5[2];
d3 ^= p5[3];
d4 ^= p5[4];
d5 ^= p5[5];
d6 ^= p5[6];
d7 ^= p5[7];
p1[0] = d0; /* Store the result (in bursts) */
p1[1] = d1;
p1[2] = d2;
p1[3] = d3;
p1[4] = d4;
p1[5] = d5;
p1[6] = d6;
p1[7] = d7;
p1 += 8;
p2 += 8;
p3 += 8;
p4 += 8;
p5 += 8;
} while (--lines > 0);
}
static void
xor_8regs_p_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2)
{
long lines = bytes / (sizeof (long)) / 8 - 1;
prefetchw(p1);
prefetch(p2);
do {
prefetchw(p1+8);
prefetch(p2+8);
once_more:
p1[0] ^= p2[0];
p1[1] ^= p2[1];
p1[2] ^= p2[2];
p1[3] ^= p2[3];
p1[4] ^= p2[4];
p1[5] ^= p2[5];
p1[6] ^= p2[6];
p1[7] ^= p2[7];
p1 += 8;
p2 += 8;
} while (--lines > 0);
if (lines == 0)
goto once_more;
}
static void
xor_8regs_p_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3)
{
long lines = bytes / (sizeof (long)) / 8 - 1;
prefetchw(p1);
prefetch(p2);
prefetch(p3);
do {
prefetchw(p1+8);
prefetch(p2+8);
prefetch(p3+8);
once_more:
p1[0] ^= p2[0] ^ p3[0];
p1[1] ^= p2[1] ^ p3[1];
p1[2] ^= p2[2] ^ p3[2];
p1[3] ^= p2[3] ^ p3[3];
p1[4] ^= p2[4] ^ p3[4];
p1[5] ^= p2[5] ^ p3[5];
p1[6] ^= p2[6] ^ p3[6];
p1[7] ^= p2[7] ^ p3[7];
p1 += 8;
p2 += 8;
p3 += 8;
} while (--lines > 0);
if (lines == 0)
goto once_more;
}
static void
xor_8regs_p_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4)
{
long lines = bytes / (sizeof (long)) / 8 - 1;
prefetchw(p1);
prefetch(p2);
prefetch(p3);
prefetch(p4);
do {
prefetchw(p1+8);
prefetch(p2+8);
prefetch(p3+8);
prefetch(p4+8);
once_more:
p1[0] ^= p2[0] ^ p3[0] ^ p4[0];
p1[1] ^= p2[1] ^ p3[1] ^ p4[1];
p1[2] ^= p2[2] ^ p3[2] ^ p4[2];
p1[3] ^= p2[3] ^ p3[3] ^ p4[3];
p1[4] ^= p2[4] ^ p3[4] ^ p4[4];
p1[5] ^= p2[5] ^ p3[5] ^ p4[5];
p1[6] ^= p2[6] ^ p3[6] ^ p4[6];
p1[7] ^= p2[7] ^ p3[7] ^ p4[7];
p1 += 8;
p2 += 8;
p3 += 8;
p4 += 8;
} while (--lines > 0);
if (lines == 0)
goto once_more;
}
static void
xor_8regs_p_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5)
{
long lines = bytes / (sizeof (long)) / 8 - 1;
prefetchw(p1);
prefetch(p2);
prefetch(p3);
prefetch(p4);
prefetch(p5);
do {
prefetchw(p1+8);
prefetch(p2+8);
prefetch(p3+8);
prefetch(p4+8);
prefetch(p5+8);
once_more:
p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0];
p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1];
p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2];
p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3];
p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4];
p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5];
p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6];
p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7];
p1 += 8;
p2 += 8;
p3 += 8;
p4 += 8;
p5 += 8;
} while (--lines > 0);
if (lines == 0)
goto once_more;
}
static void
xor_32regs_p_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2)
{
long lines = bytes / (sizeof (long)) / 8 - 1;
prefetchw(p1);
prefetch(p2);
do {
register long d0, d1, d2, d3, d4, d5, d6, d7;
prefetchw(p1+8);
prefetch(p2+8);
once_more:
d0 = p1[0]; /* Pull the stuff into registers */
d1 = p1[1]; /* ... in bursts, if possible. */
d2 = p1[2];
d3 = p1[3];
d4 = p1[4];
d5 = p1[5];
d6 = p1[6];
d7 = p1[7];
d0 ^= p2[0];
d1 ^= p2[1];
d2 ^= p2[2];
d3 ^= p2[3];
d4 ^= p2[4];
d5 ^= p2[5];
d6 ^= p2[6];
d7 ^= p2[7];
p1[0] = d0; /* Store the result (in bursts) */
p1[1] = d1;
p1[2] = d2;
p1[3] = d3;
p1[4] = d4;
p1[5] = d5;
p1[6] = d6;
p1[7] = d7;
p1 += 8;
p2 += 8;
} while (--lines > 0);
if (lines == 0)
goto once_more;
}
static void
xor_32regs_p_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3)
{
long lines = bytes / (sizeof (long)) / 8 - 1;
prefetchw(p1);
prefetch(p2);
prefetch(p3);
do {
register long d0, d1, d2, d3, d4, d5, d6, d7;
prefetchw(p1+8);
prefetch(p2+8);
prefetch(p3+8);
once_more:
d0 = p1[0]; /* Pull the stuff into registers */
d1 = p1[1]; /* ... in bursts, if possible. */
d2 = p1[2];
d3 = p1[3];
d4 = p1[4];
d5 = p1[5];
d6 = p1[6];
d7 = p1[7];
d0 ^= p2[0];
d1 ^= p2[1];
d2 ^= p2[2];
d3 ^= p2[3];
d4 ^= p2[4];
d5 ^= p2[5];
d6 ^= p2[6];
d7 ^= p2[7];
d0 ^= p3[0];
d1 ^= p3[1];
d2 ^= p3[2];
d3 ^= p3[3];
d4 ^= p3[4];
d5 ^= p3[5];
d6 ^= p3[6];
d7 ^= p3[7];
p1[0] = d0; /* Store the result (in bursts) */
p1[1] = d1;
p1[2] = d2;
p1[3] = d3;
p1[4] = d4;
p1[5] = d5;
p1[6] = d6;
p1[7] = d7;
p1 += 8;
p2 += 8;
p3 += 8;
} while (--lines > 0);
if (lines == 0)
goto once_more;
}
static void
xor_32regs_p_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4)
{
long lines = bytes / (sizeof (long)) / 8 - 1;
prefetchw(p1);
prefetch(p2);
prefetch(p3);
prefetch(p4);
do {
register long d0, d1, d2, d3, d4, d5, d6, d7;
prefetchw(p1+8);
prefetch(p2+8);
prefetch(p3+8);
prefetch(p4+8);
once_more:
d0 = p1[0]; /* Pull the stuff into registers */
d1 = p1[1]; /* ... in bursts, if possible. */
d2 = p1[2];
d3 = p1[3];
d4 = p1[4];
d5 = p1[5];
d6 = p1[6];
d7 = p1[7];
d0 ^= p2[0];
d1 ^= p2[1];
d2 ^= p2[2];
d3 ^= p2[3];
d4 ^= p2[4];
d5 ^= p2[5];
d6 ^= p2[6];
d7 ^= p2[7];
d0 ^= p3[0];
d1 ^= p3[1];
d2 ^= p3[2];
d3 ^= p3[3];
d4 ^= p3[4];
d5 ^= p3[5];
d6 ^= p3[6];
d7 ^= p3[7];
d0 ^= p4[0];
d1 ^= p4[1];
d2 ^= p4[2];
d3 ^= p4[3];
d4 ^= p4[4];
d5 ^= p4[5];
d6 ^= p4[6];
d7 ^= p4[7];
p1[0] = d0; /* Store the result (in bursts) */
p1[1] = d1;
p1[2] = d2;
p1[3] = d3;
p1[4] = d4;
p1[5] = d5;
p1[6] = d6;
p1[7] = d7;
p1 += 8;
p2 += 8;
p3 += 8;
p4 += 8;
} while (--lines > 0);
if (lines == 0)
goto once_more;
}
static void
xor_32regs_p_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5)
{
long lines = bytes / (sizeof (long)) / 8 - 1;
prefetchw(p1);
prefetch(p2);
prefetch(p3);
prefetch(p4);
prefetch(p5);
do {
register long d0, d1, d2, d3, d4, d5, d6, d7;
prefetchw(p1+8);
prefetch(p2+8);
prefetch(p3+8);
prefetch(p4+8);
prefetch(p5+8);
once_more:
d0 = p1[0]; /* Pull the stuff into registers */
d1 = p1[1]; /* ... in bursts, if possible. */
d2 = p1[2];
d3 = p1[3];
d4 = p1[4];
d5 = p1[5];
d6 = p1[6];
d7 = p1[7];
d0 ^= p2[0];
d1 ^= p2[1];
d2 ^= p2[2];
d3 ^= p2[3];
d4 ^= p2[4];
d5 ^= p2[5];
d6 ^= p2[6];
d7 ^= p2[7];
d0 ^= p3[0];
d1 ^= p3[1];
d2 ^= p3[2];
d3 ^= p3[3];
d4 ^= p3[4];
d5 ^= p3[5];
d6 ^= p3[6];
d7 ^= p3[7];
d0 ^= p4[0];
d1 ^= p4[1];
d2 ^= p4[2];
d3 ^= p4[3];
d4 ^= p4[4];
d5 ^= p4[5];
d6 ^= p4[6];
d7 ^= p4[7];
d0 ^= p5[0];
d1 ^= p5[1];
d2 ^= p5[2];
d3 ^= p5[3];
d4 ^= p5[4];
d5 ^= p5[5];
d6 ^= p5[6];
d7 ^= p5[7];
p1[0] = d0; /* Store the result (in bursts) */
p1[1] = d1;
p1[2] = d2;
p1[3] = d3;
p1[4] = d4;
p1[5] = d5;
p1[6] = d6;
p1[7] = d7;
p1 += 8;
p2 += 8;
p3 += 8;
p4 += 8;
p5 += 8;
} while (--lines > 0);
if (lines == 0)
goto once_more;
}
static struct xor_block_template xor_block_8regs = {
.name = "8regs",
.do_2 = xor_8regs_2,
.do_3 = xor_8regs_3,
.do_4 = xor_8regs_4,
.do_5 = xor_8regs_5,
};
static struct xor_block_template xor_block_32regs = {
.name = "32regs",
.do_2 = xor_32regs_2,
.do_3 = xor_32regs_3,
.do_4 = xor_32regs_4,
.do_5 = xor_32regs_5,
};
static struct xor_block_template xor_block_8regs_p __maybe_unused = {
.name = "8regs_prefetch",
.do_2 = xor_8regs_p_2,
.do_3 = xor_8regs_p_3,
.do_4 = xor_8regs_p_4,
.do_5 = xor_8regs_p_5,
};
static struct xor_block_template xor_block_32regs_p __maybe_unused = {
.name = "32regs_prefetch",
.do_2 = xor_32regs_p_2,
.do_3 = xor_32regs_p_3,
.do_4 = xor_32regs_p_4,
.do_5 = xor_32regs_p_5,
};
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_8regs_p); \
xor_speed(&xor_block_32regs); \
xor_speed(&xor_block_32regs_p); \
} while (0)

View File

@@ -34,13 +34,6 @@ static inline void arch_kexec_protect_crashkres(void) { }
static inline void arch_kexec_unprotect_crashkres(void) { } static inline void arch_kexec_unprotect_crashkres(void) { }
#endif #endif
#ifdef CONFIG_CRASH_DM_CRYPT
int crash_load_dm_crypt_keys(struct kimage *image);
ssize_t dm_crypt_keys_read(char *buf, size_t count, u64 *ppos);
#else
static inline int crash_load_dm_crypt_keys(struct kimage *image) {return 0; }
#endif
#ifndef arch_crash_handle_hotplug_event #ifndef arch_crash_handle_hotplug_event
static inline void arch_crash_handle_hotplug_event(struct kimage *image, void *arg) { } static inline void arch_crash_handle_hotplug_event(struct kimage *image, void *arg) { }
#endif #endif
@@ -96,4 +89,11 @@ static inline void crash_save_cpu(struct pt_regs *regs, int cpu) {};
static inline int kimage_crash_copy_vmcoreinfo(struct kimage *image) { return 0; }; static inline int kimage_crash_copy_vmcoreinfo(struct kimage *image) { return 0; };
#endif /* CONFIG_CRASH_DUMP*/ #endif /* CONFIG_CRASH_DUMP*/
#ifdef CONFIG_CRASH_DM_CRYPT
int crash_load_dm_crypt_keys(struct kimage *image);
ssize_t dm_crypt_keys_read(char *buf, size_t count, u64 *ppos);
#else
static inline int crash_load_dm_crypt_keys(struct kimage *image) {return 0; }
#endif
#endif /* LINUX_CRASH_CORE_H */ #endif /* LINUX_CRASH_CORE_H */

View File

@@ -21,6 +21,7 @@ void lockup_detector_soft_poweroff(void);
extern int watchdog_user_enabled; extern int watchdog_user_enabled;
extern int watchdog_thresh; extern int watchdog_thresh;
extern unsigned long watchdog_enabled; extern unsigned long watchdog_enabled;
extern int watchdog_hardlockup_miss_thresh;
extern struct cpumask watchdog_cpumask; extern struct cpumask watchdog_cpumask;
extern unsigned long *watchdog_cpumask_bits; extern unsigned long *watchdog_cpumask_bits;

View File

@@ -2,29 +2,6 @@
#ifndef _XOR_H #ifndef _XOR_H
#define _XOR_H #define _XOR_H
#define MAX_XOR_BLOCKS 4 void xor_gen(void *dest, void **srcs, unsigned int src_cnt, unsigned int bytes);
extern void xor_blocks(unsigned int count, unsigned int bytes, #endif /* _XOR_H */
void *dest, void **srcs);
struct xor_block_template {
struct xor_block_template *next;
const char *name;
int speed;
void (*do_2)(unsigned long, unsigned long * __restrict,
const unsigned long * __restrict);
void (*do_3)(unsigned long, unsigned long * __restrict,
const unsigned long * __restrict,
const unsigned long * __restrict);
void (*do_4)(unsigned long, unsigned long * __restrict,
const unsigned long * __restrict,
const unsigned long * __restrict,
const unsigned long * __restrict);
void (*do_5)(unsigned long, unsigned long * __restrict,
const unsigned long * __restrict,
const unsigned long * __restrict,
const unsigned long * __restrict,
const unsigned long * __restrict);
};
#endif

View File

@@ -27,8 +27,6 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <crypto/sha1.h>
#include "kallsyms_internal.h" #include "kallsyms_internal.h"
#include "kexec_internal.h" #include "kexec_internal.h"

View File

@@ -6,6 +6,7 @@
#include <linux/cc_platform.h> #include <linux/cc_platform.h>
#include <linux/configfs.h> #include <linux/configfs.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sysfs.h>
#define KEY_NUM_MAX 128 /* maximum dm crypt keys */ #define KEY_NUM_MAX 128 /* maximum dm crypt keys */
#define KEY_SIZE_MAX 256 /* maximum dm crypt key size */ #define KEY_SIZE_MAX 256 /* maximum dm crypt key size */
@@ -115,7 +116,7 @@ static int restore_dm_crypt_keys_to_thread_keyring(void)
addr = dm_crypt_keys_addr; addr = dm_crypt_keys_addr;
dm_crypt_keys_read((char *)&key_count, sizeof(key_count), &addr); dm_crypt_keys_read((char *)&key_count, sizeof(key_count), &addr);
if (key_count < 0 || key_count > KEY_NUM_MAX) { if (key_count > KEY_NUM_MAX) {
kexec_dprintk("Failed to read the number of dm-crypt keys\n"); kexec_dprintk("Failed to read the number of dm-crypt keys\n");
return -1; return -1;
} }
@@ -139,7 +140,7 @@ static int restore_dm_crypt_keys_to_thread_keyring(void)
return 0; return 0;
} }
static int read_key_from_user_keying(struct dm_crypt_key *dm_key) static int read_key_from_user_keyring(struct dm_crypt_key *dm_key)
{ {
const struct user_key_payload *ukp; const struct user_key_payload *ukp;
struct key *key; struct key *key;
@@ -189,7 +190,7 @@ static inline struct config_key *to_config_key(struct config_item *item)
static ssize_t config_key_description_show(struct config_item *item, char *page) static ssize_t config_key_description_show(struct config_item *item, char *page)
{ {
return sprintf(page, "%s\n", to_config_key(item)->description); return sysfs_emit(page, "%s\n", to_config_key(item)->description);
} }
static ssize_t config_key_description_store(struct config_item *item, static ssize_t config_key_description_store(struct config_item *item,
@@ -265,7 +266,7 @@ static struct config_item *config_keys_make_item(struct config_group *group,
static ssize_t config_keys_count_show(struct config_item *item, char *page) static ssize_t config_keys_count_show(struct config_item *item, char *page)
{ {
return sprintf(page, "%d\n", key_count); return sysfs_emit(page, "%d\n", key_count);
} }
CONFIGFS_ATTR_RO(config_keys_, count); CONFIGFS_ATTR_RO(config_keys_, count);
@@ -274,7 +275,7 @@ static bool is_dm_key_reused;
static ssize_t config_keys_reuse_show(struct config_item *item, char *page) static ssize_t config_keys_reuse_show(struct config_item *item, char *page)
{ {
return sprintf(page, "%d\n", is_dm_key_reused); return sysfs_emit(page, "%d\n", is_dm_key_reused);
} }
static ssize_t config_keys_reuse_store(struct config_item *item, static ssize_t config_keys_reuse_store(struct config_item *item,
@@ -321,7 +322,7 @@ static bool restore;
static ssize_t config_keys_restore_show(struct config_item *item, char *page) static ssize_t config_keys_restore_show(struct config_item *item, char *page)
{ {
return sprintf(page, "%d\n", restore); return sysfs_emit(page, "%d\n", restore);
} }
static ssize_t config_keys_restore_store(struct config_item *item, static ssize_t config_keys_restore_store(struct config_item *item,
@@ -387,7 +388,7 @@ static int build_keys_header(void)
strscpy(keys_header->keys[i].key_desc, key->description, strscpy(keys_header->keys[i].key_desc, key->description,
KEY_DESC_MAX_LEN); KEY_DESC_MAX_LEN);
r = read_key_from_user_keying(&keys_header->keys[i]); r = read_key_from_user_keyring(&keys_header->keys[i]);
if (r != 0) { if (r != 0) {
kexec_dprintk("Failed to read key %s\n", kexec_dprintk("Failed to read key %s\n",
keys_header->keys[i].key_desc); keys_header->keys[i].key_desc);
@@ -414,14 +415,16 @@ int crash_load_dm_crypt_keys(struct kimage *image)
if (key_count <= 0) { if (key_count <= 0) {
kexec_dprintk("No dm-crypt keys\n"); kexec_dprintk("No dm-crypt keys\n");
return -ENOENT; return 0;
} }
if (!is_dm_key_reused) { if (!is_dm_key_reused) {
image->dm_crypt_keys_addr = 0; image->dm_crypt_keys_addr = 0;
r = build_keys_header(); r = build_keys_header();
if (r) if (r) {
pr_err("Failed to build dm-crypt keys header, ret=%d\n", r);
return r; return r;
}
} }
kbuf.buffer = keys_header; kbuf.buffer = keys_header;
@@ -432,6 +435,7 @@ int crash_load_dm_crypt_keys(struct kimage *image)
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
r = kexec_add_buffer(&kbuf); r = kexec_add_buffer(&kbuf);
if (r) { if (r) {
pr_err("Failed to call kexec_add_buffer, ret=%d\n", r);
kvfree((void *)kbuf.buffer); kvfree((void *)kbuf.buffer);
return r; return r;
} }

View File

@@ -20,8 +20,6 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <crypto/sha1.h>
#include "kallsyms_internal.h" #include "kallsyms_internal.h"
#include "kexec_internal.h" #include "kexec_internal.h"

View File

@@ -749,14 +749,12 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
tsk->exit_state = EXIT_ZOMBIE; tsk->exit_state = EXIT_ZOMBIE;
if (unlikely(tsk->ptrace)) { if (unlikely(tsk->ptrace)) {
int sig = thread_group_leader(tsk) && int sig = thread_group_empty(tsk) && !ptrace_reparented(tsk)
thread_group_empty(tsk) && ? tsk->exit_signal : SIGCHLD;
!ptrace_reparented(tsk) ?
tsk->exit_signal : SIGCHLD;
autoreap = do_notify_parent(tsk, sig); autoreap = do_notify_parent(tsk, sig);
} else if (thread_group_leader(tsk)) { } else if (thread_group_leader(tsk)) {
autoreap = thread_group_empty(tsk) && autoreap = thread_group_empty(tsk) &&
do_notify_parent(tsk, tsk->exit_signal); do_notify_parent(tsk, tsk->exit_signal);
} else { } else {
autoreap = true; autoreap = true;
/* untraced sub-thread */ /* untraced sub-thread */

View File

@@ -347,7 +347,7 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
stack = kasan_reset_tag(vm_area->addr); stack = kasan_reset_tag(vm_area->addr);
/* Clear stale pointers from reused stack. */ /* Clear stale pointers from reused stack. */
memset(stack, 0, THREAD_SIZE); clear_pages(vm_area->addr, vm_area->nr_pages);
tsk->stack_vm_area = vm_area; tsk->stack_vm_area = vm_area;
tsk->stack = stack; tsk->stack = stack;
@@ -1016,13 +1016,14 @@ free_tsk:
__cacheline_aligned_in_smp DEFINE_SPINLOCK(mmlist_lock); __cacheline_aligned_in_smp DEFINE_SPINLOCK(mmlist_lock);
static unsigned long default_dump_filter = MMF_DUMP_FILTER_DEFAULT; static unsigned long coredump_filter = MMF_DUMP_FILTER_DEFAULT;
static int __init coredump_filter_setup(char *s) static int __init coredump_filter_setup(char *s)
{ {
default_dump_filter = if (kstrtoul(s, 0, &coredump_filter))
(simple_strtoul(s, NULL, 0) << MMF_DUMP_FILTER_SHIFT) & return 0;
MMF_DUMP_FILTER_MASK; coredump_filter <<= MMF_DUMP_FILTER_SHIFT;
coredump_filter &= MMF_DUMP_FILTER_MASK;
return 1; return 1;
} }
@@ -1108,7 +1109,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
__mm_flags_overwrite_word(mm, mmf_init_legacy_flags(flags)); __mm_flags_overwrite_word(mm, mmf_init_legacy_flags(flags));
mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK; mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK;
} else { } else {
__mm_flags_overwrite_word(mm, default_dump_filter); __mm_flags_overwrite_word(mm, coredump_filter);
mm->def_flags = 0; mm->def_flags = 0;
} }
@@ -2435,7 +2436,11 @@ __latent_entropy struct task_struct *copy_process(
rseq_fork(p, clone_flags); rseq_fork(p, clone_flags);
/* Don't start children in a dying pid namespace */ /*
* If zap_pid_ns_processes() was called after alloc_pid(), the new
* child missed SIGKILL. If current is not in the same namespace,
* we can't rely on fatal_signal_pending() below.
*/
if (unlikely(!(ns_of_pid(pid)->pid_allocated & PIDNS_ADDING))) { if (unlikely(!(ns_of_pid(pid)->pid_allocated & PIDNS_ADDING))) {
retval = -ENOMEM; retval = -ENOMEM;
goto bad_fork_core_free; goto bad_fork_core_free;
@@ -3241,11 +3246,10 @@ int ksys_unshare(unsigned long unshare_flags)
new_cred, new_fs); new_cred, new_fs);
if (err) if (err)
goto bad_unshare_cleanup_cred; goto bad_unshare_cleanup_cred;
if (new_cred) { if (new_cred) {
err = set_cred_ucounts(new_cred); err = set_cred_ucounts(new_cred);
if (err) if (err)
goto bad_unshare_cleanup_cred; goto bad_unshare_cleanup_nsproxy;
} }
if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {
@@ -3261,8 +3265,10 @@ int ksys_unshare(unsigned long unshare_flags)
shm_init_task(current); shm_init_task(current);
} }
if (new_nsproxy) if (new_nsproxy) {
switch_task_namespaces(current, new_nsproxy); switch_task_namespaces(current, new_nsproxy);
new_nsproxy = NULL;
}
task_lock(current); task_lock(current);
@@ -3291,13 +3297,15 @@ int ksys_unshare(unsigned long unshare_flags)
perf_event_namespaces(current); perf_event_namespaces(current);
bad_unshare_cleanup_nsproxy:
if (new_nsproxy)
put_nsproxy(new_nsproxy);
bad_unshare_cleanup_cred: bad_unshare_cleanup_cred:
if (new_cred) if (new_cred)
put_cred(new_cred); put_cred(new_cred);
bad_unshare_cleanup_fd: bad_unshare_cleanup_fd:
if (new_fd) if (new_fd)
put_files_struct(new_fd); put_files_struct(new_fd);
bad_unshare_cleanup_fs: bad_unshare_cleanup_fs:
if (new_fs) if (new_fs)
free_fs_struct(new_fs); free_fs_struct(new_fs);

View File

@@ -36,7 +36,7 @@ static int __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
/* /*
* Total number of tasks detected as hung since boot: * Total number of tasks detected as hung since boot:
*/ */
static unsigned long __read_mostly sysctl_hung_task_detect_count; static atomic_long_t sysctl_hung_task_detect_count = ATOMIC_LONG_INIT(0);
/* /*
* Limit number of tasks checked in a batch. * Limit number of tasks checked in a batch.
@@ -223,37 +223,36 @@ static inline void debug_show_blocker(struct task_struct *task, unsigned long ti
} }
#endif #endif
static void check_hung_task(struct task_struct *t, unsigned long timeout, /**
unsigned long prev_detect_count) * hung_task_info - Print diagnostic details for a hung task
* @t: Pointer to the detected hung task.
* @timeout: Timeout threshold for detecting hung tasks
* @this_round_count: Count of hung tasks detected in the current iteration
*
* Print structured information about the specified hung task, if warnings
* are enabled or if the panic batch threshold is exceeded.
*/
static void hung_task_info(struct task_struct *t, unsigned long timeout,
unsigned long this_round_count)
{ {
unsigned long total_hung_task;
if (!task_is_hung(t, timeout))
return;
/*
* This counter tracks the total number of tasks detected as hung
* since boot.
*/
sysctl_hung_task_detect_count++;
total_hung_task = sysctl_hung_task_detect_count - prev_detect_count;
trace_sched_process_hang(t); trace_sched_process_hang(t);
if (sysctl_hung_task_panic && total_hung_task >= sysctl_hung_task_panic) { if (sysctl_hung_task_panic && this_round_count >= sysctl_hung_task_panic) {
console_verbose(); console_verbose();
hung_task_call_panic = true; hung_task_call_panic = true;
} }
/* /*
* Ok, the task did not get scheduled for more than 2 minutes, * The given task did not get scheduled for more than
* complain: * CONFIG_DEFAULT_HUNG_TASK_TIMEOUT. Therefore, complain
* accordingly
*/ */
if (sysctl_hung_task_warnings || hung_task_call_panic) { if (sysctl_hung_task_warnings || hung_task_call_panic) {
if (sysctl_hung_task_warnings > 0) if (sysctl_hung_task_warnings > 0)
sysctl_hung_task_warnings--; sysctl_hung_task_warnings--;
pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n", pr_err("INFO: task %s:%d blocked%s for more than %ld seconds.\n",
t->comm, t->pid, (jiffies - t->last_switch_time) / HZ); t->comm, t->pid, t->in_iowait ? " in I/O wait" : "",
(jiffies - t->last_switch_time) / HZ);
pr_err(" %s %s %.*s\n", pr_err(" %s %s %.*s\n",
print_tainted(), init_utsname()->release, print_tainted(), init_utsname()->release,
(int)strcspn(init_utsname()->version, " "), (int)strcspn(init_utsname()->version, " "),
@@ -297,15 +296,14 @@ static bool rcu_lock_break(struct task_struct *g, struct task_struct *t)
/* /*
* Check whether a TASK_UNINTERRUPTIBLE does not get woken up for * Check whether a TASK_UNINTERRUPTIBLE does not get woken up for
* a really long time (120 seconds). If that happens, print out * a really long time. If that happens, print out a warning.
* a warning.
*/ */
static void check_hung_uninterruptible_tasks(unsigned long timeout) static void check_hung_uninterruptible_tasks(unsigned long timeout)
{ {
int max_count = sysctl_hung_task_check_count; int max_count = sysctl_hung_task_check_count;
unsigned long last_break = jiffies; unsigned long last_break = jiffies;
struct task_struct *g, *t; struct task_struct *g, *t;
unsigned long prev_detect_count = sysctl_hung_task_detect_count; unsigned long this_round_count;
int need_warning = sysctl_hung_task_warnings; int need_warning = sysctl_hung_task_warnings;
unsigned long si_mask = hung_task_si_mask; unsigned long si_mask = hung_task_si_mask;
@@ -316,10 +314,9 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
if (test_taint(TAINT_DIE) || did_panic) if (test_taint(TAINT_DIE) || did_panic)
return; return;
this_round_count = 0;
rcu_read_lock(); rcu_read_lock();
for_each_process_thread(g, t) { for_each_process_thread(g, t) {
if (!max_count--) if (!max_count--)
goto unlock; goto unlock;
if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) { if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) {
@@ -328,12 +325,22 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
last_break = jiffies; last_break = jiffies;
} }
check_hung_task(t, timeout, prev_detect_count); if (task_is_hung(t, timeout)) {
/*
* Increment the global counter so that userspace could
* start migrating tasks ASAP. But count the current
* round separately because userspace could reset
* the global counter at any time.
*/
atomic_long_inc(&sysctl_hung_task_detect_count);
this_round_count++;
hung_task_info(t, timeout, this_round_count);
}
} }
unlock: unlock:
rcu_read_unlock(); rcu_read_unlock();
if (!(sysctl_hung_task_detect_count - prev_detect_count)) if (!this_round_count)
return; return;
if (need_warning || hung_task_call_panic) { if (need_warning || hung_task_call_panic) {
@@ -358,6 +365,46 @@ static long hung_timeout_jiffies(unsigned long last_checked,
} }
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
/**
* proc_dohung_task_detect_count - proc handler for hung_task_detect_count
* @table: Pointer to the struct ctl_table definition for this proc entry
* @dir: Flag indicating the operation
* @buffer: User space buffer for data transfer
* @lenp: Pointer to the length of the data being transferred
* @ppos: Pointer to the current file offset
*
* This handler is used for reading the current hung task detection count
* and for resetting it to zero when a write operation is performed using a
* zero value only.
* Return: 0 on success, or a negative error code on failure.
*/
static int proc_dohung_task_detect_count(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
unsigned long detect_count;
struct ctl_table proxy_table;
int err;
proxy_table = *table;
proxy_table.data = &detect_count;
if (SYSCTL_KERN_TO_USER(dir))
detect_count = atomic_long_read(&sysctl_hung_task_detect_count);
err = proc_doulongvec_minmax(&proxy_table, dir, buffer, lenp, ppos);
if (err < 0)
return err;
if (SYSCTL_USER_TO_KERN(dir)) {
if (detect_count)
return -EINVAL;
atomic_long_set(&sysctl_hung_task_detect_count, 0);
}
return 0;
}
/* /*
* Process updating of timeout sysctl * Process updating of timeout sysctl
*/ */
@@ -438,10 +485,9 @@ static const struct ctl_table hung_task_sysctls[] = {
}, },
{ {
.procname = "hung_task_detect_count", .procname = "hung_task_detect_count",
.data = &sysctl_hung_task_detect_count,
.maxlen = sizeof(unsigned long), .maxlen = sizeof(unsigned long),
.mode = 0444, .mode = 0644,
.proc_handler = proc_doulongvec_minmax, .proc_handler = proc_dohung_task_detect_count,
}, },
{ {
.procname = "hung_task_sys_info", .procname = "hung_task_sys_info",

View File

@@ -47,7 +47,6 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <crypto/hash.h>
#include "kexec_internal.h" #include "kexec_internal.h"
atomic_t __kexec_lock = ATOMIC_INIT(0); atomic_t __kexec_lock = ATOMIC_INIT(0);

View File

@@ -801,6 +801,8 @@ EXPORT_SYMBOL(panic);
* Documentation/admin-guide/tainted-kernels.rst, including its * Documentation/admin-guide/tainted-kernels.rst, including its
* small shell script that prints the TAINT_FLAGS_COUNT bits of * small shell script that prints the TAINT_FLAGS_COUNT bits of
* /proc/sys/kernel/tainted. * /proc/sys/kernel/tainted.
*
* Also, update INIT_TAINT_BUF_MAX below.
*/ */
const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = { const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
TAINT_FLAG(PROPRIETARY_MODULE, 'P', 'G'), TAINT_FLAG(PROPRIETARY_MODULE, 'P', 'G'),
@@ -854,15 +856,54 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
} }
} }
/* The initial buffer can accommodate all taint flags in verbose
* mode, with some headroom. Once the allocator is available, the
* exact size is allocated dynamically; the initial buffer remains
* as a fallback if allocation fails.
*
* The verbose taint string currently requires up to 327 characters.
*/
#define INIT_TAINT_BUF_MAX 350
static char init_taint_buf[INIT_TAINT_BUF_MAX] __initdata;
static char *taint_buf __refdata = init_taint_buf;
static size_t taint_buf_size = INIT_TAINT_BUF_MAX;
static __init int alloc_taint_buf(void)
{
int i;
char *buf;
size_t size = 0;
size += sizeof("Tainted: ") - 1;
for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
size += 2; /* For ", " */
size += 4; /* For "[%c]=" */
size += strlen(taint_flags[i].desc);
}
size += 1; /* For NULL terminator */
buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
panic("Failed to allocate taint string buffer");
}
taint_buf = buf;
taint_buf_size = size;
return 0;
}
postcore_initcall(alloc_taint_buf);
static const char *_print_tainted(bool verbose) static const char *_print_tainted(bool verbose)
{ {
/* FIXME: what should the size be? */
static char buf[sizeof(taint_flags)];
struct seq_buf s; struct seq_buf s;
BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT); BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
seq_buf_init(&s, buf, sizeof(buf)); seq_buf_init(&s, taint_buf, taint_buf_size);
print_tainted_seq(&s, verbose); print_tainted_seq(&s, verbose);

View File

@@ -131,9 +131,8 @@ void free_pid(struct pid *pid)
wake_up_process(READ_ONCE(ns->child_reaper)); wake_up_process(READ_ONCE(ns->child_reaper));
break; break;
case PIDNS_ADDING: case PIDNS_ADDING:
/* Handle a fork failure of the first process */ /* Only possible if the 1st fork fails */
WARN_ON(ns->child_reaper); WARN_ON(READ_ONCE(ns->child_reaper));
ns->pid_allocated = 0;
break; break;
} }
@@ -230,6 +229,10 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
retried_preload = false; retried_preload = false;
idr_preload(GFP_KERNEL); idr_preload(GFP_KERNEL);
spin_lock(&pidmap_lock); spin_lock(&pidmap_lock);
/* For the case when the previous attempt to create init failed */
if (ns->pid_allocated == PIDNS_ADDING)
idr_set_cursor(&ns->idr, 0);
for (tmp = ns, i = ns->level; i >= 0;) { for (tmp = ns, i = ns->level; i >= 0;) {
int tid = set_tid[ns->level - i]; int tid = set_tid[ns->level - i];
@@ -314,6 +317,11 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
* *
* This can't be done earlier because we need to preserve other * This can't be done earlier because we need to preserve other
* error conditions. * error conditions.
*
* We need this even if copy_process() does the same check. If two
* or more tasks from parent namespace try to inject a child into a
* dead namespace, one of free_pid() calls from the copy_process()
* error path may try to wakeup the possibly freed ns->child_reaper.
*/ */
retval = -ENOMEM; retval = -ENOMEM;
if (unlikely(!(ns->pid_allocated & PIDNS_ADDING))) if (unlikely(!(ns->pid_allocated & PIDNS_ADDING)))
@@ -341,10 +349,6 @@ out_free:
idr_remove(&upid->ns->idr, upid->nr); idr_remove(&upid->ns->idr, upid->nr);
} }
/* On failure to allocate the first pid, reset the state */
if (ns->pid_allocated == PIDNS_ADDING)
idr_set_cursor(&ns->idr, 0);
spin_unlock(&pidmap_lock); spin_unlock(&pidmap_lock);
idr_preload_end(); idr_preload_end();

View File

@@ -1000,9 +1000,7 @@ static void complete_signal(int sig, struct task_struct *p, enum pid_type type)
* Found a killable thread. If the signal will be fatal, * Found a killable thread. If the signal will be fatal,
* then start taking the whole group down immediately. * then start taking the whole group down immediately.
*/ */
if (sig_fatal(p, sig) && if (sig_fatal(p, sig) && !sigismember(&t->real_blocked, sig) &&
(signal->core_state || !(signal->flags & SIGNAL_GROUP_EXIT)) &&
!sigismember(&t->real_blocked, sig) &&
(sig == SIGKILL || !p->ptrace)) { (sig == SIGKILL || !p->ptrace)) {
/* /*
* This signal will be fatal to the whole group. * This signal will be fatal to the whole group.
@@ -2173,13 +2171,13 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
bool autoreap = false; bool autoreap = false;
u64 utime, stime; u64 utime, stime;
WARN_ON_ONCE(sig == -1); if (WARN_ON_ONCE(!valid_signal(sig)))
return false;
/* do_notify_parent_cldstop should have been called instead. */ /* do_notify_parent_cldstop should have been called instead. */
WARN_ON_ONCE(task_is_stopped_or_traced(tsk)); WARN_ON_ONCE(task_is_stopped_or_traced(tsk));
WARN_ON_ONCE(!tsk->ptrace && WARN_ON_ONCE(!tsk->ptrace && !thread_group_empty(tsk));
(tsk->group_leader != tsk || !thread_group_empty(tsk)));
/* ptraced, or group-leader without sub-threads */ /* ptraced, or group-leader without sub-threads */
do_notify_pidfd(tsk); do_notify_pidfd(tsk);
@@ -2259,7 +2257,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
* Send with __send_signal as si_pid and si_uid are in the * Send with __send_signal as si_pid and si_uid are in the
* parent's namespaces. * parent's namespaces.
*/ */
if (valid_signal(sig) && sig) if (sig)
__send_signal_locked(sig, &info, tsk->parent, PIDTYPE_TGID, false); __send_signal_locked(sig, &info, tsk->parent, PIDTYPE_TGID, false);
__wake_up_parent(tsk, tsk->parent); __wake_up_parent(tsk, tsk->parent);
spin_unlock_irqrestore(&psig->siglock, flags); spin_unlock_irqrestore(&psig->siglock, flags);

View File

@@ -649,6 +649,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
goto err; goto err;
memcpy(stats, tsk->signal->stats, sizeof(*stats)); memcpy(stats, tsk->signal->stats, sizeof(*stats));
stats->version = TASKSTATS_VERSION;
send: send:
send_cpu_listeners(rep_skb, listeners); send_cpu_listeners(rep_skb, listeners);

View File

@@ -18,8 +18,6 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <crypto/sha1.h>
#include "kallsyms_internal.h" #include "kallsyms_internal.h"
#include "kexec_internal.h" #include "kexec_internal.h"

View File

@@ -60,6 +60,13 @@ unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask);
int __read_mostly sysctl_hardlockup_all_cpu_backtrace; int __read_mostly sysctl_hardlockup_all_cpu_backtrace;
# endif /* CONFIG_SMP */ # endif /* CONFIG_SMP */
/*
* Number of consecutive missed interrupts before declaring a lockup.
* Default to 1 (immediate) for NMI/Perf. Buddy will overwrite this to 3.
*/
int __read_mostly watchdog_hardlockup_miss_thresh = 1;
EXPORT_SYMBOL_GPL(watchdog_hardlockup_miss_thresh);
/* /*
* Should we panic when a soft-lockup or hard-lockup occurs: * Should we panic when a soft-lockup or hard-lockup occurs:
*/ */
@@ -137,6 +144,7 @@ __setup("nmi_watchdog=", hardlockup_panic_setup);
static DEFINE_PER_CPU(atomic_t, hrtimer_interrupts); static DEFINE_PER_CPU(atomic_t, hrtimer_interrupts);
static DEFINE_PER_CPU(int, hrtimer_interrupts_saved); static DEFINE_PER_CPU(int, hrtimer_interrupts_saved);
static DEFINE_PER_CPU(int, hrtimer_interrupts_missed);
static DEFINE_PER_CPU(bool, watchdog_hardlockup_warned); static DEFINE_PER_CPU(bool, watchdog_hardlockup_warned);
static DEFINE_PER_CPU(bool, watchdog_hardlockup_touched); static DEFINE_PER_CPU(bool, watchdog_hardlockup_touched);
static unsigned long hard_lockup_nmi_warn; static unsigned long hard_lockup_nmi_warn;
@@ -159,21 +167,33 @@ void watchdog_hardlockup_touch_cpu(unsigned int cpu)
per_cpu(watchdog_hardlockup_touched, cpu) = true; per_cpu(watchdog_hardlockup_touched, cpu) = true;
} }
static bool is_hardlockup(unsigned int cpu) static void watchdog_hardlockup_update_reset(unsigned int cpu)
{ {
int hrint = atomic_read(&per_cpu(hrtimer_interrupts, cpu)); int hrint = atomic_read(&per_cpu(hrtimer_interrupts, cpu));
if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
return true;
/* /*
* NOTE: we don't need any fancy atomic_t or READ_ONCE/WRITE_ONCE * NOTE: we don't need any fancy atomic_t or READ_ONCE/WRITE_ONCE
* for hrtimer_interrupts_saved. hrtimer_interrupts_saved is * for hrtimer_interrupts_saved. hrtimer_interrupts_saved is
* written/read by a single CPU. * written/read by a single CPU.
*/ */
per_cpu(hrtimer_interrupts_saved, cpu) = hrint; per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
per_cpu(hrtimer_interrupts_missed, cpu) = 0;
}
return false; static bool is_hardlockup(unsigned int cpu)
{
int hrint = atomic_read(&per_cpu(hrtimer_interrupts, cpu));
if (per_cpu(hrtimer_interrupts_saved, cpu) != hrint) {
watchdog_hardlockup_update_reset(cpu);
return false;
}
per_cpu(hrtimer_interrupts_missed, cpu)++;
if (per_cpu(hrtimer_interrupts_missed, cpu) % watchdog_hardlockup_miss_thresh)
return false;
return true;
} }
static void watchdog_hardlockup_kick(void) static void watchdog_hardlockup_kick(void)
@@ -187,8 +207,11 @@ static void watchdog_hardlockup_kick(void)
void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs) void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
{ {
int hardlockup_all_cpu_backtrace; int hardlockup_all_cpu_backtrace;
unsigned int this_cpu;
unsigned long flags;
if (per_cpu(watchdog_hardlockup_touched, cpu)) { if (per_cpu(watchdog_hardlockup_touched, cpu)) {
watchdog_hardlockup_update_reset(cpu);
per_cpu(watchdog_hardlockup_touched, cpu) = false; per_cpu(watchdog_hardlockup_touched, cpu) = false;
return; return;
} }
@@ -201,74 +224,73 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
* fired multiple times before we overflow'd. If it hasn't * fired multiple times before we overflow'd. If it hasn't
* then this is a good indication the cpu is stuck * then this is a good indication the cpu is stuck
*/ */
if (is_hardlockup(cpu)) { if (!is_hardlockup(cpu)) {
unsigned int this_cpu = smp_processor_id(); per_cpu(watchdog_hardlockup_warned, cpu) = false;
unsigned long flags; return;
}
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
++hardlockup_count; ++hardlockup_count;
#endif #endif
/* /*
* A poorly behaving BPF scheduler can trigger hard lockup by * A poorly behaving BPF scheduler can trigger hard lockup by
* e.g. putting numerous affinitized tasks in a single queue and * e.g. putting numerous affinitized tasks in a single queue and
* directing all CPUs at it. The following call can return true * directing all CPUs at it. The following call can return true
* only once when sched_ext is enabled and will immediately * only once when sched_ext is enabled and will immediately
* abort the BPF scheduler and print out a warning message. * abort the BPF scheduler and print out a warning message.
*/ */
if (scx_hardlockup(cpu)) if (scx_hardlockup(cpu))
return;
/* Only print hardlockups once. */
if (per_cpu(watchdog_hardlockup_warned, cpu))
return;
/*
* Prevent multiple hard-lockup reports if one cpu is already
* engaged in dumping all cpu back traces.
*/
if (hardlockup_all_cpu_backtrace) {
if (test_and_set_bit_lock(0, &hard_lockup_nmi_warn))
return; return;
/* Only print hardlockups once. */
if (per_cpu(watchdog_hardlockup_warned, cpu))
return;
/*
* Prevent multiple hard-lockup reports if one cpu is already
* engaged in dumping all cpu back traces.
*/
if (hardlockup_all_cpu_backtrace) {
if (test_and_set_bit_lock(0, &hard_lockup_nmi_warn))
return;
}
/*
* NOTE: we call printk_cpu_sync_get_irqsave() after printing
* the lockup message. While it would be nice to serialize
* that printout, we really want to make sure that if some
* other CPU somehow locked up while holding the lock associated
* with printk_cpu_sync_get_irqsave() that we can still at least
* get the message about the lockup out.
*/
pr_emerg("CPU%u: Watchdog detected hard LOCKUP on cpu %u\n", this_cpu, cpu);
printk_cpu_sync_get_irqsave(flags);
print_modules();
print_irqtrace_events(current);
if (cpu == this_cpu) {
if (regs)
show_regs(regs);
else
dump_stack();
printk_cpu_sync_put_irqrestore(flags);
} else {
printk_cpu_sync_put_irqrestore(flags);
trigger_single_cpu_backtrace(cpu);
}
if (hardlockup_all_cpu_backtrace) {
trigger_allbutcpu_cpu_backtrace(cpu);
if (!hardlockup_panic)
clear_bit_unlock(0, &hard_lockup_nmi_warn);
}
sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
if (hardlockup_panic)
nmi_panic(regs, "Hard LOCKUP");
per_cpu(watchdog_hardlockup_warned, cpu) = true;
} else {
per_cpu(watchdog_hardlockup_warned, cpu) = false;
} }
/*
* NOTE: we call printk_cpu_sync_get_irqsave() after printing
* the lockup message. While it would be nice to serialize
* that printout, we really want to make sure that if some
* other CPU somehow locked up while holding the lock associated
* with printk_cpu_sync_get_irqsave() that we can still at least
* get the message about the lockup out.
*/
this_cpu = smp_processor_id();
pr_emerg("CPU%u: Watchdog detected hard LOCKUP on cpu %u\n", this_cpu, cpu);
printk_cpu_sync_get_irqsave(flags);
print_modules();
print_irqtrace_events(current);
if (cpu == this_cpu) {
if (regs)
show_regs(regs);
else
dump_stack();
printk_cpu_sync_put_irqrestore(flags);
} else {
printk_cpu_sync_put_irqrestore(flags);
trigger_single_cpu_backtrace(cpu);
}
if (hardlockup_all_cpu_backtrace) {
trigger_allbutcpu_cpu_backtrace(cpu);
if (!hardlockup_panic)
clear_bit_unlock(0, &hard_lockup_nmi_warn);
}
sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
if (hardlockup_panic)
nmi_panic(regs, "Hard LOCKUP");
per_cpu(watchdog_hardlockup_warned, cpu) = true;
} }
#else /* CONFIG_HARDLOCKUP_DETECTOR_COUNTS_HRTIMER */ #else /* CONFIG_HARDLOCKUP_DETECTOR_COUNTS_HRTIMER */

View File

@@ -21,6 +21,7 @@ static unsigned int watchdog_next_cpu(unsigned int cpu)
int __init watchdog_hardlockup_probe(void) int __init watchdog_hardlockup_probe(void)
{ {
watchdog_hardlockup_miss_thresh = 3;
return 0; return 0;
} }
@@ -86,14 +87,6 @@ void watchdog_buddy_check_hardlockup(int hrtimer_interrupts)
{ {
unsigned int next_cpu; unsigned int next_cpu;
/*
* Test for hardlockups every 3 samples. The sample period is
* watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over
* watchdog_thresh (over by 20%).
*/
if (hrtimer_interrupts % 3 != 0)
return;
/* check for a hardlockup on the next CPU */ /* check for a hardlockup on the next CPU */
next_cpu = watchdog_next_cpu(smp_processor_id()); next_cpu = watchdog_next_cpu(smp_processor_id());
if (next_cpu >= nr_cpu_ids) if (next_cpu >= nr_cpu_ids)

View File

@@ -138,6 +138,7 @@ config TRACE_MMIO_ACCESS
source "lib/crc/Kconfig" source "lib/crc/Kconfig"
source "lib/crypto/Kconfig" source "lib/crypto/Kconfig"
source "lib/raid/Kconfig"
config XXHASH config XXHASH
tristate tristate
@@ -625,9 +626,6 @@ config PLDMFW
config ASN1_ENCODER config ASN1_ENCODER
tristate tristate
config POLYNOMIAL
tristate
config FIRMWARE_TABLE config FIRMWARE_TABLE
bool bool

View File

@@ -121,7 +121,7 @@ endif
obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o
CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any) CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
obj-y += math/ crc/ crypto/ tests/ vdso/ obj-y += math/ crc/ crypto/ tests/ vdso/ raid/
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
@@ -244,8 +244,6 @@ obj-$(CONFIG_MEMREGION) += memregion.o
obj-$(CONFIG_STMP_DEVICE) += stmp_device.o obj-$(CONFIG_STMP_DEVICE) += stmp_device.o
obj-$(CONFIG_IRQ_POLL) += irq_poll.o obj-$(CONFIG_IRQ_POLL) += irq_poll.o
obj-$(CONFIG_POLYNOMIAL) += polynomial.o
# stackdepot.c should not be instrumented or call instrumented functions. # stackdepot.c should not be instrumented or call instrumented functions.
# Prevent the compiler from calling builtins like memcmp() or bcmp() from this # Prevent the compiler from calling builtins like memcmp() or bcmp() from this
# file. # file.

View File

@@ -392,7 +392,7 @@ static void compute_syndromes(struct bch_control *bch, uint32_t *ecc,
for (j = 0; j < 2*t; j += 2) for (j = 0; j < 2*t; j += 2)
syn[j] ^= a_pow(bch, (j+1)*(i+s)); syn[j] ^= a_pow(bch, (j+1)*(i+s));
poly ^= (1 << i); poly ^= (1u << i);
} }
} while (s > 0); } while (s > 0);
@@ -612,7 +612,7 @@ static int find_poly_deg2_roots(struct bch_control *bch, struct gf_poly *poly,
while (v) { while (v) {
i = deg(v); i = deg(v);
r ^= bch->xi_tab[i]; r ^= bch->xi_tab[i];
v ^= (1 << i); v ^= (1u << i);
} }
/* verify root */ /* verify root */
if ((gf_sqr(bch, r)^r) == u) { if ((gf_sqr(bch, r)^r) == u) {
@@ -1116,7 +1116,7 @@ static void build_mod8_tables(struct bch_control *bch, const uint32_t *g)
for (b = 0; b < 4; b++) { for (b = 0; b < 4; b++) {
/* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */ /* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */
tab = bch->mod8_tab + (b*256+i)*l; tab = bch->mod8_tab + (b*256+i)*l;
data = i << (8*b); data = (unsigned int)i << (8*b);
while (data) { while (data) {
d = deg(data); d = deg(data);
/* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */ /* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */

View File

@@ -251,7 +251,7 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
if (file) if (file)
pr_crit("kernel BUG at %s:%u!\n", file, line); pr_crit("kernel BUG at %s:%u!\n", file, line);
else else
pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n", pr_crit("kernel BUG at %pB [verbose debug info unavailable]\n",
(void *)bugaddr); (void *)bugaddr);
return BUG_TRAP_TYPE_BUG; return BUG_TRAP_TYPE_BUG;
@@ -260,7 +260,7 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
enum bug_trap_type report_bug_entry(struct bug_entry *bug, struct pt_regs *regs) enum bug_trap_type report_bug_entry(struct bug_entry *bug, struct pt_regs *regs)
{ {
enum bug_trap_type ret; enum bug_trap_type ret;
bool rcu = false; bool rcu;
rcu = warn_rcu_enter(); rcu = warn_rcu_enter();
ret = __report_bug(bug, bug_addr(bug), regs); ret = __report_bug(bug, bug_addr(bug), regs);
@@ -272,7 +272,7 @@ enum bug_trap_type report_bug_entry(struct bug_entry *bug, struct pt_regs *regs)
enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
{ {
enum bug_trap_type ret; enum bug_trap_type ret;
bool rcu = false; bool rcu;
rcu = warn_rcu_enter(); rcu = warn_rcu_enter();
ret = __report_bug(NULL, bugaddr, regs); ret = __report_bug(NULL, bugaddr, regs);

View File

@@ -135,7 +135,7 @@ static unsigned int INIT get_bits(struct bunzip_data *bd, char bits_wanted)
} }
/* Avoid 32-bit overflow (dump bit buffer to top of output) */ /* Avoid 32-bit overflow (dump bit buffer to top of output) */
if (bd->inbufBitCount >= 24) { if (bd->inbufBitCount >= 24) {
bits = bd->inbufBits&((1 << bd->inbufBitCount)-1); bits = bd->inbufBits & ((1ULL << bd->inbufBitCount) - 1);
bits_wanted -= bd->inbufBitCount; bits_wanted -= bd->inbufBitCount;
bits <<= bits_wanted; bits <<= bits_wanted;
bd->inbufBitCount = 0; bd->inbufBitCount = 0;
@@ -146,7 +146,7 @@ static unsigned int INIT get_bits(struct bunzip_data *bd, char bits_wanted)
} }
/* Calculate result */ /* Calculate result */
bd->inbufBitCount -= bits_wanted; bd->inbufBitCount -= bits_wanted;
bits |= (bd->inbufBits >> bd->inbufBitCount)&((1 << bits_wanted)-1); bits |= (bd->inbufBits >> bd->inbufBitCount) & ((1ULL << bits_wanted) - 1);
return bits; return bits;
} }

View File

@@ -1,5 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
#include <linux/module.h> #include <linux/module.h>
#include <linux/glob.h> #include <linux/glob.h>
#include <linux/export.h>
/* /*
* The only reason this code can be compiled as a module is because the * The only reason this code can be compiled as a module is because the
@@ -20,7 +22,7 @@ MODULE_LICENSE("Dual MIT/GPL");
* Pattern metacharacters are ?, *, [ and \. * Pattern metacharacters are ?, *, [ and \.
* (And, inside character classes, !, - and ].) * (And, inside character classes, !, - and ].)
* *
* This is small and simple implementation intended for device blacklists * This is a small and simple implementation intended for device denylists
* where a string is matched against a number of patterns. Thus, it * where a string is matched against a number of patterns. Thus, it
* does not preprocess the patterns. It is non-recursive, and run-time * does not preprocess the patterns. It is non-recursive, and run-time
* is at most quadratic: strlen(@str)*strlen(@pat). * is at most quadratic: strlen(@str)*strlen(@pat).
@@ -45,7 +47,7 @@ bool __pure glob_match(char const *pat, char const *str)
* (no exception for /), it can be easily proved that there's * (no exception for /), it can be easily proved that there's
* never a need to backtrack multiple levels. * never a need to backtrack multiple levels.
*/ */
char const *back_pat = NULL, *back_str; char const *back_pat = NULL, *back_str = NULL;
/* /*
* Loop over each token (character or class) in pat, matching * Loop over each token (character or class) in pat, matching
@@ -71,7 +73,7 @@ bool __pure glob_match(char const *pat, char const *str)
if (c == '\0') /* No possible match */ if (c == '\0') /* No possible match */
return false; return false;
bool match = false, inverted = (*pat == '!'); bool match = false, inverted = (*pat == '!');
char const *class = pat + inverted; char const *class = inverted ? pat + 1 : pat;
unsigned char a = *class++; unsigned char a = *class++;
/* /*
@@ -94,7 +96,8 @@ bool __pure glob_match(char const *pat, char const *str)
class += 2; class += 2;
/* Any special action if a > b? */ /* Any special action if a > b? */
} }
match |= (a <= c && c <= b); if (a <= c && c <= b)
match = true;
} while ((a = *class++) != ']'); } while ((a = *class++) != ']');
if (match == inverted) if (match == inverted)

View File

@@ -9,7 +9,7 @@
* based on gzip-1.0.3 * based on gzip-1.0.3
* *
* Nicolas Pitre <nico@fluxnic.net>, 1999/04/14 : * Nicolas Pitre <nico@fluxnic.net>, 1999/04/14 :
* Little mods for all variable to reside either into rodata or bss segments * Little mods for all variables to reside either into rodata or bss segments
* by marking constant variables with 'const' and initializing all the others * by marking constant variables with 'const' and initializing all the others
* at run-time only. This allows for the kernel uncompressor to run * at run-time only. This allows for the kernel uncompressor to run
* directly from Flash or ROM memory on embedded systems. * directly from Flash or ROM memory on embedded systems.
@@ -286,7 +286,7 @@ static void free(void *where)
the longer codes. The time it costs to decode the longer codes is the longer codes. The time it costs to decode the longer codes is
then traded against the time it takes to make longer tables. then traded against the time it takes to make longer tables.
This results of this trade are in the variables lbits and dbits The results of this trade are in the variables lbits and dbits
below. lbits is the number of bits the first level table for literal/ below. lbits is the number of bits the first level table for literal/
length codes can decode in one step, and dbits is the same thing for length codes can decode in one step, and dbits is the same thing for
the distance codes. Subsequent tables are also less than or equal to the distance codes. Subsequent tables are also less than or equal to
@@ -811,6 +811,8 @@ DEBG("<fix");
/* decompress until an end-of-block code */ /* decompress until an end-of-block code */
if (inflate_codes(tl, td, bl, bd)) { if (inflate_codes(tl, td, bl, bd)) {
huft_free(tl);
huft_free(td);
free(l); free(l);
return 1; return 1;
} }
@@ -1007,10 +1009,10 @@ DEBG("dyn5d ");
DEBG("dyn6 "); DEBG("dyn6 ");
/* decompress until an end-of-block code */ /* decompress until an end-of-block code */
if (inflate_codes(tl, td, bl, bd)) { if (inflate_codes(tl, td, bl, bd))
ret = 1; ret = 1;
goto out; else
} ret = 0;
DEBG("dyn7 "); DEBG("dyn7 ");
@@ -1019,7 +1021,6 @@ DEBG("dyn7 ");
huft_free(td); huft_free(td);
DEBG(">"); DEBG(">");
ret = 0;
out: out:
free(ll); free(ll);
return ret; return ret;

View File

@@ -50,7 +50,6 @@ static void merge_final(void *priv, list_cmp_func_t cmp, struct list_head *head,
struct list_head *a, struct list_head *b) struct list_head *a, struct list_head *b)
{ {
struct list_head *tail = head; struct list_head *tail = head;
u8 count = 0;
for (;;) { for (;;) {
/* if equal, take 'a' -- important for sort stability */ /* if equal, take 'a' -- important for sort stability */
@@ -76,15 +75,6 @@ static void merge_final(void *priv, list_cmp_func_t cmp, struct list_head *head,
/* Finish linking remainder of list b on to tail */ /* Finish linking remainder of list b on to tail */
tail->next = b; tail->next = b;
do { do {
/*
* If the merge is highly unbalanced (e.g. the input is
* already sorted), this loop may run many iterations.
* Continue callbacks to the client even though no
* element comparison is needed, so the client's cmp()
* routine can invoke cond_resched() periodically.
*/
if (unlikely(!++count))
cmp(priv, b, b);
b->prev = tail; b->prev = tail;
tail = b; tail = b;
b = b->next; b = b->next;

View File

@@ -5,6 +5,9 @@ config CORDIC
This option provides an implementation of the CORDIC algorithm; This option provides an implementation of the CORDIC algorithm;
calculations are in fixed point. Module will be called cordic. calculations are in fixed point. Module will be called cordic.
config POLYNOMIAL
tristate
config PRIME_NUMBERS config PRIME_NUMBERS
tristate "Simple prime number generator for testing" tristate "Simple prime number generator for testing"
help help

View File

@@ -2,6 +2,7 @@
obj-y += div64.o gcd.o lcm.o int_log.o int_pow.o int_sqrt.o reciprocal_div.o obj-y += div64.o gcd.o lcm.o int_log.o int_pow.o int_sqrt.o reciprocal_div.o
obj-$(CONFIG_CORDIC) += cordic.o obj-$(CONFIG_CORDIC) += cordic.o
obj-$(CONFIG_POLYNOMIAL) += polynomial.o
obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o
obj-$(CONFIG_RATIONAL) += rational.o obj-$(CONFIG_RATIONAL) += rational.o

View File

@@ -10,21 +10,19 @@
* *
*/ */
#include <linux/kernel.h> #include <linux/export.h>
#include <linux/math.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/polynomial.h> #include <linux/polynomial.h>
/* /*
* Originally this was part of drivers/hwmon/bt1-pvt.c. * The following conversion is an example:
* There the following conversion is used and should serve as an example here:
* *
* The original translation formulae of the temperature (in degrees of Celsius) * The original translation formulae of the temperature (in degrees of Celsius)
* to PVT data and vice-versa are following: * to PVT data and vice-versa are following:
* *
* N = 1.8322e-8*(T^4) + 2.343e-5*(T^3) + 8.7018e-3*(T^2) + 3.9269*(T^1) + * N = 1.8322e-8*(T^4) + 2.343e-5*(T^3) + 8.7018e-3*(T^2) + 3.9269*(T^1) + 1.7204e2
* 1.7204e2 * T = -1.6743e-11*(N^4) + 8.1542e-8*(N^3) + -1.8201e-4*(N^2) + 3.1020e-1*(N^1) - 4.838e1
* T = -1.6743e-11*(N^4) + 8.1542e-8*(N^3) + -1.8201e-4*(N^2) +
* 3.1020e-1*(N^1) - 4.838e1
* *
* where T = [-48.380, 147.438]C and N = [0, 1023]. * where T = [-48.380, 147.438]C and N = [0, 1023].
* *
@@ -35,10 +33,9 @@
* formulae to accept millidegrees of Celsius. Here what they look like after * formulae to accept millidegrees of Celsius. Here what they look like after
* the alterations: * the alterations:
* *
* N = (18322e-20*(T^4) + 2343e-13*(T^3) + 87018e-9*(T^2) + 39269e-3*T + * N = (18322e-20*(T^4) + 2343e-13*(T^3) + 87018e-9*(T^2) + 39269e-3*T + 17204e2) / 1e4
* 17204e2) / 1e4 * T = -16743e-12*(D^4) + 81542e-9*(D^3) - 182010e-6*(D^2) + 310200e-3*D - 48380
* T = -16743e-12*(D^4) + 81542e-9*(D^3) - 182010e-6*(D^2) + 310200e-3*D - *
* 48380
* where T = [-48380, 147438] mC and N = [0, 1023]. * where T = [-48380, 147438] mC and N = [0, 1023].
* *
* static const struct polynomial poly_temp_to_N = { * static const struct polynomial poly_temp_to_N = {
@@ -68,13 +65,13 @@
* polynomial_calc - calculate a polynomial using integer arithmetic * polynomial_calc - calculate a polynomial using integer arithmetic
* *
* @poly: pointer to the descriptor of the polynomial * @poly: pointer to the descriptor of the polynomial
* @data: input value of the polynimal * @data: input value of the polynomial
* *
* Calculate the result of a polynomial using only integer arithmetic. For * Calculate the result of a polynomial using only integer arithmetic. For
* this to work without too much loss of precision the coefficients has to * this to work without too much loss of precision the coefficients has to
* be altered. This is called factor redistribution. * be altered. This is called factor redistribution.
* *
* Returns the result of the polynomial calculation. * Return: the result of the polynomial calculation.
*/ */
long polynomial_calc(const struct polynomial *poly, long data) long polynomial_calc(const struct polynomial *poly, long data)
{ {

View File

@@ -315,7 +315,7 @@ bool match_wildcard(const char *pattern, const char *str)
} }
} }
if (*p == '*') while (*p == '*')
++p; ++p;
return !*p; return !*p;
} }

3
lib/raid/.kunitconfig Normal file
View File

@@ -0,0 +1,3 @@
CONFIG_KUNIT=y
CONFIG_BTRFS_FS=y
CONFIG_XOR_KUNIT_TEST=y

30
lib/raid/Kconfig Normal file
View File

@@ -0,0 +1,30 @@
# SPDX-License-Identifier: GPL-2.0
config XOR_BLOCKS
tristate
# selected by architectures that provide an optimized XOR implementation
config XOR_BLOCKS_ARCH
depends on XOR_BLOCKS
default y if ALPHA
default y if ARM
default y if ARM64
default y if CPU_HAS_LSX # loongarch
default y if ALTIVEC # powerpc
default y if RISCV_ISA_V
default y if SPARC
default y if S390
default y if X86_32
default y if X86_64
bool
config XOR_KUNIT_TEST
tristate "KUnit tests for xor_gen" if !KUNIT_ALL_TESTS
depends on KUNIT
depends on XOR_BLOCKS
default KUNIT_ALL_TESTS
help
Unit tests for the XOR library functions.
This is intended to help people writing architecture-specific
optimized versions. If unsure, say N.

3
lib/raid/Makefile Normal file
View File

@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += xor/

42
lib/raid/xor/Makefile Normal file
View File

@@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0
ccflags-y += -I $(src)
obj-$(CONFIG_XOR_BLOCKS) += xor.o
xor-y += xor-core.o
xor-y += xor-8regs.o
xor-y += xor-32regs.o
xor-y += xor-8regs-prefetch.o
xor-y += xor-32regs-prefetch.o
ifeq ($(CONFIG_XOR_BLOCKS_ARCH),y)
CFLAGS_xor-core.o += -I$(src)/$(SRCARCH)
endif
xor-$(CONFIG_ALPHA) += alpha/xor.o
xor-$(CONFIG_ARM) += arm/xor.o
ifeq ($(CONFIG_ARM),y)
xor-$(CONFIG_KERNEL_MODE_NEON) += arm/xor-neon.o arm/xor-neon-glue.o
endif
xor-$(CONFIG_ARM64) += arm64/xor-neon.o arm64/xor-neon-glue.o
xor-$(CONFIG_CPU_HAS_LSX) += loongarch/xor_simd.o
xor-$(CONFIG_CPU_HAS_LSX) += loongarch/xor_simd_glue.o
xor-$(CONFIG_ALTIVEC) += powerpc/xor_vmx.o powerpc/xor_vmx_glue.o
xor-$(CONFIG_RISCV_ISA_V) += riscv/xor.o riscv/xor-glue.o
xor-$(CONFIG_SPARC32) += sparc/xor-sparc32.o
xor-$(CONFIG_SPARC64) += sparc/xor-sparc64.o sparc/xor-sparc64-glue.o
xor-$(CONFIG_S390) += s390/xor.o
xor-$(CONFIG_X86_32) += x86/xor-avx.o x86/xor-sse.o x86/xor-mmx.o
xor-$(CONFIG_X86_64) += x86/xor-avx.o x86/xor-sse.o
obj-y += tests/
CFLAGS_arm/xor-neon.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_arm/xor-neon.o += $(CC_FLAGS_NO_FPU)
CFLAGS_arm64/xor-neon.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_arm64/xor-neon.o += $(CC_FLAGS_NO_FPU)
CFLAGS_powerpc/xor_vmx.o += -mhard-float -maltivec \
$(call cc-option,-mabi=altivec) \
-isystem $(shell $(CC) -print-file-name=include)

View File

@@ -1,9 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */ // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* include/asm-alpha/xor.h * Optimized XOR parity functions for alpha EV5 and EV6
*
* Optimized RAID-5 checksumming functions for alpha EV5 and EV6
*/ */
#include "xor_impl.h"
#include "xor_arch.h"
extern void extern void
xor_alpha_2(unsigned long bytes, unsigned long * __restrict p1, xor_alpha_2(unsigned long bytes, unsigned long * __restrict p1,
@@ -832,35 +832,17 @@ xor_alpha_prefetch_5: \n\
.end xor_alpha_prefetch_5 \n\ .end xor_alpha_prefetch_5 \n\
"); ");
static struct xor_block_template xor_block_alpha = { DO_XOR_BLOCKS(alpha, xor_alpha_2, xor_alpha_3, xor_alpha_4, xor_alpha_5);
.name = "alpha",
.do_2 = xor_alpha_2, struct xor_block_template xor_block_alpha = {
.do_3 = xor_alpha_3, .name = "alpha",
.do_4 = xor_alpha_4, .xor_gen = xor_gen_alpha,
.do_5 = xor_alpha_5,
}; };
static struct xor_block_template xor_block_alpha_prefetch = { DO_XOR_BLOCKS(alpha_prefetch, xor_alpha_prefetch_2, xor_alpha_prefetch_3,
.name = "alpha prefetch", xor_alpha_prefetch_4, xor_alpha_prefetch_5);
.do_2 = xor_alpha_prefetch_2,
.do_3 = xor_alpha_prefetch_3, struct xor_block_template xor_block_alpha_prefetch = {
.do_4 = xor_alpha_prefetch_4, .name = "alpha prefetch",
.do_5 = xor_alpha_prefetch_5, .xor_gen = xor_gen_alpha_prefetch,
}; };
/* For grins, also test the generic routines. */
#include <asm-generic/xor.h>
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_32regs); \
xor_speed(&xor_block_alpha); \
xor_speed(&xor_block_alpha_prefetch); \
} while (0)
/* Force the use of alpha_prefetch if EV6, as it is significantly
faster in the cold cache case. */
#define XOR_SELECT_TEMPLATE(FASTEST) \
(implver() == IMPLVER_EV6 ? &xor_block_alpha_prefetch : FASTEST)

View File

@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <asm/special_insns.h>
extern struct xor_block_template xor_block_alpha;
extern struct xor_block_template xor_block_alpha_prefetch;
/*
* Force the use of alpha_prefetch if EV6, as it is significantly faster in the
* cold cache case.
*/
static __always_inline void __init arch_xor_init(void)
{
if (implver() == IMPLVER_EV6) {
xor_force(&xor_block_alpha_prefetch);
} else {
xor_register(&xor_block_8regs);
xor_register(&xor_block_32regs);
xor_register(&xor_block_alpha);
xor_register(&xor_block_alpha_prefetch);
}
}

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001 Russell King
*/
#include "xor_impl.h"
#include "xor_arch.h"
static void xor_gen_neon(void *dest, void **srcs, unsigned int src_cnt,
unsigned int bytes)
{
kernel_neon_begin();
xor_gen_neon_inner(dest, srcs, src_cnt, bytes);
kernel_neon_end();
}
struct xor_block_template xor_block_neon = {
.name = "neon",
.xor_gen = xor_gen_neon,
};

View File

@@ -1,15 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* linux/arch/arm/lib/xor-neon.c
*
* Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org> * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
*/ */
#include <linux/raid/xor.h> #include "xor_impl.h"
#include <linux/module.h> #include "xor_arch.h"
MODULE_DESCRIPTION("NEON accelerated XOR implementation");
MODULE_LICENSE("GPL");
#ifndef __ARM_NEON__ #ifndef __ARM_NEON__
#error You should compile this file with '-march=armv7-a -mfloat-abi=softfp -mfpu=neon' #error You should compile this file with '-march=armv7-a -mfloat-abi=softfp -mfpu=neon'
@@ -25,14 +20,7 @@ MODULE_LICENSE("GPL");
#pragma GCC optimize "tree-vectorize" #pragma GCC optimize "tree-vectorize"
#endif #endif
#pragma GCC diagnostic ignored "-Wunused-variable" #define NO_TEMPLATE
#include <asm-generic/xor.h> #include "../xor-8regs.c"
struct xor_block_template const xor_block_neon_inner = { __DO_XOR_BLOCKS(neon_inner, xor_8regs_2, xor_8regs_3, xor_8regs_4, xor_8regs_5);
.name = "__inner_neon__",
.do_2 = xor_8regs_2,
.do_3 = xor_8regs_3,
.do_4 = xor_8regs_4,
.do_5 = xor_8regs_5,
};
EXPORT_SYMBOL(xor_block_neon_inner);

View File

@@ -1,13 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only */ // SPDX-License-Identifier: GPL-2.0-only
/* /*
* arch/arm/include/asm/xor.h
*
* Copyright (C) 2001 Russell King * Copyright (C) 2001 Russell King
*/ */
#include <linux/hardirq.h> #include "xor_impl.h"
#include <asm-generic/xor.h> #include "xor_arch.h"
#include <asm/hwcap.h>
#include <asm/neon.h>
#define __XOR(a1, a2) a1 ^= a2 #define __XOR(a1, a2) a1 ^= a2
@@ -131,95 +127,10 @@ xor_arm4regs_5(unsigned long bytes, unsigned long * __restrict p1,
} while (--lines); } while (--lines);
} }
static struct xor_block_template xor_block_arm4regs = { DO_XOR_BLOCKS(arm4regs, xor_arm4regs_2, xor_arm4regs_3, xor_arm4regs_4,
.name = "arm4regs", xor_arm4regs_5);
.do_2 = xor_arm4regs_2,
.do_3 = xor_arm4regs_3, struct xor_block_template xor_block_arm4regs = {
.do_4 = xor_arm4regs_4, .name = "arm4regs",
.do_5 = xor_arm4regs_5, .xor_gen = xor_gen_arm4regs,
}; };
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
xor_speed(&xor_block_arm4regs); \
xor_speed(&xor_block_8regs); \
xor_speed(&xor_block_32regs); \
NEON_TEMPLATES; \
} while (0)
#ifdef CONFIG_KERNEL_MODE_NEON
extern struct xor_block_template const xor_block_neon_inner;
static void
xor_neon_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2)
{
if (in_interrupt()) {
xor_arm4regs_2(bytes, p1, p2);
} else {
kernel_neon_begin();
xor_block_neon_inner.do_2(bytes, p1, p2);
kernel_neon_end();
}
}
static void
xor_neon_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3)
{
if (in_interrupt()) {
xor_arm4regs_3(bytes, p1, p2, p3);
} else {
kernel_neon_begin();
xor_block_neon_inner.do_3(bytes, p1, p2, p3);
kernel_neon_end();
}
}
static void
xor_neon_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4)
{
if (in_interrupt()) {
xor_arm4regs_4(bytes, p1, p2, p3, p4);
} else {
kernel_neon_begin();
xor_block_neon_inner.do_4(bytes, p1, p2, p3, p4);
kernel_neon_end();
}
}
static void
xor_neon_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2,
const unsigned long * __restrict p3,
const unsigned long * __restrict p4,
const unsigned long * __restrict p5)
{
if (in_interrupt()) {
xor_arm4regs_5(bytes, p1, p2, p3, p4, p5);
} else {
kernel_neon_begin();
xor_block_neon_inner.do_5(bytes, p1, p2, p3, p4, p5);
kernel_neon_end();
}
}
static struct xor_block_template xor_block_neon = {
.name = "neon",
.do_2 = xor_neon_2,
.do_3 = xor_neon_3,
.do_4 = xor_neon_4,
.do_5 = xor_neon_5
};
#define NEON_TEMPLATES \
do { if (cpu_has_neon()) xor_speed(&xor_block_neon); } while (0)
#else
#define NEON_TEMPLATES
#endif

View File

@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2001 Russell King
*/
#include <asm/neon.h>
extern struct xor_block_template xor_block_arm4regs;
extern struct xor_block_template xor_block_neon;
void xor_gen_neon_inner(void *dest, void **srcs, unsigned int src_cnt,
unsigned int bytes);
static __always_inline void __init arch_xor_init(void)
{
xor_register(&xor_block_arm4regs);
xor_register(&xor_block_8regs);
xor_register(&xor_block_32regs);
#ifdef CONFIG_KERNEL_MODE_NEON
if (cpu_has_neon())
xor_register(&xor_block_neon);
#endif
}

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Authors: Jackie Liu <liuyun01@kylinos.cn>
* Copyright (C) 2018,Tianjin KYLIN Information Technology Co., Ltd.
*/
#include <asm/simd.h>
#include "xor_impl.h"
#include "xor_arch.h"
#include "xor-neon.h"
#define XOR_TEMPLATE(_name) \
static void xor_gen_##_name(void *dest, void **srcs, unsigned int src_cnt, \
unsigned int bytes) \
{ \
scoped_ksimd() \
xor_gen_##_name##_inner(dest, srcs, src_cnt, bytes); \
} \
\
struct xor_block_template xor_block_##_name = { \
.name = __stringify(_name), \
.xor_gen = xor_gen_##_name, \
};
XOR_TEMPLATE(neon);
XOR_TEMPLATE(eor3);

View File

@@ -1,17 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* arch/arm64/lib/xor-neon.c
*
* Authors: Jackie Liu <liuyun01@kylinos.cn> * Authors: Jackie Liu <liuyun01@kylinos.cn>
* Copyright (C) 2018,Tianjin KYLIN Information Technology Co., Ltd. * Copyright (C) 2018,Tianjin KYLIN Information Technology Co., Ltd.
*/ */
#include <linux/raid/xor.h> #include <linux/cache.h>
#include <linux/module.h>
#include <asm/neon-intrinsics.h> #include <asm/neon-intrinsics.h>
#include "xor_impl.h"
#include "xor_arch.h"
#include "xor-neon.h"
static void xor_arm64_neon_2(unsigned long bytes, unsigned long * __restrict p1, static void __xor_neon_2(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2) const unsigned long * __restrict p2)
{ {
uint64_t *dp1 = (uint64_t *)p1; uint64_t *dp1 = (uint64_t *)p1;
uint64_t *dp2 = (uint64_t *)p2; uint64_t *dp2 = (uint64_t *)p2;
@@ -37,9 +37,9 @@ static void xor_arm64_neon_2(unsigned long bytes, unsigned long * __restrict p1,
} while (--lines > 0); } while (--lines > 0);
} }
static void xor_arm64_neon_3(unsigned long bytes, unsigned long * __restrict p1, static void __xor_neon_3(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p2,
const unsigned long * __restrict p3) const unsigned long * __restrict p3)
{ {
uint64_t *dp1 = (uint64_t *)p1; uint64_t *dp1 = (uint64_t *)p1;
uint64_t *dp2 = (uint64_t *)p2; uint64_t *dp2 = (uint64_t *)p2;
@@ -73,10 +73,10 @@ static void xor_arm64_neon_3(unsigned long bytes, unsigned long * __restrict p1,
} while (--lines > 0); } while (--lines > 0);
} }
static void xor_arm64_neon_4(unsigned long bytes, unsigned long * __restrict p1, static void __xor_neon_4(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p2,
const unsigned long * __restrict p3, const unsigned long * __restrict p3,
const unsigned long * __restrict p4) const unsigned long * __restrict p4)
{ {
uint64_t *dp1 = (uint64_t *)p1; uint64_t *dp1 = (uint64_t *)p1;
uint64_t *dp2 = (uint64_t *)p2; uint64_t *dp2 = (uint64_t *)p2;
@@ -118,11 +118,11 @@ static void xor_arm64_neon_4(unsigned long bytes, unsigned long * __restrict p1,
} while (--lines > 0); } while (--lines > 0);
} }
static void xor_arm64_neon_5(unsigned long bytes, unsigned long * __restrict p1, static void __xor_neon_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p2, const unsigned long * __restrict p2,
const unsigned long * __restrict p3, const unsigned long * __restrict p3,
const unsigned long * __restrict p4, const unsigned long * __restrict p4,
const unsigned long * __restrict p5) const unsigned long * __restrict p5)
{ {
uint64_t *dp1 = (uint64_t *)p1; uint64_t *dp1 = (uint64_t *)p1;
uint64_t *dp2 = (uint64_t *)p2; uint64_t *dp2 = (uint64_t *)p2;
@@ -172,14 +172,8 @@ static void xor_arm64_neon_5(unsigned long bytes, unsigned long * __restrict p1,
} while (--lines > 0); } while (--lines > 0);
} }
struct xor_block_template xor_block_inner_neon __ro_after_init = { __DO_XOR_BLOCKS(neon_inner, __xor_neon_2, __xor_neon_3, __xor_neon_4,
.name = "__inner_neon__", __xor_neon_5);
.do_2 = xor_arm64_neon_2,
.do_3 = xor_arm64_neon_3,
.do_4 = xor_arm64_neon_4,
.do_5 = xor_arm64_neon_5,
};
EXPORT_SYMBOL(xor_block_inner_neon);
static inline uint64x2_t eor3(uint64x2_t p, uint64x2_t q, uint64x2_t r) static inline uint64x2_t eor3(uint64x2_t p, uint64x2_t q, uint64x2_t r)
{ {
@@ -191,10 +185,9 @@ static inline uint64x2_t eor3(uint64x2_t p, uint64x2_t q, uint64x2_t r)
return res; return res;
} }
static void xor_arm64_eor3_3(unsigned long bytes, static void __xor_eor3_3(unsigned long bytes, unsigned long * __restrict p1,
unsigned long * __restrict p1, const unsigned long * __restrict p2,
const unsigned long * __restrict p2, const unsigned long * __restrict p3)
const unsigned long * __restrict p3)
{ {
uint64_t *dp1 = (uint64_t *)p1; uint64_t *dp1 = (uint64_t *)p1;
uint64_t *dp2 = (uint64_t *)p2; uint64_t *dp2 = (uint64_t *)p2;
@@ -226,11 +219,10 @@ static void xor_arm64_eor3_3(unsigned long bytes,
} while (--lines > 0); } while (--lines > 0);
} }
static void xor_arm64_eor3_4(unsigned long bytes, static void __xor_eor3_4(unsigned long bytes, unsigned long * __restrict p1,
unsigned long * __restrict p1, const unsigned long * __restrict p2,
const unsigned long * __restrict p2, const unsigned long * __restrict p3,
const unsigned long * __restrict p3, const unsigned long * __restrict p4)
const unsigned long * __restrict p4)
{ {
uint64_t *dp1 = (uint64_t *)p1; uint64_t *dp1 = (uint64_t *)p1;
uint64_t *dp2 = (uint64_t *)p2; uint64_t *dp2 = (uint64_t *)p2;
@@ -270,12 +262,11 @@ static void xor_arm64_eor3_4(unsigned long bytes,
} while (--lines > 0); } while (--lines > 0);
} }
static void xor_arm64_eor3_5(unsigned long bytes, static void __xor_eor3_5(unsigned long bytes, unsigned long * __restrict p1,
unsigned long * __restrict p1, const unsigned long * __restrict p2,
const unsigned long * __restrict p2, const unsigned long * __restrict p3,
const unsigned long * __restrict p3, const unsigned long * __restrict p4,
const unsigned long * __restrict p4, const unsigned long * __restrict p5)
const unsigned long * __restrict p5)
{ {
uint64_t *dp1 = (uint64_t *)p1; uint64_t *dp1 = (uint64_t *)p1;
uint64_t *dp2 = (uint64_t *)p2; uint64_t *dp2 = (uint64_t *)p2;
@@ -317,22 +308,5 @@ static void xor_arm64_eor3_5(unsigned long bytes,
} while (--lines > 0); } while (--lines > 0);
} }
static int __init xor_neon_init(void) __DO_XOR_BLOCKS(eor3_inner, __xor_neon_2, __xor_eor3_3, __xor_eor3_4,
{ __xor_eor3_5);
if (cpu_have_named_feature(SHA3)) {
xor_block_inner_neon.do_3 = xor_arm64_eor3_3;
xor_block_inner_neon.do_4 = xor_arm64_eor3_4;
xor_block_inner_neon.do_5 = xor_arm64_eor3_5;
}
return 0;
}
module_init(xor_neon_init);
static void __exit xor_neon_exit(void)
{
}
module_exit(xor_neon_exit);
MODULE_AUTHOR("Jackie Liu <liuyun01@kylinos.cn>");
MODULE_DESCRIPTION("ARMv8 XOR Extensions");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
void xor_gen_neon_inner(void *dest, void **srcs, unsigned int src_cnt,
unsigned int bytes);
void xor_gen_eor3_inner(void *dest, void **srcs, unsigned int src_cnt,
unsigned int bytes);

View File

@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Authors: Jackie Liu <liuyun01@kylinos.cn>
* Copyright (C) 2018,Tianjin KYLIN Information Technology Co., Ltd.
*/
#include <asm/simd.h>
extern struct xor_block_template xor_block_neon;
extern struct xor_block_template xor_block_eor3;
static __always_inline void __init arch_xor_init(void)
{
xor_register(&xor_block_8regs);
xor_register(&xor_block_32regs);
if (cpu_has_neon()) {
if (cpu_have_named_feature(SHA3))
xor_register(&xor_block_eor3);
else
xor_register(&xor_block_neon);
}
}

Some files were not shown because too many files have changed in this diff Show More