mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
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:
6
.mailmap
6
.mailmap
@@ -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>
|
||||||
|
|||||||
7
CREDITS
7
CREDITS
@@ -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)
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 */
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 */
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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);
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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 */
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
174
crypto/xor.c
174
crypto/xor.c
@@ -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);
|
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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 = ®->hr_slots[i];
|
slot = ®->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(®->hr_write_timeout_work, o2hb_write_timeout);
|
INIT_DELAYED_WORK(®->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(®->hr_item), reg_bdev(reg));
|
config_item_name(®->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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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++) {
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
18
kernel/pid.c
18
kernel/pid.c
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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)) */
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
11
lib/glob.c
11
lib/glob.c
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -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
3
lib/raid/.kunitconfig
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
CONFIG_KUNIT=y
|
||||||
|
CONFIG_BTRFS_FS=y
|
||||||
|
CONFIG_XOR_KUNIT_TEST=y
|
||||||
30
lib/raid/Kconfig
Normal file
30
lib/raid/Kconfig
Normal 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
3
lib/raid/Makefile
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
obj-y += xor/
|
||||||
42
lib/raid/xor/Makefile
Normal file
42
lib/raid/xor/Makefile
Normal 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)
|
||||||
@@ -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)
|
|
||||||
22
lib/raid/xor/alpha/xor_arch.h
Normal file
22
lib/raid/xor/alpha/xor_arch.h
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
lib/raid/xor/arm/xor-neon-glue.c
Normal file
19
lib/raid/xor/arm/xor-neon-glue.c
Normal 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,
|
||||||
|
};
|
||||||
@@ -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);
|
|
||||||
@@ -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
|
|
||||||
22
lib/raid/xor/arm/xor_arch.h
Normal file
22
lib/raid/xor/arm/xor_arch.h
Normal 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
|
||||||
|
}
|
||||||
26
lib/raid/xor/arm64/xor-neon-glue.c
Normal file
26
lib/raid/xor/arm64/xor-neon-glue.c
Normal 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);
|
||||||
@@ -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");
|
|
||||||
6
lib/raid/xor/arm64/xor-neon.h
Normal file
6
lib/raid/xor/arm64/xor-neon.h
Normal 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);
|
||||||
21
lib/raid/xor/arm64/xor_arch.h
Normal file
21
lib/raid/xor/arm64/xor_arch.h
Normal 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
Reference in New Issue
Block a user