mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 14:30:06 -04:00
Merge tag 'mm-nonmm-stable-2026-06-21-10-22' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull non-MM updates from Andrew Morton:
- "taskstats: fix TGID dead-thread stat retention" (Yiyang Chen)
Fix a taskstats TGID aggregation bug where fields added in the TGID
query path were not preserved after thread exit, and adds a kselftest
covering the regression.
- "lib/tests: string_helpers: Slight improvements" (Andy Shevchenko)
Improve lib/tests/string_helpers_kunit.c a little
- "lib/base64: decode fixes" (Josh Law)
Address minor issues in lib/base64.c
- "selftests/filelock: Make output more kselftestish" (Mark Brown)
Make the output from the ofdlocks test a bit easier for tooling to
work with. Also ignore the generated file
- "uaccess: unify inline vs outline copy_{from,to}_user() selection"
(Yury Norov)
Simplify the usercopy code by removing the selectability of inlining
copy_{from,to}_user().
- "ocfs2: validate inline xattr header consumers" (ZhengYuan Huang)
Fix a number of possible issues in the ocfs2 xattr code
- "lib and lib/cmdline enhancements" (Dmitry Antipov)
Provide additional robustness checking in the cmdline handling code
and its in-kernel testing and selftests
- "cleanup the RAID6 P/Q library" (Christoph Hellwig)
Clean up the RAID6 P/Q library to match the recent updates to the
RAID 5 XOR library and other CRC/crypto libraries
- "ocfs2: harden inode validators against forged metadata" (Michael
Bommarito)
Add three structural checks to OCFS2 dinode validation so malformed
on-disk fields are rejected before ocfs2_populate_inode() copies them
into the in-core inode
- "lib/raid: replace __get_free_pages() call with kmalloc()" (Mike
Rapoport)
Clean up the lib/raid code by using kmalloc() in more places
* tag 'mm-nonmm-stable-2026-06-21-10-22' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (108 commits)
ocfs2: fix circular locking dependency in ocfs2_dio_end_io_write
ocfs2: fix NULL h_transaction deref in ocfs2_assure_trans_credits
lib: interval_tree_test: validate benchmark parameters
ocfs2: avoid moving extents to occupied clusters
treewide: fix transposed "sign" typos and update spelling.txt
ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec
fat: reject BPB volumes whose data area starts beyond total sectors
selftests/uevent: increase __UEVENT_BUFFER_SIZE to avoid ENOBUFS on busy systems
lib/test_firmware: allocate the configured into_buf size
fs: efs: remove unneeded debug prints
checkpatch: cuppress warnings when Reported-by: is followed by Link:
MAINTAINERS: add Alexander as a kcov reviewer
mailmap: update Alexander Sverdlin's Email addresses
fs: fat: inode: replace sprintf() with scnprintf()
ocfs2: fix out-of-bounds write in ocfs2_remove_refcount_extent
ocfs2: fix race between ocfs2_control_install_private() and ocfs2_control_release()
ocfs2/dlm: require a ref for locking_state debugfs open
ocfs2: reject FITRIM ranges shorter than a cluster
ocfs2: validate fast symlink target during inode read
ocfs2: add journal NULL check in ocfs2_checkpoint_inode()
...
This commit is contained in:
@@ -481,6 +481,7 @@ ForEachMacros:
|
||||
- 'genradix_for_each'
|
||||
- 'genradix_for_each_from'
|
||||
- 'genradix_for_each_reverse'
|
||||
- 'guard'
|
||||
- 'hash_for_each'
|
||||
- 'hash_for_each_possible'
|
||||
- 'hash_for_each_possible_rcu'
|
||||
@@ -674,6 +675,7 @@ ForEachMacros:
|
||||
- 'rq_list_for_each'
|
||||
- 'rq_list_for_each_safe'
|
||||
- 'sample_read_group__for_each'
|
||||
- 'scoped_guard'
|
||||
- 'scsi_for_each_prot_sg'
|
||||
- 'scsi_for_each_sg'
|
||||
- 'sctp_for_each_hentry'
|
||||
|
||||
16
.mailmap
16
.mailmap
@@ -36,13 +36,14 @@ Alexander Lobakin <alobakin@pm.me> <bloodyreaper@yandex.ru>
|
||||
Alexander Mikhalitsyn <alexander@mihalicyn.com> <alexander.mikhalitsyn@virtuozzo.com>
|
||||
Alexander Mikhalitsyn <alexander@mihalicyn.com> <aleksandr.mikhalitsyn@canonical.com>
|
||||
Alexander Mikhalitsyn <alexander@mihalicyn.com> <aleksandr.mikhalitsyn@futurfusion.io>
|
||||
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin.ext@nsn.com>
|
||||
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@gmx.de>
|
||||
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@nokia.com>
|
||||
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@nsn.com>
|
||||
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@siemens.com>
|
||||
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@sysgo.com>
|
||||
Alexander Sverdlin <alexander.sverdlin@gmail.com> <subaparts@yandex.ru>
|
||||
Alexander Sverdlin <alex@sverdlin.org> <alexander.sverdlin.ext@nsn.com>
|
||||
Alexander Sverdlin <alex@sverdlin.org> <alexander.sverdlin@gmail.com>
|
||||
Alexander Sverdlin <alex@sverdlin.org> <alexander.sverdlin@gmx.de>
|
||||
Alexander Sverdlin <alex@sverdlin.org> <alexander.sverdlin@nokia.com>
|
||||
Alexander Sverdlin <alex@sverdlin.org> <alexander.sverdlin@nsn.com>
|
||||
Alexander Sverdlin <alex@sverdlin.org> <alexander.sverdlin@sysgo.com>
|
||||
Alexander Sverdlin <alex@sverdlin.org> <asv@kernel.org>
|
||||
Alexander Sverdlin <alex@sverdlin.org> <subaparts@yandex.ru>
|
||||
Alexandre Belloni <alexandre.belloni@bootlin.com> <alexandre.belloni@free-electrons.com>
|
||||
Alexandre Ghiti <alex@ghiti.fr> <alexandre.ghiti@canonical.com>
|
||||
Alexei Avshalom Lazar <quic_ailizaro@quicinc.com> <ailizaro@codeaurora.org>
|
||||
@@ -438,6 +439,7 @@ John Stultz <johnstul@us.ibm.com>
|
||||
Jonas Gorski <jonas.gorski@gmail.com> <jogo@openwrt.org>
|
||||
Jonathan Cameron <jic23@kernel.org> <jonathan.cameron@huawei.com>
|
||||
Jordan Crouse <jordan@cosmicpenguin.net> <jcrouse@codeaurora.org>
|
||||
Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com> <jorge.ramirez-ortiz@linaro.org>
|
||||
<josh@joshtriplett.org> <josh@freedesktop.org>
|
||||
<josh@joshtriplett.org> <josh@kernel.org>
|
||||
<josh@joshtriplett.org> <josht@linux.vnet.ibm.com>
|
||||
|
||||
4
CREDITS
4
CREDITS
@@ -3373,6 +3373,10 @@ N: Anil Ravindranath
|
||||
E: anil_ravindranath@pmc-sierra.com
|
||||
D: PMC-Sierra MaxRAID driver
|
||||
|
||||
N: Dwaipayan Ray
|
||||
E: dwaipayanray1@gmail.com
|
||||
D: checkpatch improvements
|
||||
|
||||
N: Eric S. Raymond
|
||||
E: esr@thyrsus.com
|
||||
W: http://www.tuxedo.org/~esr/
|
||||
|
||||
@@ -82,9 +82,9 @@ xor_val xor a series of source buffers and set a flag if the
|
||||
pq generate the p+q (raid6 syndrome) from a series of source buffers
|
||||
pq_val validate that a p and or q buffer are in sync with a given series of
|
||||
sources
|
||||
datap (raid6_datap_recov) recover a raid6 data block and the p block
|
||||
datap (raid6_recov_datap) recover a raid6 data block and the p block
|
||||
from the given sources
|
||||
2data (raid6_2data_recov) recover 2 raid6 data blocks from the given
|
||||
2data (raid6_recov_2data) recover 2 raid6 data blocks from the given
|
||||
sources
|
||||
======== ====================================================================
|
||||
|
||||
|
||||
@@ -184,6 +184,13 @@ Available options:
|
||||
Override checking of perl version. Runtime errors may be encountered after
|
||||
enabling this flag if the perl version does not meet the minimum specified.
|
||||
|
||||
- --spdx-cxx-comments
|
||||
|
||||
Don't force C comments ``/* */`` for SPDX license (required by old
|
||||
toolchains), allow also C++ comments ``//``.
|
||||
|
||||
NOTE: it should *not* be used for Linux mainline.
|
||||
|
||||
- --codespell
|
||||
|
||||
Use the codespell dictionary for checking spelling errors.
|
||||
@@ -210,6 +217,13 @@ Available options:
|
||||
|
||||
Display the help text.
|
||||
|
||||
Configuration file
|
||||
==================
|
||||
|
||||
Default configuration options can be stored in ``.checkpatch.conf``, search
|
||||
path: ``.:$HOME:.scripts`` or in a directory specified by ``$CHECKPATCH_CONFIG_DIR``
|
||||
environment variable (falling back to the default search path).
|
||||
|
||||
Message Levels
|
||||
==============
|
||||
|
||||
|
||||
@@ -237,6 +237,9 @@ Both ``kcov_remote_start`` and ``kcov_remote_stop`` annotations and the
|
||||
collection sections. The way a handle is used depends on the context where the
|
||||
matching code section executes.
|
||||
|
||||
A thread can use two separate KCOV instances to collect remote coverage and
|
||||
normal coverage at the same time.
|
||||
|
||||
KCOV supports collecting remote coverage from the following contexts:
|
||||
|
||||
1. Global kernel background tasks. These are the tasks that are spawned during
|
||||
@@ -262,6 +265,9 @@ gets saved to the ``kcov_handle`` field in the current ``task_struct`` and
|
||||
needs to be passed to the newly spawned local tasks via custom kernel code
|
||||
modifications. Those tasks should in turn use the passed handle in their
|
||||
``kcov_remote_start`` and ``kcov_remote_stop`` annotations.
|
||||
In the kernel, common handles are wrapped in a ``kcov_common_handle_id``, which
|
||||
consumes no space in builds without ``CONFIG_KCOV``; subsystems that integrate
|
||||
with this mechanism should not need to use any ``#ifdef CONFIG_KCOV`` or such.
|
||||
|
||||
KCOV follows a predefined format for both global and common handles. Each
|
||||
handle is a ``u64`` integer. Currently, only the one top and the lower 4 bytes
|
||||
|
||||
@@ -6020,8 +6020,6 @@ F: drivers/input/keyboard/charlieplex_keypad.c
|
||||
CHECKPATCH
|
||||
M: Andy Whitcroft <apw@canonical.com>
|
||||
M: Joe Perches <joe@perches.com>
|
||||
R: Dwaipayan Ray <dwaipayanray1@gmail.com>
|
||||
R: Lukas Bulwahn <lukas.bulwahn@gmail.com>
|
||||
S: Maintained
|
||||
F: scripts/checkpatch.pl
|
||||
|
||||
@@ -13933,8 +13931,9 @@ F: fs/proc/kcore.c
|
||||
F: include/linux/kcore.h
|
||||
|
||||
KCOV
|
||||
R: Dmitry Vyukov <dvyukov@google.com>
|
||||
R: Andrey Konovalov <andreyknvl@gmail.com>
|
||||
R: Alexander Potapenko <glider@google.com>
|
||||
R: Dmitry Vyukov <dvyukov@google.com>
|
||||
L: kasan-dev@googlegroups.com
|
||||
S: Maintained
|
||||
B: https://bugzilla.kernel.org/buglist.cgi?component=Sanitizers&product=Memory%20Management
|
||||
@@ -25051,7 +25050,7 @@ F: drivers/md/md*
|
||||
F: drivers/md/raid*
|
||||
F: include/linux/raid/
|
||||
F: include/uapi/linux/raid/
|
||||
F: lib/raid6/
|
||||
F: lib/raid/raid6/
|
||||
|
||||
SOLIDRUN CLEARFOG SUPPORT
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
|
||||
27
Makefile
27
Makefile
@@ -829,12 +829,6 @@ endif # KBUILD_EXTMOD
|
||||
# Defaults to vmlinux, but the arch makefile usually adds further targets
|
||||
all: vmlinux
|
||||
|
||||
CFLAGS_GCOV := -fprofile-arcs -ftest-coverage
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
CFLAGS_GCOV += -fno-tree-loop-im
|
||||
endif
|
||||
export CFLAGS_GCOV
|
||||
|
||||
# The arch Makefiles can override CC_FLAGS_FTRACE. We may also append it later.
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
CC_FLAGS_FTRACE := -pg
|
||||
@@ -1162,6 +1156,27 @@ endif
|
||||
# Ensure compilers do not transform certain loops into calls to wcslen()
|
||||
KBUILD_CFLAGS += -fno-builtin-wcslen
|
||||
|
||||
CFLAGS_GCOV := -fprofile-arcs -ftest-coverage
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
CFLAGS_GCOV += -fno-tree-loop-im
|
||||
# Use atomic counter updates to avoid concurrent-access crashes in GCOV.
|
||||
# Only enable if -fprofile-update=prefer-atomic does not introduce new
|
||||
# undefined symbols (e.g. libatomic calls that the kernel cannot link).
|
||||
CFLAGS_GCOV += $(call try-run,\
|
||||
echo 'long long x; void f(void){x++;}' | \
|
||||
$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w -fprofile-arcs \
|
||||
-ftest-coverage -x c - -c -o "$$TMP.base" && \
|
||||
echo 'long long x; void f(void){x++;}' | \
|
||||
$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w -fprofile-arcs \
|
||||
-ftest-coverage -fprofile-update=prefer-atomic \
|
||||
-x c - -c -o "$$TMP" && \
|
||||
$(NM) "$$TMP.base" | grep ' U ' > "$$TMP.ubase" || true ; \
|
||||
$(NM) "$$TMP" | grep ' U ' > "$$TMP.utest" || true ; \
|
||||
cmp -s "$$TMP.ubase" "$$TMP.utest",\
|
||||
-fprofile-update=prefer-atomic)
|
||||
endif
|
||||
export CFLAGS_GCOV
|
||||
|
||||
# change __FILE__ to the relative path to the source directory
|
||||
ifdef building_out_of_srctree
|
||||
KBUILD_CPPFLAGS += -fmacro-prefix-map=$(srcroot)/=
|
||||
|
||||
@@ -628,8 +628,7 @@ static inline unsigned long __clear_user(void __user *to, unsigned long n)
|
||||
return res;
|
||||
}
|
||||
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
#define __clear_user __clear_user
|
||||
|
||||
|
||||
@@ -616,8 +616,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
}
|
||||
#define __clear_user(addr, n) (memset((void __force *)addr, 0, n), 0)
|
||||
#endif
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
|
||||
{
|
||||
|
||||
@@ -562,7 +562,7 @@ &sdc1_rclk {
|
||||
*
|
||||
* This has entries that are defined by Qcard even if they go to the main
|
||||
* board. In cases where the pulls may be board dependent we defer those
|
||||
* settings to the board device tree. Drive strengths tend to be assinged here
|
||||
* settings to the board device tree. Drive strengths tend to be assigned here
|
||||
* but could conceivably be overwridden by board device trees.
|
||||
*/
|
||||
|
||||
|
||||
@@ -456,8 +456,7 @@ do { \
|
||||
unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u8, label); \
|
||||
} while (0)
|
||||
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
extern unsigned long __must_check __arch_clear_user(void __user *to, unsigned long n);
|
||||
static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n)
|
||||
|
||||
@@ -26,8 +26,7 @@ unsigned long raw_copy_from_user(void *to, const void __user *from,
|
||||
unsigned long n);
|
||||
unsigned long raw_copy_to_user(void __user *to, const void *from,
|
||||
unsigned long n);
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
__kernel_size_t __clear_user_hexagon(void __user *dest, unsigned long count);
|
||||
#define __clear_user(a, s) __clear_user_hexagon((a), (s))
|
||||
|
||||
@@ -292,8 +292,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
return __copy_user((__force void *)to, from, n);
|
||||
}
|
||||
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
/*
|
||||
* __clear_user: - Zero a block of memory in user space, with less checking.
|
||||
|
||||
@@ -377,8 +377,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
return __constant_copy_to_user(to, from, n);
|
||||
return __generic_copy_to_user(to, from, n);
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
#define __get_kernel_nofault(dst, src, type, err_label) \
|
||||
do { \
|
||||
|
||||
@@ -250,8 +250,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
return __copy_tofrom_user(to, (__force const void __user *)from, n);
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
/*
|
||||
* Copy a null terminated string from userspace.
|
||||
|
||||
@@ -433,8 +433,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
return __cu_len_r;
|
||||
}
|
||||
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
extern __kernel_size_t __bzero(void __user *addr, __kernel_size_t size);
|
||||
|
||||
|
||||
@@ -57,8 +57,7 @@ extern unsigned long
|
||||
raw_copy_from_user(void *to, const void __user *from, unsigned long n);
|
||||
extern unsigned long
|
||||
raw_copy_to_user(void __user *to, const void *from, unsigned long n);
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
extern long strncpy_from_user(char *__to, const char __user *__from,
|
||||
long __len);
|
||||
|
||||
@@ -218,8 +218,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long size)
|
||||
{
|
||||
return __copy_tofrom_user((__force void *)to, from, size);
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
extern unsigned long __clear_user(void __user *addr, unsigned long size);
|
||||
|
||||
|
||||
@@ -197,7 +197,6 @@ unsigned long __must_check raw_copy_to_user(void __user *dst, const void *src,
|
||||
unsigned long len);
|
||||
unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src,
|
||||
unsigned long len);
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
#endif /* __PARISC_UACCESS_H */
|
||||
|
||||
@@ -406,9 +406,6 @@ config ARCH_RV32I
|
||||
bool "RV32I"
|
||||
depends on NONPORTABLE
|
||||
select 32BIT
|
||||
select GENERIC_LIB_ASHLDI3
|
||||
select GENERIC_LIB_ASHRDI3
|
||||
select GENERIC_LIB_LSHRDI3
|
||||
select GENERIC_LIB_UCMPDI2
|
||||
|
||||
config ARCH_RV64I
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm-generic/asm-prototypes.h>
|
||||
|
||||
long long __lshrdi3(long long a, int b);
|
||||
long long __ashrdi3(long long a, int b);
|
||||
long long __ashldi3(long long a, int b);
|
||||
|
||||
long long __lshrti3(long long a, int b);
|
||||
long long __ashrti3(long long a, int b);
|
||||
long long __ashlti3(long long a, int b);
|
||||
|
||||
@@ -32,6 +32,15 @@ __efistub___init_text_end = __init_text_end;
|
||||
__efistub_sysfb_primary_display = sysfb_primary_display;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These double-word integer shifts are used by the library code, and
|
||||
* the first two of them are required to link EFI stub. Note __ashrdi3()
|
||||
* is not actually used by the stub but this may change in the future.
|
||||
*/
|
||||
PROVIDE(__efistub___lshrdi3 = __lshrdi3);
|
||||
PROVIDE(__efistub___ashldi3 = __ashldi3);
|
||||
PROVIDE(__efistub___ashrdi3 = __ashrdi3);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __RISCV_KERNEL_IMAGE_VARS_H */
|
||||
|
||||
@@ -16,6 +16,7 @@ ifeq ($(CONFIG_MMU), y)
|
||||
lib-$(CONFIG_RISCV_ISA_V) += uaccess_vector.o
|
||||
endif
|
||||
lib-$(CONFIG_MMU) += uaccess.o
|
||||
lib-$(CONFIG_32BIT) += ashldi3.o ashrdi3.o lshrdi3.o
|
||||
lib-$(CONFIG_64BIT) += tishift.o
|
||||
lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o
|
||||
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
|
||||
|
||||
36
arch/riscv/lib/ashldi3.S
Normal file
36
arch/riscv/lib/ashldi3.S
Normal file
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/**
|
||||
* Adopted for the Linux kernel from IPXE project, see
|
||||
* https://github.com/ipxe/ipxe/blob/master/src/arch/riscv32/libgcc/llshift.S
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
/**
|
||||
* Shift left
|
||||
*
|
||||
* @v a1:a0 Value to shift
|
||||
* @v a2 Shift amount
|
||||
* @ret a1:a0 Shifted value
|
||||
*/
|
||||
|
||||
SYM_FUNC_START(__ashldi3)
|
||||
|
||||
/* Perform shift by 32 bits, if applicable */
|
||||
li t0, 32
|
||||
sub t1, t0, a2
|
||||
bgtz t1, 1f
|
||||
mv a1, a0
|
||||
mv a0, zero
|
||||
1: /* Perform shift by modulo-32 bits, if applicable */
|
||||
andi a2, a2, 0x1f
|
||||
beqz a2, 2f
|
||||
srl t2, a0, t1
|
||||
sll a0, a0, a2
|
||||
sll a1, a1, a2
|
||||
or a1, a1, t2
|
||||
2: ret
|
||||
|
||||
SYM_FUNC_END(__ashldi3)
|
||||
EXPORT_SYMBOL(__ashldi3)
|
||||
36
arch/riscv/lib/ashrdi3.S
Normal file
36
arch/riscv/lib/ashrdi3.S
Normal file
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/**
|
||||
* Adopted for the Linux kernel from IPXE project, see
|
||||
* https://github.com/ipxe/ipxe/blob/master/src/arch/riscv32/libgcc/llshift.S
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
/**
|
||||
* Arithmetic shift right
|
||||
*
|
||||
* @v a1:a0 Value to shift
|
||||
* @v a2 Shift amount
|
||||
* @ret a1:a0 Shifted value
|
||||
*/
|
||||
|
||||
SYM_FUNC_START(__ashrdi3)
|
||||
|
||||
/* Perform shift by 32 bits, if applicable */
|
||||
li t0, 32
|
||||
sub t1, t0, a2
|
||||
bgtz t1, 1f
|
||||
mv a0, a1
|
||||
srai a1, a1, 31
|
||||
1: /* Perform shift by modulo-32 bits, if applicable */
|
||||
andi a2, a2, 0x1f
|
||||
beqz a2, 2f
|
||||
sll t2, a1, t1
|
||||
sra a1, a1, a2
|
||||
srl a0, a0, a2
|
||||
or a0, a0, t2
|
||||
2: ret
|
||||
|
||||
SYM_FUNC_END(__ashrdi3)
|
||||
EXPORT_SYMBOL(__ashrdi3)
|
||||
36
arch/riscv/lib/lshrdi3.S
Normal file
36
arch/riscv/lib/lshrdi3.S
Normal file
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/**
|
||||
* Adopted for the Linux kernel from IPXE project, see
|
||||
* https://github.com/ipxe/ipxe/blob/master/src/arch/riscv32/libgcc/llshift.S
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
/**
|
||||
* Logical shift right
|
||||
*
|
||||
* @v a1:a0 Value to shift
|
||||
* @v a2 Shift amount
|
||||
* @ret a1:a0 Shifted value
|
||||
*/
|
||||
|
||||
SYM_FUNC_START(__lshrdi3)
|
||||
|
||||
/* Perform shift by 32 bits, if applicable */
|
||||
li t0, 32
|
||||
sub t1, t0, a2
|
||||
bgtz t1, 1f
|
||||
mv a0, a1
|
||||
mv a1, zero
|
||||
1: /* Perform shift by modulo-32 bits, if applicable */
|
||||
andi a2, a2, 0x1f
|
||||
beqz a2, 2f
|
||||
sll t2, a1, t1
|
||||
srl a1, a1, a2
|
||||
srl a0, a0, a2
|
||||
or a0, a0, t2
|
||||
2: ret
|
||||
|
||||
SYM_FUNC_END(__lshrdi3)
|
||||
EXPORT_SYMBOL(__lshrdi3)
|
||||
@@ -30,8 +30,7 @@ void debug_user_asce(int exit);
|
||||
#define uaccess_kmsan_or_inline __always_inline
|
||||
#endif
|
||||
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
static uaccess_kmsan_or_inline __must_check unsigned long
|
||||
raw_copy_from_user(void *to, const void __user *from, unsigned long size)
|
||||
|
||||
@@ -95,8 +95,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
return __copy_user((__force void *)to, from, n);
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
/*
|
||||
* Clear the area and return remaining number of bytes
|
||||
|
||||
@@ -190,8 +190,7 @@ static inline unsigned long raw_copy_from_user(void *to, const void __user *from
|
||||
return __copy_user((__force void __user *) to, from, n);
|
||||
}
|
||||
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
static inline unsigned long __clear_user(void __user *addr, unsigned long size)
|
||||
{
|
||||
|
||||
@@ -231,8 +231,7 @@ unsigned long __must_check raw_copy_from_user(void *to,
|
||||
unsigned long __must_check raw_copy_to_user(void __user *to,
|
||||
const void *from,
|
||||
unsigned long size);
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
unsigned long __must_check raw_copy_in_user(void __user *to,
|
||||
const void __user *from,
|
||||
|
||||
@@ -27,8 +27,7 @@ static inline int __access_ok(const void __user *ptr, unsigned long size);
|
||||
#define __access_ok __access_ok
|
||||
#define __clear_user __clear_user
|
||||
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
#include <asm-generic/uaccess.h>
|
||||
|
||||
|
||||
@@ -237,8 +237,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
prefetch(from);
|
||||
return __xtensa_copy_user((__force void *)to, from, n);
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
|
||||
/*
|
||||
* We need to return the number of bytes not cleared. Our memset()
|
||||
|
||||
@@ -6,14 +6,14 @@ config MODULE_SIG_KEY
|
||||
default "certs/signing_key.pem"
|
||||
depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
|
||||
help
|
||||
Provide the file name of a private key/certificate in PEM format,
|
||||
or a PKCS#11 URI according to RFC7512. The file should contain, or
|
||||
the URI should identify, both the certificate and its corresponding
|
||||
private key.
|
||||
Provide the file name of a private key/certificate in PEM format,
|
||||
or a PKCS#11 URI according to RFC7512. The file should contain, or
|
||||
the URI should identify, both the certificate and its corresponding
|
||||
private key.
|
||||
|
||||
If this option is unchanged from its default "certs/signing_key.pem",
|
||||
then the kernel will automatically generate the private key and
|
||||
certificate as described in Documentation/admin-guide/module-signing.rst
|
||||
If this option is unchanged from its default "certs/signing_key.pem",
|
||||
then the kernel will automatically generate the private key and
|
||||
certificate as described in Documentation/admin-guide/module-signing.rst
|
||||
|
||||
choice
|
||||
prompt "Type of module signing key to be generated"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/raid/pq.h>
|
||||
#include <linux/raid/pq_tables.h>
|
||||
#include <linux/async_tx.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
@@ -119,7 +120,7 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks,
|
||||
for (i = 0; i < disks; i++) {
|
||||
if (blocks[i] == NULL) {
|
||||
BUG_ON(i > disks - 3); /* P or Q can't be zero */
|
||||
srcs[i] = raid6_get_zero_page();
|
||||
srcs[i] = page_address(ZERO_PAGE(0));
|
||||
} else {
|
||||
srcs[i] = page_address(blocks[i]) + offsets[i];
|
||||
|
||||
@@ -131,11 +132,11 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks,
|
||||
}
|
||||
}
|
||||
if (submit->flags & ASYNC_TX_PQ_XOR_DST) {
|
||||
BUG_ON(!raid6_call.xor_syndrome);
|
||||
BUG_ON(!raid6_can_xor_syndrome());
|
||||
if (start >= 0)
|
||||
raid6_call.xor_syndrome(disks, start, stop, len, srcs);
|
||||
raid6_xor_syndrome(disks, start, stop, len, srcs);
|
||||
} else
|
||||
raid6_call.gen_syndrome(disks, len, srcs);
|
||||
raid6_gen_syndrome(disks, len, srcs);
|
||||
async_tx_sync_epilog(submit);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/raid/pq.h>
|
||||
#include <linux/raid/pq_tables.h>
|
||||
#include <linux/async_tx.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
@@ -414,11 +415,11 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
|
||||
async_tx_quiesce(&submit->depend_tx);
|
||||
for (i = 0; i < disks; i++)
|
||||
if (blocks[i] == NULL)
|
||||
ptrs[i] = raid6_get_zero_page();
|
||||
ptrs[i] = page_address(ZERO_PAGE(0));
|
||||
else
|
||||
ptrs[i] = page_address(blocks[i]) + offs[i];
|
||||
|
||||
raid6_2data_recov(disks, bytes, faila, failb, ptrs);
|
||||
raid6_recov_2data(disks, bytes, faila, failb, ptrs);
|
||||
|
||||
async_tx_sync_epilog(submit);
|
||||
|
||||
@@ -497,11 +498,11 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
|
||||
async_tx_quiesce(&submit->depend_tx);
|
||||
for (i = 0; i < disks; i++)
|
||||
if (blocks[i] == NULL)
|
||||
ptrs[i] = raid6_get_zero_page();
|
||||
ptrs[i] = page_address(ZERO_PAGE(0));
|
||||
else
|
||||
ptrs[i] = page_address(blocks[i]) + offs[i];
|
||||
|
||||
raid6_datap_recov(disks, bytes, faila, ptrs);
|
||||
raid6_recov_datap(disks, bytes, faila, ptrs);
|
||||
|
||||
async_tx_sync_epilog(submit);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/raid/pq.h>
|
||||
#include <linux/raid/pq_tables.h>
|
||||
|
||||
#include "dmaengine.h"
|
||||
|
||||
|
||||
@@ -95,8 +95,10 @@ CFLAGS_zboot-decompress-gzip.o += -I$(srctree)/lib/zlib_inflate
|
||||
zboot-obj-$(CONFIG_KERNEL_ZSTD) := zboot-decompress-zstd.o lib-xxhash.o
|
||||
CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd
|
||||
|
||||
zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o lib-ashldi3.o
|
||||
zboot-obj-$(CONFIG_LOONGARCH) += lib-clz_ctz.o lib-ashldi3.o
|
||||
zboot-riscv-obj-$(CONFIG_32BIT) := lib-ashldi3.o lib-lshrdi3.o
|
||||
zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o $(zboot-riscv-obj-y)
|
||||
zboot-loongarch-obj-$(CONFIG_32BIT) := lib-ashldi3.o lib-lshrdi3.o
|
||||
zboot-obj-$(CONFIG_LOONGARCH) += lib-clz_ctz.o $(zboot-loongarch-obj-y)
|
||||
lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y)
|
||||
|
||||
lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
* &drm_crtc_state.degamma_lut.
|
||||
*
|
||||
* “DEGAMMA_LUT_SIZE”:
|
||||
* Unsinged range property to give the size of the lookup table to be set
|
||||
* Unsigned range property to give the size of the lookup table to be set
|
||||
* on the DEGAMMA_LUT property (the size depends on the underlying
|
||||
* hardware). If drivers support multiple LUT sizes then they should
|
||||
* publish the largest size, and sub-sample smaller sized LUTs (e.g. for
|
||||
|
||||
@@ -6958,7 +6958,7 @@ raid5_store_rmw_level(struct mddev *mddev, const char *page, size_t len)
|
||||
if (kstrtoul(page, 10, &new))
|
||||
return -EINVAL;
|
||||
|
||||
if (new != PARITY_DISABLE_RMW && !raid6_call.xor_syndrome)
|
||||
if (new != PARITY_DISABLE_RMW && !raid6_can_xor_syndrome())
|
||||
return -EINVAL;
|
||||
|
||||
if (new != PARITY_DISABLE_RMW &&
|
||||
@@ -7649,7 +7649,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
|
||||
conf->level = mddev->new_level;
|
||||
if (conf->level == 6) {
|
||||
conf->max_degraded = 2;
|
||||
if (raid6_call.xor_syndrome)
|
||||
if (raid6_can_xor_syndrome())
|
||||
conf->rmw_level = PARITY_ENABLE_RMW;
|
||||
else
|
||||
conf->rmw_level = PARITY_DISABLE_RMW;
|
||||
|
||||
@@ -394,7 +394,6 @@ static void tsi721_db_dpc(struct work_struct *work)
|
||||
idb_work);
|
||||
struct rio_mport *mport;
|
||||
struct rio_dbell *dbell;
|
||||
int found = 0;
|
||||
u32 wr_ptr, rd_ptr;
|
||||
u64 *idb_entry;
|
||||
u32 regval;
|
||||
@@ -412,6 +411,8 @@ static void tsi721_db_dpc(struct work_struct *work)
|
||||
rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE)) % IDB_QSIZE;
|
||||
|
||||
while (wr_ptr != rd_ptr) {
|
||||
int found = 0;
|
||||
|
||||
idb_entry = (u64 *)(priv->idb_base +
|
||||
(TSI721_IDB_ENTRY_SIZE * rd_ptr));
|
||||
rd_ptr++;
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
#define EFCT_HW_EQ_DEPTH 1024
|
||||
|
||||
/*
|
||||
* A CQ will be assinged to each WQ
|
||||
* A CQ will be assigned to each WQ
|
||||
* (CQ must have 2X entries of the WQ for abort
|
||||
* processing), plus a separate one for each RQ PAIR and one for MQ
|
||||
*/
|
||||
|
||||
@@ -2488,7 +2488,7 @@ struct isci_request *sci_request_by_tag(struct isci_host *ihost, u16 io_tag)
|
||||
* free remote node ids
|
||||
* @idev: This is the device object which is requesting the a remote node
|
||||
* id
|
||||
* @node_id: This is the remote node id that is assinged to the device if one
|
||||
* @node_id: This is the remote node id that is assigned to the device if one
|
||||
* is available
|
||||
*
|
||||
* enum sci_status SCI_FAILURE_OUT_OF_RESOURCES if there are no available remote
|
||||
|
||||
@@ -464,7 +464,7 @@ static enum sci_status sci_port_set_phy(struct isci_port *iport, struct isci_phy
|
||||
{
|
||||
/* Check to see if we can add this phy to a port
|
||||
* that means that the phy is not part of a port and that the port does
|
||||
* not already have a phy assinged to the phy index.
|
||||
* not already have a phy assigned to the phy index.
|
||||
*/
|
||||
if (!iport->phy_table[iphy->phy_index] &&
|
||||
!phy_get_non_dummy_port(iphy) &&
|
||||
|
||||
@@ -259,7 +259,7 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost,
|
||||
if (!phy_mask)
|
||||
continue;
|
||||
/*
|
||||
* Make sure that one or more of the phys were not already assinged to
|
||||
* Make sure that one or more of the phys were not already assigned to
|
||||
* a different port. */
|
||||
if ((phy_mask & ~assigned_phy_mask) == 0) {
|
||||
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
|
||||
|
||||
@@ -282,9 +282,7 @@ struct usbip_device {
|
||||
void (*unusable)(struct usbip_device *);
|
||||
} eh_ops;
|
||||
|
||||
#ifdef CONFIG_KCOV
|
||||
u64 kcov_handle;
|
||||
#endif
|
||||
struct kcov_common_handle_id kcov_handle;
|
||||
};
|
||||
|
||||
#define kthread_get_run(threadfn, data, namefmt, ...) \
|
||||
@@ -339,29 +337,4 @@ static inline int interface_to_devnum(struct usb_interface *interface)
|
||||
return udev->devnum;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KCOV
|
||||
|
||||
static inline void usbip_kcov_handle_init(struct usbip_device *ud)
|
||||
{
|
||||
ud->kcov_handle = kcov_common_handle();
|
||||
}
|
||||
|
||||
static inline void usbip_kcov_remote_start(struct usbip_device *ud)
|
||||
{
|
||||
kcov_remote_start_common(ud->kcov_handle);
|
||||
}
|
||||
|
||||
static inline void usbip_kcov_remote_stop(void)
|
||||
{
|
||||
kcov_remote_stop();
|
||||
}
|
||||
|
||||
#else /* CONFIG_KCOV */
|
||||
|
||||
static inline void usbip_kcov_handle_init(struct usbip_device *ud) { }
|
||||
static inline void usbip_kcov_remote_start(struct usbip_device *ud) { }
|
||||
static inline void usbip_kcov_remote_stop(void) { }
|
||||
|
||||
#endif /* CONFIG_KCOV */
|
||||
|
||||
#endif /* __USBIP_COMMON_H */
|
||||
|
||||
@@ -261,9 +261,9 @@ int vhci_rx_loop(void *data)
|
||||
if (usbip_event_happened(ud))
|
||||
break;
|
||||
|
||||
usbip_kcov_remote_start(ud);
|
||||
kcov_remote_start_common(ud->kcov_handle);
|
||||
vhci_rx_pdu(ud);
|
||||
usbip_kcov_remote_stop();
|
||||
kcov_remote_stop();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -425,7 +425,7 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
|
||||
vdev->ud.tcp_rx = tcp_rx;
|
||||
vdev->ud.tcp_tx = tcp_tx;
|
||||
vdev->ud.status = VDEV_ST_NOTASSIGNED;
|
||||
usbip_kcov_handle_init(&vdev->ud);
|
||||
vdev->ud.kcov_handle = kcov_common_handle();
|
||||
|
||||
spin_unlock(&vdev->ud.lock);
|
||||
spin_unlock_irqrestore(&vhci->lock, flags);
|
||||
|
||||
@@ -44,7 +44,7 @@ struct vhost_worker {
|
||||
/* Used to serialize device wide flushing with worker swapping. */
|
||||
struct mutex mutex;
|
||||
struct llist_head work_list;
|
||||
u64 kcov_handle;
|
||||
struct kcov_common_handle_id kcov_handle;
|
||||
u32 id;
|
||||
int attachment_cnt;
|
||||
bool killed;
|
||||
|
||||
@@ -78,7 +78,7 @@ config FS_DAX
|
||||
--map=mem:
|
||||
https://docs.pmem.io/ndctl-user-guide/ndctl-man-pages/ndctl-create-namespace
|
||||
|
||||
For ndctl to work CONFIG_DEV_DAX needs to be enabled as well. For most
|
||||
For ndctl to work CONFIG_DEV_DAX needs to be enabled as well. For most
|
||||
file systems DAX support needs to be manually enabled globally or
|
||||
per-inode using a mount option as well. See the file documentation in
|
||||
Documentation/filesystems/dax.rst for details.
|
||||
@@ -116,8 +116,8 @@ config FILE_LOCKING
|
||||
default y
|
||||
help
|
||||
This option enables standard file locking support, required
|
||||
for filesystems like NFS and for the flock() system
|
||||
call. Disabling this option saves about 11k.
|
||||
for filesystems like NFS and for the flock() system
|
||||
call. Disabling this option saves about 11k.
|
||||
|
||||
source "fs/crypto/Kconfig"
|
||||
|
||||
|
||||
@@ -1410,7 +1410,7 @@ static void generate_pq_vertical_step(struct btrfs_raid_bio *rbio, unsigned int
|
||||
rbio_qstripe_paddr(rbio, sector_nr, step_nr));
|
||||
|
||||
assert_rbio(rbio);
|
||||
raid6_call.gen_syndrome(rbio->real_stripes, step, pointers);
|
||||
raid6_gen_syndrome(rbio->real_stripes, step, pointers);
|
||||
} else {
|
||||
/* raid5 */
|
||||
memcpy(pointers[rbio->nr_data], pointers[0], step);
|
||||
@@ -1987,10 +1987,10 @@ static void recover_vertical_step(struct btrfs_raid_bio *rbio,
|
||||
}
|
||||
|
||||
if (failb == rbio->real_stripes - 2) {
|
||||
raid6_datap_recov(rbio->real_stripes, step,
|
||||
raid6_recov_datap(rbio->real_stripes, step,
|
||||
faila, pointers);
|
||||
} else {
|
||||
raid6_2data_recov(rbio->real_stripes, step,
|
||||
raid6_recov_2data(rbio->real_stripes, step,
|
||||
faila, failb, pointers);
|
||||
}
|
||||
} else {
|
||||
@@ -2644,7 +2644,7 @@ static bool verify_one_parity_step(struct btrfs_raid_bio *rbio,
|
||||
if (has_qstripe) {
|
||||
assert_rbio(rbio);
|
||||
/* RAID6, call the library function to fill in our P/Q. */
|
||||
raid6_call.gen_syndrome(rbio->real_stripes, step, pointers);
|
||||
raid6_gen_syndrome(rbio->real_stripes, step, pointers);
|
||||
} else {
|
||||
/* RAID5. */
|
||||
memcpy(pointers[nr_data], pointers[0], step);
|
||||
|
||||
@@ -18,16 +18,9 @@ int efs_get_block(struct inode *inode, sector_t iblock,
|
||||
|
||||
if (create)
|
||||
return error;
|
||||
if (iblock >= inode->i_blocks) {
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* i have no idea why this happens as often as it does
|
||||
*/
|
||||
pr_warn("%s(): block %d >= %ld (filesize %ld)\n",
|
||||
__func__, block, inode->i_blocks, inode->i_size);
|
||||
#endif
|
||||
if (iblock >= inode->i_blocks)
|
||||
return 0;
|
||||
}
|
||||
|
||||
phys = efs_map_block(inode, iblock);
|
||||
if (phys)
|
||||
map_bh(bh_result, inode->i_sb, phys);
|
||||
@@ -42,16 +35,8 @@ int efs_bmap(struct inode *inode, efs_block_t block) {
|
||||
}
|
||||
|
||||
/* are we about to read past the end of a file ? */
|
||||
if (!(block < inode->i_blocks)) {
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* i have no idea why this happens as often as it does
|
||||
*/
|
||||
pr_warn("%s(): block %d >= %ld (filesize %ld)\n",
|
||||
__func__, block, inode->i_blocks, inode->i_size);
|
||||
#endif
|
||||
if (!(block < inode->i_blocks))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return efs_map_block(inode, block);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,37 @@ static void fat_checksum_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, fat_checksum("ABCDEFGHA "), (u8)98);
|
||||
}
|
||||
|
||||
static void fat_clus_to_blknr_test(struct kunit *test)
|
||||
{
|
||||
struct msdos_sb_info sbi = {
|
||||
.sec_per_clus = 4,
|
||||
.data_start = 100,
|
||||
};
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (sector_t)100,
|
||||
fat_clus_to_blknr(&sbi, FAT_START_ENT));
|
||||
KUNIT_EXPECT_EQ(test, (sector_t)112, fat_clus_to_blknr(&sbi, 5));
|
||||
}
|
||||
|
||||
static void fat_get_blknr_offset_test(struct kunit *test)
|
||||
{
|
||||
struct msdos_sb_info sbi = {
|
||||
.dir_per_block = 16,
|
||||
.dir_per_block_bits = 4,
|
||||
};
|
||||
|
||||
sector_t blknr;
|
||||
int offset;
|
||||
|
||||
fat_get_blknr_offset(&sbi, 0, &blknr, &offset);
|
||||
KUNIT_EXPECT_EQ(test, (sector_t)0, blknr);
|
||||
KUNIT_EXPECT_EQ(test, 0, offset);
|
||||
|
||||
fat_get_blknr_offset(&sbi, (10 << 4) | 7, &blknr, &offset);
|
||||
KUNIT_EXPECT_EQ(test, (sector_t)10, blknr);
|
||||
KUNIT_EXPECT_EQ(test, 7, offset);
|
||||
}
|
||||
|
||||
struct fat_timestamp_testcase {
|
||||
const char *name;
|
||||
struct timespec64 ts;
|
||||
@@ -341,6 +372,8 @@ static void fat_truncate_atime_test(struct kunit *test)
|
||||
|
||||
static struct kunit_case fat_test_cases[] = {
|
||||
KUNIT_CASE(fat_checksum_test),
|
||||
KUNIT_CASE(fat_clus_to_blknr_test),
|
||||
KUNIT_CASE(fat_get_blknr_offset_test),
|
||||
KUNIT_CASE_PARAM(fat_time_fat2unix_test, fat_time_gen_params),
|
||||
KUNIT_CASE_PARAM(fat_time_unix2fat_test, fat_time_gen_params),
|
||||
KUNIT_CASE_PARAM(fat_time_unix2fat_clamp_test,
|
||||
|
||||
@@ -1738,6 +1738,14 @@ int fat_fill_super(struct super_block *sb, struct fs_context *fc,
|
||||
if (total_sectors == 0)
|
||||
total_sectors = bpb.fat_total_sect;
|
||||
|
||||
if (total_sectors < sbi->data_start) {
|
||||
if (!silent)
|
||||
fat_msg(sb, KERN_ERR,
|
||||
"data area starts beyond volume (%lu > %u)",
|
||||
sbi->data_start, total_sectors);
|
||||
goto out_invalid;
|
||||
}
|
||||
|
||||
total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
|
||||
|
||||
if (!is_fat32(sbi))
|
||||
@@ -1786,7 +1794,7 @@ int fat_fill_super(struct super_block *sb, struct fs_context *fc,
|
||||
*/
|
||||
|
||||
error = -EINVAL;
|
||||
sprintf(buf, "cp%d", sbi->options.codepage);
|
||||
scnprintf(buf, sizeof(buf), "cp%d", sbi->options.codepage);
|
||||
sbi->nls_disk = load_nls(buf);
|
||||
if (!sbi->nls_disk) {
|
||||
fat_msg(sb, KERN_ERR, "codepage %s not found", buf);
|
||||
|
||||
@@ -7576,7 +7576,7 @@ int ocfs2_trim_mainbm(struct super_block *sb, struct fstrim_range *range)
|
||||
len = range->len >> osb->s_clustersize_bits;
|
||||
minlen = range->minlen >> osb->s_clustersize_bits;
|
||||
|
||||
if (minlen >= osb->bitmap_cpg || range->len < sb->s_blocksize)
|
||||
if (minlen >= osb->bitmap_cpg || range->len < osb->s_clustersize)
|
||||
return -EINVAL;
|
||||
|
||||
trace_ocfs2_trim_mainbm(start, len, minlen);
|
||||
|
||||
@@ -2372,6 +2372,15 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
|
||||
unlock:
|
||||
up_write(&oi->ip_alloc_sem);
|
||||
|
||||
if (data_ac) {
|
||||
ocfs2_free_alloc_context(data_ac);
|
||||
data_ac = NULL;
|
||||
}
|
||||
if (meta_ac) {
|
||||
ocfs2_free_alloc_context(meta_ac);
|
||||
meta_ac = NULL;
|
||||
}
|
||||
|
||||
/* everything looks good, let's start the cleanup */
|
||||
if (!ret && dwc->dw_orphaned) {
|
||||
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
|
||||
@@ -2383,10 +2392,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
|
||||
ocfs2_inode_unlock(inode, 1);
|
||||
brelse(di_bh);
|
||||
out:
|
||||
if (data_ac)
|
||||
ocfs2_free_alloc_context(data_ac);
|
||||
if (meta_ac)
|
||||
ocfs2_free_alloc_context(meta_ac);
|
||||
ocfs2_run_deallocs(osb, &dealloc);
|
||||
ocfs2_dio_free_write_ctx(inode, dwc);
|
||||
|
||||
|
||||
@@ -344,8 +344,6 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
|
||||
wait_on_buffer(bh);
|
||||
put_bh(bh);
|
||||
bhs[i] = NULL;
|
||||
} else if (bh && buffer_uptodate(bh)) {
|
||||
clear_buffer_uptodate(bh);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -374,8 +372,11 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
|
||||
BUG_ON(buffer_jbd(bh));
|
||||
clear_buffer_needs_validate(bh);
|
||||
status = validate(sb, bh);
|
||||
if (status)
|
||||
if (status) {
|
||||
if (buffer_uptodate(bh))
|
||||
clear_buffer_uptodate(bh);
|
||||
goto read_failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -556,6 +556,7 @@ static int debug_lockres_open(struct inode *inode, struct file *file)
|
||||
struct dlm_ctxt *dlm = inode->i_private;
|
||||
struct debug_lockres *dl;
|
||||
void *buf;
|
||||
int status = -ENOMEM;
|
||||
|
||||
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
@@ -568,16 +569,23 @@ static int debug_lockres_open(struct inode *inode, struct file *file)
|
||||
dl->dl_len = PAGE_SIZE;
|
||||
dl->dl_buf = buf;
|
||||
|
||||
dlm_grab(dlm);
|
||||
dl->dl_ctxt = dlm;
|
||||
/* ->release uses dl_ctxt after open, so it needs a real pin. */
|
||||
dl->dl_ctxt = dlm_grab(dlm);
|
||||
if (!dl->dl_ctxt) {
|
||||
status = -ENOENT;
|
||||
goto bailseq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bailseq:
|
||||
seq_release_private(inode, file);
|
||||
bailfree:
|
||||
kfree(buf);
|
||||
bail:
|
||||
mlog_errno(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
if (status != -ENOENT)
|
||||
mlog_errno(status);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int debug_lockres_release(struct inode *inode, struct file *file)
|
||||
|
||||
@@ -3134,6 +3134,22 @@ static void *ocfs2_dlm_seq_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
* - Add last pr/ex unlock times and first lock wait time in usecs
|
||||
*/
|
||||
#define OCFS2_DLM_DEBUG_STR_VERSION 4
|
||||
|
||||
/*
|
||||
* The debug iterator snapshots lockres by value, so a userspace-stack LVB
|
||||
* pointer copied from the original lockres must be rebased to the copied
|
||||
* lksb before the dump walks the raw bytes.
|
||||
*/
|
||||
static void ocfs2_dlm_seq_rebase_lvb(struct ocfs2_lock_res *lockres)
|
||||
{
|
||||
if (!ocfs2_stack_supports_plocks())
|
||||
return;
|
||||
|
||||
if (lockres->l_lksb.lksb_fsdlm.sb_lvbptr)
|
||||
lockres->l_lksb.lksb_fsdlm.sb_lvbptr =
|
||||
(char *)&lockres->l_lksb + sizeof(struct dlm_lksb);
|
||||
}
|
||||
|
||||
static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
|
||||
{
|
||||
int i;
|
||||
@@ -3191,6 +3207,7 @@ static int ocfs2_dlm_seq_show(struct seq_file *m, void *v)
|
||||
lockres->l_blocking);
|
||||
|
||||
/* Dump the raw LVB */
|
||||
ocfs2_dlm_seq_rebase_lvb(lockres);
|
||||
lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
|
||||
for(i = 0; i < DLM_LVB_LEN; i++)
|
||||
seq_printf(m, "0x%x\t", lvb[i]);
|
||||
|
||||
@@ -444,21 +444,26 @@ int ocfs2_truncate_file(struct inode *inode,
|
||||
struct ocfs2_dinode *fe = NULL;
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
|
||||
/* We trust di_bh because it comes from ocfs2_inode_lock(), which
|
||||
* already validated it */
|
||||
/*
|
||||
* On local mounts ocfs2_inode_lock_update() skips the inode
|
||||
* refresh path, so truncation still needs to reject an inode
|
||||
* state that no longer matches di_bh.
|
||||
*/
|
||||
fe = (struct ocfs2_dinode *) di_bh->b_data;
|
||||
|
||||
trace_ocfs2_truncate_file((unsigned long long)OCFS2_I(inode)->ip_blkno,
|
||||
(unsigned long long)le64_to_cpu(fe->i_size),
|
||||
(unsigned long long)new_i_size);
|
||||
|
||||
mlog_bug_on_msg(le64_to_cpu(fe->i_size) != i_size_read(inode),
|
||||
"Inode %llu, inode i_size = %lld != di "
|
||||
"i_size = %llu, i_flags = 0x%x\n",
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno,
|
||||
i_size_read(inode),
|
||||
(unsigned long long)le64_to_cpu(fe->i_size),
|
||||
le32_to_cpu(fe->i_flags));
|
||||
if (unlikely(le64_to_cpu(fe->i_size) != i_size_read(inode))) {
|
||||
status = ocfs2_error(inode->i_sb,
|
||||
"Inode %llu has inconsistent i_size: inode = %lld, dinode = %llu, i_flags = 0x%x\n",
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno,
|
||||
i_size_read(inode),
|
||||
(unsigned long long)le64_to_cpu(fe->i_size),
|
||||
le32_to_cpu(fe->i_flags));
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (new_i_size > le64_to_cpu(fe->i_size)) {
|
||||
trace_ocfs2_truncate_file_error(
|
||||
|
||||
206
fs/ocfs2/inode.c
206
fs/ocfs2/inode.c
@@ -13,6 +13,7 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/fs_dirent.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
@@ -64,7 +65,40 @@ static int ocfs2_filecheck_read_inode_block_full(struct inode *inode,
|
||||
static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
|
||||
struct buffer_head *bh);
|
||||
static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
|
||||
struct buffer_head *bh);
|
||||
struct buffer_head *bh);
|
||||
|
||||
static bool ocfs2_valid_inode_mode(umode_t mode)
|
||||
{
|
||||
return fs_umode_to_ftype(mode) != FT_UNKNOWN;
|
||||
}
|
||||
|
||||
static bool ocfs2_dinode_has_unexpected_rdev(struct ocfs2_dinode *di)
|
||||
{
|
||||
umode_t mode = le16_to_cpu(di->i_mode);
|
||||
|
||||
if (le32_to_cpu(di->i_flags) & OCFS2_SYSTEM_FL)
|
||||
return false;
|
||||
|
||||
return !S_ISCHR(mode) && !S_ISBLK(mode) && di->id1.dev1.i_rdev != 0;
|
||||
}
|
||||
|
||||
static bool ocfs2_dinode_has_size_without_clusters(struct super_block *sb,
|
||||
struct ocfs2_dinode *di)
|
||||
{
|
||||
umode_t mode = le16_to_cpu(di->i_mode);
|
||||
|
||||
if (le32_to_cpu(di->i_flags) & OCFS2_SYSTEM_FL)
|
||||
return false;
|
||||
if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)
|
||||
return false;
|
||||
if (!le64_to_cpu(di->i_size) || le32_to_cpu(di->i_clusters))
|
||||
return false;
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
return true;
|
||||
|
||||
return !ocfs2_sparse_alloc(OCFS2_SB(sb)) && S_ISREG(mode);
|
||||
}
|
||||
|
||||
void ocfs2_set_inode_flags(struct inode *inode)
|
||||
{
|
||||
@@ -1494,6 +1528,86 @@ int ocfs2_validate_inode_block(struct super_block *sb,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reject dinodes whose i_mode does not name one of the seven
|
||||
* canonical POSIX file types. ocfs2_populate_inode() copies
|
||||
* i_mode verbatim into inode->i_mode and then dispatches via
|
||||
* switch (mode & S_IFMT) to file/dir/symlink/special_file iops;
|
||||
* an unrecognised type falls into ocfs2_special_file_iops with
|
||||
* init_special_inode(), which interprets i_rdev. Constrain the
|
||||
* type here so the dispatch only ever sees a value mkfs.ocfs2 /
|
||||
* VFS can produce.
|
||||
*/
|
||||
if (!ocfs2_valid_inode_mode(le16_to_cpu(di->i_mode))) {
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode #%llu: mode 0%o has unknown file type\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
le16_to_cpu(di->i_mode));
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* id1.dev1.i_rdev is the device-number arm of the id1 union and
|
||||
* is only meaningful for character and block device inodes. For
|
||||
* any other regular user-visible file type the on-disk value
|
||||
* must be zero. ocfs2_populate_inode() currently runs
|
||||
*
|
||||
* inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev));
|
||||
*
|
||||
* unconditionally, before the S_IFMT switch decides whether the
|
||||
* inode is a special file. As a result, an i_rdev value present
|
||||
* on a non-device inode is silently published into the in-core
|
||||
* inode; a subsequent forced re-read or in-core mode mutation
|
||||
* (cluster peer with raw write access to the shared LUN,
|
||||
* on-disk corruption, or a separately forged dinode) can then
|
||||
* expose the attacker-controlled device number to
|
||||
* init_special_inode() without ever showing an unusual i_mode
|
||||
* at validation time.
|
||||
*
|
||||
* System inodes (OCFS2_SYSTEM_FL) legitimately use the bitmap1
|
||||
* and journal1 arms of the same union (allocator i_used /
|
||||
* i_total counters and the journal ij_flags /
|
||||
* ij_recovery_generation pair); those bytes are not an i_rdev
|
||||
* and must not be checked here. Restrict the cross-check to
|
||||
* non-system inodes, which is the full attacker-controllable
|
||||
* surface.
|
||||
*/
|
||||
if (ocfs2_dinode_has_unexpected_rdev(di)) {
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode #%llu: non-device mode 0%o with i_rdev %llu\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
le16_to_cpu(di->i_mode),
|
||||
(unsigned long long)le64_to_cpu(di->id1.dev1.i_rdev));
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-inline directories must not have i_size without allocated
|
||||
* clusters: directory growth adds storage before advancing i_size,
|
||||
* and readdir walks i_size block-by-block. A forged directory
|
||||
* with zero clusters and a huge i_size would repeatedly fault on
|
||||
* holes while advancing through the claimed size.
|
||||
*
|
||||
* Non-inline regular files have the same invariant on non-sparse
|
||||
* volumes. Sparse regular files are different: truncate can
|
||||
* legitimately grow i_size without allocating clusters, so keep
|
||||
* the sparse-alloc carveout for S_IFREG only. System inodes and
|
||||
* inline-data dinodes have their own storage rules.
|
||||
*/
|
||||
if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
|
||||
if (S_ISDIR(le16_to_cpu(di->i_mode)))
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode #%llu: directory i_size %llu with i_clusters 0 and no inline-data flag\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
(unsigned long long)le64_to_cpu(di->i_size));
|
||||
else
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode #%llu: regular file i_size %llu with i_clusters 0 and no inline-data flag on non-sparse volume\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
(unsigned long long)le64_to_cpu(di->i_size));
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) {
|
||||
struct ocfs2_inline_data *data = &di->id2.i_data;
|
||||
|
||||
@@ -1525,6 +1639,29 @@ int ocfs2_validate_inode_block(struct super_block *sb,
|
||||
}
|
||||
}
|
||||
|
||||
if (S_ISLNK(le16_to_cpu(di->i_mode)) &&
|
||||
!le32_to_cpu(di->i_clusters)) {
|
||||
int max_inline = ocfs2_fast_symlink_chars(sb);
|
||||
u64 i_size = le64_to_cpu(di->i_size);
|
||||
|
||||
if (i_size >= max_inline) {
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode #%llu: fast symlink i_size %llu exceeds max %d\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
(unsigned long long)i_size,
|
||||
max_inline - 1);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (strnlen((char *)di->id2.i_symlink, i_size + 1) != i_size) {
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode #%llu: fast symlink is not NUL-terminated at i_size %llu\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
(unsigned long long)i_size);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
if (le32_to_cpu(di->i_flags) & OCFS2_CHAIN_FL) {
|
||||
struct ocfs2_chain_list *cl = &di->id2.i_chain;
|
||||
u16 bpc = 1 << (OCFS2_SB(sb)->s_clustersize_bits -
|
||||
@@ -1559,6 +1696,38 @@ int ocfs2_validate_inode_block(struct super_block *sb,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ocfs2_dinode_has_extents(di)) {
|
||||
struct ocfs2_extent_list *el = &di->id2.i_list;
|
||||
u16 count = le16_to_cpu(el->l_count);
|
||||
u16 next_free = le16_to_cpu(el->l_next_free_rec);
|
||||
|
||||
if (count == 0) {
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode %llu: extent list l_count is zero\n",
|
||||
(unsigned long long)bh->b_blocknr);
|
||||
goto bail;
|
||||
}
|
||||
/*
|
||||
* The exact capacity depends on i_xattr_inline_size, another
|
||||
* unvalidated on-disk field. Inline xattrs only shrink the
|
||||
* list, so the no-xattr maximum is a safe upper bound that a
|
||||
* valid l_count never exceeds.
|
||||
*/
|
||||
if (count > ocfs2_extent_recs_per_inode(sb)) {
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode %llu: extent list l_count %u exceeds max %u\n",
|
||||
(unsigned long long)bh->b_blocknr, count,
|
||||
ocfs2_extent_recs_per_inode(sb));
|
||||
goto bail;
|
||||
}
|
||||
if (next_free > count) {
|
||||
rc = ocfs2_error(sb,
|
||||
"Invalid dinode %llu: extent list l_next_free_rec %u exceeds l_count %u\n",
|
||||
(unsigned long long)bh->b_blocknr, next_free, count);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
bail:
|
||||
@@ -1624,6 +1793,40 @@ static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
le32_to_cpu(di->i_fs_generation));
|
||||
rc = -OCFS2_FILECHECK_ERR_GENERATION;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (!ocfs2_valid_inode_mode(le16_to_cpu(di->i_mode))) {
|
||||
mlog(ML_ERROR,
|
||||
"Filecheck: invalid dinode #%llu: mode 0%o has unknown file type\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
le16_to_cpu(di->i_mode));
|
||||
rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ocfs2_dinode_has_unexpected_rdev(di)) {
|
||||
mlog(ML_ERROR,
|
||||
"Filecheck: invalid dinode #%llu: non-device mode 0%o with i_rdev %llu\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
le16_to_cpu(di->i_mode),
|
||||
(unsigned long long)le64_to_cpu(di->id1.dev1.i_rdev));
|
||||
rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ocfs2_dinode_has_size_without_clusters(sb, di)) {
|
||||
if (S_ISDIR(le16_to_cpu(di->i_mode)))
|
||||
mlog(ML_ERROR,
|
||||
"Filecheck: invalid dinode #%llu: directory i_size %llu with i_clusters 0 and no inline-data flag\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
(unsigned long long)le64_to_cpu(di->i_size));
|
||||
else
|
||||
mlog(ML_ERROR,
|
||||
"Filecheck: invalid dinode #%llu: regular file i_size %llu with i_clusters 0 and no inline-data flag on non-sparse volume\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
(unsigned long long)le64_to_cpu(di->i_size));
|
||||
rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
|
||||
}
|
||||
|
||||
bail:
|
||||
@@ -1812,4 +2015,3 @@ const struct ocfs2_caching_operations ocfs2_inode_caching_ops = {
|
||||
.co_io_lock = ocfs2_inode_cache_io_lock,
|
||||
.co_io_unlock = ocfs2_inode_cache_io_unlock,
|
||||
};
|
||||
|
||||
|
||||
@@ -473,8 +473,12 @@ int ocfs2_extend_trans(handle_t *handle, int nblocks)
|
||||
*/
|
||||
int ocfs2_assure_trans_credits(handle_t *handle, int nblocks)
|
||||
{
|
||||
int old_nblks = jbd2_handle_buffer_credits(handle);
|
||||
int old_nblks;
|
||||
|
||||
if (is_handle_aborted(handle))
|
||||
return -EROFS;
|
||||
|
||||
old_nblks = jbd2_handle_buffer_credits(handle);
|
||||
trace_ocfs2_assure_trans_credits(old_nblks);
|
||||
if (old_nblks >= nblocks)
|
||||
return 0;
|
||||
@@ -1022,11 +1026,8 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb,
|
||||
struct ocfs2_dinode *fe;
|
||||
|
||||
fe = (struct ocfs2_dinode *)bh->b_data;
|
||||
|
||||
/* The journal bh on the osb always comes from ocfs2_journal_init()
|
||||
* and was validated there inside ocfs2_inode_lock_full(). It's a
|
||||
* code bug if we mess it up. */
|
||||
BUG_ON(!OCFS2_IS_VALID_DINODE(fe));
|
||||
if (WARN_ON(!OCFS2_IS_VALID_DINODE(fe)))
|
||||
return -EIO;
|
||||
|
||||
flags = le32_to_cpu(fe->id1.journal1.ij_flags);
|
||||
if (dirty)
|
||||
|
||||
@@ -196,6 +196,9 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
|
||||
if (ocfs2_mount_local(osb))
|
||||
return;
|
||||
|
||||
if (!osb->journal)
|
||||
return;
|
||||
|
||||
if (!ocfs2_ci_fully_checkpointed(INODE_CACHE(inode))) {
|
||||
/* WARNING: This only kicks off a single
|
||||
* checkpoint. If someone races you and adds more
|
||||
|
||||
@@ -534,6 +534,8 @@ static void ocfs2_probe_alloc_group(struct inode *inode, struct buffer_head *bh,
|
||||
u32 base_cpos = ocfs2_blocks_to_clusters(inode->i_sb,
|
||||
le64_to_cpu(gd->bg_blkno));
|
||||
|
||||
*phys_cpos = 0;
|
||||
|
||||
for (i = base_bit; i < le16_to_cpu(gd->bg_bits); i++) {
|
||||
|
||||
used = ocfs2_test_bit(i, (unsigned long *)gd->bg_bitmap);
|
||||
@@ -555,7 +557,7 @@ static void ocfs2_probe_alloc_group(struct inode *inode, struct buffer_head *bh,
|
||||
last_free_bits++;
|
||||
|
||||
if (last_free_bits == move_len) {
|
||||
i -= move_len;
|
||||
i = i - move_len + 1;
|
||||
*goal_bit = i;
|
||||
*phys_cpos = base_cpos + i;
|
||||
break;
|
||||
|
||||
@@ -494,8 +494,6 @@ struct ocfs2_super
|
||||
struct rb_root osb_rf_lock_tree;
|
||||
struct ocfs2_refcount_tree *osb_ref_tree_lru;
|
||||
|
||||
struct mutex system_file_mutex;
|
||||
|
||||
/*
|
||||
* OCFS2 needs to schedule several different types of work which
|
||||
* require cluster locking, disk I/O, recovery waits, etc. Since these
|
||||
|
||||
@@ -302,7 +302,7 @@ static int ocfs2_add_recovery_chunk(struct super_block *sb,
|
||||
if (!rc)
|
||||
return -ENOMEM;
|
||||
rc->rc_chunk = chunk;
|
||||
rc->rc_bitmap = kmalloc(sb->s_blocksize, GFP_NOFS);
|
||||
rc->rc_bitmap = kzalloc(sb->s_blocksize, GFP_NOFS);
|
||||
if (!rc->rc_bitmap) {
|
||||
kfree(rc);
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -2131,10 +2131,15 @@ static int ocfs2_remove_refcount_extent(handle_t *handle,
|
||||
rb->rf_flags = 0;
|
||||
rb->rf_parent = 0;
|
||||
rb->rf_cpos = 0;
|
||||
memset(&rb->rf_records, 0, sb->s_blocksize -
|
||||
offsetof(struct ocfs2_refcount_block, rf_records));
|
||||
rb->rf_records.rl_used = 0;
|
||||
rb->rf_records.rl_reserved2 = 0;
|
||||
rb->rf_records.rl_reserved1 = 0;
|
||||
/* rl_count determines the memset size and fortify object size. */
|
||||
rb->rf_records.rl_count =
|
||||
cpu_to_le16(ocfs2_refcount_recs_per_rb(sb));
|
||||
memset(rb->rf_records.rl_recs, 0,
|
||||
le16_to_cpu(rb->rf_records.rl_count) *
|
||||
sizeof(*rb->rf_records.rl_recs));
|
||||
}
|
||||
|
||||
ocfs2_journal_dirty(handle, ref_root_bh);
|
||||
|
||||
@@ -327,18 +327,14 @@ static int ocfs2_control_install_private(struct file *file)
|
||||
ocfs2_control_this_node = p->op_this_node;
|
||||
running_proto.pv_major = p->op_proto.pv_major;
|
||||
running_proto.pv_minor = p->op_proto.pv_minor;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&ocfs2_control_lock);
|
||||
|
||||
if (!rc && set_p) {
|
||||
/* We set the global values successfully */
|
||||
atomic_inc(&ocfs2_control_opened);
|
||||
ocfs2_control_set_handshake_state(file,
|
||||
OCFS2_CONTROL_HANDSHAKE_VALID);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&ocfs2_control_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -231,8 +231,16 @@ static int ocfs2_validate_gd_parent(struct super_block *sb,
|
||||
int resize)
|
||||
{
|
||||
unsigned int max_bits;
|
||||
unsigned int max_bitmap_bits;
|
||||
unsigned int max_bitmap_size;
|
||||
int suballocator;
|
||||
struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data;
|
||||
|
||||
suballocator = le64_to_cpu(di->i_blkno) != OCFS2_SB(sb)->bitmap_blkno;
|
||||
max_bitmap_size = ocfs2_group_bitmap_size(sb, suballocator,
|
||||
OCFS2_SB(sb)->s_feature_incompat);
|
||||
max_bitmap_bits = max_bitmap_size * 8;
|
||||
|
||||
if (di->i_blkno != gd->bg_parent_dinode) {
|
||||
do_error("Group descriptor #%llu has bad parent pointer (%llu, expected %llu)\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
@@ -240,6 +248,20 @@ static int ocfs2_validate_gd_parent(struct super_block *sb,
|
||||
(unsigned long long)le64_to_cpu(di->i_blkno));
|
||||
}
|
||||
|
||||
if (le16_to_cpu(gd->bg_size) > max_bitmap_size) {
|
||||
do_error("Group descriptor #%llu has bitmap size %u but physical max of %u\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
le16_to_cpu(gd->bg_size),
|
||||
max_bitmap_size);
|
||||
}
|
||||
|
||||
if (le16_to_cpu(gd->bg_bits) > max_bitmap_bits) {
|
||||
do_error("Group descriptor #%llu has bit count %u but physical max of %u\n",
|
||||
(unsigned long long)bh->b_blocknr,
|
||||
le16_to_cpu(gd->bg_bits),
|
||||
max_bitmap_bits);
|
||||
}
|
||||
|
||||
max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) * le16_to_cpu(di->id2.i_chain.cl_bpc);
|
||||
if (le16_to_cpu(gd->bg_bits) > max_bits) {
|
||||
do_error("Group descriptor #%llu has bit count of %u\n",
|
||||
|
||||
@@ -1996,8 +1996,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
|
||||
spin_lock_init(&osb->osb_xattr_lock);
|
||||
ocfs2_init_steal_slots(osb);
|
||||
|
||||
mutex_init(&osb->system_file_mutex);
|
||||
|
||||
atomic_set(&osb->alloc_stats.moves, 0);
|
||||
atomic_set(&osb->alloc_stats.local_data, 0);
|
||||
atomic_set(&osb->alloc_stats.bitmap_data, 0);
|
||||
|
||||
@@ -98,11 +98,9 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
|
||||
} else
|
||||
arr = get_local_system_inode(osb, type, slot);
|
||||
|
||||
mutex_lock(&osb->system_file_mutex);
|
||||
if (arr && ((inode = *arr) != NULL)) {
|
||||
/* get a ref in addition to the array ref */
|
||||
inode = igrab(inode);
|
||||
mutex_unlock(&osb->system_file_mutex);
|
||||
BUG_ON(!inode);
|
||||
|
||||
return inode;
|
||||
@@ -112,11 +110,10 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
|
||||
inode = _ocfs2_get_system_file_inode(osb, type, slot);
|
||||
|
||||
/* add one more if putting into array for first time */
|
||||
if (arr && inode) {
|
||||
*arr = igrab(inode);
|
||||
BUG_ON(!*arr);
|
||||
if (inode && arr && !*arr && !cmpxchg(&(*arr), NULL, inode)) {
|
||||
inode = igrab(inode);
|
||||
BUG_ON(!inode);
|
||||
}
|
||||
mutex_unlock(&osb->system_file_mutex);
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
||||
123
fs/ocfs2/xattr.c
123
fs/ocfs2/xattr.c
@@ -950,15 +950,51 @@ static int ocfs2_xattr_list_entries(struct inode *inode,
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_ibody_lookup_header(struct inode *inode,
|
||||
struct ocfs2_dinode *di,
|
||||
struct ocfs2_xattr_header **header)
|
||||
{
|
||||
u16 xattr_count;
|
||||
size_t max_entries;
|
||||
u16 inline_size = le16_to_cpu(di->i_xattr_inline_size);
|
||||
|
||||
if (inline_size > inode->i_sb->s_blocksize ||
|
||||
inline_size < sizeof(struct ocfs2_xattr_header)) {
|
||||
ocfs2_error(inode->i_sb,
|
||||
"Invalid xattr inline size %u in inode %llu\n",
|
||||
inline_size,
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
*header = (struct ocfs2_xattr_header *)
|
||||
((void *)di + inode->i_sb->s_blocksize - inline_size);
|
||||
|
||||
xattr_count = le16_to_cpu((*header)->xh_count);
|
||||
max_entries = (inline_size - sizeof(struct ocfs2_xattr_header)) /
|
||||
sizeof(struct ocfs2_xattr_entry);
|
||||
|
||||
if (xattr_count > max_entries) {
|
||||
ocfs2_error(inode->i_sb,
|
||||
"xattr entry count %u exceeds maximum %zu in inode %llu\n",
|
||||
xattr_count, max_entries,
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
|
||||
struct ocfs2_dinode *di)
|
||||
{
|
||||
struct ocfs2_xattr_header *xh;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
xh = (struct ocfs2_xattr_header *)
|
||||
((void *)di + inode->i_sb->s_blocksize -
|
||||
le16_to_cpu(di->i_xattr_inline_size));
|
||||
ret = ocfs2_xattr_ibody_lookup_header(inode, di, &xh);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < le16_to_cpu(xh->xh_count); i++)
|
||||
if (!ocfs2_xattr_is_local(&xh->xh_entries[i]))
|
||||
@@ -975,39 +1011,13 @@ static int ocfs2_xattr_ibody_list(struct inode *inode,
|
||||
struct ocfs2_xattr_header *header = NULL;
|
||||
struct ocfs2_inode_info *oi = OCFS2_I(inode);
|
||||
int ret = 0;
|
||||
u16 xattr_count;
|
||||
size_t max_entries;
|
||||
u16 inline_size;
|
||||
|
||||
if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
|
||||
return ret;
|
||||
|
||||
inline_size = le16_to_cpu(di->i_xattr_inline_size);
|
||||
|
||||
/* Validate inline size is reasonable */
|
||||
if (inline_size > inode->i_sb->s_blocksize ||
|
||||
inline_size < sizeof(struct ocfs2_xattr_header)) {
|
||||
ocfs2_error(inode->i_sb,
|
||||
"Invalid xattr inline size %u in inode %llu\n",
|
||||
inline_size,
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
header = (struct ocfs2_xattr_header *)
|
||||
((void *)di + inode->i_sb->s_blocksize - inline_size);
|
||||
|
||||
xattr_count = le16_to_cpu(header->xh_count);
|
||||
max_entries = (inline_size - sizeof(struct ocfs2_xattr_header)) /
|
||||
sizeof(struct ocfs2_xattr_entry);
|
||||
|
||||
if (xattr_count > max_entries) {
|
||||
ocfs2_error(inode->i_sb,
|
||||
"xattr entry count %u exceeds maximum %zu in inode %llu\n",
|
||||
xattr_count, max_entries,
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
ret = ocfs2_xattr_ibody_lookup_header(inode, di, &header);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size);
|
||||
|
||||
@@ -1200,8 +1210,9 @@ static int ocfs2_xattr_ibody_get(struct inode *inode,
|
||||
return -ENODATA;
|
||||
|
||||
xs->end = (void *)di + inode->i_sb->s_blocksize;
|
||||
xs->header = (struct ocfs2_xattr_header *)
|
||||
(xs->end - le16_to_cpu(di->i_xattr_inline_size));
|
||||
ret = ocfs2_xattr_ibody_lookup_header(inode, di, &xs->header);
|
||||
if (ret)
|
||||
return ret;
|
||||
xs->base = (void *)xs->header;
|
||||
xs->here = xs->header->xh_entries;
|
||||
|
||||
@@ -2465,9 +2476,9 @@ static int ocfs2_xattr_ibody_remove(struct inode *inode,
|
||||
.vb_access = ocfs2_journal_access_di,
|
||||
};
|
||||
|
||||
header = (struct ocfs2_xattr_header *)
|
||||
((void *)di + inode->i_sb->s_blocksize -
|
||||
le16_to_cpu(di->i_xattr_inline_size));
|
||||
ret = ocfs2_xattr_ibody_lookup_header(inode, di, &header);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ocfs2_remove_value_outside(inode, &vb, header,
|
||||
ref_ci, ref_root_bh);
|
||||
@@ -2726,12 +2737,14 @@ static int ocfs2_xattr_ibody_find(struct inode *inode,
|
||||
|
||||
xs->xattr_bh = xs->inode_bh;
|
||||
xs->end = (void *)di + inode->i_sb->s_blocksize;
|
||||
if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)
|
||||
xs->header = (struct ocfs2_xattr_header *)
|
||||
(xs->end - le16_to_cpu(di->i_xattr_inline_size));
|
||||
else
|
||||
if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
|
||||
ret = ocfs2_xattr_ibody_lookup_header(inode, di, &xs->header);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
xs->header = (struct ocfs2_xattr_header *)
|
||||
(xs->end - OCFS2_SB(inode->i_sb)->s_xattr_inline_size);
|
||||
}
|
||||
xs->base = (void *)xs->header;
|
||||
xs->here = xs->header->xh_entries;
|
||||
|
||||
@@ -6003,14 +6016,17 @@ static int ocfs2_xattr_inline_attach_refcount(struct inode *inode,
|
||||
struct ocfs2_cached_dealloc_ctxt *dealloc)
|
||||
{
|
||||
struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
|
||||
struct ocfs2_xattr_header *header = (struct ocfs2_xattr_header *)
|
||||
(fe_bh->b_data + inode->i_sb->s_blocksize -
|
||||
le16_to_cpu(di->i_xattr_inline_size));
|
||||
struct ocfs2_xattr_header *header;
|
||||
int ret;
|
||||
struct ocfs2_xattr_value_buf vb = {
|
||||
.vb_bh = fe_bh,
|
||||
.vb_access = ocfs2_journal_access_di,
|
||||
};
|
||||
|
||||
ret = ocfs2_xattr_ibody_lookup_header(inode, di, &header);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ocfs2_xattr_attach_refcount_normal(inode, &vb, header,
|
||||
ref_ci, ref_root_bh, dealloc);
|
||||
}
|
||||
@@ -6495,12 +6511,10 @@ static int ocfs2_reflink_xattr_inline(struct ocfs2_xattr_reflink *args)
|
||||
handle_t *handle;
|
||||
struct ocfs2_super *osb = OCFS2_SB(args->old_inode->i_sb);
|
||||
struct ocfs2_dinode *di = (struct ocfs2_dinode *)args->old_bh->b_data;
|
||||
int inline_size = le16_to_cpu(di->i_xattr_inline_size);
|
||||
int header_off = osb->sb->s_blocksize - inline_size;
|
||||
struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)
|
||||
(args->old_bh->b_data + header_off);
|
||||
struct ocfs2_xattr_header *new_xh = (struct ocfs2_xattr_header *)
|
||||
(args->new_bh->b_data + header_off);
|
||||
int inline_size;
|
||||
int header_off;
|
||||
struct ocfs2_xattr_header *xh;
|
||||
struct ocfs2_xattr_header *new_xh;
|
||||
struct ocfs2_alloc_context *meta_ac = NULL;
|
||||
struct ocfs2_inode_info *new_oi;
|
||||
struct ocfs2_dinode *new_di;
|
||||
@@ -6509,6 +6523,15 @@ static int ocfs2_reflink_xattr_inline(struct ocfs2_xattr_reflink *args)
|
||||
.vb_access = ocfs2_journal_access_di,
|
||||
};
|
||||
|
||||
ret = ocfs2_xattr_ibody_lookup_header(args->old_inode, di, &xh);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
inline_size = le16_to_cpu(di->i_xattr_inline_size);
|
||||
header_off = osb->sb->s_blocksize - inline_size;
|
||||
new_xh = (struct ocfs2_xattr_header *)
|
||||
(args->new_bh->b_data + header_off);
|
||||
|
||||
ret = ocfs2_reflink_lock_xattr_allocators(osb, xh, args->ref_root_bh,
|
||||
&credits, &meta_ac);
|
||||
if (ret) {
|
||||
|
||||
@@ -3513,28 +3513,42 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
|
||||
struct tgid_iter {
|
||||
unsigned int tgid;
|
||||
struct task_struct *task;
|
||||
struct pid_namespace *const pid_ns;
|
||||
};
|
||||
static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter)
|
||||
{
|
||||
struct pid *pid;
|
||||
|
||||
if (iter.task)
|
||||
put_task_struct(iter.task);
|
||||
rcu_read_lock();
|
||||
retry:
|
||||
iter.task = NULL;
|
||||
pid = find_ge_pid(iter.tgid, ns);
|
||||
if (pid) {
|
||||
iter.tgid = pid_nr_ns(pid, ns);
|
||||
iter.task = pid_task(pid, PIDTYPE_TGID);
|
||||
if (!iter.task) {
|
||||
iter.tgid += 1;
|
||||
goto retry;
|
||||
}
|
||||
get_task_struct(iter.task);
|
||||
static struct tgid_iter
|
||||
make_tgid_iter(unsigned int init_tgid, struct pid_namespace *pid_ns)
|
||||
{
|
||||
return (struct tgid_iter){
|
||||
.tgid = init_tgid - 1,
|
||||
.pid_ns = pid_ns,
|
||||
};
|
||||
}
|
||||
|
||||
static bool next_tgid(struct tgid_iter *it)
|
||||
{
|
||||
if (it->task) {
|
||||
put_task_struct(it->task);
|
||||
it->task = NULL;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
while (1) {
|
||||
it->tgid += 1;
|
||||
const auto pid = find_ge_pid(it->tgid, it->pid_ns);
|
||||
if (pid) {
|
||||
it->tgid = pid_nr_ns(pid, it->pid_ns);
|
||||
it->task = pid_task(pid, PIDTYPE_TGID);
|
||||
if (it->task) {
|
||||
get_task_struct(it->task);
|
||||
rcu_read_unlock();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
rcu_read_unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return iter;
|
||||
}
|
||||
|
||||
#define TGID_OFFSET (FIRST_PROCESS_ENTRY + 2)
|
||||
@@ -3542,9 +3556,8 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite
|
||||
/* for the /proc/ directory itself, after non-process stuff has been done */
|
||||
int proc_pid_readdir(struct file *file, struct dir_context *ctx)
|
||||
{
|
||||
struct tgid_iter iter;
|
||||
struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb);
|
||||
struct pid_namespace *ns = proc_pid_ns(file_inode(file)->i_sb);
|
||||
struct pid_namespace *pid_ns = proc_pid_ns(file_inode(file)->i_sb);
|
||||
loff_t pos = ctx->pos;
|
||||
|
||||
if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
|
||||
@@ -3560,11 +3573,9 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx)
|
||||
return 0;
|
||||
ctx->pos = pos = pos + 1;
|
||||
}
|
||||
iter.tgid = pos - TGID_OFFSET;
|
||||
iter.task = NULL;
|
||||
for (iter = next_tgid(ns, iter);
|
||||
iter.task;
|
||||
iter.tgid += 1, iter = next_tgid(ns, iter)) {
|
||||
|
||||
auto iter = make_tgid_iter(pos - TGID_OFFSET, pid_ns);
|
||||
while (next_tgid(&iter)) {
|
||||
char name[10 + 1];
|
||||
unsigned int len;
|
||||
|
||||
|
||||
@@ -427,9 +427,13 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
|
||||
if (xlate_proc_name(name, parent, &fn) != 0)
|
||||
goto out;
|
||||
qstr.name = fn;
|
||||
qstr.len = strlen(fn);
|
||||
if (qstr.len == 0 || qstr.len >= 256) {
|
||||
WARN(1, "name len %u\n", qstr.len);
|
||||
qstr.len = strnlen(fn, NAME_MAX + 1);
|
||||
if (qstr.len == 0) {
|
||||
WARN(1, "empty name\n");
|
||||
return NULL;
|
||||
}
|
||||
if (qstr.len > NAME_MAX) {
|
||||
WARN(1, "name too long\n");
|
||||
return NULL;
|
||||
}
|
||||
if (qstr.len == 1 && fn[0] == '.') {
|
||||
|
||||
@@ -91,8 +91,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
memcpy((void __force *)to, from, n);
|
||||
return 0;
|
||||
}
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_USER
|
||||
#endif /* CONFIG_UACCESS_MEMCPY */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Extend a 32-bit counter to 63 bits
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: December 3, 2006
|
||||
* Copyright: MontaVista Software, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_CNT32_TO_63_H__
|
||||
#define __LINUX_CNT32_TO_63_H__
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/* this is used only to give gcc a clue about good code generation */
|
||||
union cnt32_to_63 {
|
||||
struct {
|
||||
#if defined(__LITTLE_ENDIAN)
|
||||
u32 lo, hi;
|
||||
#elif defined(__BIG_ENDIAN)
|
||||
u32 hi, lo;
|
||||
#endif
|
||||
};
|
||||
u64 val;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* cnt32_to_63 - Expand a 32-bit counter to a 63-bit counter
|
||||
* @cnt_lo: The low part of the counter
|
||||
*
|
||||
* Many hardware clock counters are only 32 bits wide and therefore have
|
||||
* a relatively short period making wrap-arounds rather frequent. This
|
||||
* is a problem when implementing sched_clock() for example, where a 64-bit
|
||||
* non-wrapping monotonic value is expected to be returned.
|
||||
*
|
||||
* To overcome that limitation, let's extend a 32-bit counter to 63 bits
|
||||
* in a completely lock free fashion. Bits 0 to 31 of the clock are provided
|
||||
* by the hardware while bits 32 to 62 are stored in memory. The top bit in
|
||||
* memory is used to synchronize with the hardware clock half-period. When
|
||||
* the top bit of both counters (hardware and in memory) differ then the
|
||||
* memory is updated with a new value, incrementing it when the hardware
|
||||
* counter wraps around.
|
||||
*
|
||||
* Because a word store in memory is atomic then the incremented value will
|
||||
* always be in synch with the top bit indicating to any potential concurrent
|
||||
* reader if the value in memory is up to date or not with regards to the
|
||||
* needed increment. And any race in updating the value in memory is harmless
|
||||
* as the same value would simply be stored more than once.
|
||||
*
|
||||
* The restrictions for the algorithm to work properly are:
|
||||
*
|
||||
* 1) this code must be called at least once per each half period of the
|
||||
* 32-bit counter;
|
||||
*
|
||||
* 2) this code must not be preempted for a duration longer than the
|
||||
* 32-bit counter half period minus the longest period between two
|
||||
* calls to this code;
|
||||
*
|
||||
* Those requirements ensure proper update to the state bit in memory.
|
||||
* This is usually not a problem in practice, but if it is then a kernel
|
||||
* timer should be scheduled to manage for this code to be executed often
|
||||
* enough.
|
||||
*
|
||||
* And finally:
|
||||
*
|
||||
* 3) the cnt_lo argument must be seen as a globally incrementing value,
|
||||
* meaning that it should be a direct reference to the counter data which
|
||||
* can be evaluated according to a specific ordering within the macro,
|
||||
* and not the result of a previous evaluation stored in a variable.
|
||||
*
|
||||
* For example, this is wrong:
|
||||
*
|
||||
* u32 partial = get_hw_count();
|
||||
* u64 full = cnt32_to_63(partial);
|
||||
* return full;
|
||||
*
|
||||
* This is fine:
|
||||
*
|
||||
* u64 full = cnt32_to_63(get_hw_count());
|
||||
* return full;
|
||||
*
|
||||
* Note that the top bit (bit 63) in the returned value should be considered
|
||||
* as garbage. It is not cleared here because callers are likely to use a
|
||||
* multiplier on the returned value which can get rid of the top bit
|
||||
* implicitly by making the multiplier even, therefore saving on a runtime
|
||||
* clear-bit instruction. Otherwise caller must remember to clear the top
|
||||
* bit explicitly.
|
||||
*/
|
||||
#define cnt32_to_63(cnt_lo) \
|
||||
({ \
|
||||
static u32 __m_cnt_hi; \
|
||||
union cnt32_to_63 __x; \
|
||||
__x.hi = __m_cnt_hi; \
|
||||
smp_rmb(); \
|
||||
__x.lo = (cnt_lo); \
|
||||
if (unlikely((s32)(__x.hi ^ __x.lo) < 0)) \
|
||||
__m_cnt_hi = __x.hi = (__x.hi ^ 0x80000000) + (__x.hi >> 31); \
|
||||
__x.val; \
|
||||
})
|
||||
|
||||
#endif
|
||||
@@ -36,7 +36,7 @@
|
||||
*
|
||||
* Return: A pointer with @error encoded within its value.
|
||||
*/
|
||||
static inline void * __must_check ERR_PTR(long error)
|
||||
static __always_inline void * __must_check ERR_PTR(long error)
|
||||
{
|
||||
return (void *) error;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ static inline void * __must_check ERR_PTR(long error)
|
||||
* @ptr: An error pointer.
|
||||
* Return: The error code within @ptr.
|
||||
*/
|
||||
static inline long __must_check PTR_ERR(__force const void *ptr)
|
||||
static __always_inline long __must_check PTR_ERR(__force const void *ptr)
|
||||
{
|
||||
return (long) ptr;
|
||||
}
|
||||
@@ -73,7 +73,7 @@ static inline long __must_check PTR_ERR(__force const void *ptr)
|
||||
* @ptr: The pointer to check.
|
||||
* Return: true if @ptr is an error pointer, false otherwise.
|
||||
*/
|
||||
static inline bool __must_check IS_ERR(__force const void *ptr)
|
||||
static __always_inline bool __must_check IS_ERR(__force const void *ptr)
|
||||
{
|
||||
return IS_ERR_VALUE((unsigned long)ptr);
|
||||
}
|
||||
@@ -87,7 +87,7 @@ static inline bool __must_check IS_ERR(__force const void *ptr)
|
||||
*
|
||||
* Like IS_ERR(), but also returns true for a null pointer.
|
||||
*/
|
||||
static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
|
||||
static __always_inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
|
||||
{
|
||||
return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr);
|
||||
}
|
||||
@@ -99,7 +99,7 @@ static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
|
||||
* Explicitly cast an error-valued pointer to another pointer type in such a
|
||||
* way as to make it clear that's what's going on.
|
||||
*/
|
||||
static inline void * __must_check ERR_CAST(__force const void *ptr)
|
||||
static __always_inline void * __must_check ERR_CAST(__force const void *ptr)
|
||||
{
|
||||
/* cast away the const */
|
||||
return (void *) ptr;
|
||||
@@ -122,7 +122,7 @@ static inline void * __must_check ERR_CAST(__force const void *ptr)
|
||||
*
|
||||
* Return: The error code within @ptr if it is an error pointer; 0 otherwise.
|
||||
*/
|
||||
static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
|
||||
static __always_inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
|
||||
{
|
||||
if (IS_ERR(ptr))
|
||||
return PTR_ERR(ptr);
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#define __initdata __section(".init.data")
|
||||
#define __initconst __section(".init.rodata")
|
||||
#define __exitdata __section(".exit.data")
|
||||
#define __exit_call __used __section(".exitcall.exit")
|
||||
#define __exit_call __maybe_unused __section(".exitcall.exit")
|
||||
|
||||
/*
|
||||
* modpost check for section mismatches during the kernel build.
|
||||
|
||||
@@ -21,8 +21,6 @@ enum kcov_mode {
|
||||
KCOV_MODE_TRACE_PC = 2,
|
||||
/* Collecting comparison operands mode. */
|
||||
KCOV_MODE_TRACE_CMP = 3,
|
||||
/* The process owns a KCOV remote reference. */
|
||||
KCOV_MODE_REMOTE = 4,
|
||||
};
|
||||
|
||||
#define KCOV_IN_CTXSW (1 << 30)
|
||||
@@ -43,11 +41,11 @@ do { \
|
||||
/* See Documentation/dev-tools/kcov.rst for usage details. */
|
||||
void kcov_remote_start(u64 handle);
|
||||
void kcov_remote_stop(void);
|
||||
u64 kcov_common_handle(void);
|
||||
struct kcov_common_handle_id kcov_common_handle(void);
|
||||
|
||||
static inline void kcov_remote_start_common(u64 id)
|
||||
static inline void kcov_remote_start_common(struct kcov_common_handle_id id)
|
||||
{
|
||||
kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_COMMON, id));
|
||||
kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_COMMON, id.val));
|
||||
}
|
||||
|
||||
static inline void kcov_remote_start_usb(u64 id)
|
||||
@@ -99,11 +97,11 @@ static inline void kcov_prepare_switch(struct task_struct *t) {}
|
||||
static inline void kcov_finish_switch(struct task_struct *t) {}
|
||||
static inline void kcov_remote_start(u64 handle) {}
|
||||
static inline void kcov_remote_stop(void) {}
|
||||
static inline u64 kcov_common_handle(void)
|
||||
static inline struct kcov_common_handle_id kcov_common_handle(void)
|
||||
{
|
||||
return 0;
|
||||
return (struct kcov_common_handle_id){};
|
||||
}
|
||||
static inline void kcov_remote_start_common(u64 id) {}
|
||||
static inline void kcov_remote_start_common(struct kcov_common_handle_id id) {}
|
||||
static inline void kcov_remote_start_usb(u64 id) {}
|
||||
static inline void kcov_remote_start_usb_softirq(u64 id) {}
|
||||
static inline void kcov_remote_stop_softirq(void) {}
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
*
|
||||
* | add | del_first | del_all
|
||||
* add | - | - | -
|
||||
* del_first | | L | L
|
||||
* del_all | | | -
|
||||
* del_first | - | L | L
|
||||
* del_all | - | - | -
|
||||
*
|
||||
* Where, a particular row's operation can happen concurrently with a column's
|
||||
* operation, with "-" being no lock needed, while "L" being lock is needed.
|
||||
|
||||
@@ -1,206 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* -*- linux-c -*- ------------------------------------------------------- *
|
||||
/*
|
||||
* Copyright 2003 H. Peter Anvin - All Rights Reserved
|
||||
*
|
||||
* Copyright 2003 H. Peter Anvin - All Rights Reserved
|
||||
*
|
||||
* ----------------------------------------------------------------------- */
|
||||
* Public interface to the RAID6 P/Q calculation and recovery library.
|
||||
*/
|
||||
#ifndef LINUX_RAID_PQ_H
|
||||
#define LINUX_RAID_PQ_H
|
||||
|
||||
#ifndef LINUX_RAID_RAID6_H
|
||||
#define LINUX_RAID_RAID6_H
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define RAID6_MIN_DISKS 4
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/mm.h>
|
||||
void raid6_gen_syndrome(int disks, size_t bytes, void **ptrs);
|
||||
void raid6_xor_syndrome(int disks, int start, int stop, size_t bytes,
|
||||
void **ptrs);
|
||||
bool raid6_can_xor_syndrome(void);
|
||||
|
||||
/* This should be const but the raid6 code is too convoluted for that. */
|
||||
static inline void *raid6_get_zero_page(void)
|
||||
{
|
||||
return page_address(ZERO_PAGE(0));
|
||||
}
|
||||
void raid6_recov_2data(int disks, size_t bytes, int faila, int failb,
|
||||
void **ptrs);
|
||||
void raid6_recov_datap(int disks, size_t bytes, int faila,
|
||||
void **ptrs);
|
||||
|
||||
#else /* ! __KERNEL__ */
|
||||
/* Used for testing in user space */
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Not standard, but glibc defines it */
|
||||
#define BITS_PER_LONG __WORDSIZE
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
# define PAGE_SIZE 4096
|
||||
#endif
|
||||
#ifndef PAGE_SHIFT
|
||||
# define PAGE_SHIFT 12
|
||||
#endif
|
||||
extern const char raid6_empty_zero_page[PAGE_SIZE];
|
||||
|
||||
#define __init
|
||||
#define __exit
|
||||
#ifndef __attribute_const__
|
||||
# define __attribute_const__ __attribute__((const))
|
||||
#endif
|
||||
#define noinline __attribute__((noinline))
|
||||
|
||||
#define preempt_enable()
|
||||
#define preempt_disable()
|
||||
#define cpu_has_feature(x) 1
|
||||
#define enable_kernel_altivec()
|
||||
#define disable_kernel_altivec()
|
||||
|
||||
#undef EXPORT_SYMBOL
|
||||
#define EXPORT_SYMBOL(sym)
|
||||
#undef EXPORT_SYMBOL_GPL
|
||||
#define EXPORT_SYMBOL_GPL(sym)
|
||||
#define MODULE_LICENSE(licence)
|
||||
#define MODULE_DESCRIPTION(desc)
|
||||
#define subsys_initcall(x)
|
||||
#define module_exit(x)
|
||||
|
||||
#define IS_ENABLED(x) (x)
|
||||
#define CONFIG_RAID6_PQ_BENCHMARK 1
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/* Routine choices */
|
||||
struct raid6_calls {
|
||||
void (*gen_syndrome)(int, size_t, void **);
|
||||
void (*xor_syndrome)(int, int, int, size_t, void **);
|
||||
int (*valid)(void); /* Returns 1 if this routine set is usable */
|
||||
const char *name; /* Name of this routine set */
|
||||
int priority; /* Relative priority ranking if non-zero */
|
||||
};
|
||||
|
||||
/* Selected algorithm */
|
||||
extern struct raid6_calls raid6_call;
|
||||
|
||||
/* Various routine sets */
|
||||
extern const struct raid6_calls raid6_intx1;
|
||||
extern const struct raid6_calls raid6_intx2;
|
||||
extern const struct raid6_calls raid6_intx4;
|
||||
extern const struct raid6_calls raid6_intx8;
|
||||
extern const struct raid6_calls raid6_mmxx1;
|
||||
extern const struct raid6_calls raid6_mmxx2;
|
||||
extern const struct raid6_calls raid6_sse1x1;
|
||||
extern const struct raid6_calls raid6_sse1x2;
|
||||
extern const struct raid6_calls raid6_sse2x1;
|
||||
extern const struct raid6_calls raid6_sse2x2;
|
||||
extern const struct raid6_calls raid6_sse2x4;
|
||||
extern const struct raid6_calls raid6_altivec1;
|
||||
extern const struct raid6_calls raid6_altivec2;
|
||||
extern const struct raid6_calls raid6_altivec4;
|
||||
extern const struct raid6_calls raid6_altivec8;
|
||||
extern const struct raid6_calls raid6_avx2x1;
|
||||
extern const struct raid6_calls raid6_avx2x2;
|
||||
extern const struct raid6_calls raid6_avx2x4;
|
||||
extern const struct raid6_calls raid6_avx512x1;
|
||||
extern const struct raid6_calls raid6_avx512x2;
|
||||
extern const struct raid6_calls raid6_avx512x4;
|
||||
extern const struct raid6_calls raid6_s390vx8;
|
||||
extern const struct raid6_calls raid6_vpermxor1;
|
||||
extern const struct raid6_calls raid6_vpermxor2;
|
||||
extern const struct raid6_calls raid6_vpermxor4;
|
||||
extern const struct raid6_calls raid6_vpermxor8;
|
||||
extern const struct raid6_calls raid6_lsx;
|
||||
extern const struct raid6_calls raid6_lasx;
|
||||
extern const struct raid6_calls raid6_rvvx1;
|
||||
extern const struct raid6_calls raid6_rvvx2;
|
||||
extern const struct raid6_calls raid6_rvvx4;
|
||||
extern const struct raid6_calls raid6_rvvx8;
|
||||
|
||||
struct raid6_recov_calls {
|
||||
void (*data2)(int, size_t, int, int, void **);
|
||||
void (*datap)(int, size_t, int, void **);
|
||||
int (*valid)(void);
|
||||
const char *name;
|
||||
int priority;
|
||||
};
|
||||
|
||||
extern const struct raid6_recov_calls raid6_recov_intx1;
|
||||
extern const struct raid6_recov_calls raid6_recov_ssse3;
|
||||
extern const struct raid6_recov_calls raid6_recov_avx2;
|
||||
extern const struct raid6_recov_calls raid6_recov_avx512;
|
||||
extern const struct raid6_recov_calls raid6_recov_s390xc;
|
||||
extern const struct raid6_recov_calls raid6_recov_neon;
|
||||
extern const struct raid6_recov_calls raid6_recov_lsx;
|
||||
extern const struct raid6_recov_calls raid6_recov_lasx;
|
||||
extern const struct raid6_recov_calls raid6_recov_rvv;
|
||||
|
||||
extern const struct raid6_calls raid6_neonx1;
|
||||
extern const struct raid6_calls raid6_neonx2;
|
||||
extern const struct raid6_calls raid6_neonx4;
|
||||
extern const struct raid6_calls raid6_neonx8;
|
||||
|
||||
/* Algorithm list */
|
||||
extern const struct raid6_calls * const raid6_algos[];
|
||||
extern const struct raid6_recov_calls *const raid6_recov_algos[];
|
||||
int raid6_select_algo(void);
|
||||
|
||||
/* Return values from chk_syndrome */
|
||||
#define RAID6_OK 0
|
||||
#define RAID6_P_BAD 1
|
||||
#define RAID6_Q_BAD 2
|
||||
#define RAID6_PQ_BAD 3
|
||||
|
||||
/* Galois field tables */
|
||||
extern const u8 raid6_gfmul[256][256] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_vgfmul[256][32] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_gfexp[256] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_gflog[256] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_gfinv[256] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_gfexi[256] __attribute__((aligned(256)));
|
||||
|
||||
/* Recovery routines */
|
||||
extern void (*raid6_2data_recov)(int disks, size_t bytes, int faila, int failb,
|
||||
void **ptrs);
|
||||
extern void (*raid6_datap_recov)(int disks, size_t bytes, int faila,
|
||||
void **ptrs);
|
||||
void raid6_dual_recov(int disks, size_t bytes, int faila, int failb,
|
||||
void **ptrs);
|
||||
|
||||
/* Some definitions to allow code to be compiled for testing in userspace */
|
||||
#ifndef __KERNEL__
|
||||
|
||||
# define jiffies raid6_jiffies()
|
||||
# define printk printf
|
||||
# define pr_err(format, ...) fprintf(stderr, format, ## __VA_ARGS__)
|
||||
# define pr_info(format, ...) fprintf(stdout, format, ## __VA_ARGS__)
|
||||
# define GFP_KERNEL 0
|
||||
# define __get_free_pages(x, y) ((unsigned long)mmap(NULL, PAGE_SIZE << (y), \
|
||||
PROT_READ|PROT_WRITE, \
|
||||
MAP_PRIVATE|MAP_ANONYMOUS,\
|
||||
0, 0))
|
||||
# define free_pages(x, y) munmap((void *)(x), PAGE_SIZE << (y))
|
||||
|
||||
static inline void cpu_relax(void)
|
||||
{
|
||||
/* Nothing */
|
||||
}
|
||||
|
||||
#undef HZ
|
||||
#define HZ 1000
|
||||
static inline uint32_t raid6_jiffies(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec*1000 + tv.tv_usec/1000;
|
||||
}
|
||||
|
||||
static inline void *raid6_get_zero_page(void)
|
||||
{
|
||||
return raid6_empty_zero_page;
|
||||
}
|
||||
|
||||
#endif /* ! __KERNEL__ */
|
||||
|
||||
#endif /* LINUX_RAID_RAID6_H */
|
||||
#endif /* LINUX_RAID_PQ_H */
|
||||
|
||||
19
include/linux/raid/pq_tables.h
Normal file
19
include/linux/raid/pq_tables.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright 2003 H. Peter Anvin - All Rights Reserved
|
||||
*
|
||||
* Galois field tables for the Linux RAID6 P/Q parity algorithm.
|
||||
*/
|
||||
#ifndef _LINUX_RAID_PQ_TABLES_H
|
||||
#define _LINUX_RAID_PQ_TABLES_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
extern const u8 raid6_gfmul[256][256] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_vgfmul[256][32] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_gfexp[256] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_gflog[256] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_gfinv[256] __attribute__((aligned(256)));
|
||||
extern const u8 raid6_gfexi[256] __attribute__((aligned(256)));
|
||||
|
||||
#endif /* _LINUX_RAID_PQ_TABLES_H */
|
||||
@@ -1532,6 +1532,9 @@ struct task_struct {
|
||||
/* KCOV descriptor wired with this task or NULL: */
|
||||
struct kcov *kcov;
|
||||
|
||||
/* KCOV descriptor for remote coverage collection from other tasks: */
|
||||
struct kcov *kcov_remote;
|
||||
|
||||
/* KCOV common handle for remote coverage collection: */
|
||||
u64 kcov_handle;
|
||||
|
||||
|
||||
@@ -1084,9 +1084,7 @@ struct sk_buff {
|
||||
__u16 network_header;
|
||||
__u16 mac_header;
|
||||
|
||||
#ifdef CONFIG_KCOV
|
||||
u64 kcov_handle;
|
||||
#endif
|
||||
struct kcov_common_handle_id kcov_handle;
|
||||
|
||||
); /* end headers group */
|
||||
|
||||
@@ -5440,20 +5438,14 @@ static inline void skb_reset_csum_not_inet(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
static inline void skb_set_kcov_handle(struct sk_buff *skb,
|
||||
const u64 kcov_handle)
|
||||
struct kcov_common_handle_id kcov_handle)
|
||||
{
|
||||
#ifdef CONFIG_KCOV
|
||||
skb->kcov_handle = kcov_handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u64 skb_get_kcov_handle(struct sk_buff *skb)
|
||||
static inline struct kcov_common_handle_id skb_get_kcov_handle(struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_KCOV
|
||||
return skb->kcov_handle;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void skb_mark_for_recycle(struct sk_buff *skb)
|
||||
|
||||
@@ -224,6 +224,12 @@ struct ustat {
|
||||
char f_fpack[6];
|
||||
};
|
||||
|
||||
struct kcov_common_handle_id {
|
||||
#ifdef CONFIG_KCOV
|
||||
u64 val;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* struct callback_head - callback structure for use with RCU and task_work
|
||||
* @next: next update requests in a list
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
* the 6 functions (copy_{to,from}_user(), __copy_{to,from}_user_inatomic())
|
||||
* that are used instead. Out of those, __... ones are inlined. Plain
|
||||
* copy_{to,from}_user() might or might not be inlined. If you want them
|
||||
* inlined, have asm/uaccess.h define INLINE_COPY_{TO,FROM}_USER.
|
||||
* inlined, have asm/uaccess.h define INLINE_COPY_USER.
|
||||
*
|
||||
* NOTE: only copy_from_user() zero-pads the destination in case of short copy.
|
||||
* Neither __copy_from_user() nor __copy_from_user_inatomic() zero anything
|
||||
@@ -157,7 +157,7 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
}
|
||||
|
||||
/*
|
||||
* Architectures that #define INLINE_COPY_TO_USER use this function
|
||||
* Architectures that #define INLINE_COPY_USER use this function
|
||||
* directly in the normal copy_to/from_user(), the other ones go
|
||||
* through an extern _copy_to/from_user(), which expands the same code
|
||||
* here.
|
||||
@@ -190,10 +190,6 @@ _inline_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
memset(to + (n - res), 0, res);
|
||||
return res;
|
||||
}
|
||||
#ifndef INLINE_COPY_FROM_USER
|
||||
extern __must_check unsigned long
|
||||
_copy_from_user(void *, const void __user *, unsigned long);
|
||||
#endif
|
||||
|
||||
static inline __must_check unsigned long
|
||||
_inline_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
@@ -207,7 +203,13 @@ _inline_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
}
|
||||
return n;
|
||||
}
|
||||
#ifndef INLINE_COPY_TO_USER
|
||||
#ifdef INLINE_COPY_USER
|
||||
# define _copy_to_user _inline_copy_to_user
|
||||
# define _copy_from_user _inline_copy_from_user
|
||||
#else
|
||||
extern __must_check unsigned long
|
||||
_copy_from_user(void *, const void __user *, unsigned long);
|
||||
|
||||
extern __must_check unsigned long
|
||||
_copy_to_user(void __user *, const void *, unsigned long);
|
||||
#endif
|
||||
@@ -217,11 +219,7 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
if (!check_copy_size(to, n, false))
|
||||
return n;
|
||||
#ifdef INLINE_COPY_FROM_USER
|
||||
return _inline_copy_from_user(to, from, n);
|
||||
#else
|
||||
return _copy_from_user(to, from, n);
|
||||
#endif
|
||||
}
|
||||
|
||||
static __always_inline unsigned long __must_check
|
||||
@@ -229,12 +227,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
if (!check_copy_size(from, n, true))
|
||||
return n;
|
||||
|
||||
#ifdef INLINE_COPY_TO_USER
|
||||
return _inline_copy_to_user(to, from, n);
|
||||
#else
|
||||
return _copy_to_user(to, from, n);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef copy_mc_to_kernel
|
||||
|
||||
24
init/Kconfig
24
init/Kconfig
@@ -1061,14 +1061,14 @@ config PAGE_COUNTER
|
||||
bool
|
||||
|
||||
config CGROUP_FAVOR_DYNMODS
|
||||
bool "Favor dynamic modification latency reduction by default"
|
||||
help
|
||||
This option enables the "favordynmods" mount option by default
|
||||
which reduces the latencies of dynamic cgroup modifications such
|
||||
as task migrations and controller on/offs at the cost of making
|
||||
hot path operations such as forks and exits more expensive.
|
||||
bool "Favor dynamic modification latency reduction by default"
|
||||
help
|
||||
This option enables the "favordynmods" mount option by default
|
||||
which reduces the latencies of dynamic cgroup modifications such
|
||||
as task migrations and controller on/offs at the cost of making
|
||||
hot path operations such as forks and exits more expensive.
|
||||
|
||||
Say N if unsure.
|
||||
Say N if unsure.
|
||||
|
||||
config MEMCG
|
||||
bool "Memory controller"
|
||||
@@ -1150,7 +1150,7 @@ config GROUP_SCHED_WEIGHT
|
||||
def_bool n
|
||||
|
||||
config GROUP_SCHED_BANDWIDTH
|
||||
def_bool n
|
||||
def_bool n
|
||||
|
||||
config FAIR_GROUP_SCHED
|
||||
bool "Group scheduling for SCHED_OTHER"
|
||||
@@ -1656,10 +1656,10 @@ config LD_ORPHAN_WARN
|
||||
depends on $(ld-option,--orphan-handling=error)
|
||||
|
||||
config LD_ORPHAN_WARN_LEVEL
|
||||
string
|
||||
depends on LD_ORPHAN_WARN
|
||||
default "error" if WERROR
|
||||
default "warn"
|
||||
string
|
||||
depends on LD_ORPHAN_WARN
|
||||
default "error" if WERROR
|
||||
default "warn"
|
||||
|
||||
config SYSCTL
|
||||
bool
|
||||
|
||||
@@ -3700,7 +3700,7 @@ __bpf_kfunc int bpf_copy_from_user_task_str(void *dst, u32 dst__sz,
|
||||
return ret + 1;
|
||||
}
|
||||
|
||||
/* Keep unsinged long in prototype so that kfunc is usable when emitted to
|
||||
/* Keep unsigned long in prototype so that kfunc is usable when emitted to
|
||||
* vmlinux.h in BPF programs directly, but note that while in BPF prog, the
|
||||
* unsigned long always points to 8-byte region on stack, the kernel may only
|
||||
* read and write the 4-bytes on 32-bit.
|
||||
|
||||
104
kernel/kcov.c
104
kernel/kcov.c
@@ -368,6 +368,7 @@ static void kcov_start(struct task_struct *t, struct kcov *kcov,
|
||||
WRITE_ONCE(t->kcov_mode, mode);
|
||||
}
|
||||
|
||||
/* operates on coverage-generator-owned fields */
|
||||
static void kcov_stop(struct task_struct *t)
|
||||
{
|
||||
WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED);
|
||||
@@ -377,16 +378,17 @@ static void kcov_stop(struct task_struct *t)
|
||||
t->kcov_area = NULL;
|
||||
}
|
||||
|
||||
/* operates on coverage-generator-owned fields */
|
||||
static void kcov_task_reset(struct task_struct *t)
|
||||
{
|
||||
kcov_stop(t);
|
||||
t->kcov_sequence = 0;
|
||||
t->kcov_handle = 0;
|
||||
}
|
||||
|
||||
void kcov_task_init(struct task_struct *t)
|
||||
{
|
||||
kcov_task_reset(t);
|
||||
t->kcov_remote = NULL;
|
||||
t->kcov_handle = current->kcov_handle;
|
||||
}
|
||||
|
||||
@@ -423,11 +425,14 @@ static void kcov_remote_reset(struct kcov *kcov)
|
||||
static void kcov_disable(struct task_struct *t, struct kcov *kcov)
|
||||
__must_hold(&kcov->lock)
|
||||
{
|
||||
kcov_task_reset(t);
|
||||
if (kcov->remote)
|
||||
if (kcov->remote) {
|
||||
t->kcov_handle = 0;
|
||||
t->kcov_remote = NULL;
|
||||
kcov_remote_reset(kcov);
|
||||
else
|
||||
} else {
|
||||
kcov_task_reset(t);
|
||||
kcov_reset(kcov);
|
||||
}
|
||||
}
|
||||
|
||||
static void kcov_get(struct kcov *kcov)
|
||||
@@ -453,41 +458,47 @@ void kcov_task_exit(struct task_struct *t)
|
||||
unsigned long flags;
|
||||
|
||||
kcov = t->kcov;
|
||||
if (kcov == NULL)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&kcov->lock, flags);
|
||||
kcov_debug("t = %px, kcov->t = %px\n", t, kcov->t);
|
||||
/*
|
||||
* For KCOV_ENABLE devices we want to make sure that t->kcov->t == t,
|
||||
* which comes down to:
|
||||
* WARN_ON(!kcov->remote && kcov->t != t);
|
||||
*
|
||||
* For KCOV_REMOTE_ENABLE devices, the exiting task is either:
|
||||
*
|
||||
* 1. A remote task between kcov_remote_start() and kcov_remote_stop().
|
||||
* In this case we should print a warning right away, since a task
|
||||
* shouldn't be exiting when it's in a kcov coverage collection
|
||||
* section. Here t points to the task that is collecting remote
|
||||
* coverage, and t->kcov->t points to the thread that created the
|
||||
* kcov device. Which means that to detect this case we need to
|
||||
* check that t != t->kcov->t, and this gives us the following:
|
||||
* WARN_ON(kcov->remote && kcov->t != t);
|
||||
*
|
||||
* 2. The task that created kcov exiting without calling KCOV_DISABLE,
|
||||
* and then again we make sure that t->kcov->t == t:
|
||||
* WARN_ON(kcov->remote && kcov->t != t);
|
||||
*
|
||||
* By combining all three checks into one we get:
|
||||
*/
|
||||
if (WARN_ON(kcov->t != t)) {
|
||||
if (kcov) {
|
||||
spin_lock_irqsave(&kcov->lock, flags);
|
||||
kcov_debug("t = %px, kcov->t = %px\n", t, kcov->t);
|
||||
/*
|
||||
* This could be a remote task between kcov_remote_start() and
|
||||
* kcov_remote_stop().
|
||||
* In this case we should print a warning right away, since a
|
||||
* task shouldn't be exiting when it's in a kcov coverage
|
||||
* collection section.
|
||||
*
|
||||
* Otherwise, this should be a task that created a local
|
||||
* kcov instance and hasn't called KCOV_DISABLE.
|
||||
* Make sure that t->kcov->t is consistent.
|
||||
*/
|
||||
if (WARN_ON(kcov->remote) || WARN_ON(kcov->t != t)) {
|
||||
spin_unlock_irqrestore(&kcov->lock, flags);
|
||||
return;
|
||||
}
|
||||
/* Just to not leave dangling references behind. */
|
||||
kcov_disable(t, kcov);
|
||||
spin_unlock_irqrestore(&kcov->lock, flags);
|
||||
return;
|
||||
kcov_put(kcov);
|
||||
}
|
||||
kcov = t->kcov_remote;
|
||||
if (kcov) {
|
||||
spin_lock_irqsave(&kcov->lock, flags);
|
||||
kcov_debug("t = %px, kcov->t = %px\n", t, kcov->t);
|
||||
/*
|
||||
* This is a KCOV_REMOTE_ENABLE device, and the task is the
|
||||
* user task which has requested remote coverage collection.
|
||||
* Make sure that t->kcov->t is consistent.
|
||||
*/
|
||||
if (WARN_ON(!kcov->remote) || WARN_ON(kcov->t != t)) {
|
||||
spin_unlock_irqrestore(&kcov->lock, flags);
|
||||
return;
|
||||
}
|
||||
/* Just to not leave dangling references behind. */
|
||||
kcov_disable(t, kcov);
|
||||
spin_unlock_irqrestore(&kcov->lock, flags);
|
||||
kcov_put(kcov);
|
||||
}
|
||||
/* Just to not leave dangling references behind. */
|
||||
kcov_disable(t, kcov);
|
||||
spin_unlock_irqrestore(&kcov->lock, flags);
|
||||
kcov_put(kcov);
|
||||
}
|
||||
|
||||
static int kcov_mmap(struct file *filep, struct vm_area_struct *vma)
|
||||
@@ -629,9 +640,9 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
|
||||
case KCOV_DISABLE:
|
||||
/* Disable coverage for the current task. */
|
||||
unused = arg;
|
||||
if (unused != 0 || current->kcov != kcov)
|
||||
return -EINVAL;
|
||||
t = current;
|
||||
if (unused != 0 || (kcov != t->kcov && kcov != t->kcov_remote))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(kcov->t != t))
|
||||
return -EINVAL;
|
||||
kcov_disable(t, kcov);
|
||||
@@ -641,7 +652,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
|
||||
if (kcov->mode != KCOV_MODE_INIT || !kcov->area)
|
||||
return -EINVAL;
|
||||
t = current;
|
||||
if (kcov->t != NULL || t->kcov != NULL)
|
||||
if (kcov->t != NULL || t->kcov_remote != NULL)
|
||||
return -EBUSY;
|
||||
remote_arg = (struct kcov_remote_arg *)arg;
|
||||
mode = kcov_get_mode(remote_arg->trace_mode);
|
||||
@@ -651,8 +662,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
|
||||
LONG_MAX / sizeof(unsigned long))
|
||||
return -EINVAL;
|
||||
kcov->mode = mode;
|
||||
t->kcov = kcov;
|
||||
t->kcov_mode = KCOV_MODE_REMOTE;
|
||||
t->kcov_remote = kcov;
|
||||
kcov->t = t;
|
||||
kcov->remote = true;
|
||||
kcov->remote_size = remote_arg->area_size;
|
||||
@@ -1083,11 +1093,11 @@ void kcov_remote_stop(void)
|
||||
EXPORT_SYMBOL(kcov_remote_stop);
|
||||
|
||||
/* See the comment before kcov_remote_start() for usage details. */
|
||||
u64 kcov_common_handle(void)
|
||||
struct kcov_common_handle_id kcov_common_handle(void)
|
||||
{
|
||||
if (!in_task())
|
||||
return 0;
|
||||
return current->kcov_handle;
|
||||
return (struct kcov_common_handle_id){ .val = 0 };
|
||||
return (struct kcov_common_handle_id){ .val = current->kcov_handle };
|
||||
}
|
||||
EXPORT_SYMBOL(kcov_common_handle);
|
||||
|
||||
@@ -1109,10 +1119,10 @@ static void __init selftest(void)
|
||||
* potentially traced functions in this region.
|
||||
*/
|
||||
start = jiffies;
|
||||
current->kcov_mode = KCOV_MODE_TRACE_PC;
|
||||
WRITE_ONCE(current->kcov_mode, KCOV_MODE_TRACE_PC);
|
||||
while ((jiffies - start) * MSEC_PER_SEC / HZ < 300)
|
||||
;
|
||||
current->kcov_mode = 0;
|
||||
WRITE_ONCE(current->kcov_mode, 0);
|
||||
pr_err("done running self test\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -210,13 +210,39 @@ static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tgid_stats_add_task(struct taskstats *stats,
|
||||
struct task_struct *tsk, u64 now_ns)
|
||||
{
|
||||
u64 delta, utime, stime;
|
||||
|
||||
/*
|
||||
* Each accounting subsystem calls its functions here to
|
||||
* accumulate its per-task stats for tsk, into the per-tgid structure
|
||||
*
|
||||
* per-task-foo(stats, tsk);
|
||||
*/
|
||||
delayacct_add_tsk(stats, tsk);
|
||||
|
||||
/* calculate task elapsed time in nsec */
|
||||
delta = now_ns - tsk->start_time;
|
||||
/* Convert to micro seconds */
|
||||
do_div(delta, NSEC_PER_USEC);
|
||||
stats->ac_etime += delta;
|
||||
|
||||
task_cputime(tsk, &utime, &stime);
|
||||
stats->ac_utime += div_u64(utime, NSEC_PER_USEC);
|
||||
stats->ac_stime += div_u64(stime, NSEC_PER_USEC);
|
||||
|
||||
stats->nvcsw += tsk->nvcsw;
|
||||
stats->nivcsw += tsk->nivcsw;
|
||||
}
|
||||
|
||||
static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
|
||||
{
|
||||
struct task_struct *tsk, *first;
|
||||
unsigned long flags;
|
||||
int rc = -ESRCH;
|
||||
u64 delta, utime, stime;
|
||||
u64 start_time;
|
||||
u64 now_ns;
|
||||
|
||||
/*
|
||||
* Add additional stats from live tasks except zombie thread group
|
||||
@@ -233,30 +259,12 @@ static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
|
||||
else
|
||||
memset(stats, 0, sizeof(*stats));
|
||||
|
||||
start_time = ktime_get_ns();
|
||||
now_ns = ktime_get_ns();
|
||||
for_each_thread(first, tsk) {
|
||||
if (tsk->exit_state)
|
||||
continue;
|
||||
/*
|
||||
* Accounting subsystem can call its functions here to
|
||||
* fill in relevant parts of struct taskstsats as follows
|
||||
*
|
||||
* per-task-foo(stats, tsk);
|
||||
*/
|
||||
delayacct_add_tsk(stats, tsk);
|
||||
|
||||
/* calculate task elapsed time in nsec */
|
||||
delta = start_time - tsk->start_time;
|
||||
/* Convert to micro seconds */
|
||||
do_div(delta, NSEC_PER_USEC);
|
||||
stats->ac_etime += delta;
|
||||
|
||||
task_cputime(tsk, &utime, &stime);
|
||||
stats->ac_utime += div_u64(utime, NSEC_PER_USEC);
|
||||
stats->ac_stime += div_u64(stime, NSEC_PER_USEC);
|
||||
|
||||
stats->nvcsw += tsk->nvcsw;
|
||||
stats->nivcsw += tsk->nivcsw;
|
||||
tgid_stats_add_task(stats, tsk, now_ns);
|
||||
}
|
||||
|
||||
unlock_task_sighand(first, &flags);
|
||||
@@ -275,18 +283,14 @@ static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
|
||||
static void fill_tgid_exit(struct task_struct *tsk)
|
||||
{
|
||||
unsigned long flags;
|
||||
u64 now_ns;
|
||||
|
||||
spin_lock_irqsave(&tsk->sighand->siglock, flags);
|
||||
if (!tsk->signal->stats)
|
||||
goto ret;
|
||||
|
||||
/*
|
||||
* Each accounting subsystem calls its functions here to
|
||||
* accumalate its per-task stats for tsk, into the per-tgid structure
|
||||
*
|
||||
* per-task-foo(tsk->signal->stats, tsk);
|
||||
*/
|
||||
delayacct_add_tsk(tsk->signal->stats, tsk);
|
||||
now_ns = ktime_get_ns();
|
||||
tgid_stats_add_task(tsk->signal->stats, tsk, now_ns);
|
||||
ret:
|
||||
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
|
||||
return;
|
||||
|
||||
13
lib/Kconfig
13
lib/Kconfig
@@ -8,17 +8,6 @@ config BINARY_PRINTF
|
||||
|
||||
menu "Library routines"
|
||||
|
||||
config RAID6_PQ
|
||||
tristate
|
||||
|
||||
config RAID6_PQ_BENCHMARK
|
||||
bool "Automatically choose fastest RAID6 PQ functions"
|
||||
depends on RAID6_PQ
|
||||
default y
|
||||
help
|
||||
Benchmark all available RAID6 PQ functions on init and choose the
|
||||
fastest one.
|
||||
|
||||
config LINEAR_RANGES
|
||||
tristate
|
||||
|
||||
@@ -603,7 +592,7 @@ config OBJAGG
|
||||
config LWQ_TEST
|
||||
bool "Boot-time test for lwq queuing"
|
||||
help
|
||||
Run boot-time test of light-weight queuing.
|
||||
Run boot-time test of light-weight queuing.
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
@@ -2976,6 +2976,16 @@ config BITS_TEST
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SHDI3_KUNIT_TEST
|
||||
tristate "KUnit test for __ashldi3(), __ashrdi3(), and __lshrdi3()"
|
||||
depends on KUNIT
|
||||
depends on ARM || XTENSA || MICROBLAZE || ((RISCV || SPARC) && !64BIT)
|
||||
help
|
||||
This builds the unit test for __ashldi3(), __ashrdi3(), and
|
||||
__lshrdi3() helper functions used to implement 64-bit arithmetic
|
||||
shift left, arithmetic shift right and logical shift right,
|
||||
respectively, on a 32-bit CPUs.
|
||||
|
||||
config SLUB_KUNIT_TEST
|
||||
tristate "KUnit test for SLUB cache error detection" if !KUNIT_ALL_TESTS
|
||||
depends on SLUB_DEBUG && KUNIT
|
||||
|
||||
@@ -167,7 +167,6 @@ obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
|
||||
obj-$(CONFIG_ZSTD_COMPRESS) += zstd/
|
||||
obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/
|
||||
obj-$(CONFIG_XZ_DEC) += xz/
|
||||
obj-$(CONFIG_RAID6_PQ) += raid6/
|
||||
|
||||
lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
|
||||
lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
|
||||
|
||||
@@ -122,7 +122,7 @@ EXPORT_SYMBOL_GPL(base64_encode);
|
||||
* @src: the string to decode. Doesn't need to be NUL-terminated.
|
||||
* @srclen: the length of @src in bytes
|
||||
* @dst: (output) the decoded binary data
|
||||
* @padding: whether to append '=' padding characters
|
||||
* @padding: whether the input is expected to include '=' padding characters
|
||||
* @variant: which base64 variant to use
|
||||
*
|
||||
* Decodes a string using the selected Base64 variant.
|
||||
@@ -168,15 +168,16 @@ int base64_decode(const char *src, int srclen, u8 *dst, bool padding, enum base6
|
||||
return -1;
|
||||
|
||||
val = (base64_rev_tables[s[0]] << 12) | (base64_rev_tables[s[1]] << 6);
|
||||
*bp++ = val >> 10;
|
||||
|
||||
if (srclen == 2) {
|
||||
if (val & 0x800003ff)
|
||||
return -1;
|
||||
*bp++ = val >> 10;
|
||||
} else {
|
||||
val |= base64_rev_tables[s[2]];
|
||||
if (val & 0x80000003)
|
||||
return -1;
|
||||
*bp++ = val >> 10;
|
||||
*bp++ = val >> 2;
|
||||
}
|
||||
return bp - dst;
|
||||
|
||||
80
lib/bug.c
80
lib/bug.c
@@ -1,41 +1,41 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
Generic support for BUG()
|
||||
|
||||
This respects the following config options:
|
||||
|
||||
CONFIG_BUG - emit BUG traps. Nothing happens without this.
|
||||
CONFIG_GENERIC_BUG - enable this code.
|
||||
CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit relative pointers for bug_addr and file
|
||||
CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG
|
||||
|
||||
CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable
|
||||
(though they're generally always on).
|
||||
|
||||
CONFIG_GENERIC_BUG is set by each architecture using this code.
|
||||
|
||||
To use this, your architecture must:
|
||||
|
||||
1. Set up the config options:
|
||||
- Enable CONFIG_GENERIC_BUG if CONFIG_BUG
|
||||
|
||||
2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON)
|
||||
- Define HAVE_ARCH_BUG
|
||||
- Implement BUG() to generate a faulting instruction
|
||||
- NOTE: struct bug_entry does not have "file" or "line" entries
|
||||
when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate
|
||||
the values accordingly.
|
||||
|
||||
3. Implement the trap
|
||||
- In the illegal instruction trap handler (typically), verify
|
||||
that the fault was in kernel mode, and call report_bug()
|
||||
- report_bug() will return whether it was a false alarm, a warning,
|
||||
or an actual bug.
|
||||
- You must implement the is_valid_bugaddr(bugaddr) callback which
|
||||
returns true if the eip is a real kernel address, and it points
|
||||
to the expected BUG trap instruction.
|
||||
|
||||
Jeremy Fitzhardinge <jeremy@goop.org> 2006
|
||||
* Generic support for BUG()
|
||||
*
|
||||
* This respects the following config options:
|
||||
*
|
||||
* CONFIG_BUG - emit BUG traps. Nothing happens without this.
|
||||
* CONFIG_GENERIC_BUG - enable this code.
|
||||
* CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit relative pointers for bug_addr and file
|
||||
* CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG
|
||||
*
|
||||
* CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable
|
||||
* (though they're generally always on).
|
||||
*
|
||||
* CONFIG_GENERIC_BUG is set by each architecture using this code.
|
||||
*
|
||||
* To use this, your architecture must:
|
||||
*
|
||||
* 1. Set up the config options:
|
||||
* - Enable CONFIG_GENERIC_BUG if CONFIG_BUG
|
||||
*
|
||||
* 2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON)
|
||||
* - Define HAVE_ARCH_BUG
|
||||
* - Implement BUG() to generate a faulting instruction
|
||||
* - NOTE: struct bug_entry does not have "file" or "line" entries
|
||||
* when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate
|
||||
* the values accordingly.
|
||||
*
|
||||
* 3. Implement the trap
|
||||
* - In the illegal instruction trap handler (typically), verify
|
||||
* that the fault was in kernel mode, and call report_bug()
|
||||
* - report_bug() will return whether it was a false alarm, a warning,
|
||||
* or an actual bug.
|
||||
* - You must implement the is_valid_bugaddr(bugaddr) callback which
|
||||
* returns true if the eip is a real kernel address, and it points
|
||||
* to the expected BUG trap instruction.
|
||||
*
|
||||
* Jeremy Fitzhardinge <jeremy@goop.org> 2006
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) fmt
|
||||
@@ -72,7 +72,7 @@ static struct bug_entry *module_find_bug(unsigned long bugaddr)
|
||||
|
||||
guard(rcu)();
|
||||
list_for_each_entry_rcu(mod, &module_bug_list, bug_list) {
|
||||
unsigned i;
|
||||
unsigned int i;
|
||||
|
||||
bug = mod->bug_table;
|
||||
for (i = 0; i < mod->num_bugs; ++i, ++bug)
|
||||
@@ -192,14 +192,14 @@ void __warn_printf(const char *fmt, struct pt_regs *regs)
|
||||
}
|
||||
#endif
|
||||
|
||||
printk("%s", fmt);
|
||||
pr_warn("%s", fmt);
|
||||
}
|
||||
|
||||
static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long bugaddr, struct pt_regs *regs)
|
||||
{
|
||||
bool warning, once, done, no_cut, has_args;
|
||||
const char *file, *fmt;
|
||||
unsigned line;
|
||||
unsigned int line;
|
||||
|
||||
if (!bug) {
|
||||
if (!is_valid_bugaddr(bugaddr))
|
||||
@@ -247,7 +247,7 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
|
||||
* extra debugging message it writes before triggering the handler.
|
||||
*/
|
||||
if (!no_cut) {
|
||||
printk(KERN_DEFAULT CUT_HERE);
|
||||
pr_info(CUT_HERE);
|
||||
__warn_printf(fmt, has_args ? regs : NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ static int get_range(char **str, int *pint, int n)
|
||||
* When @pint is NULL the function can be used as a validator of
|
||||
* the current option in the string.
|
||||
*
|
||||
* Return values:
|
||||
* Return:
|
||||
* 0 - no int in string
|
||||
* 1 - int found, no subsequent comma
|
||||
* 2 - int found including a subsequent comma
|
||||
@@ -145,44 +145,54 @@ EXPORT_SYMBOL(get_options);
|
||||
*
|
||||
* Parses a string into a number. The number stored at @ptr is
|
||||
* potentially suffixed with K, M, G, T, P, E.
|
||||
*
|
||||
* Return: The value as recognized by simple_strtoull() multiplied
|
||||
* by the value as specified by suffix, if any.
|
||||
*/
|
||||
|
||||
unsigned long long memparse(const char *ptr, char **retptr)
|
||||
{
|
||||
char *endptr; /* local pointer to end of parsed string */
|
||||
|
||||
unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
|
||||
unsigned int shl = 0;
|
||||
|
||||
/* Consume valid suffix even in case of overflow. */
|
||||
switch (*endptr) {
|
||||
case 'E':
|
||||
case 'e':
|
||||
ret <<= 10;
|
||||
shl += 10;
|
||||
fallthrough;
|
||||
case 'P':
|
||||
case 'p':
|
||||
ret <<= 10;
|
||||
shl += 10;
|
||||
fallthrough;
|
||||
case 'T':
|
||||
case 't':
|
||||
ret <<= 10;
|
||||
shl += 10;
|
||||
fallthrough;
|
||||
case 'G':
|
||||
case 'g':
|
||||
ret <<= 10;
|
||||
shl += 10;
|
||||
fallthrough;
|
||||
case 'M':
|
||||
case 'm':
|
||||
ret <<= 10;
|
||||
shl += 10;
|
||||
fallthrough;
|
||||
case 'K':
|
||||
case 'k':
|
||||
ret <<= 10;
|
||||
endptr++;
|
||||
shl += 10;
|
||||
fallthrough;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (shl && likely(ptr != endptr)) {
|
||||
/* Have valid suffix with preceding number. */
|
||||
if (unlikely(check_shl_overflow(ret, shl, &ret)))
|
||||
ret = ULLONG_MAX;
|
||||
endptr++;
|
||||
}
|
||||
|
||||
if (retptr)
|
||||
*retptr = endptr;
|
||||
|
||||
@@ -198,7 +208,7 @@ EXPORT_SYMBOL(memparse);
|
||||
* This function parses a string containing a comma-separated list of
|
||||
* strings like a=b,c.
|
||||
*
|
||||
* Return true if there's such option in the string, or return false.
|
||||
* Return: True if there's such option in the string or false otherwise.
|
||||
*/
|
||||
bool parse_option_str(const char *str, const char *option)
|
||||
{
|
||||
|
||||
@@ -219,9 +219,9 @@ static int __init ei_debugfs_init(void)
|
||||
dir = debugfs_create_dir("error_injection", NULL);
|
||||
|
||||
file = debugfs_create_file("list", 0444, dir, NULL, &ei_fops);
|
||||
if (!file) {
|
||||
if (IS_ERR(file)) {
|
||||
debugfs_remove(dir);
|
||||
return -ENOMEM;
|
||||
return PTR_ERR(file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/interval_tree.h>
|
||||
#include <linux/prandom.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/printk.h>
|
||||
#include <asm/timex.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/maple_tree.h>
|
||||
@@ -311,6 +312,27 @@ static inline int span_iteration_check(void) {return 0; }
|
||||
|
||||
static int interval_tree_test_init(void)
|
||||
{
|
||||
if (nnodes <= 0) {
|
||||
pr_warn("nnodes must be positive\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (nsearches <= 0) {
|
||||
pr_warn("nsearches must be positive\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (perf_loops <= 0) {
|
||||
pr_warn("perf_loops must be positive\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (search_loops <= 0) {
|
||||
pr_warn("search_loops must be positive\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (max_endpoint < 2) {
|
||||
pr_warn("max_endpoint must be at least 2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nodes = kmalloc_objs(struct interval_tree_node, nnodes);
|
||||
if (!nodes)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -39,25 +39,30 @@ const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert non-negative integer string representation in explicitly given radix
|
||||
* to an integer. A maximum of max_chars characters will be converted.
|
||||
/**
|
||||
* _parse_integer_limit - Convert integer string representation to an integer
|
||||
* @s: Integer string representation
|
||||
* @base: Radix
|
||||
* @p: Where to store result
|
||||
* @max_chars: Maximum amount of characters to convert
|
||||
*
|
||||
* Return number of characters consumed maybe or-ed with overflow bit.
|
||||
* If overflow occurs, result integer (incorrect) is still returned.
|
||||
* Convert non-negative integer string representation in explicitly given
|
||||
* radix to an integer. If overflow occurs, value at @p is set to ULLONG_MAX.
|
||||
*
|
||||
* Don't you dare use this function.
|
||||
* This function is the workhorse of other string conversion functions and it
|
||||
* is discouraged to use it explicitly. Consider kstrto*() family instead.
|
||||
*
|
||||
* Return: Number of characters consumed, maybe ORed with overflow bit
|
||||
*/
|
||||
noinline
|
||||
unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned long long *p,
|
||||
size_t max_chars)
|
||||
{
|
||||
unsigned int rv, overflow = 0;
|
||||
unsigned long long res;
|
||||
unsigned int rv;
|
||||
|
||||
res = 0;
|
||||
rv = 0;
|
||||
while (max_chars--) {
|
||||
for (rv = 0; rv < max_chars; rv++, s++) {
|
||||
unsigned int c = *s;
|
||||
unsigned int lc = _tolower(c);
|
||||
unsigned int val;
|
||||
@@ -76,15 +81,17 @@ unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned lon
|
||||
* it in the max base we support (16)
|
||||
*/
|
||||
if (unlikely(res & (~0ull << 60))) {
|
||||
if (res > div_u64(ULLONG_MAX - val, base))
|
||||
rv |= KSTRTOX_OVERFLOW;
|
||||
if (check_mul_overflow(res, base, &res) ||
|
||||
check_add_overflow(res, val, &res)) {
|
||||
res = ULLONG_MAX;
|
||||
overflow = KSTRTOX_OVERFLOW;
|
||||
}
|
||||
} else {
|
||||
res = res * base + val;
|
||||
}
|
||||
res = res * base + val;
|
||||
rv++;
|
||||
s++;
|
||||
}
|
||||
*p = res;
|
||||
return rv;
|
||||
return rv | overflow;
|
||||
}
|
||||
|
||||
noinline
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/sched/debug.h>
|
||||
@@ -27,6 +28,8 @@ static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
|
||||
/* "in progress" flag of arch_trigger_cpumask_backtrace */
|
||||
static unsigned long backtrace_flag;
|
||||
|
||||
#define NMI_BT_TIMEOUT_SEC 10
|
||||
|
||||
/*
|
||||
* When raise() is called it will be passed a pointer to the
|
||||
* backtrace_mask. Architectures that call nmi_cpu_backtrace()
|
||||
@@ -68,14 +71,20 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
|
||||
raise(to_cpumask(backtrace_mask));
|
||||
}
|
||||
|
||||
/* Wait for up to 10 seconds for all CPUs to do the backtrace */
|
||||
for (i = 0; i < 10 * 1000; i++) {
|
||||
/* Wait for up to NMI_BT_TIMEOUT_SEC seconds for all CPUs to do the backtrace */
|
||||
for (i = 0; i < NMI_BT_TIMEOUT_SEC * 1000; i++) {
|
||||
if (cpumask_empty(to_cpumask(backtrace_mask)))
|
||||
break;
|
||||
mdelay(1);
|
||||
touch_softlockup_watchdog();
|
||||
}
|
||||
nmi_backtrace_stall_check(to_cpumask(backtrace_mask));
|
||||
|
||||
if (!cpumask_empty(to_cpumask(backtrace_mask))) {
|
||||
pr_warn("After " __stringify(NMI_BT_TIMEOUT_SEC) " seconds, these CPUS still haven't responded to the NMI: %*pbl\n",
|
||||
cpumask_pr_args(to_cpumask(backtrace_mask)));
|
||||
|
||||
nmi_backtrace_stall_check(to_cpumask(backtrace_mask));
|
||||
}
|
||||
|
||||
/*
|
||||
* Force flush any remote buffers that might be stuck in IRQ context
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user