diff options
author | Mike Pagano <mpagano@gentoo.org> | 2024-02-23 07:36:43 -0500 |
---|---|---|
committer | Mike Pagano <mpagano@gentoo.org> | 2024-02-23 07:36:43 -0500 |
commit | 7b014874ff8ed257468786dcb602a63cd368cd52 (patch) | |
tree | 6817b56092b9e92adcd074ca41d156b82c85cf6c | |
parent | ASoC: max98388: Correct the includes (diff) | |
download | linux-patches-7b014874ff8ed257468786dcb602a63cd368cd52.tar.gz linux-patches-7b014874ff8ed257468786dcb602a63cd368cd52.tar.bz2 linux-patches-7b014874ff8ed257468786dcb602a63cd368cd52.zip |
Linux patch 6.6.18
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1017_linux-6.6.18.patch | 15595 |
2 files changed, 15599 insertions, 0 deletions
diff --git a/0000_README b/0000_README index 5bd93d3c..ff88075d 100644 --- a/0000_README +++ b/0000_README @@ -111,6 +111,10 @@ Patch: 1016_linux-6.6.17.patch From: https://www.kernel.org Desc: Linux 6.6.17 +Patch: 1017_linux-6.6.18.patch +From: https://www.kernel.org +Desc: Linux 6.6.18 + Patch: 1510_fs-enable-link-security-restrictions-by-default.patch From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/ Desc: Enable link security restrictions by default. diff --git a/1017_linux-6.6.18.patch b/1017_linux-6.6.18.patch new file mode 100644 index 00000000..d63cba7c --- /dev/null +++ b/1017_linux-6.6.18.patch @@ -0,0 +1,15595 @@ +diff --git a/Documentation/ABI/testing/sysfs-class-net-statistics b/Documentation/ABI/testing/sysfs-class-net-statistics +index 55db27815361b..53e508c6936a5 100644 +--- a/Documentation/ABI/testing/sysfs-class-net-statistics ++++ b/Documentation/ABI/testing/sysfs-class-net-statistics +@@ -1,4 +1,4 @@ +-What: /sys/class/<iface>/statistics/collisions ++What: /sys/class/net/<iface>/statistics/collisions + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -6,7 +6,7 @@ Description: + Indicates the number of collisions seen by this network device. + This value might not be relevant with all MAC layers. + +-What: /sys/class/<iface>/statistics/multicast ++What: /sys/class/net/<iface>/statistics/multicast + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -14,7 +14,7 @@ Description: + Indicates the number of multicast packets received by this + network device. + +-What: /sys/class/<iface>/statistics/rx_bytes ++What: /sys/class/net/<iface>/statistics/rx_bytes + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -23,7 +23,7 @@ Description: + See the network driver for the exact meaning of when this + value is incremented. + +-What: /sys/class/<iface>/statistics/rx_compressed ++What: /sys/class/net/<iface>/statistics/rx_compressed + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -32,7 +32,7 @@ Description: + network device. This value might only be relevant for interfaces + that support packet compression (e.g: PPP). + +-What: /sys/class/<iface>/statistics/rx_crc_errors ++What: /sys/class/net/<iface>/statistics/rx_crc_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -41,7 +41,7 @@ Description: + by this network device. Note that the specific meaning might + depend on the MAC layer used by the interface. + +-What: /sys/class/<iface>/statistics/rx_dropped ++What: /sys/class/net/<iface>/statistics/rx_dropped + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -51,7 +51,7 @@ Description: + packet processing. See the network driver for the exact + meaning of this value. + +-What: /sys/class/<iface>/statistics/rx_errors ++What: /sys/class/net/<iface>/statistics/rx_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -59,7 +59,7 @@ Description: + Indicates the number of receive errors on this network device. + See the network driver for the exact meaning of this value. + +-What: /sys/class/<iface>/statistics/rx_fifo_errors ++What: /sys/class/net/<iface>/statistics/rx_fifo_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -68,7 +68,7 @@ Description: + network device. See the network driver for the exact + meaning of this value. + +-What: /sys/class/<iface>/statistics/rx_frame_errors ++What: /sys/class/net/<iface>/statistics/rx_frame_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -78,7 +78,7 @@ Description: + on the MAC layer protocol used. See the network driver for + the exact meaning of this value. + +-What: /sys/class/<iface>/statistics/rx_length_errors ++What: /sys/class/net/<iface>/statistics/rx_length_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -87,7 +87,7 @@ Description: + error, oversized or undersized. See the network driver for the + exact meaning of this value. + +-What: /sys/class/<iface>/statistics/rx_missed_errors ++What: /sys/class/net/<iface>/statistics/rx_missed_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -96,7 +96,7 @@ Description: + due to lack of capacity in the receive side. See the network + driver for the exact meaning of this value. + +-What: /sys/class/<iface>/statistics/rx_nohandler ++What: /sys/class/net/<iface>/statistics/rx_nohandler + Date: February 2016 + KernelVersion: 4.6 + Contact: netdev@vger.kernel.org +@@ -104,7 +104,7 @@ Description: + Indicates the number of received packets that were dropped on + an inactive device by the network core. + +-What: /sys/class/<iface>/statistics/rx_over_errors ++What: /sys/class/net/<iface>/statistics/rx_over_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -114,7 +114,7 @@ Description: + (e.g: larger than MTU). See the network driver for the exact + meaning of this value. + +-What: /sys/class/<iface>/statistics/rx_packets ++What: /sys/class/net/<iface>/statistics/rx_packets + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -122,7 +122,7 @@ Description: + Indicates the total number of good packets received by this + network device. + +-What: /sys/class/<iface>/statistics/tx_aborted_errors ++What: /sys/class/net/<iface>/statistics/tx_aborted_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -132,7 +132,7 @@ Description: + a medium collision). See the network driver for the exact + meaning of this value. + +-What: /sys/class/<iface>/statistics/tx_bytes ++What: /sys/class/net/<iface>/statistics/tx_bytes + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -143,7 +143,7 @@ Description: + transmitted packets or all packets that have been queued for + transmission. + +-What: /sys/class/<iface>/statistics/tx_carrier_errors ++What: /sys/class/net/<iface>/statistics/tx_carrier_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -152,7 +152,7 @@ Description: + because of carrier errors (e.g: physical link down). See the + network driver for the exact meaning of this value. + +-What: /sys/class/<iface>/statistics/tx_compressed ++What: /sys/class/net/<iface>/statistics/tx_compressed + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -161,7 +161,7 @@ Description: + this might only be relevant for devices that support + compression (e.g: PPP). + +-What: /sys/class/<iface>/statistics/tx_dropped ++What: /sys/class/net/<iface>/statistics/tx_dropped + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -170,7 +170,7 @@ Description: + See the driver for the exact reasons as to why the packets were + dropped. + +-What: /sys/class/<iface>/statistics/tx_errors ++What: /sys/class/net/<iface>/statistics/tx_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -179,7 +179,7 @@ Description: + a network device. See the driver for the exact reasons as to + why the packets were dropped. + +-What: /sys/class/<iface>/statistics/tx_fifo_errors ++What: /sys/class/net/<iface>/statistics/tx_fifo_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -188,7 +188,7 @@ Description: + FIFO error. See the driver for the exact reasons as to why the + packets were dropped. + +-What: /sys/class/<iface>/statistics/tx_heartbeat_errors ++What: /sys/class/net/<iface>/statistics/tx_heartbeat_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -197,7 +197,7 @@ Description: + reported as heartbeat errors. See the driver for the exact + reasons as to why the packets were dropped. + +-What: /sys/class/<iface>/statistics/tx_packets ++What: /sys/class/net/<iface>/statistics/tx_packets + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -206,7 +206,7 @@ Description: + device. See the driver for whether this reports the number of all + attempted or successful transmissions. + +-What: /sys/class/<iface>/statistics/tx_window_errors ++What: /sys/class/net/<iface>/statistics/tx_window_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst +index 7acd64c61f50c..29fd5213eeb2b 100644 +--- a/Documentation/arch/arm64/silicon-errata.rst ++++ b/Documentation/arch/arm64/silicon-errata.rst +@@ -235,3 +235,10 @@ stable kernels. + +----------------+-----------------+-----------------+-----------------------------+ + | ASR | ASR8601 | #8601001 | N/A | + +----------------+-----------------+-----------------+-----------------------------+ +++----------------+-----------------+-----------------+-----------------------------+ ++| Microsoft | Azure Cobalt 100| #2139208 | ARM64_ERRATUM_2139208 | +++----------------+-----------------+-----------------+-----------------------------+ ++| Microsoft | Azure Cobalt 100| #2067961 | ARM64_ERRATUM_2067961 | +++----------------+-----------------+-----------------+-----------------------------+ ++| Microsoft | Azure Cobalt 100| #2253138 | ARM64_ERRATUM_2253138 | +++----------------+-----------------+-----------------+-----------------------------+ +diff --git a/Documentation/arch/ia64/features.rst b/Documentation/arch/ia64/features.rst +index d7226fdcf5f8c..056838d2ab55c 100644 +--- a/Documentation/arch/ia64/features.rst ++++ b/Documentation/arch/ia64/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features ia64 ++.. kernel-feat:: features ia64 +diff --git a/Documentation/networking/devlink/devlink-port.rst b/Documentation/networking/devlink/devlink-port.rst +index e33ad2401ad70..562f46b412744 100644 +--- a/Documentation/networking/devlink/devlink-port.rst ++++ b/Documentation/networking/devlink/devlink-port.rst +@@ -126,7 +126,7 @@ Users may also set the RoCE capability of the function using + `devlink port function set roce` command. + + Users may also set the function as migratable using +-'devlink port function set migratable' command. ++`devlink port function set migratable` command. + + Users may also set the IPsec crypto capability of the function using + `devlink port function set ipsec_crypto` command. +diff --git a/Documentation/sphinx/kernel_feat.py b/Documentation/sphinx/kernel_feat.py +index b9df61eb45013..03ace5f01b5c0 100644 +--- a/Documentation/sphinx/kernel_feat.py ++++ b/Documentation/sphinx/kernel_feat.py +@@ -109,7 +109,7 @@ class KernelFeat(Directive): + else: + out_lines += line + "\n" + +- nodeList = self.nestedParse(out_lines, fname) ++ nodeList = self.nestedParse(out_lines, self.arguments[0]) + return nodeList + + def nestedParse(self, lines, fname): +diff --git a/Makefile b/Makefile +index 3330c00c0a471..b7198af9e59b4 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 17 ++SUBLEVEL = 18 + EXTRAVERSION = + NAME = Hurr durr I'ma ninja sloth + +diff --git a/arch/Kconfig b/arch/Kconfig +index 12d51495caec1..20c2c93d2c889 100644 +--- a/arch/Kconfig ++++ b/arch/Kconfig +@@ -681,6 +681,7 @@ config SHADOW_CALL_STACK + bool "Shadow Call Stack" + depends on ARCH_SUPPORTS_SHADOW_CALL_STACK + depends on DYNAMIC_FTRACE_WITH_ARGS || DYNAMIC_FTRACE_WITH_REGS || !FUNCTION_GRAPH_TRACER ++ depends on MMU + help + This option enables the compiler's Shadow Call Stack, which + uses a shadow stack to protect function return addresses from +diff --git a/arch/arc/include/asm/jump_label.h b/arch/arc/include/asm/jump_label.h +index 9d96180797396..a339223d9e052 100644 +--- a/arch/arc/include/asm/jump_label.h ++++ b/arch/arc/include/asm/jump_label.h +@@ -31,7 +31,7 @@ + static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) + { +- asm_volatile_goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" ++ asm goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" + "1: \n" + "nop \n" + ".pushsection __jump_table, \"aw\" \n" +@@ -47,7 +47,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, + static __always_inline bool arch_static_branch_jump(struct static_key *key, + bool branch) + { +- asm_volatile_goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" ++ asm goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" + "1: \n" + "b %l[l_yes] \n" + ".pushsection __jump_table, \"aw\" \n" +diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h +index e12d7d096fc03..e4eb54f6cd9fe 100644 +--- a/arch/arm/include/asm/jump_label.h ++++ b/arch/arm/include/asm/jump_label.h +@@ -11,7 +11,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + WASM(nop) "\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".word 1b, %l[l_yes], %c0\n\t" +@@ -25,7 +25,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + WASM(b) " %l[l_yes]\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".word 1b, %l[l_yes], %c0\n\t" +diff --git a/arch/arm64/include/asm/alternative-macros.h b/arch/arm64/include/asm/alternative-macros.h +index 94b486192e1f1..a3652b6bb740d 100644 +--- a/arch/arm64/include/asm/alternative-macros.h ++++ b/arch/arm64/include/asm/alternative-macros.h +@@ -229,7 +229,7 @@ alternative_has_cap_likely(const unsigned long cpucap) + compiletime_assert(cpucap < ARM64_NCAPS, + "cpucap must be < ARM64_NCAPS"); + +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE_CB("b %l[l_no]", %[cpucap], alt_cb_patch_nops) + : + : [cpucap] "i" (cpucap) +@@ -247,7 +247,7 @@ alternative_has_cap_unlikely(const unsigned long cpucap) + compiletime_assert(cpucap < ARM64_NCAPS, + "cpucap must be < ARM64_NCAPS"); + +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE("nop", "b %l[l_yes]", %[cpucap]) + : + : [cpucap] "i" (cpucap) +diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h +index 7c7493cb571f9..52f076afeb960 100644 +--- a/arch/arm64/include/asm/cputype.h ++++ b/arch/arm64/include/asm/cputype.h +@@ -61,6 +61,7 @@ + #define ARM_CPU_IMP_HISI 0x48 + #define ARM_CPU_IMP_APPLE 0x61 + #define ARM_CPU_IMP_AMPERE 0xC0 ++#define ARM_CPU_IMP_MICROSOFT 0x6D + + #define ARM_CPU_PART_AEM_V8 0xD0F + #define ARM_CPU_PART_FOUNDATION 0xD00 +@@ -135,6 +136,8 @@ + + #define AMPERE_CPU_PART_AMPERE1 0xAC3 + ++#define MICROSOFT_CPU_PART_AZURE_COBALT_100 0xD49 /* Based on r0p0 of ARM Neoverse N2 */ ++ + #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) + #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) + #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) +@@ -193,6 +196,7 @@ + #define MIDR_APPLE_M2_BLIZZARD_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX) + #define MIDR_APPLE_M2_AVALANCHE_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) + #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1) ++#define MIDR_MICROSOFT_AZURE_COBALT_100 MIDR_CPU_MODEL(ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_AZURE_COBALT_100) + + /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */ + #define MIDR_FUJITSU_ERRATUM_010001 MIDR_FUJITSU_A64FX +diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h +index 48ddc0f45d228..6aafbb7899916 100644 +--- a/arch/arm64/include/asm/jump_label.h ++++ b/arch/arm64/include/asm/jump_label.h +@@ -18,7 +18,7 @@ + static __always_inline bool arch_static_branch(struct static_key * const key, + const bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: nop \n\t" + " .pushsection __jump_table, \"aw\" \n\t" + " .align 3 \n\t" +@@ -35,7 +35,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, + static __always_inline bool arch_static_branch_jump(struct static_key * const key, + const bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: b %l[l_yes] \n\t" + " .pushsection __jump_table, \"aw\" \n\t" + " .align 3 \n\t" +diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c +index 87787a012bea8..7bba831f62c33 100644 +--- a/arch/arm64/kernel/cpu_errata.c ++++ b/arch/arm64/kernel/cpu_errata.c +@@ -390,6 +390,7 @@ static const struct midr_range erratum_1463225[] = { + static const struct midr_range trbe_overwrite_fill_mode_cpus[] = { + #ifdef CONFIG_ARM64_ERRATUM_2139208 + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), ++ MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), + #endif + #ifdef CONFIG_ARM64_ERRATUM_2119858 + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), +@@ -403,6 +404,7 @@ static const struct midr_range trbe_overwrite_fill_mode_cpus[] = { + static const struct midr_range tsb_flush_fail_cpus[] = { + #ifdef CONFIG_ARM64_ERRATUM_2067961 + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), ++ MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), + #endif + #ifdef CONFIG_ARM64_ERRATUM_2054223 + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), +@@ -415,6 +417,7 @@ static const struct midr_range tsb_flush_fail_cpus[] = { + static struct midr_range trbe_write_out_of_range_cpus[] = { + #ifdef CONFIG_ARM64_ERRATUM_2253138 + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), ++ MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), + #endif + #ifdef CONFIG_ARM64_ERRATUM_2224489 + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), +diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c +index f9b3adebcb187..1e1e0511c0081 100644 +--- a/arch/arm64/kernel/fpsimd.c ++++ b/arch/arm64/kernel/fpsimd.c +@@ -1686,7 +1686,7 @@ void fpsimd_preserve_current_state(void) + void fpsimd_signal_preserve_current_state(void) + { + fpsimd_preserve_current_state(); +- if (test_thread_flag(TIF_SVE)) ++ if (current->thread.fp_type == FP_STATE_SVE) + sve_to_fpsimd(current); + } + +diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c +index 0e8beb3349ea2..425b1bc17a3f6 100644 +--- a/arch/arm64/kernel/signal.c ++++ b/arch/arm64/kernel/signal.c +@@ -242,7 +242,7 @@ static int preserve_sve_context(struct sve_context __user *ctx) + vl = task_get_sme_vl(current); + vq = sve_vq_from_vl(vl); + flags |= SVE_SIG_FLAG_SM; +- } else if (test_thread_flag(TIF_SVE)) { ++ } else if (current->thread.fp_type == FP_STATE_SVE) { + vq = sve_vq_from_vl(vl); + } + +@@ -878,7 +878,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user, + if (system_supports_sve() || system_supports_sme()) { + unsigned int vq = 0; + +- if (add_all || test_thread_flag(TIF_SVE) || ++ if (add_all || current->thread.fp_type == FP_STATE_SVE || + thread_sm_enabled(¤t->thread)) { + int vl = max(sve_max_vl(), sme_max_vl()); + +diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c +index 6ff3ec18c9258..b2c8084cdb95d 100644 +--- a/arch/arm64/kvm/pkvm.c ++++ b/arch/arm64/kvm/pkvm.c +@@ -101,6 +101,17 @@ void __init kvm_hyp_reserve(void) + hyp_mem_base); + } + ++static void __pkvm_destroy_hyp_vm(struct kvm *host_kvm) ++{ ++ if (host_kvm->arch.pkvm.handle) { ++ WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, ++ host_kvm->arch.pkvm.handle)); ++ } ++ ++ host_kvm->arch.pkvm.handle = 0; ++ free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc); ++} ++ + /* + * Allocates and donates memory for hypervisor VM structs at EL2. + * +@@ -181,7 +192,7 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm) + return 0; + + destroy_vm: +- pkvm_destroy_hyp_vm(host_kvm); ++ __pkvm_destroy_hyp_vm(host_kvm); + return ret; + free_vm: + free_pages_exact(hyp_vm, hyp_vm_sz); +@@ -194,23 +205,19 @@ int pkvm_create_hyp_vm(struct kvm *host_kvm) + { + int ret = 0; + +- mutex_lock(&host_kvm->lock); ++ mutex_lock(&host_kvm->arch.config_lock); + if (!host_kvm->arch.pkvm.handle) + ret = __pkvm_create_hyp_vm(host_kvm); +- mutex_unlock(&host_kvm->lock); ++ mutex_unlock(&host_kvm->arch.config_lock); + + return ret; + } + + void pkvm_destroy_hyp_vm(struct kvm *host_kvm) + { +- if (host_kvm->arch.pkvm.handle) { +- WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, +- host_kvm->arch.pkvm.handle)); +- } +- +- host_kvm->arch.pkvm.handle = 0; +- free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc); ++ mutex_lock(&host_kvm->arch.config_lock); ++ __pkvm_destroy_hyp_vm(host_kvm); ++ mutex_unlock(&host_kvm->arch.config_lock); + } + + int pkvm_init_host_vm(struct kvm *host_kvm) +diff --git a/arch/csky/include/asm/jump_label.h b/arch/csky/include/asm/jump_label.h +index 98a3f4b168bd2..ef2e37a10a0fe 100644 +--- a/arch/csky/include/asm/jump_label.h ++++ b/arch/csky/include/asm/jump_label.h +@@ -12,7 +12,7 @@ + static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: nop32 \n" + " .pushsection __jump_table, \"aw\" \n" + " .align 2 \n" +@@ -29,7 +29,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, + static __always_inline bool arch_static_branch_jump(struct static_key *key, + bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: bsr32 %l[label] \n" + " .pushsection __jump_table, \"aw\" \n" + " .align 2 \n" +diff --git a/arch/loongarch/include/asm/jump_label.h b/arch/loongarch/include/asm/jump_label.h +index 3cea299a5ef58..29acfe3de3faa 100644 +--- a/arch/loongarch/include/asm/jump_label.h ++++ b/arch/loongarch/include/asm/jump_label.h +@@ -22,7 +22,7 @@ + + static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: nop \n\t" + JUMP_TABLE_ENTRY + : : "i"(&((char *)key)[branch]) : : l_yes); +@@ -35,7 +35,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co + + static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: b %l[l_yes] \n\t" + JUMP_TABLE_ENTRY + : : "i"(&((char *)key)[branch]) : : l_yes); +diff --git a/arch/loongarch/mm/kasan_init.c b/arch/loongarch/mm/kasan_init.c +index cc3e81fe0186f..c608adc998458 100644 +--- a/arch/loongarch/mm/kasan_init.c ++++ b/arch/loongarch/mm/kasan_init.c +@@ -44,6 +44,9 @@ void *kasan_mem_to_shadow(const void *addr) + unsigned long xrange = (maddr >> XRANGE_SHIFT) & 0xffff; + unsigned long offset = 0; + ++ if (maddr >= FIXADDR_START) ++ return (void *)(kasan_early_shadow_page); ++ + maddr &= XRANGE_SHADOW_MASK; + switch (xrange) { + case XKPRANGE_CC_SEG: +diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h +index 4044eaf989ac7..0921ddda11a4b 100644 +--- a/arch/mips/include/asm/checksum.h ++++ b/arch/mips/include/asm/checksum.h +@@ -241,7 +241,8 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + " .set pop" + : "=&r" (sum), "=&r" (tmp) + : "r" (saddr), "r" (daddr), +- "0" (htonl(len)), "r" (htonl(proto)), "r" (sum)); ++ "0" (htonl(len)), "r" (htonl(proto)), "r" (sum) ++ : "memory"); + + return csum_fold(sum); + } +diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h +index c5c6864e64bc4..405c85173f2c1 100644 +--- a/arch/mips/include/asm/jump_label.h ++++ b/arch/mips/include/asm/jump_label.h +@@ -36,7 +36,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\t" B_INSN " 2f\n\t" ++ asm goto("1:\t" B_INSN " 2f\n\t" + "2:\t.insn\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + WORD_INSN " 1b, %l[l_yes], %0\n\t" +@@ -50,7 +50,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\t" J_INSN " %l[l_yes]\n\t" ++ asm goto("1:\t" J_INSN " %l[l_yes]\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + WORD_INSN " 1b, %l[l_yes], %0\n\t" + ".popsection\n\t" +diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h +index daf3cf244ea97..701a233583c2c 100644 +--- a/arch/mips/include/asm/ptrace.h ++++ b/arch/mips/include/asm/ptrace.h +@@ -154,6 +154,8 @@ static inline long regs_return_value(struct pt_regs *regs) + } + + #define instruction_pointer(regs) ((regs)->cp0_epc) ++extern unsigned long exception_ip(struct pt_regs *regs); ++#define exception_ip(regs) exception_ip(regs) + #define profile_pc(regs) instruction_pointer(regs) + + extern asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall); +diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c +index d9df543f7e2c4..59288c13b581b 100644 +--- a/arch/mips/kernel/ptrace.c ++++ b/arch/mips/kernel/ptrace.c +@@ -31,6 +31,7 @@ + #include <linux/seccomp.h> + #include <linux/ftrace.h> + ++#include <asm/branch.h> + #include <asm/byteorder.h> + #include <asm/cpu.h> + #include <asm/cpu-info.h> +@@ -48,6 +49,12 @@ + #define CREATE_TRACE_POINTS + #include <trace/events/syscalls.h> + ++unsigned long exception_ip(struct pt_regs *regs) ++{ ++ return exception_epc(regs); ++} ++EXPORT_SYMBOL(exception_ip); ++ + /* + * Called by kernel/ptrace.c when detaching.. + * +diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig +index 8c45b98dfe0e4..4adeb73d5885c 100644 +--- a/arch/parisc/Kconfig ++++ b/arch/parisc/Kconfig +@@ -24,7 +24,6 @@ config PARISC + select RTC_DRV_GENERIC + select INIT_ALL_POSSIBLE + select BUG +- select BUILDTIME_TABLE_SORT + select HAVE_PCI + select HAVE_PERF_EVENTS + select HAVE_KERNEL_BZIP2 +diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h +index 74d17d7e759da..5937d5edaba1e 100644 +--- a/arch/parisc/include/asm/assembly.h ++++ b/arch/parisc/include/asm/assembly.h +@@ -576,6 +576,7 @@ + .section __ex_table,"aw" ! \ + .align 4 ! \ + .word (fault_addr - .), (except_addr - .) ! \ ++ or %r0,%r0,%r0 ! \ + .previous + + +diff --git a/arch/parisc/include/asm/extable.h b/arch/parisc/include/asm/extable.h +new file mode 100644 +index 0000000000000..4ea23e3d79dc9 +--- /dev/null ++++ b/arch/parisc/include/asm/extable.h +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __PARISC_EXTABLE_H ++#define __PARISC_EXTABLE_H ++ ++#include <asm/ptrace.h> ++#include <linux/compiler.h> ++ ++/* ++ * The exception table consists of three addresses: ++ * ++ * - A relative address to the instruction that is allowed to fault. ++ * - A relative address at which the program should continue (fixup routine) ++ * - An asm statement which specifies which CPU register will ++ * receive -EFAULT when an exception happens if the lowest bit in ++ * the fixup address is set. ++ * ++ * Note: The register specified in the err_opcode instruction will be ++ * modified at runtime if a fault happens. Register %r0 will be ignored. ++ * ++ * Since relative addresses are used, 32bit values are sufficient even on ++ * 64bit kernel. ++ */ ++ ++struct pt_regs; ++int fixup_exception(struct pt_regs *regs); ++ ++#define ARCH_HAS_RELATIVE_EXTABLE ++struct exception_table_entry { ++ int insn; /* relative address of insn that is allowed to fault. */ ++ int fixup; /* relative address of fixup routine */ ++ int err_opcode; /* sample opcode with register which holds error code */ ++}; ++ ++#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr, opcode )\ ++ ".section __ex_table,\"aw\"\n" \ ++ ".align 4\n" \ ++ ".word (" #fault_addr " - .), (" #except_addr " - .)\n" \ ++ opcode "\n" \ ++ ".previous\n" ++ ++/* ++ * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry ++ * (with lowest bit set) for which the fault handler in fixup_exception() will ++ * load -EFAULT on fault into the register specified by the err_opcode instruction, ++ * and zeroes the target register in case of a read fault in get_user(). ++ */ ++#define ASM_EXCEPTIONTABLE_VAR(__err_var) \ ++ int __err_var = 0 ++#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr, register )\ ++ ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1, "or %%r0,%%r0," register) ++ ++static inline void swap_ex_entry_fixup(struct exception_table_entry *a, ++ struct exception_table_entry *b, ++ struct exception_table_entry tmp, ++ int delta) ++{ ++ a->fixup = b->fixup + delta; ++ b->fixup = tmp.fixup - delta; ++ a->err_opcode = b->err_opcode; ++ b->err_opcode = tmp.err_opcode; ++} ++#define swap_ex_entry_fixup swap_ex_entry_fixup ++ ++#endif +diff --git a/arch/parisc/include/asm/jump_label.h b/arch/parisc/include/asm/jump_label.h +index 94428798b6aa6..317ebc5edc9fe 100644 +--- a/arch/parisc/include/asm/jump_label.h ++++ b/arch/parisc/include/asm/jump_label.h +@@ -12,7 +12,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".align %1\n\t" +@@ -29,7 +29,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "b,n %l[l_yes]\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".align %1\n\t" +diff --git a/arch/parisc/include/asm/special_insns.h b/arch/parisc/include/asm/special_insns.h +index c822bd0c0e3c6..51f40eaf77806 100644 +--- a/arch/parisc/include/asm/special_insns.h ++++ b/arch/parisc/include/asm/special_insns.h +@@ -8,7 +8,8 @@ + "copy %%r0,%0\n" \ + "8:\tlpa %%r0(%1),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ ++ "or %%r0,%%r0,%%r0") \ + : "=&r" (pa) \ + : "r" (va) \ + : "memory" \ +@@ -22,7 +23,8 @@ + "copy %%r0,%0\n" \ + "8:\tlpa %%r0(%%sr3,%1),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ ++ "or %%r0,%%r0,%%r0") \ + : "=&r" (pa) \ + : "r" (va) \ + : "memory" \ +diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h +index 4165079898d9e..88d0ae5769dde 100644 +--- a/arch/parisc/include/asm/uaccess.h ++++ b/arch/parisc/include/asm/uaccess.h +@@ -7,6 +7,7 @@ + */ + #include <asm/page.h> + #include <asm/cache.h> ++#include <asm/extable.h> + + #include <linux/bug.h> + #include <linux/string.h> +@@ -26,37 +27,6 @@ + #define STD_USER(sr, x, ptr) __put_user_asm(sr, "std", x, ptr) + #endif + +-/* +- * The exception table contains two values: the first is the relative offset to +- * the address of the instruction that is allowed to fault, and the second is +- * the relative offset to the address of the fixup routine. Since relative +- * addresses are used, 32bit values are sufficient even on 64bit kernel. +- */ +- +-#define ARCH_HAS_RELATIVE_EXTABLE +-struct exception_table_entry { +- int insn; /* relative address of insn that is allowed to fault. */ +- int fixup; /* relative address of fixup routine */ +-}; +- +-#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ +- ".section __ex_table,\"aw\"\n" \ +- ".align 4\n" \ +- ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ +- ".previous\n" +- +-/* +- * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry +- * (with lowest bit set) for which the fault handler in fixup_exception() will +- * load -EFAULT into %r29 for a read or write fault, and zeroes the target +- * register in case of a read fault in get_user(). +- */ +-#define ASM_EXCEPTIONTABLE_REG 29 +-#define ASM_EXCEPTIONTABLE_VAR(__variable) \ +- register long __variable __asm__ ("r29") = 0 +-#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\ +- ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1) +- + #define __get_user_internal(sr, val, ptr) \ + ({ \ + ASM_EXCEPTIONTABLE_VAR(__gu_err); \ +@@ -83,7 +53,7 @@ struct exception_table_entry { + \ + __asm__("1: " ldx " 0(%%sr%2,%3),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ + : "=r"(__gu_val), "+r"(__gu_err) \ + : "i"(sr), "r"(ptr)); \ + \ +@@ -115,8 +85,8 @@ struct exception_table_entry { + "1: ldw 0(%%sr%2,%3),%0\n" \ + "2: ldw 4(%%sr%2,%3),%R0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%1") \ + : "=&r"(__gu_tmp.l), "+r"(__gu_err) \ + : "i"(sr), "r"(ptr)); \ + \ +@@ -174,7 +144,7 @@ struct exception_table_entry { + __asm__ __volatile__ ( \ + "1: " stx " %1,0(%%sr%2,%3)\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ + : "+r"(__pu_err) \ + : "r"(x), "i"(sr), "r"(ptr)) + +@@ -186,15 +156,14 @@ struct exception_table_entry { + "1: stw %1,0(%%sr%2,%3)\n" \ + "2: stw %R1,4(%%sr%2,%3)\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%0") \ + : "+r"(__pu_err) \ + : "r"(__val), "i"(sr), "r"(ptr)); \ + } while (0) + + #endif /* !defined(CONFIG_64BIT) */ + +- + /* + * Complex access routines -- external declarations + */ +@@ -216,7 +185,4 @@ unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src, + #define INLINE_COPY_TO_USER + #define INLINE_COPY_FROM_USER + +-struct pt_regs; +-int fixup_exception(struct pt_regs *regs); +- + #endif /* __PARISC_UACCESS_H */ +diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c +index 268d90a9325b4..393822f167270 100644 +--- a/arch/parisc/kernel/cache.c ++++ b/arch/parisc/kernel/cache.c +@@ -58,7 +58,7 @@ int pa_serialize_tlb_flushes __ro_after_init; + + struct pdc_cache_info cache_info __ro_after_init; + #ifndef CONFIG_PA20 +-struct pdc_btlb_info btlb_info __ro_after_init; ++struct pdc_btlb_info btlb_info; + #endif + + DEFINE_STATIC_KEY_TRUE(parisc_has_cache); +@@ -850,7 +850,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, + #endif + " fic,m %3(%4,%0)\n" + "2: sync\n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1") + : "+r" (start), "+r" (error) + : "r" (end), "r" (dcache_stride), "i" (SR_USER)); + } +@@ -865,7 +865,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, + #endif + " fdc,m %3(%4,%0)\n" + "2: sync\n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1") + : "+r" (start), "+r" (error) + : "r" (end), "r" (icache_stride), "i" (SR_USER)); + } +diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c +index ed8b759480614..8be4558ef33c0 100644 +--- a/arch/parisc/kernel/drivers.c ++++ b/arch/parisc/kernel/drivers.c +@@ -1004,6 +1004,9 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data) + + pr_info("\n"); + ++ /* Prevent hung task messages when printing on serial console */ ++ cond_resched(); ++ + pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n", + hpa, parisc_hardware_description(&dev->id)); + +diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c +index ce25acfe4889d..c520e551a1652 100644 +--- a/arch/parisc/kernel/unaligned.c ++++ b/arch/parisc/kernel/unaligned.c +@@ -120,8 +120,8 @@ static int emulate_ldh(struct pt_regs *regs, int toreg) + "2: ldbs 1(%%sr1,%3), %0\n" + " depw %2, 23, 24, %0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") + : "+r" (val), "+r" (ret), "=&r" (temp1) + : "r" (saddr), "r" (regs->isr) ); + +@@ -152,8 +152,8 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop) + " mtctl %2,11\n" + " vshd %0,%3,%0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") + : "+r" (val), "+r" (ret), "=&r" (temp1), "=&r" (temp2) + : "r" (saddr), "r" (regs->isr) ); + +@@ -189,8 +189,8 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) + " mtsar %%r19\n" + " shrpd %0,%%r20,%%sar,%0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") + : "=r" (val), "+r" (ret) + : "0" (val), "r" (saddr), "r" (regs->isr) + : "r19", "r20" ); +@@ -209,9 +209,9 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) + " vshd %0,%R0,%0\n" + " vshd %R0,%4,%R0\n" + "4: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b, "%1") + : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1) + : "r" (regs->isr) ); + } +@@ -244,8 +244,8 @@ static int emulate_sth(struct pt_regs *regs, int frreg) + "1: stb %1, 0(%%sr1, %3)\n" + "2: stb %2, 1(%%sr1, %3)\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") + : "+r" (ret), "=&r" (temp1) + : "r" (val), "r" (regs->ior), "r" (regs->isr) ); + +@@ -285,8 +285,8 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop) + " stw %%r20,0(%%sr1,%2)\n" + " stw %%r21,4(%%sr1,%2)\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") + : "+r" (ret) + : "r" (val), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r22", "r1" ); +@@ -329,10 +329,10 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) + "3: std %%r20,0(%%sr1,%2)\n" + "4: std %%r21,8(%%sr1,%2)\n" + "5: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b, "%0") + : "+r" (ret) + : "r" (val), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r22", "r1" ); +@@ -357,11 +357,11 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) + "4: stw %%r1,4(%%sr1,%2)\n" + "5: stw %R1,8(%%sr1,%2)\n" + "6: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b, "%0") + : "+r" (ret) + : "r" (val), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r1" ); +diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c +index 2fe5b44986e09..c39de84e98b05 100644 +--- a/arch/parisc/mm/fault.c ++++ b/arch/parisc/mm/fault.c +@@ -150,11 +150,16 @@ int fixup_exception(struct pt_regs *regs) + * Fix up get_user() and put_user(). + * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() sets the least-significant + * bit in the relative address of the fixup routine to indicate +- * that gr[ASM_EXCEPTIONTABLE_REG] should be loaded with +- * -EFAULT to report a userspace access error. ++ * that the register encoded in the "or %r0,%r0,register" ++ * opcode should be loaded with -EFAULT to report a userspace ++ * access error. + */ + if (fix->fixup & 1) { +- regs->gr[ASM_EXCEPTIONTABLE_REG] = -EFAULT; ++ int fault_error_reg = fix->err_opcode & 0x1f; ++ if (!WARN_ON(!fault_error_reg)) ++ regs->gr[fault_error_reg] = -EFAULT; ++ pr_debug("Unalignment fixup of register %d at %pS\n", ++ fault_error_reg, (void*)regs->iaoq[0]); + + /* zero target register for get_user() */ + if (parisc_acctyp(0, regs->iir) == VM_READ) { +diff --git a/arch/powerpc/include/asm/jump_label.h b/arch/powerpc/include/asm/jump_label.h +index 93ce3ec253877..2f2a86ed2280a 100644 +--- a/arch/powerpc/include/asm/jump_label.h ++++ b/arch/powerpc/include/asm/jump_label.h +@@ -17,7 +17,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "nop # arch_static_branch\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".long 1b - ., %l[l_yes] - .\n\t" +@@ -32,7 +32,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "b %l[l_yes] # arch_static_branch_jump\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".long 1b - ., %l[l_yes] - .\n\t" +diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h +index 4ae4ab9090a2d..ade5f094dbd22 100644 +--- a/arch/powerpc/include/asm/reg.h ++++ b/arch/powerpc/include/asm/reg.h +@@ -617,6 +617,8 @@ + #endif + #define SPRN_HID2 0x3F8 /* Hardware Implementation Register 2 */ + #define SPRN_HID2_GEKKO 0x398 /* Gekko HID2 Register */ ++#define SPRN_HID2_G2_LE 0x3F3 /* G2_LE HID2 Register */ ++#define HID2_G2_LE_HBE (1<<18) /* High BAT Enable (G2_LE) */ + #define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ + #define SPRN_IABR2 0x3FA /* 83xx */ + #define SPRN_IBCR 0x135 /* 83xx Insn Breakpoint Control Reg */ +diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h +index bf5dde1a41147..15c5691dd2184 100644 +--- a/arch/powerpc/include/asm/thread_info.h ++++ b/arch/powerpc/include/asm/thread_info.h +@@ -14,7 +14,7 @@ + + #ifdef __KERNEL__ + +-#ifdef CONFIG_KASAN ++#if defined(CONFIG_KASAN) && CONFIG_THREAD_SHIFT < 15 + #define MIN_THREAD_SHIFT (CONFIG_THREAD_SHIFT + 1) + #else + #define MIN_THREAD_SHIFT CONFIG_THREAD_SHIFT +diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h +index fb725ec77926e..4c96de9cd1e99 100644 +--- a/arch/powerpc/include/asm/uaccess.h ++++ b/arch/powerpc/include/asm/uaccess.h +@@ -74,7 +74,7 @@ __pu_failed: \ + /* -mprefixed can generate offsets beyond range, fall back hack */ + #ifdef CONFIG_PPC_KERNEL_PREFIXED + #define __put_user_asm_goto(x, addr, label, op) \ +- asm_volatile_goto( \ ++ asm goto( \ + "1: " op " %0,0(%1) # put_user\n" \ + EX_TABLE(1b, %l2) \ + : \ +@@ -83,7 +83,7 @@ __pu_failed: \ + : label) + #else + #define __put_user_asm_goto(x, addr, label, op) \ +- asm_volatile_goto( \ ++ asm goto( \ + "1: " op "%U1%X1 %0,%1 # put_user\n" \ + EX_TABLE(1b, %l2) \ + : \ +@@ -97,7 +97,7 @@ __pu_failed: \ + __put_user_asm_goto(x, ptr, label, "std") + #else /* __powerpc64__ */ + #define __put_user_asm2_goto(x, addr, label) \ +- asm_volatile_goto( \ ++ asm goto( \ + "1: stw%X1 %0, %1\n" \ + "2: stw%X1 %L0, %L1\n" \ + EX_TABLE(1b, %l2) \ +@@ -146,7 +146,7 @@ do { \ + /* -mprefixed can generate offsets beyond range, fall back hack */ + #ifdef CONFIG_PPC_KERNEL_PREFIXED + #define __get_user_asm_goto(x, addr, label, op) \ +- asm_volatile_goto( \ ++ asm_goto_output( \ + "1: "op" %0,0(%1) # get_user\n" \ + EX_TABLE(1b, %l2) \ + : "=r" (x) \ +@@ -155,7 +155,7 @@ do { \ + : label) + #else + #define __get_user_asm_goto(x, addr, label, op) \ +- asm_volatile_goto( \ ++ asm_goto_output( \ + "1: "op"%U1%X1 %0, %1 # get_user\n" \ + EX_TABLE(1b, %l2) \ + : "=r" (x) \ +@@ -169,7 +169,7 @@ do { \ + __get_user_asm_goto(x, addr, label, "ld") + #else /* __powerpc64__ */ + #define __get_user_asm2_goto(x, addr, label) \ +- asm_volatile_goto( \ ++ asm_goto_output( \ + "1: lwz%X1 %0, %1\n" \ + "2: lwz%X1 %L0, %L1\n" \ + EX_TABLE(1b, %l2) \ +diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S +index f29ce3dd6140f..bfd3f442e5eb9 100644 +--- a/arch/powerpc/kernel/cpu_setup_6xx.S ++++ b/arch/powerpc/kernel/cpu_setup_6xx.S +@@ -26,6 +26,15 @@ BEGIN_FTR_SECTION + bl __init_fpu_registers + END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE) + bl setup_common_caches ++ ++ /* ++ * This assumes that all cores using __setup_cpu_603 with ++ * MMU_FTR_USE_HIGH_BATS are G2_LE compatible ++ */ ++BEGIN_MMU_FTR_SECTION ++ bl setup_g2_le_hid2 ++END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) ++ + mtlr r5 + blr + _GLOBAL(__setup_cpu_604) +@@ -115,6 +124,16 @@ SYM_FUNC_START_LOCAL(setup_604_hid0) + blr + SYM_FUNC_END(setup_604_hid0) + ++/* Enable high BATs for G2_LE and derivatives like e300cX */ ++SYM_FUNC_START_LOCAL(setup_g2_le_hid2) ++ mfspr r11,SPRN_HID2_G2_LE ++ oris r11,r11,HID2_G2_LE_HBE@h ++ mtspr SPRN_HID2_G2_LE,r11 ++ sync ++ isync ++ blr ++SYM_FUNC_END(setup_g2_le_hid2) ++ + /* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some + * erratas we work around here. + * Moto MPC710CE.pdf describes them, those are errata +@@ -495,4 +514,3 @@ _GLOBAL(__restore_cpu_setup) + mtcr r7 + blr + _ASM_NOKPROBE_SYMBOL(__restore_cpu_setup) +- +diff --git a/arch/powerpc/kernel/cpu_specs_e500mc.h b/arch/powerpc/kernel/cpu_specs_e500mc.h +index ceb06b109f831..2ae8e9a7b461c 100644 +--- a/arch/powerpc/kernel/cpu_specs_e500mc.h ++++ b/arch/powerpc/kernel/cpu_specs_e500mc.h +@@ -8,7 +8,8 @@ + + #ifdef CONFIG_PPC64 + #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ +- PPC_FEATURE_HAS_FPU | PPC_FEATURE_64) ++ PPC_FEATURE_HAS_FPU | PPC_FEATURE_64 | \ ++ PPC_FEATURE_BOOKE) + #else + #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ + PPC_FEATURE_BOOKE) +diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S +index bd863702d8121..1ad059a9e2fef 100644 +--- a/arch/powerpc/kernel/interrupt_64.S ++++ b/arch/powerpc/kernel/interrupt_64.S +@@ -52,7 +52,8 @@ _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name) + mr r10,r1 + ld r1,PACAKSAVE(r13) + std r10,0(r1) +- std r11,_NIP(r1) ++ std r11,_LINK(r1) ++ std r11,_NIP(r1) /* Saved LR is also the next instruction */ + std r12,_MSR(r1) + std r0,GPR0(r1) + std r10,GPR1(r1) +@@ -70,7 +71,6 @@ _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name) + std r9,GPR13(r1) + SAVE_NVGPRS(r1) + std r11,_XER(r1) +- std r11,_LINK(r1) + std r11,_CTR(r1) + + li r11,\trapnr +diff --git a/arch/powerpc/kernel/irq_64.c b/arch/powerpc/kernel/irq_64.c +index 938e66829eae6..d5c48d1b0a31e 100644 +--- a/arch/powerpc/kernel/irq_64.c ++++ b/arch/powerpc/kernel/irq_64.c +@@ -230,7 +230,7 @@ notrace __no_kcsan void arch_local_irq_restore(unsigned long mask) + * This allows interrupts to be unmasked without hard disabling, and + * also without new hard interrupts coming in ahead of pending ones. + */ +- asm_volatile_goto( ++ asm goto( + "1: \n" + " lbz 9,%0(13) \n" + " cmpwi 9,0 \n" +diff --git a/arch/powerpc/mm/kasan/init_32.c b/arch/powerpc/mm/kasan/init_32.c +index a70828a6d9357..aa9aa11927b2f 100644 +--- a/arch/powerpc/mm/kasan/init_32.c ++++ b/arch/powerpc/mm/kasan/init_32.c +@@ -64,6 +64,7 @@ int __init __weak kasan_init_region(void *start, size_t size) + if (ret) + return ret; + ++ k_start = k_start & PAGE_MASK; + block = memblock_alloc(k_end - k_start, PAGE_SIZE); + if (!block) + return -ENOMEM; +diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c +index d4d6de0628b05..47d9a65324472 100644 +--- a/arch/powerpc/platforms/pseries/lpar.c ++++ b/arch/powerpc/platforms/pseries/lpar.c +@@ -662,8 +662,12 @@ u64 pseries_paravirt_steal_clock(int cpu) + { + struct lppaca *lppaca = &lppaca_of(cpu); + +- return be64_to_cpu(READ_ONCE(lppaca->enqueue_dispatch_tb)) + +- be64_to_cpu(READ_ONCE(lppaca->ready_enqueue_tb)); ++ /* ++ * VPA steal time counters are reported at TB frequency. Hence do a ++ * conversion to ns before returning ++ */ ++ return tb_to_ns(be64_to_cpu(READ_ONCE(lppaca->enqueue_dispatch_tb)) + ++ be64_to_cpu(READ_ONCE(lppaca->ready_enqueue_tb))); + } + #endif + +diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h +index b7b58258f6c7c..f4157034efa9c 100644 +--- a/arch/riscv/include/asm/hwcap.h ++++ b/arch/riscv/include/asm/hwcap.h +@@ -98,7 +98,7 @@ riscv_has_extension_likely(const unsigned long ext) + "ext must be < RISCV_ISA_EXT_MAX"); + + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE("j %l[l_no]", "nop", 0, %[ext], 1) + : + : [ext] "i" (ext) +@@ -121,7 +121,7 @@ riscv_has_extension_unlikely(const unsigned long ext) + "ext must be < RISCV_ISA_EXT_MAX"); + + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE("nop", "j %l[l_yes]", 0, %[ext], 1) + : + : [ext] "i" (ext) +diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h +index 14a5ea8d8ef0f..4a35d787c0191 100644 +--- a/arch/riscv/include/asm/jump_label.h ++++ b/arch/riscv/include/asm/jump_label.h +@@ -17,7 +17,7 @@ + static __always_inline bool arch_static_branch(struct static_key * const key, + const bool branch) + { +- asm_volatile_goto( ++ asm goto( + " .align 2 \n\t" + " .option push \n\t" + " .option norelax \n\t" +@@ -39,7 +39,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, + static __always_inline bool arch_static_branch_jump(struct static_key * const key, + const bool branch) + { +- asm_volatile_goto( ++ asm goto( + " .align 2 \n\t" + " .option push \n\t" + " .option norelax \n\t" +diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h +index 895f774bbcc55..bf78cf381dfcd 100644 +--- a/arch/s390/include/asm/jump_label.h ++++ b/arch/s390/include/asm/jump_label.h +@@ -25,7 +25,7 @@ + */ + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("0: brcl 0,%l[label]\n" ++ asm goto("0: brcl 0,%l[label]\n" + ".pushsection __jump_table,\"aw\"\n" + ".balign 8\n" + ".long 0b-.,%l[label]-.\n" +@@ -39,7 +39,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("0: brcl 15,%l[label]\n" ++ asm goto("0: brcl 15,%l[label]\n" + ".pushsection __jump_table,\"aw\"\n" + ".balign 8\n" + ".long 0b-.,%l[label]-.\n" +diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h +index 94eb529dcb776..2718cbea826a7 100644 +--- a/arch/sparc/include/asm/jump_label.h ++++ b/arch/sparc/include/asm/jump_label.h +@@ -10,7 +10,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "nop\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" +@@ -26,7 +26,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "b %l[l_yes]\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" +diff --git a/arch/um/Makefile b/arch/um/Makefile +index 82f05f2506348..34957dcb88b9c 100644 +--- a/arch/um/Makefile ++++ b/arch/um/Makefile +@@ -115,7 +115,9 @@ archprepare: + $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h + + LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static +-LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie) ++ifdef CONFIG_LD_SCRIPT_DYN ++LINK-$(call gcc-min-version, 60100)$(CONFIG_CC_IS_CLANG) += -no-pie ++endif + LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib + + CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \ +diff --git a/arch/um/include/asm/cpufeature.h b/arch/um/include/asm/cpufeature.h +index 4b6d1b526bc12..66fe06db872f0 100644 +--- a/arch/um/include/asm/cpufeature.h ++++ b/arch/um/include/asm/cpufeature.h +@@ -75,7 +75,7 @@ extern void setup_clear_cpu_cap(unsigned int bit); + */ + static __always_inline bool _static_cpu_has(u16 bit) + { +- asm_volatile_goto("1: jmp 6f\n" ++ asm goto("1: jmp 6f\n" + "2:\n" + ".skip -(((5f-4f) - (2b-1b)) > 0) * " + "((5f-4f) - (2b-1b)),0x90\n" +diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu +index 00468adf180f1..87396575cfa77 100644 +--- a/arch/x86/Kconfig.cpu ++++ b/arch/x86/Kconfig.cpu +@@ -375,7 +375,7 @@ config X86_CMOV + config X86_MINIMUM_CPU_FAMILY + int + default "64" if X86_64 +- default "6" if X86_32 && (MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MATOM || MCRUSOE || MCORE2 || MK7 || MK8) ++ default "6" if X86_32 && (MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MATOM || MCORE2 || MK7 || MK8) + default "5" if X86_32 && X86_CMPXCHG64 + default "4" + +diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile +index f33e45ed14376..3cece19b74732 100644 +--- a/arch/x86/boot/Makefile ++++ b/arch/x86/boot/Makefile +@@ -89,7 +89,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE + + SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) + +-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p' ++sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi.._stub_entry\|efi\(32\)\?_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|_e\?data\|z_.*\)$$/\#define ZO_\2 0x\1/p' + + quiet_cmd_zoffset = ZOFFSET $@ + cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@ +diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S +index b22f34b8684a7..083ec6d7722a1 100644 +--- a/arch/x86/boot/compressed/vmlinux.lds.S ++++ b/arch/x86/boot/compressed/vmlinux.lds.S +@@ -43,11 +43,13 @@ SECTIONS + *(.rodata.*) + _erodata = . ; + } +- .data : { ++ .data : ALIGN(0x1000) { + _data = . ; + *(.data) + *(.data.*) +- *(.bss.efistub) ++ ++ /* Add 4 bytes of extra space for a CRC-32 checksum */ ++ . = ALIGN(. + 4, 0x200); + _edata = . ; + } + . = ALIGN(L1_CACHE_BYTES); +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b04ca8e2b213c..a1bbedd989e42 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -36,66 +36,20 @@ SYSSEG = 0x1000 /* historical load address >> 4 */ + #define ROOT_RDONLY 1 + #endif + ++ .set salign, 0x1000 ++ .set falign, 0x200 ++ + .code16 + .section ".bstext", "ax" +- +- .global bootsect_start +-bootsect_start: + #ifdef CONFIG_EFI_STUB + # "MZ", MS-DOS header + .word MZ_MAGIC +-#endif +- +- # Normalize the start address +- ljmp $BOOTSEG, $start2 +- +-start2: +- movw %cs, %ax +- movw %ax, %ds +- movw %ax, %es +- movw %ax, %ss +- xorw %sp, %sp +- sti +- cld +- +- movw $bugger_off_msg, %si +- +-msg_loop: +- lodsb +- andb %al, %al +- jz bs_die +- movb $0xe, %ah +- movw $7, %bx +- int $0x10 +- jmp msg_loop +- +-bs_die: +- # Allow the user to press a key, then reboot +- xorw %ax, %ax +- int $0x16 +- int $0x19 +- +- # int 0x19 should never return. In case it does anyway, +- # invoke the BIOS reset code... +- ljmp $0xf000,$0xfff0 +- +-#ifdef CONFIG_EFI_STUB + .org 0x38 + # + # Offset to the PE header. + # + .long LINUX_PE_MAGIC + .long pe_header +-#endif /* CONFIG_EFI_STUB */ +- +- .section ".bsdata", "a" +-bugger_off_msg: +- .ascii "Use a boot loader.\r\n" +- .ascii "\n" +- .ascii "Remove disk and press any key to reboot...\r\n" +- .byte 0 +- +-#ifdef CONFIG_EFI_STUB + pe_header: + .long PE_MAGIC + +@@ -124,30 +78,26 @@ optional_header: + .byte 0x02 # MajorLinkerVersion + .byte 0x14 # MinorLinkerVersion + +- # Filled in by build.c +- .long 0 # SizeOfCode ++ .long ZO__data # SizeOfCode + +- .long 0 # SizeOfInitializedData ++ .long ZO__end - ZO__data # SizeOfInitializedData + .long 0 # SizeOfUninitializedData + +- # Filled in by build.c +- .long 0x0000 # AddressOfEntryPoint ++ .long setup_size + ZO_efi_pe_entry # AddressOfEntryPoint + +- .long 0x0200 # BaseOfCode ++ .long setup_size # BaseOfCode + #ifdef CONFIG_X86_32 + .long 0 # data + #endif + + extra_header_fields: +- # PE specification requires ImageBase to be 64k aligned +- .set image_base, (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff + #ifdef CONFIG_X86_32 +- .long image_base # ImageBase ++ .long 0 # ImageBase + #else +- .quad image_base # ImageBase ++ .quad 0 # ImageBase + #endif +- .long 0x20 # SectionAlignment +- .long 0x20 # FileAlignment ++ .long salign # SectionAlignment ++ .long falign # FileAlignment + .word 0 # MajorOperatingSystemVersion + .word 0 # MinorOperatingSystemVersion + .word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion +@@ -156,12 +106,9 @@ extra_header_fields: + .word 0 # MinorSubsystemVersion + .long 0 # Win32VersionValue + +- # +- # The size of the bzImage is written in tools/build.c +- # +- .long 0 # SizeOfImage ++ .long setup_size + ZO__end # SizeOfImage + +- .long 0x200 # SizeOfHeaders ++ .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) + #ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES +@@ -192,87 +139,77 @@ extra_header_fields: + + # Section table + section_table: +- # +- # The offset & size fields are filled in by build.c. +- # + .ascii ".setup" + .byte 0 + .byte 0 +- .long 0 +- .long 0x0 # startup_{32,64} +- .long 0 # Size of initialized data +- # on disk +- .long 0x0 # startup_{32,64} +- .long 0 # PointerToRelocations +- .long 0 # PointerToLineNumbers +- .word 0 # NumberOfRelocations +- .word 0 # NumberOfLineNumbers +- .long IMAGE_SCN_CNT_CODE | \ +- IMAGE_SCN_MEM_READ | \ +- IMAGE_SCN_MEM_EXECUTE | \ +- IMAGE_SCN_ALIGN_16BYTES # Characteristics ++ .long pecompat_fstart - salign # VirtualSize ++ .long salign # VirtualAddress ++ .long pecompat_fstart - salign # SizeOfRawData ++ .long salign # PointerToRawData + +- # +- # The EFI application loader requires a relocation section +- # because EFI applications must be relocatable. The .reloc +- # offset & size fields are filled in by build.c. +- # +- .ascii ".reloc" +- .byte 0 +- .byte 0 +- .long 0 +- .long 0 +- .long 0 # SizeOfRawData +- .long 0 # PointerToRawData +- .long 0 # PointerToRelocations +- .long 0 # PointerToLineNumbers +- .word 0 # NumberOfRelocations +- .word 0 # NumberOfLineNumbers ++ .long 0, 0, 0 + .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ + IMAGE_SCN_MEM_READ | \ +- IMAGE_SCN_MEM_DISCARDABLE | \ +- IMAGE_SCN_ALIGN_1BYTES # Characteristics ++ IMAGE_SCN_MEM_DISCARDABLE # Characteristics + + #ifdef CONFIG_EFI_MIXED +- # +- # The offset & size fields are filled in by build.c. +- # + .asciz ".compat" +- .long 0 +- .long 0x0 +- .long 0 # Size of initialized data +- # on disk +- .long 0x0 +- .long 0 # PointerToRelocations +- .long 0 # PointerToLineNumbers +- .word 0 # NumberOfRelocations +- .word 0 # NumberOfLineNumbers ++ ++ .long pecompat_fsize # VirtualSize ++ .long pecompat_fstart # VirtualAddress ++ .long pecompat_fsize # SizeOfRawData ++ .long pecompat_fstart # PointerToRawData ++ ++ .long 0, 0, 0 + .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ + IMAGE_SCN_MEM_READ | \ +- IMAGE_SCN_MEM_DISCARDABLE | \ +- IMAGE_SCN_ALIGN_1BYTES # Characteristics ++ IMAGE_SCN_MEM_DISCARDABLE # Characteristics ++ ++ /* ++ * Put the IA-32 machine type and the associated entry point address in ++ * the .compat section, so loaders can figure out which other execution ++ * modes this image supports. ++ */ ++ .pushsection ".pecompat", "a", @progbits ++ .balign salign ++ .globl pecompat_fstart ++pecompat_fstart: ++ .byte 0x1 # Version ++ .byte 8 # Size ++ .word IMAGE_FILE_MACHINE_I386 # PE machine type ++ .long setup_size + ZO_efi32_pe_entry # Entrypoint ++ .byte 0x0 # Sentinel ++ .popsection ++#else ++ .set pecompat_fstart, setup_size + #endif +- +- # +- # The offset & size fields are filled in by build.c. +- # + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 +- .long 0 +- .long 0x0 # startup_{32,64} +- .long 0 # Size of initialized data ++ .long ZO__data ++ .long setup_size ++ .long ZO__data # Size of initialized data + # on disk +- .long 0x0 # startup_{32,64} ++ .long setup_size + .long 0 # PointerToRelocations + .long 0 # PointerToLineNumbers + .word 0 # NumberOfRelocations + .word 0 # NumberOfLineNumbers + .long IMAGE_SCN_CNT_CODE | \ + IMAGE_SCN_MEM_READ | \ +- IMAGE_SCN_MEM_EXECUTE | \ +- IMAGE_SCN_ALIGN_16BYTES # Characteristics ++ IMAGE_SCN_MEM_EXECUTE # Characteristics ++ ++ .ascii ".data\0\0\0" ++ .long ZO__end - ZO__data # VirtualSize ++ .long setup_size + ZO__data # VirtualAddress ++ .long ZO__edata - ZO__data # SizeOfRawData ++ .long setup_size + ZO__data # PointerToRawData ++ ++ .long 0, 0, 0 ++ .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ ++ IMAGE_SCN_MEM_READ | \ ++ IMAGE_SCN_MEM_WRITE # Characteristics + + .set section_count, (. - section_table) / 40 + #endif /* CONFIG_EFI_STUB */ +@@ -286,12 +223,12 @@ sentinel: .byte 0xff, 0xff /* Used to detect broken loaders */ + + .globl hdr + hdr: +-setup_sects: .byte 0 /* Filled in by build.c */ ++ .byte setup_sects - 1 + root_flags: .word ROOT_RDONLY +-syssize: .long 0 /* Filled in by build.c */ ++syssize: .long ZO__edata / 16 + ram_size: .word 0 /* Obsolete */ + vid_mode: .word SVGA_MODE +-root_dev: .word 0 /* Filled in by build.c */ ++root_dev: .word 0 /* Default to major/minor 0/0 */ + boot_flag: .word 0xAA55 + + # offset 512, entry point +@@ -579,9 +516,25 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr + # define INIT_SIZE VO_INIT_SIZE + #endif + ++ .macro __handover_offset ++#ifndef CONFIG_EFI_HANDOVER_PROTOCOL ++ .long 0 ++#elif !defined(CONFIG_X86_64) ++ .long ZO_efi32_stub_entry ++#else ++ /* Yes, this is really how we defined it :( */ ++ .long ZO_efi64_stub_entry - 0x200 ++#ifdef CONFIG_EFI_MIXED ++ .if ZO_efi32_stub_entry != ZO_efi64_stub_entry - 0x200 ++ .error "32-bit and 64-bit EFI entry points do not match" ++ .endif ++#endif ++#endif ++ .endm ++ + init_size: .long INIT_SIZE # kernel initialization size +-handover_offset: .long 0 # Filled in by build.c +-kernel_info_offset: .long 0 # Filled in by build.c ++handover_offset: __handover_offset ++kernel_info_offset: .long ZO_kernel_info + + # End of setup header ##################################################### + +diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld +index 49546c247ae25..3a2d1360abb01 100644 +--- a/arch/x86/boot/setup.ld ++++ b/arch/x86/boot/setup.ld +@@ -10,10 +10,11 @@ ENTRY(_start) + SECTIONS + { + . = 0; +- .bstext : { *(.bstext) } +- .bsdata : { *(.bsdata) } ++ .bstext : { ++ *(.bstext) ++ . = 495; ++ } =0xffffffff + +- . = 495; + .header : { *(.header) } + .entrytext : { *(.entrytext) } + .inittext : { *(.inittext) } +@@ -23,6 +24,9 @@ SECTIONS + .text : { *(.text .text.*) } + .text32 : { *(.text32) } + ++ .pecompat : { *(.pecompat) } ++ PROVIDE(pecompat_fsize = setup_size - pecompat_fstart); ++ + . = ALIGN(16); + .rodata : { *(.rodata*) } + +@@ -38,8 +42,10 @@ SECTIONS + .signature : { + setup_sig = .; + LONG(0x5a5aaa55) +- } + ++ setup_size = ALIGN(ABSOLUTE(.), 4096); ++ setup_sects = ABSOLUTE(setup_size / 512); ++ } + + . = ALIGN(16); + .bss : +diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c +index bd247692b7017..10311d77c67f8 100644 +--- a/arch/x86/boot/tools/build.c ++++ b/arch/x86/boot/tools/build.c +@@ -40,10 +40,6 @@ typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + +-#define DEFAULT_MAJOR_ROOT 0 +-#define DEFAULT_MINOR_ROOT 0 +-#define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT) +- + /* Minimal number of setup sectors */ + #define SETUP_SECT_MIN 5 + #define SETUP_SECT_MAX 64 +@@ -51,22 +47,7 @@ typedef unsigned int u32; + /* This must be large enough to hold the entire setup */ + u8 buf[SETUP_SECT_MAX*512]; + +-#define PECOFF_RELOC_RESERVE 0x20 +- +-#ifdef CONFIG_EFI_MIXED +-#define PECOFF_COMPAT_RESERVE 0x20 +-#else +-#define PECOFF_COMPAT_RESERVE 0x0 +-#endif +- +-static unsigned long efi32_stub_entry; +-static unsigned long efi64_stub_entry; +-static unsigned long efi_pe_entry; +-static unsigned long efi32_pe_entry; +-static unsigned long kernel_info; +-static unsigned long startup_64; +-static unsigned long _ehead; +-static unsigned long _end; ++static unsigned long _edata; + + /*----------------------------------------------------------------------*/ + +@@ -152,180 +133,6 @@ static void usage(void) + die("Usage: build setup system zoffset.h image"); + } + +-#ifdef CONFIG_EFI_STUB +- +-static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset) +-{ +- unsigned int pe_header; +- unsigned short num_sections; +- u8 *section; +- +- pe_header = get_unaligned_le32(&buf[0x3c]); +- num_sections = get_unaligned_le16(&buf[pe_header + 6]); +- +-#ifdef CONFIG_X86_32 +- section = &buf[pe_header + 0xa8]; +-#else +- section = &buf[pe_header + 0xb8]; +-#endif +- +- while (num_sections > 0) { +- if (strncmp((char*)section, section_name, 8) == 0) { +- /* section header size field */ +- put_unaligned_le32(size, section + 0x8); +- +- /* section header vma field */ +- put_unaligned_le32(vma, section + 0xc); +- +- /* section header 'size of initialised data' field */ +- put_unaligned_le32(datasz, section + 0x10); +- +- /* section header 'file offset' field */ +- put_unaligned_le32(offset, section + 0x14); +- +- break; +- } +- section += 0x28; +- num_sections--; +- } +-} +- +-static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) +-{ +- update_pecoff_section_header_fields(section_name, offset, size, size, offset); +-} +- +-static void update_pecoff_setup_and_reloc(unsigned int size) +-{ +- u32 setup_offset = 0x200; +- u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE; +-#ifdef CONFIG_EFI_MIXED +- u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE; +-#endif +- u32 setup_size = reloc_offset - setup_offset; +- +- update_pecoff_section_header(".setup", setup_offset, setup_size); +- update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE); +- +- /* +- * Modify .reloc section contents with a single entry. The +- * relocation is applied to offset 10 of the relocation section. +- */ +- put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]); +- put_unaligned_le32(10, &buf[reloc_offset + 4]); +- +-#ifdef CONFIG_EFI_MIXED +- update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE); +- +- /* +- * Put the IA-32 machine type (0x14c) and the associated entry point +- * address in the .compat section, so loaders can figure out which other +- * execution modes this image supports. +- */ +- buf[compat_offset] = 0x1; +- buf[compat_offset + 1] = 0x8; +- put_unaligned_le16(0x14c, &buf[compat_offset + 2]); +- put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]); +-#endif +-} +- +-static void update_pecoff_text(unsigned int text_start, unsigned int file_sz, +- unsigned int init_sz) +-{ +- unsigned int pe_header; +- unsigned int text_sz = file_sz - text_start; +- unsigned int bss_sz = init_sz - file_sz; +- +- pe_header = get_unaligned_le32(&buf[0x3c]); +- +- /* +- * The PE/COFF loader may load the image at an address which is +- * misaligned with respect to the kernel_alignment field in the setup +- * header. +- * +- * In order to avoid relocating the kernel to correct the misalignment, +- * add slack to allow the buffer to be aligned within the declared size +- * of the image. +- */ +- bss_sz += CONFIG_PHYSICAL_ALIGN; +- init_sz += CONFIG_PHYSICAL_ALIGN; +- +- /* +- * Size of code: Subtract the size of the first sector (512 bytes) +- * which includes the header. +- */ +- put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]); +- +- /* Size of image */ +- put_unaligned_le32(init_sz, &buf[pe_header + 0x50]); +- +- /* +- * Address of entry point for PE/COFF executable +- */ +- put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]); +- +- update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz, +- text_sz, text_start); +-} +- +-static int reserve_pecoff_reloc_section(int c) +-{ +- /* Reserve 0x20 bytes for .reloc section */ +- memset(buf+c, 0, PECOFF_RELOC_RESERVE); +- return PECOFF_RELOC_RESERVE; +-} +- +-static void efi_stub_defaults(void) +-{ +- /* Defaults for old kernel */ +-#ifdef CONFIG_X86_32 +- efi_pe_entry = 0x10; +-#else +- efi_pe_entry = 0x210; +- startup_64 = 0x200; +-#endif +-} +- +-static void efi_stub_entry_update(void) +-{ +- unsigned long addr = efi32_stub_entry; +- +-#ifdef CONFIG_EFI_HANDOVER_PROTOCOL +-#ifdef CONFIG_X86_64 +- /* Yes, this is really how we defined it :( */ +- addr = efi64_stub_entry - 0x200; +-#endif +- +-#ifdef CONFIG_EFI_MIXED +- if (efi32_stub_entry != addr) +- die("32-bit and 64-bit EFI entry points do not match\n"); +-#endif +-#endif +- put_unaligned_le32(addr, &buf[0x264]); +-} +- +-#else +- +-static inline void update_pecoff_setup_and_reloc(unsigned int size) {} +-static inline void update_pecoff_text(unsigned int text_start, +- unsigned int file_sz, +- unsigned int init_sz) {} +-static inline void efi_stub_defaults(void) {} +-static inline void efi_stub_entry_update(void) {} +- +-static inline int reserve_pecoff_reloc_section(int c) +-{ +- return 0; +-} +-#endif /* CONFIG_EFI_STUB */ +- +-static int reserve_pecoff_compat_section(int c) +-{ +- /* Reserve 0x20 bytes for .compat section */ +- memset(buf+c, 0, PECOFF_COMPAT_RESERVE); +- return PECOFF_COMPAT_RESERVE; +-} +- + /* + * Parse zoffset.h and find the entry points. We could just #include zoffset.h + * but that would mean tools/build would have to be rebuilt every time. It's +@@ -354,14 +161,7 @@ static void parse_zoffset(char *fname) + p = (char *)buf; + + while (p && *p) { +- PARSE_ZOFS(p, efi32_stub_entry); +- PARSE_ZOFS(p, efi64_stub_entry); +- PARSE_ZOFS(p, efi_pe_entry); +- PARSE_ZOFS(p, efi32_pe_entry); +- PARSE_ZOFS(p, kernel_info); +- PARSE_ZOFS(p, startup_64); +- PARSE_ZOFS(p, _ehead); +- PARSE_ZOFS(p, _end); ++ PARSE_ZOFS(p, _edata); + + p = strchr(p, '\n'); + while (p && (*p == '\r' || *p == '\n')) +@@ -371,17 +171,14 @@ static void parse_zoffset(char *fname) + + int main(int argc, char ** argv) + { +- unsigned int i, sz, setup_sectors, init_sz; ++ unsigned int i, sz, setup_sectors; + int c; +- u32 sys_size; + struct stat sb; + FILE *file, *dest; + int fd; + void *kernel; + u32 crc = 0xffffffffUL; + +- efi_stub_defaults(); +- + if (argc != 5) + usage(); + parse_zoffset(argv[3]); +@@ -403,72 +200,27 @@ int main(int argc, char ** argv) + die("Boot block hasn't got boot flag (0xAA55)"); + fclose(file); + +- c += reserve_pecoff_compat_section(c); +- c += reserve_pecoff_reloc_section(c); +- + /* Pad unused space with zeros */ +- setup_sectors = (c + 511) / 512; ++ setup_sectors = (c + 4095) / 4096; ++ setup_sectors *= 8; + if (setup_sectors < SETUP_SECT_MIN) + setup_sectors = SETUP_SECT_MIN; + i = setup_sectors*512; + memset(buf+c, 0, i-c); + +- update_pecoff_setup_and_reloc(i); +- +- /* Set the default root device */ +- put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); +- + /* Open and stat the kernel file */ + fd = open(argv[2], O_RDONLY); + if (fd < 0) + die("Unable to open `%s': %m", argv[2]); + if (fstat(fd, &sb)) + die("Unable to stat `%s': %m", argv[2]); +- sz = sb.st_size; ++ if (_edata != sb.st_size) ++ die("Unexpected file size `%s': %u != %u", argv[2], _edata, ++ sb.st_size); ++ sz = _edata - 4; + kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0); + if (kernel == MAP_FAILED) + die("Unable to mmap '%s': %m", argv[2]); +- /* Number of 16-byte paragraphs, including space for a 4-byte CRC */ +- sys_size = (sz + 15 + 4) / 16; +-#ifdef CONFIG_EFI_STUB +- /* +- * COFF requires minimum 32-byte alignment of sections, and +- * adding a signature is problematic without that alignment. +- */ +- sys_size = (sys_size + 1) & ~1; +-#endif +- +- /* Patch the setup code with the appropriate size parameters */ +- buf[0x1f1] = setup_sectors-1; +- put_unaligned_le32(sys_size, &buf[0x1f4]); +- +- init_sz = get_unaligned_le32(&buf[0x260]); +-#ifdef CONFIG_EFI_STUB +- /* +- * The decompression buffer will start at ImageBase. When relocating +- * the compressed kernel to its end, we must ensure that the head +- * section does not get overwritten. The head section occupies +- * [i, i + _ehead), and the destination is [init_sz - _end, init_sz). +- * +- * At present these should never overlap, because 'i' is at most 32k +- * because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the +- * calculation of INIT_SIZE in boot/header.S ensures that +- * 'init_sz - _end' is at least 64k. +- * +- * For future-proofing, increase init_sz if necessary. +- */ +- +- if (init_sz - _end < i + _ehead) { +- init_sz = (i + _ehead + _end + 4095) & ~4095; +- put_unaligned_le32(init_sz, &buf[0x260]); +- } +-#endif +- update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz); +- +- efi_stub_entry_update(); +- +- /* Update kernel_info offset. */ +- put_unaligned_le32(kernel_info, &buf[0x268]); + + crc = partial_crc32(buf, i, crc); + if (fwrite(buf, 1, i, dest) != i) +@@ -479,13 +231,6 @@ int main(int argc, char ** argv) + if (fwrite(kernel, 1, sz, dest) != sz) + die("Writing kernel failed"); + +- /* Add padding leaving 4 bytes for the checksum */ +- while (sz++ < (sys_size*16) - 4) { +- crc = partial_crc32_one('\0', crc); +- if (fwrite("\0", 1, 1, dest) != 1) +- die("Writing padding failed"); +- } +- + /* Write the CRC */ + put_unaligned_le32(crc, buf); + if (fwrite(buf, 1, 4, dest) != 4) +diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h +index 35389b2af88ee..0216f63a366b5 100644 +--- a/arch/x86/include/asm/barrier.h ++++ b/arch/x86/include/asm/barrier.h +@@ -81,22 +81,4 @@ do { \ + + #include <asm-generic/barrier.h> + +-/* +- * Make previous memory operations globally visible before +- * a WRMSR. +- * +- * MFENCE makes writes visible, but only affects load/store +- * instructions. WRMSR is unfortunately not a load/store +- * instruction and is unaffected by MFENCE. The LFENCE ensures +- * that the WRMSR is not reordered. +- * +- * Most WRMSRs are full serializing instructions themselves and +- * do not require this barrier. This is only required for the +- * IA32_TSC_DEADLINE and X2APIC MSRs. +- */ +-static inline void weak_wrmsr_fence(void) +-{ +- asm volatile("mfence; lfence" : : : "memory"); +-} +- + #endif /* _ASM_X86_BARRIER_H */ +diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h +index a26bebbdff87e..a1273698fc430 100644 +--- a/arch/x86/include/asm/cpufeature.h ++++ b/arch/x86/include/asm/cpufeature.h +@@ -168,7 +168,7 @@ extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit); + */ + static __always_inline bool _static_cpu_has(u16 bit) + { +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE_TERNARY("jmp 6f", %P[feature], "", "jmp %l[t_no]") + ".pushsection .altinstr_aux,\"ax\"\n" + "6:\n" +diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h +index 58cb9495e40f4..0091f10083143 100644 +--- a/arch/x86/include/asm/cpufeatures.h ++++ b/arch/x86/include/asm/cpufeatures.h +@@ -308,10 +308,10 @@ + #define X86_FEATURE_SMBA (11*32+21) /* "" Slow Memory Bandwidth Allocation */ + #define X86_FEATURE_BMEC (11*32+22) /* "" Bandwidth Monitoring Event Configuration */ + #define X86_FEATURE_USER_SHSTK (11*32+23) /* Shadow stack support for user mode applications */ +- + #define X86_FEATURE_SRSO (11*32+24) /* "" AMD BTB untrain RETs */ + #define X86_FEATURE_SRSO_ALIAS (11*32+25) /* "" AMD BTB untrain RETs through aliasing */ + #define X86_FEATURE_IBPB_ON_VMEXIT (11*32+26) /* "" Issue an IBPB only on VMEXIT */ ++#define X86_FEATURE_APIC_MSRS_FENCE (11*32+27) /* "" IA32_TSC_DEADLINE and X2APIC MSRs need fencing */ + + /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ + #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */ +diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h +index 071572e23d3a0..cbbef32517f00 100644 +--- a/arch/x86/include/asm/jump_label.h ++++ b/arch/x86/include/asm/jump_label.h +@@ -24,7 +24,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:" ++ asm goto("1:" + "jmp %l[l_yes] # objtool NOPs this \n\t" + JUMP_TABLE_ENTRY + : : "i" (key), "i" (2 | branch) : : l_yes); +@@ -38,7 +38,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) + { +- asm_volatile_goto("1:" ++ asm goto("1:" + ".byte " __stringify(BYTES_NOP5) "\n\t" + JUMP_TABLE_ENTRY + : : "i" (key), "i" (branch) : : l_yes); +@@ -52,7 +52,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co + + static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) + { +- asm_volatile_goto("1:" ++ asm goto("1:" + "jmp %l[l_yes]\n\t" + JUMP_TABLE_ENTRY + : : "i" (key), "i" (branch) : : l_yes); +diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h +index a3669a7774edb..191f1d8f05061 100644 +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -734,4 +734,22 @@ bool arch_is_platform_page(u64 paddr); + + extern bool gds_ucode_mitigated(void); + ++/* ++ * Make previous memory operations globally visible before ++ * a WRMSR. ++ * ++ * MFENCE makes writes visible, but only affects load/store ++ * instructions. WRMSR is unfortunately not a load/store ++ * instruction and is unaffected by MFENCE. The LFENCE ensures ++ * that the WRMSR is not reordered. ++ * ++ * Most WRMSRs are full serializing instructions themselves and ++ * do not require this barrier. This is only required for the ++ * IA32_TSC_DEADLINE and X2APIC MSRs. ++ */ ++static inline void weak_wrmsr_fence(void) ++{ ++ alternative("mfence; lfence", "", ALT_NOT(X86_FEATURE_APIC_MSRS_FENCE)); ++} ++ + #endif /* _ASM_X86_PROCESSOR_H */ +diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h +index 4b081e0d3306b..363266cbcadaf 100644 +--- a/arch/x86/include/asm/rmwcc.h ++++ b/arch/x86/include/asm/rmwcc.h +@@ -13,7 +13,7 @@ + #define __GEN_RMWcc(fullop, _var, cc, clobbers, ...) \ + ({ \ + bool c = false; \ +- asm_volatile_goto (fullop "; j" #cc " %l[cc_label]" \ ++ asm goto (fullop "; j" #cc " %l[cc_label]" \ + : : [var] "m" (_var), ## __VA_ARGS__ \ + : clobbers : cc_label); \ + if (0) { \ +diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h +index d6cd9344f6c78..48f8dd47cf688 100644 +--- a/arch/x86/include/asm/special_insns.h ++++ b/arch/x86/include/asm/special_insns.h +@@ -205,7 +205,7 @@ static inline void clwb(volatile void *__p) + #ifdef CONFIG_X86_USER_SHADOW_STACK + static inline int write_user_shstk_64(u64 __user *addr, u64 val) + { +- asm_volatile_goto("1: wrussq %[val], (%[addr])\n" ++ asm goto("1: wrussq %[val], (%[addr])\n" + _ASM_EXTABLE(1b, %l[fail]) + :: [addr] "r" (addr), [val] "r" (val) + :: fail); +diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h +index 5c367c1290c35..237dc8cdd12b9 100644 +--- a/arch/x86/include/asm/uaccess.h ++++ b/arch/x86/include/asm/uaccess.h +@@ -133,7 +133,7 @@ extern int __get_user_bad(void); + + #ifdef CONFIG_X86_32 + #define __put_user_goto_u64(x, addr, label) \ +- asm_volatile_goto("\n" \ ++ asm goto("\n" \ + "1: movl %%eax,0(%1)\n" \ + "2: movl %%edx,4(%1)\n" \ + _ASM_EXTABLE_UA(1b, %l2) \ +@@ -295,7 +295,7 @@ do { \ + } while (0) + + #define __get_user_asm(x, addr, itype, ltype, label) \ +- asm_volatile_goto("\n" \ ++ asm_goto_output("\n" \ + "1: mov"itype" %[umem],%[output]\n" \ + _ASM_EXTABLE_UA(1b, %l2) \ + : [output] ltype(x) \ +@@ -375,7 +375,7 @@ do { \ + __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ + __typeof__(*(_ptr)) __old = *_old; \ + __typeof__(*(_ptr)) __new = (_new); \ +- asm_volatile_goto("\n" \ ++ asm_goto_output("\n" \ + "1: " LOCK_PREFIX "cmpxchg"itype" %[new], %[ptr]\n"\ + _ASM_EXTABLE_UA(1b, %l[label]) \ + : CC_OUT(z) (success), \ +@@ -394,7 +394,7 @@ do { \ + __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ + __typeof__(*(_ptr)) __old = *_old; \ + __typeof__(*(_ptr)) __new = (_new); \ +- asm_volatile_goto("\n" \ ++ asm_goto_output("\n" \ + "1: " LOCK_PREFIX "cmpxchg8b %[ptr]\n" \ + _ASM_EXTABLE_UA(1b, %l[label]) \ + : CC_OUT(z) (success), \ +@@ -477,7 +477,7 @@ struct __large_struct { unsigned long buf[100]; }; + * aliasing issues. + */ + #define __put_user_goto(x, addr, itype, ltype, label) \ +- asm_volatile_goto("\n" \ ++ asm goto("\n" \ + "1: mov"itype" %0,%1\n" \ + _ASM_EXTABLE_UA(1b, %l2) \ + : : ltype(x), "m" (__m(addr)) \ +diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c +index 6e4f23f314ac5..bb3efc825bf4f 100644 +--- a/arch/x86/kernel/cpu/amd.c ++++ b/arch/x86/kernel/cpu/amd.c +@@ -1157,6 +1157,9 @@ static void init_amd(struct cpuinfo_x86 *c) + if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && + cpu_has_amd_erratum(c, amd_erratum_1485)) + msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT); ++ ++ /* AMD CPUs don't need fencing after x2APIC/TSC_DEADLINE MSR writes. */ ++ clear_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); + } + + #ifdef CONFIG_X86_32 +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index 4e5ffc8b0e469..d98d023ae497f 100644 +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -1858,6 +1858,13 @@ static void identify_cpu(struct cpuinfo_x86 *c) + c->apicid = apic->phys_pkg_id(c->initial_apicid, 0); + #endif + ++ ++ /* ++ * Set default APIC and TSC_DEADLINE MSR fencing flag. AMD and ++ * Hygon will clear it in ->c_init() below. ++ */ ++ set_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); ++ + /* + * Vendor-specific initialization. In this section we + * canonicalize the feature flags, meaning if there are +diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c +index a7b3ef4c4de91..6e738759779e8 100644 +--- a/arch/x86/kernel/cpu/hygon.c ++++ b/arch/x86/kernel/cpu/hygon.c +@@ -348,6 +348,9 @@ static void init_hygon(struct cpuinfo_x86 *c) + set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); + + check_null_seg_clears_base(c); ++ ++ /* Hygon CPUs don't need fencing after x2APIC/TSC_DEADLINE MSR writes. */ ++ clear_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); + } + + static void cpu_detect_tlb_hygon(struct cpuinfo_x86 *c) +diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c +index 558076dbde5bf..247f2225aa9f3 100644 +--- a/arch/x86/kernel/fpu/signal.c ++++ b/arch/x86/kernel/fpu/signal.c +@@ -274,12 +274,13 @@ static int __restore_fpregs_from_user(void __user *buf, u64 ufeatures, + * Attempt to restore the FPU registers directly from user memory. + * Pagefaults are handled and any errors returned are fatal. + */ +-static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, +- bool fx_only, unsigned int size) ++static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, bool fx_only) + { + struct fpu *fpu = ¤t->thread.fpu; + int ret; + ++ /* Restore enabled features only. */ ++ xrestore &= fpu->fpstate->user_xfeatures; + retry: + fpregs_lock(); + /* Ensure that XFD is up to date */ +@@ -309,7 +310,7 @@ static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, + if (ret != X86_TRAP_PF) + return false; + +- if (!fault_in_readable(buf, size)) ++ if (!fault_in_readable(buf, fpu->fpstate->user_size)) + goto retry; + return false; + } +@@ -339,7 +340,6 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx, + struct user_i387_ia32_struct env; + bool success, fx_only = false; + union fpregs_state *fpregs; +- unsigned int state_size; + u64 user_xfeatures = 0; + + if (use_xsave()) { +@@ -349,17 +349,14 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx, + return false; + + fx_only = !fx_sw_user.magic1; +- state_size = fx_sw_user.xstate_size; + user_xfeatures = fx_sw_user.xfeatures; + } else { + user_xfeatures = XFEATURE_MASK_FPSSE; +- state_size = fpu->fpstate->user_size; + } + + if (likely(!ia32_fxstate)) { + /* Restore the FPU registers directly from user memory. */ +- return restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only, +- state_size); ++ return restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only); + } + + /* +diff --git a/arch/x86/kvm/svm/svm_ops.h b/arch/x86/kvm/svm/svm_ops.h +index 36c8af87a707a..4e725854c63a1 100644 +--- a/arch/x86/kvm/svm/svm_ops.h ++++ b/arch/x86/kvm/svm/svm_ops.h +@@ -8,7 +8,7 @@ + + #define svm_asm(insn, clobber...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) "\n\t" \ ++ asm goto("1: " __stringify(insn) "\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ + ::: clobber : fault); \ + return; \ +@@ -18,7 +18,7 @@ fault: \ + + #define svm_asm1(insn, op1, clobber...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) " %0\n\t" \ ++ asm goto("1: " __stringify(insn) " %0\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ + :: op1 : clobber : fault); \ + return; \ +@@ -28,7 +28,7 @@ fault: \ + + #define svm_asm2(insn, op1, op2, clobber...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) " %1, %0\n\t" \ ++ asm goto("1: " __stringify(insn) " %1, %0\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ + :: op1, op2 : clobber : fault); \ + return; \ +diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c +index 90c1f7f07e53b..1549461fa42b7 100644 +--- a/arch/x86/kvm/vmx/pmu_intel.c ++++ b/arch/x86/kvm/vmx/pmu_intel.c +@@ -71,7 +71,7 @@ static int fixed_pmc_events[] = { + static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) + { + struct kvm_pmc *pmc; +- u8 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl; ++ u64 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl; + int i; + + pmu->fixed_ctr_ctrl = data; +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index 9bba5352582c3..792245d7aa356 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -745,7 +745,7 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx, + */ + static int kvm_cpu_vmxoff(void) + { +- asm_volatile_goto("1: vmxoff\n\t" ++ asm goto("1: vmxoff\n\t" + _ASM_EXTABLE(1b, %l[fault]) + ::: "cc", "memory" : fault); + +@@ -2789,7 +2789,7 @@ static int kvm_cpu_vmxon(u64 vmxon_pointer) + + cr4_set_bits(X86_CR4_VMXE); + +- asm_volatile_goto("1: vmxon %[vmxon_pointer]\n\t" ++ asm goto("1: vmxon %[vmxon_pointer]\n\t" + _ASM_EXTABLE(1b, %l[fault]) + : : [vmxon_pointer] "m"(vmxon_pointer) + : : fault); +diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h +index 33af7b4c6eb4a..6a0c6e81f7f3e 100644 +--- a/arch/x86/kvm/vmx/vmx_ops.h ++++ b/arch/x86/kvm/vmx/vmx_ops.h +@@ -94,7 +94,7 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field) + + #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT + +- asm_volatile_goto("1: vmread %[field], %[output]\n\t" ++ asm_goto_output("1: vmread %[field], %[output]\n\t" + "jna %l[do_fail]\n\t" + + _ASM_EXTABLE(1b, %l[do_exception]) +@@ -188,7 +188,7 @@ static __always_inline unsigned long vmcs_readl(unsigned long field) + + #define vmx_asm1(insn, op1, error_args...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) " %0\n\t" \ ++ asm goto("1: " __stringify(insn) " %0\n\t" \ + ".byte 0x2e\n\t" /* branch not taken hint */ \ + "jna %l[error]\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ +@@ -205,7 +205,7 @@ fault: \ + + #define vmx_asm2(insn, op1, op2, error_args...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) " %1, %0\n\t" \ ++ asm goto("1: " __stringify(insn) " %1, %0\n\t" \ + ".byte 0x2e\n\t" /* branch not taken hint */ \ + "jna %l[error]\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index e179db7c17dad..3d8472d00024c 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -5300,7 +5300,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, + if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING) { + vcpu->arch.nmi_pending = 0; + atomic_set(&vcpu->arch.nmi_queued, events->nmi.pending); +- kvm_make_request(KVM_REQ_NMI, vcpu); ++ if (events->nmi.pending) ++ kvm_make_request(KVM_REQ_NMI, vcpu); + } + static_call(kvm_x86_set_nmi_mask)(vcpu, events->nmi.masked); + +diff --git a/arch/x86/mm/ident_map.c b/arch/x86/mm/ident_map.c +index 968d7005f4a72..f50cc210a9818 100644 +--- a/arch/x86/mm/ident_map.c ++++ b/arch/x86/mm/ident_map.c +@@ -26,18 +26,31 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page, + for (; addr < end; addr = next) { + pud_t *pud = pud_page + pud_index(addr); + pmd_t *pmd; ++ bool use_gbpage; + + next = (addr & PUD_MASK) + PUD_SIZE; + if (next > end) + next = end; + +- if (info->direct_gbpages) { +- pud_t pudval; ++ /* if this is already a gbpage, this portion is already mapped */ ++ if (pud_large(*pud)) ++ continue; ++ ++ /* Is using a gbpage allowed? */ ++ use_gbpage = info->direct_gbpages; + +- if (pud_present(*pud)) +- continue; ++ /* Don't use gbpage if it maps more than the requested region. */ ++ /* at the begining: */ ++ use_gbpage &= ((addr & ~PUD_MASK) == 0); ++ /* ... or at the end: */ ++ use_gbpage &= ((next & ~PUD_MASK) == 0); ++ ++ /* Never overwrite existing mappings */ ++ use_gbpage &= !pud_present(*pud); ++ ++ if (use_gbpage) { ++ pud_t pudval; + +- addr &= PUD_MASK; + pudval = __pud((addr - info->offset) | info->page_flag); + set_pud(pud, pudval); + continue; +diff --git a/arch/xtensa/include/asm/jump_label.h b/arch/xtensa/include/asm/jump_label.h +index c812bf85021c0..46c8596259d2d 100644 +--- a/arch/xtensa/include/asm/jump_label.h ++++ b/arch/xtensa/include/asm/jump_label.h +@@ -13,7 +13,7 @@ + static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "_nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".word 1b, %l[l_yes], %c0\n\t" +@@ -38,7 +38,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, + * make it reachable and wrap both into a no-transform block + * to avoid any assembler interference with this. + */ +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + ".begin no-transform\n\t" + "_j %l[l_yes]\n\t" + "2:\n\t" +diff --git a/block/blk-mq.c b/block/blk-mq.c +index 257b0addd47e5..d8b47f534df93 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -767,11 +767,16 @@ static void req_bio_endio(struct request *rq, struct bio *bio, + /* + * Partial zone append completions cannot be supported as the + * BIO fragments may end up not being written sequentially. ++ * For such case, force the completed nbytes to be equal to ++ * the BIO size so that bio_advance() sets the BIO remaining ++ * size to 0 and we end up calling bio_endio() before returning. + */ +- if (bio->bi_iter.bi_size != nbytes) ++ if (bio->bi_iter.bi_size != nbytes) { + bio->bi_status = BLK_STS_IOERR; +- else ++ nbytes = bio->bi_iter.bi_size; ++ } else { + bio->bi_iter.bi_sector = rq->__sector; ++ } + } + + bio_advance(bio, nbytes); +diff --git a/block/blk-wbt.c b/block/blk-wbt.c +index 0bb613139becb..f8fda9cf583e1 100644 +--- a/block/blk-wbt.c ++++ b/block/blk-wbt.c +@@ -165,9 +165,9 @@ static void wb_timestamp(struct rq_wb *rwb, unsigned long *var) + */ + static bool wb_recent_wait(struct rq_wb *rwb) + { +- struct bdi_writeback *wb = &rwb->rqos.disk->bdi->wb; ++ struct backing_dev_info *bdi = rwb->rqos.disk->bdi; + +- return time_before(jiffies, wb->dirty_sleep + HZ); ++ return time_before(jiffies, bdi->last_bdp_sleep + HZ); + } + + static inline struct rq_wait *get_rq_wait(struct rq_wb *rwb, +diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c +index 82c44d4899b96..e24c829d7a015 100644 +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -91,13 +91,13 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, + if (!(msg->msg_flags & MSG_MORE)) { + err = hash_alloc_result(sk, ctx); + if (err) +- goto unlock_free; ++ goto unlock_free_result; + ahash_request_set_crypt(&ctx->req, NULL, + ctx->result, 0); + err = crypto_wait_req(crypto_ahash_final(&ctx->req), + &ctx->wait); + if (err) +- goto unlock_free; ++ goto unlock_free_result; + } + goto done_more; + } +@@ -170,6 +170,7 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, + + unlock_free: + af_alg_free_sg(&ctx->sgl); ++unlock_free_result: + hash_free_result(sk, ctx); + ctx->more = false; + goto unlock; +diff --git a/drivers/android/binder.c b/drivers/android/binder.c +index 71a40a4c546f5..8460458ebe3d4 100644 +--- a/drivers/android/binder.c ++++ b/drivers/android/binder.c +@@ -478,6 +478,16 @@ binder_enqueue_thread_work_ilocked(struct binder_thread *thread, + { + WARN_ON(!list_empty(&thread->waiting_thread_node)); + binder_enqueue_work_ilocked(work, &thread->todo); ++ ++ /* (e)poll-based threads require an explicit wakeup signal when ++ * queuing their own work; they rely on these events to consume ++ * messages without I/O block. Without it, threads risk waiting ++ * indefinitely without handling the work. ++ */ ++ if (thread->looper & BINDER_LOOPER_STATE_POLL && ++ thread->pid == current->pid && !thread->process_todo) ++ wake_up_interruptible_sync(&thread->wait); ++ + thread->process_todo = true; + } + +diff --git a/drivers/base/core.c b/drivers/base/core.c +index 4d8b315c48a15..2cc0ab8541680 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -283,10 +283,12 @@ static bool device_is_ancestor(struct device *dev, struct device *target) + return false; + } + ++#define DL_MARKER_FLAGS (DL_FLAG_INFERRED | \ ++ DL_FLAG_CYCLE | \ ++ DL_FLAG_MANAGED) + static inline bool device_link_flag_is_sync_state_only(u32 flags) + { +- return (flags & ~(DL_FLAG_INFERRED | DL_FLAG_CYCLE)) == +- (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED); ++ return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY; + } + + /** +@@ -2057,9 +2059,14 @@ static int fw_devlink_create_devlink(struct device *con, + + /* + * SYNC_STATE_ONLY device links don't block probing and supports cycles. +- * So cycle detection isn't necessary and shouldn't be done. ++ * So, one might expect that cycle detection isn't necessary for them. ++ * However, if the device link was marked as SYNC_STATE_ONLY because ++ * it's part of a cycle, then we still need to do cycle detection. This ++ * is because the consumer and supplier might be part of multiple cycles ++ * and we need to detect all those cycles. + */ +- if (!(flags & DL_FLAG_SYNC_STATE_ONLY)) { ++ if (!device_link_flag_is_sync_state_only(flags) || ++ flags & DL_FLAG_CYCLE) { + device_links_write_lock(); + if (__fw_devlink_relax_cycles(con, sup_handle)) { + __fwnode_link_cycle(link); +diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c +index 5cb2023581d4d..84443b6bd8825 100644 +--- a/drivers/base/power/domain.c ++++ b/drivers/base/power/domain.c +@@ -1102,7 +1102,7 @@ static int __init genpd_power_off_unused(void) + + return 0; + } +-late_initcall(genpd_power_off_unused); ++late_initcall_sync(genpd_power_off_unused); + + #ifdef CONFIG_PM_SLEEP + +diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c +index 3d5e6d705fc6e..44b19e6961763 100644 +--- a/drivers/connector/cn_proc.c ++++ b/drivers/connector/cn_proc.c +@@ -108,9 +108,8 @@ static inline void send_msg(struct cn_msg *msg) + filter_data[1] = 0; + } + +- if (cn_netlink_send_mult(msg, msg->len, 0, CN_IDX_PROC, GFP_NOWAIT, +- cn_filter, (void *)filter_data) == -ESRCH) +- atomic_set(&proc_event_num_listeners, 0); ++ cn_netlink_send_mult(msg, msg->len, 0, CN_IDX_PROC, GFP_NOWAIT, ++ cn_filter, (void *)filter_data); + + local_unlock(&local_event.lock); + } +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index f97166fba9d93..17fb01853dbf4 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -520,10 +520,16 @@ EXPORT_SYMBOL_GPL(sev_platform_init); + + static int __sev_platform_shutdown_locked(int *error) + { +- struct sev_device *sev = psp_master->sev_data; ++ struct psp_device *psp = psp_master; ++ struct sev_device *sev; + int ret; + +- if (!sev || sev->state == SEV_STATE_UNINIT) ++ if (!psp || !psp->sev_data) ++ return 0; ++ ++ sev = psp->sev_data; ++ ++ if (sev->state == SEV_STATE_UNINIT) + return 0; + + ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error); +diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c +index 2828e9573e90b..da8a4c8f28768 100644 +--- a/drivers/firewire/core-device.c ++++ b/drivers/firewire/core-device.c +@@ -100,10 +100,9 @@ static int textual_leaf_to_string(const u32 *block, char *buf, size_t size) + * @buf: where to put the string + * @size: size of @buf, in bytes + * +- * The string is taken from a minimal ASCII text descriptor leaf after +- * the immediate entry with @key. The string is zero-terminated. +- * An overlong string is silently truncated such that it and the +- * zero byte fit into @size. ++ * The string is taken from a minimal ASCII text descriptor leaf just after the entry with the ++ * @key. The string is zero-terminated. An overlong string is silently truncated such that it ++ * and the zero byte fit into @size. + * + * Returns strlen(buf) or a negative error code. + */ +diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile +index a1157c2a71704..ef4c12f0877ba 100644 +--- a/drivers/firmware/efi/libstub/Makefile ++++ b/drivers/firmware/efi/libstub/Makefile +@@ -108,13 +108,6 @@ lib-y := $(patsubst %.o,%.stub.o,$(lib-y)) + # https://bugs.llvm.org/show_bug.cgi?id=46480 + STUBCOPY_FLAGS-y += --remove-section=.note.gnu.property + +-# +-# For x86, bootloaders like systemd-boot or grub-efi do not zero-initialize the +-# .bss section, so the .bss section of the EFI stub needs to be included in the +-# .data section of the compressed kernel to ensure initialization. Rename the +-# .bss section here so it's easy to pick out in the linker script. +-# +-STUBCOPY_FLAGS-$(CONFIG_X86) += --rename-section .bss=.bss.efistub,load,alloc + STUBCOPY_RELOC-$(CONFIG_X86_32) := R_386_32 + STUBCOPY_RELOC-$(CONFIG_X86_64) := R_X86_64_64 + +diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c +index 4a11470bed5ea..7bcc5170043fc 100644 +--- a/drivers/firmware/efi/libstub/x86-stub.c ++++ b/drivers/firmware/efi/libstub/x86-stub.c +@@ -458,9 +458,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle, + efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, + efi_system_table_t *sys_table_arg) + { +- struct boot_params *boot_params; +- struct setup_header *hdr; +- void *image_base; ++ static struct boot_params boot_params __page_aligned_bss; ++ struct setup_header *hdr = &boot_params.hdr; + efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; + int options_size = 0; + efi_status_t status; +@@ -478,30 +477,9 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, + efi_exit(handle, status); + } + +- image_base = efi_table_attr(image, image_base); +- +- status = efi_allocate_pages(sizeof(struct boot_params), +- (unsigned long *)&boot_params, ULONG_MAX); +- if (status != EFI_SUCCESS) { +- efi_err("Failed to allocate lowmem for boot params\n"); +- efi_exit(handle, status); +- } +- +- memset(boot_params, 0x0, sizeof(struct boot_params)); +- +- hdr = &boot_params->hdr; +- +- /* Copy the setup header from the second sector to boot_params */ +- memcpy(&hdr->jump, image_base + 512, +- sizeof(struct setup_header) - offsetof(struct setup_header, jump)); +- +- /* +- * Fill out some of the header fields ourselves because the +- * EFI firmware loader doesn't load the first sector. +- */ ++ /* Assign the setup_header fields that the kernel actually cares about */ + hdr->root_flags = 1; + hdr->vid_mode = 0xffff; +- hdr->boot_flag = 0xAA55; + + hdr->type_of_loader = 0x21; + +@@ -510,25 +488,13 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, + if (!cmdline_ptr) + goto fail; + +- efi_set_u64_split((unsigned long)cmdline_ptr, +- &hdr->cmd_line_ptr, &boot_params->ext_cmd_line_ptr); +- +- hdr->ramdisk_image = 0; +- hdr->ramdisk_size = 0; +- +- /* +- * Disregard any setup data that was provided by the bootloader: +- * setup_data could be pointing anywhere, and we have no way of +- * authenticating or validating the payload. +- */ +- hdr->setup_data = 0; ++ efi_set_u64_split((unsigned long)cmdline_ptr, &hdr->cmd_line_ptr, ++ &boot_params.ext_cmd_line_ptr); + +- efi_stub_entry(handle, sys_table_arg, boot_params); ++ efi_stub_entry(handle, sys_table_arg, &boot_params); + /* not reached */ + + fail: +- efi_free(sizeof(struct boot_params), (unsigned long)boot_params); +- + efi_exit(handle, status); + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 7791367e7c024..79261bec26542 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -4133,7 +4133,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) + drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true); + + cancel_delayed_work_sync(&adev->delayed_init_work); +- flush_delayed_work(&adev->gfx.gfx_off_delay_work); + + amdgpu_ras_suspend(adev); + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +index ef4cb921781d7..053983e9f4aef 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +@@ -702,8 +702,15 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable) + + if (adev->gfx.gfx_off_req_count == 0 && + !adev->gfx.gfx_off_state) { +- schedule_delayed_work(&adev->gfx.gfx_off_delay_work, ++ /* If going to s2idle, no need to wait */ ++ if (adev->in_s0ix) { ++ if (!amdgpu_dpm_set_powergating_by_smu(adev, ++ AMD_IP_BLOCK_TYPE_GFX, true)) ++ adev->gfx.gfx_off_state = true; ++ } else { ++ schedule_delayed_work(&adev->gfx.gfx_off_delay_work, + delay); ++ } + } + } else { + if (adev->gfx.gfx_off_req_count == 0) { +diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c +index 6f7c031dd197a..f24e34dc33d1d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c +@@ -204,6 +204,12 @@ static u32 cik_ih_get_wptr(struct amdgpu_device *adev, + tmp = RREG32(mmIH_RB_CNTL); + tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; + WREG32(mmIH_RB_CNTL, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; ++ WREG32(mmIH_RB_CNTL, tmp); + } + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c +index b8c47e0cf37ad..c19681492efa7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c +@@ -216,6 +216,11 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32(mmIH_RB_CNTL, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32(mmIH_RB_CNTL, tmp); + + out: + return (wptr & ih->ptr_mask); +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index c2b9dfc6451d5..495eb4cad0e1a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -4020,8 +4020,6 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) + err = 0; + adev->gfx.mec2_fw = NULL; + } +- amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2); +- amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT); + + gfx_v10_0_check_fw_write_wait(adev); + out: +diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +index aecad530b10a6..2c02ae69883d2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +@@ -215,6 +215,11 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32(mmIH_RB_CNTL, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32(mmIH_RB_CNTL, tmp); + + out: + return (wptr & ih->ptr_mask); +diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c +index ec0c8f8b465ab..f432dc72df6a9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c +@@ -418,6 +418,12 @@ static u32 ih_v6_0_get_wptr(struct amdgpu_device *adev, + tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c +index 8fb05eae340ad..b8da0fc29378c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c +@@ -418,6 +418,13 @@ static u32 ih_v6_1_get_wptr(struct amdgpu_device *adev, + tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +index b6a8478dabf43..737eff53f54f0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +@@ -442,6 +442,12 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev, + tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c +index 9a24f17a57502..cada9f300a7f5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c +@@ -119,6 +119,12 @@ static u32 si_ih_get_wptr(struct amdgpu_device *adev, + tmp = RREG32(IH_RB_CNTL); + tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; + WREG32(IH_RB_CNTL, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; ++ WREG32(IH_RB_CNTL, tmp); + } + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c +index 8b2ff2b281b0a..5a77ab587b599 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc21.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc21.c +@@ -50,13 +50,13 @@ static const struct amd_ip_funcs soc21_common_ip_funcs; + /* SOC21 */ + static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn0[] = { + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, + }; + + static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn1[] = { + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 0)}, + }; + + static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode_vcn0 = { +diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +index 917707bba7f36..450b6e8315091 100644 +--- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +@@ -219,6 +219,12 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32(mmIH_RB_CNTL, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32(mmIH_RB_CNTL, tmp); ++ + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +index d364c6dd152c3..bf68e18e3824b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +@@ -373,6 +373,12 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +index dbc99536440f2..131e7b769519c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +@@ -421,6 +421,12 @@ static u32 vega20_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 56a61ac2b3f5a..83c263e2d7171 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -6072,7 +6072,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + if (recalculate_timing) { + freesync_mode = get_highest_refresh_rate_mode(aconnector, false); + drm_mode_copy(&saved_mode, &mode); ++ saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio; + drm_mode_copy(&mode, freesync_mode); ++ mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio; + } else { + decide_crtc_timing_for_drm_display_mode( + &mode, preferred_mode, scale); +@@ -10358,11 +10360,13 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + goto fail; + } + +- ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); +- if (ret) { +- DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); +- ret = -EINVAL; +- goto fail; ++ if (dc_resource_is_dsc_encoding_supported(dc)) { ++ ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); ++ if (ret) { ++ DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); ++ ret = -EINVAL; ++ goto fail; ++ } + } + + ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context, vars); +diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile +index c206812dc6897..0ba9a7997d561 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile +@@ -72,11 +72,11 @@ CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn10/dcn10_fpu.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/dcn20_fpu.o := $(dml_ccflags) +-CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags) ++CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20.o := $(dml_ccflags) +-CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) ++CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20v2.o := $(dml_ccflags) +-CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags) ++CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_rq_dlg_calc_21.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +index 5a0b045189569..16a62e0187122 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +@@ -517,6 +517,7 @@ enum link_training_result dp_check_link_loss_status( + { + enum link_training_result status = LINK_TRAINING_SUCCESS; + union lane_status lane_status; ++ union lane_align_status_updated dpcd_lane_status_updated; + uint8_t dpcd_buf[6] = {0}; + uint32_t lane; + +@@ -532,10 +533,12 @@ enum link_training_result dp_check_link_loss_status( + * check lanes status + */ + lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane); ++ dpcd_lane_status_updated.raw = dpcd_buf[4]; + + if (!lane_status.bits.CHANNEL_EQ_DONE_0 || + !lane_status.bits.CR_DONE_0 || +- !lane_status.bits.SYMBOL_LOCKED_0) { ++ !lane_status.bits.SYMBOL_LOCKED_0 || ++ !dp_is_interlane_aligned(dpcd_lane_status_updated)) { + /* if one of the channel equalization, clock + * recovery or symbol lock is dropped + * consider it as (link has been +diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c +index 834a5e28abbe5..7352bde299d54 100644 +--- a/drivers/gpu/drm/drm_prime.c ++++ b/drivers/gpu/drm/drm_prime.c +@@ -820,7 +820,7 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev, + if (max_segment == 0) + max_segment = UINT_MAX; + err = sg_alloc_table_from_pages_segment(sg, pages, nr_pages, 0, +- nr_pages << PAGE_SHIFT, ++ (unsigned long)nr_pages << PAGE_SHIFT, + max_segment, GFP_KERNEL); + if (err) { + kfree(sg); +diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c +index 5f68e31a3e4e1..0915f3b68752e 100644 +--- a/drivers/gpu/drm/msm/msm_gem_prime.c ++++ b/drivers/gpu/drm/msm/msm_gem_prime.c +@@ -26,7 +26,7 @@ int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) + { + void *vaddr; + +- vaddr = msm_gem_get_vaddr(obj); ++ vaddr = msm_gem_get_vaddr_locked(obj); + if (IS_ERR(vaddr)) + return PTR_ERR(vaddr); + iosys_map_set_vaddr(map, vaddr); +@@ -36,7 +36,7 @@ int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) + + void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map) + { +- msm_gem_put_vaddr(obj); ++ msm_gem_put_vaddr_locked(obj); + } + + struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, +diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c +index 7f64c66673002..5c10b559a5957 100644 +--- a/drivers/gpu/drm/msm/msm_gpu.c ++++ b/drivers/gpu/drm/msm/msm_gpu.c +@@ -749,12 +749,14 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + struct msm_ringbuffer *ring = submit->ring; + unsigned long flags; + +- pm_runtime_get_sync(&gpu->pdev->dev); ++ WARN_ON(!mutex_is_locked(&gpu->lock)); + +- mutex_lock(&gpu->lock); ++ pm_runtime_get_sync(&gpu->pdev->dev); + + msm_gpu_hw_init(gpu); + ++ submit->seqno = submit->hw_fence->seqno; ++ + update_sw_cntrs(gpu); + + /* +@@ -779,11 +781,8 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + gpu->funcs->submit(gpu, submit); + gpu->cur_ctx_seqno = submit->queue->ctx->seqno; + +- hangcheck_timer_reset(gpu); +- +- mutex_unlock(&gpu->lock); +- + pm_runtime_put(&gpu->pdev->dev); ++ hangcheck_timer_reset(gpu); + } + + /* +diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c +index 5cc8d358cc975..d5512037c38bc 100644 +--- a/drivers/gpu/drm/msm/msm_iommu.c ++++ b/drivers/gpu/drm/msm/msm_iommu.c +@@ -21,6 +21,8 @@ struct msm_iommu_pagetable { + struct msm_mmu base; + struct msm_mmu *parent; + struct io_pgtable_ops *pgtbl_ops; ++ const struct iommu_flush_ops *tlb; ++ struct device *iommu_dev; + unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */ + phys_addr_t ttbr; + u32 asid; +@@ -201,11 +203,33 @@ static const struct msm_mmu_funcs pagetable_funcs = { + + static void msm_iommu_tlb_flush_all(void *cookie) + { ++ struct msm_iommu_pagetable *pagetable = cookie; ++ struct adreno_smmu_priv *adreno_smmu; ++ ++ if (!pm_runtime_get_if_in_use(pagetable->iommu_dev)) ++ return; ++ ++ adreno_smmu = dev_get_drvdata(pagetable->parent->dev); ++ ++ pagetable->tlb->tlb_flush_all((void *)adreno_smmu->cookie); ++ ++ pm_runtime_put_autosuspend(pagetable->iommu_dev); + } + + static void msm_iommu_tlb_flush_walk(unsigned long iova, size_t size, + size_t granule, void *cookie) + { ++ struct msm_iommu_pagetable *pagetable = cookie; ++ struct adreno_smmu_priv *adreno_smmu; ++ ++ if (!pm_runtime_get_if_in_use(pagetable->iommu_dev)) ++ return; ++ ++ adreno_smmu = dev_get_drvdata(pagetable->parent->dev); ++ ++ pagetable->tlb->tlb_flush_walk(iova, size, granule, (void *)adreno_smmu->cookie); ++ ++ pm_runtime_put_autosuspend(pagetable->iommu_dev); + } + + static void msm_iommu_tlb_add_page(struct iommu_iotlb_gather *gather, +@@ -213,7 +237,7 @@ static void msm_iommu_tlb_add_page(struct iommu_iotlb_gather *gather, + { + } + +-static const struct iommu_flush_ops null_tlb_ops = { ++static const struct iommu_flush_ops tlb_ops = { + .tlb_flush_all = msm_iommu_tlb_flush_all, + .tlb_flush_walk = msm_iommu_tlb_flush_walk, + .tlb_add_page = msm_iommu_tlb_add_page, +@@ -254,10 +278,10 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) + + /* The incoming cfg will have the TTBR1 quirk enabled */ + ttbr0_cfg.quirks &= ~IO_PGTABLE_QUIRK_ARM_TTBR1; +- ttbr0_cfg.tlb = &null_tlb_ops; ++ ttbr0_cfg.tlb = &tlb_ops; + + pagetable->pgtbl_ops = alloc_io_pgtable_ops(ARM_64_LPAE_S1, +- &ttbr0_cfg, iommu->domain); ++ &ttbr0_cfg, pagetable); + + if (!pagetable->pgtbl_ops) { + kfree(pagetable); +@@ -279,6 +303,8 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) + + /* Needed later for TLB flush */ + pagetable->parent = parent; ++ pagetable->tlb = ttbr1_cfg->tlb; ++ pagetable->iommu_dev = ttbr1_cfg->iommu_dev; + pagetable->pgsize_bitmap = ttbr0_cfg.pgsize_bitmap; + pagetable->ttbr = ttbr0_cfg.arm_lpae_s1_cfg.ttbr; + +diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c +index 40c0bc35a44ce..7f5e0a961bba7 100644 +--- a/drivers/gpu/drm/msm/msm_ringbuffer.c ++++ b/drivers/gpu/drm/msm/msm_ringbuffer.c +@@ -21,8 +21,6 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) + + msm_fence_init(submit->hw_fence, fctx); + +- submit->seqno = submit->hw_fence->seqno; +- + mutex_lock(&priv->lru.lock); + + for (i = 0; i < submit->nr_bos; i++) { +@@ -34,8 +32,13 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) + + mutex_unlock(&priv->lru.lock); + ++ /* TODO move submit path over to using a per-ring lock.. */ ++ mutex_lock(&gpu->lock); ++ + msm_gpu_submit(gpu, submit); + ++ mutex_unlock(&gpu->lock); ++ + return dma_fence_get(submit->hw_fence); + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c +index ca762ea554136..93f08f9479d89 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fence.c ++++ b/drivers/gpu/drm/nouveau/nouveau_fence.c +@@ -103,6 +103,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) + void + nouveau_fence_context_del(struct nouveau_fence_chan *fctx) + { ++ cancel_work_sync(&fctx->uevent_work); + nouveau_fence_context_kill(fctx, 0); + nvif_event_dtor(&fctx->event); + fctx->dead = 1; +@@ -145,12 +146,13 @@ nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fc + return drop; + } + +-static int +-nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc) ++static void ++nouveau_fence_uevent_work(struct work_struct *work) + { +- struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event); ++ struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan, ++ uevent_work); + unsigned long flags; +- int ret = NVIF_EVENT_KEEP; ++ int drop = 0; + + spin_lock_irqsave(&fctx->lock, flags); + if (!list_empty(&fctx->pending)) { +@@ -160,11 +162,20 @@ nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc + fence = list_entry(fctx->pending.next, typeof(*fence), head); + chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); + if (nouveau_fence_update(chan, fctx)) +- ret = NVIF_EVENT_DROP; ++ drop = 1; + } ++ if (drop) ++ nvif_event_block(&fctx->event); ++ + spin_unlock_irqrestore(&fctx->lock, flags); ++} + +- return ret; ++static int ++nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc) ++{ ++ struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event); ++ schedule_work(&fctx->uevent_work); ++ return NVIF_EVENT_KEEP; + } + + void +@@ -178,6 +189,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha + } args; + int ret; + ++ INIT_WORK(&fctx->uevent_work, nouveau_fence_uevent_work); + INIT_LIST_HEAD(&fctx->flip); + INIT_LIST_HEAD(&fctx->pending); + spin_lock_init(&fctx->lock); +diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h +index 64d33ae7f3561..8bc065acfe358 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fence.h ++++ b/drivers/gpu/drm/nouveau/nouveau_fence.h +@@ -44,6 +44,7 @@ struct nouveau_fence_chan { + u32 context; + char name[32]; + ++ struct work_struct uevent_work; + struct nvif_event event; + int notify_ref, dead, killed; + }; +diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c +index 186351ecf72fd..ec9f307370fa8 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_svm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_svm.c +@@ -1011,7 +1011,7 @@ nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id) + if (ret) + return ret; + +- buffer->fault = kvcalloc(sizeof(*buffer->fault), buffer->entries, GFP_KERNEL); ++ buffer->fault = kvcalloc(buffer->entries, sizeof(*buffer->fault), GFP_KERNEL); + if (!buffer->fault) + return -ENOMEM; + +diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c +index 148f09aaf99a7..c5716fd0aed38 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_drv.c ++++ b/drivers/gpu/drm/virtio/virtgpu_drv.c +@@ -94,6 +94,7 @@ static int virtio_gpu_probe(struct virtio_device *vdev) + goto err_free; + } + ++ dma_set_max_seg_size(dev->dev, dma_max_mapping_size(dev->dev) ?: UINT_MAX); + ret = virtio_gpu_init(vdev, dev); + if (ret) + goto err_free; +diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c +index d9ef45fcaeab1..7903c8638e817 100644 +--- a/drivers/hid/bpf/hid_bpf_dispatch.c ++++ b/drivers/hid/bpf/hid_bpf_dispatch.c +@@ -241,6 +241,39 @@ int hid_bpf_reconnect(struct hid_device *hdev) + return 0; + } + ++static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct bpf_prog *prog, ++ __u32 flags) ++{ ++ int fd, err, prog_type; ++ ++ prog_type = hid_bpf_get_prog_attach_type(prog); ++ if (prog_type < 0) ++ return prog_type; ++ ++ if (prog_type >= HID_BPF_PROG_TYPE_MAX) ++ return -EINVAL; ++ ++ if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) { ++ err = hid_bpf_allocate_event_data(hdev); ++ if (err) ++ return err; ++ } ++ ++ fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, prog, flags); ++ if (fd < 0) ++ return fd; ++ ++ if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) { ++ err = hid_bpf_reconnect(hdev); ++ if (err) { ++ close_fd(fd); ++ return err; ++ } ++ } ++ ++ return fd; ++} ++ + /** + * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device + * +@@ -257,18 +290,13 @@ noinline int + hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) + { + struct hid_device *hdev; ++ struct bpf_prog *prog; + struct device *dev; +- int fd, err, prog_type = hid_bpf_get_prog_attach_type(prog_fd); ++ int err, fd; + + if (!hid_bpf_ops) + return -EINVAL; + +- if (prog_type < 0) +- return prog_type; +- +- if (prog_type >= HID_BPF_PROG_TYPE_MAX) +- return -EINVAL; +- + if ((flags & ~HID_BPF_FLAG_MASK)) + return -EINVAL; + +@@ -278,25 +306,29 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) + + hdev = to_hid_device(dev); + +- if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) { +- err = hid_bpf_allocate_event_data(hdev); +- if (err) +- return err; ++ /* ++ * take a ref on the prog itself, it will be released ++ * on errors or when it'll be detached ++ */ ++ prog = bpf_prog_get(prog_fd); ++ if (IS_ERR(prog)) { ++ err = PTR_ERR(prog); ++ goto out_dev_put; + } + +- fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags); +- if (fd < 0) +- return fd; +- +- if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) { +- err = hid_bpf_reconnect(hdev); +- if (err) { +- close_fd(fd); +- return err; +- } ++ fd = do_hid_bpf_attach_prog(hdev, prog_fd, prog, flags); ++ if (fd < 0) { ++ err = fd; ++ goto out_prog_put; + } + + return fd; ++ ++ out_prog_put: ++ bpf_prog_put(prog); ++ out_dev_put: ++ put_device(dev); ++ return err; + } + + /** +@@ -323,8 +355,10 @@ hid_bpf_allocate_context(unsigned int hid_id) + hdev = to_hid_device(dev); + + ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL); +- if (!ctx_kern) ++ if (!ctx_kern) { ++ put_device(dev); + return NULL; ++ } + + ctx_kern->ctx.hid = hdev; + +@@ -341,10 +375,15 @@ noinline void + hid_bpf_release_context(struct hid_bpf_ctx *ctx) + { + struct hid_bpf_ctx_kern *ctx_kern; ++ struct hid_device *hid; + + ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); ++ hid = (struct hid_device *)ctx_kern->ctx.hid; /* ignore const */ + + kfree(ctx_kern); ++ ++ /* get_device() is called by bus_find_device() */ ++ put_device(&hid->dev); + } + + /** +diff --git a/drivers/hid/bpf/hid_bpf_dispatch.h b/drivers/hid/bpf/hid_bpf_dispatch.h +index 63dfc8605cd21..fbe0639d09f26 100644 +--- a/drivers/hid/bpf/hid_bpf_dispatch.h ++++ b/drivers/hid/bpf/hid_bpf_dispatch.h +@@ -12,9 +12,9 @@ struct hid_bpf_ctx_kern { + + int hid_bpf_preload_skel(void); + void hid_bpf_free_links_and_skel(void); +-int hid_bpf_get_prog_attach_type(int prog_fd); ++int hid_bpf_get_prog_attach_type(struct bpf_prog *prog); + int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd, +- __u32 flags); ++ struct bpf_prog *prog, __u32 flags); + void __hid_bpf_destroy_device(struct hid_device *hdev); + int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type, + struct hid_bpf_ctx_kern *ctx_kern); +diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c +index eca34b7372f95..aa8e1c79cdf55 100644 +--- a/drivers/hid/bpf/hid_bpf_jmp_table.c ++++ b/drivers/hid/bpf/hid_bpf_jmp_table.c +@@ -196,6 +196,7 @@ static void __hid_bpf_do_release_prog(int map_fd, unsigned int idx) + static void hid_bpf_release_progs(struct work_struct *work) + { + int i, j, n, map_fd = -1; ++ bool hdev_destroyed; + + if (!jmp_table.map) + return; +@@ -220,6 +221,12 @@ static void hid_bpf_release_progs(struct work_struct *work) + if (entry->hdev) { + hdev = entry->hdev; + type = entry->type; ++ /* ++ * hdev is still valid, even if we are called after hid_destroy_device(): ++ * when hid_bpf_attach() gets called, it takes a ref on the dev through ++ * bus_find_device() ++ */ ++ hdev_destroyed = hdev->bpf.destroyed; + + hid_bpf_populate_hdev(hdev, type); + +@@ -232,12 +239,19 @@ static void hid_bpf_release_progs(struct work_struct *work) + if (test_bit(next->idx, jmp_table.enabled)) + continue; + +- if (next->hdev == hdev && next->type == type) ++ if (next->hdev == hdev && next->type == type) { ++ /* ++ * clear the hdev reference and decrement the device ref ++ * that was taken during bus_find_device() while calling ++ * hid_bpf_attach() ++ */ + next->hdev = NULL; ++ put_device(&hdev->dev); ++ } + } + +- /* if type was rdesc fixup, reconnect device */ +- if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP) ++ /* if type was rdesc fixup and the device is not gone, reconnect device */ ++ if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP && !hdev_destroyed) + hid_bpf_reconnect(hdev); + } + } +@@ -333,15 +347,10 @@ static int hid_bpf_insert_prog(int prog_fd, struct bpf_prog *prog) + return err; + } + +-int hid_bpf_get_prog_attach_type(int prog_fd) ++int hid_bpf_get_prog_attach_type(struct bpf_prog *prog) + { +- struct bpf_prog *prog = NULL; +- int i; + int prog_type = HID_BPF_PROG_TYPE_UNDEF; +- +- prog = bpf_prog_get(prog_fd); +- if (IS_ERR(prog)) +- return PTR_ERR(prog); ++ int i; + + for (i = 0; i < HID_BPF_PROG_TYPE_MAX; i++) { + if (hid_bpf_btf_ids[i] == prog->aux->attach_btf_id) { +@@ -350,8 +359,6 @@ int hid_bpf_get_prog_attach_type(int prog_fd) + } + } + +- bpf_prog_put(prog); +- + return prog_type; + } + +@@ -388,19 +395,13 @@ static const struct bpf_link_ops hid_bpf_link_lops = { + /* called from syscall */ + noinline int + __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, +- int prog_fd, __u32 flags) ++ int prog_fd, struct bpf_prog *prog, __u32 flags) + { + struct bpf_link_primer link_primer; + struct hid_bpf_link *link; +- struct bpf_prog *prog = NULL; + struct hid_bpf_prog_entry *prog_entry; + int cnt, err = -EINVAL, prog_table_idx = -1; + +- /* take a ref on the prog itself */ +- prog = bpf_prog_get(prog_fd); +- if (IS_ERR(prog)) +- return PTR_ERR(prog); +- + mutex_lock(&hid_bpf_attach_lock); + + link = kzalloc(sizeof(*link), GFP_USER); +@@ -467,7 +468,6 @@ __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, + err_unlock: + mutex_unlock(&hid_bpf_attach_lock); + +- bpf_prog_put(prog); + kfree(link); + + return err; +diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c +index c4e1fa0273c84..8be4d576da773 100644 +--- a/drivers/hid/i2c-hid/i2c-hid-of.c ++++ b/drivers/hid/i2c-hid/i2c-hid-of.c +@@ -87,6 +87,7 @@ static int i2c_hid_of_probe(struct i2c_client *client) + if (!ihid_of) + return -ENOMEM; + ++ ihid_of->client = client; + ihid_of->ops.power_up = i2c_hid_of_power_up; + ihid_of->ops.power_down = i2c_hid_of_power_down; + +diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c +index 3f704b8072e8a..7659c98d94292 100644 +--- a/drivers/hid/wacom_sys.c ++++ b/drivers/hid/wacom_sys.c +@@ -2080,7 +2080,7 @@ static int wacom_allocate_inputs(struct wacom *wacom) + return 0; + } + +-static int wacom_register_inputs(struct wacom *wacom) ++static int wacom_setup_inputs(struct wacom *wacom) + { + struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); +@@ -2099,10 +2099,6 @@ static int wacom_register_inputs(struct wacom *wacom) + input_free_device(pen_input_dev); + wacom_wac->pen_input = NULL; + pen_input_dev = NULL; +- } else { +- error = input_register_device(pen_input_dev); +- if (error) +- goto fail; + } + + error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac); +@@ -2111,10 +2107,6 @@ static int wacom_register_inputs(struct wacom *wacom) + input_free_device(touch_input_dev); + wacom_wac->touch_input = NULL; + touch_input_dev = NULL; +- } else { +- error = input_register_device(touch_input_dev); +- if (error) +- goto fail; + } + + error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); +@@ -2123,7 +2115,34 @@ static int wacom_register_inputs(struct wacom *wacom) + input_free_device(pad_input_dev); + wacom_wac->pad_input = NULL; + pad_input_dev = NULL; +- } else { ++ } ++ ++ return 0; ++} ++ ++static int wacom_register_inputs(struct wacom *wacom) ++{ ++ struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; ++ struct wacom_wac *wacom_wac = &(wacom->wacom_wac); ++ int error = 0; ++ ++ pen_input_dev = wacom_wac->pen_input; ++ touch_input_dev = wacom_wac->touch_input; ++ pad_input_dev = wacom_wac->pad_input; ++ ++ if (pen_input_dev) { ++ error = input_register_device(pen_input_dev); ++ if (error) ++ goto fail; ++ } ++ ++ if (touch_input_dev) { ++ error = input_register_device(touch_input_dev); ++ if (error) ++ goto fail; ++ } ++ ++ if (pad_input_dev) { + error = input_register_device(pad_input_dev); + if (error) + goto fail; +@@ -2376,6 +2395,20 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) + if (error) + goto fail; + ++ error = wacom_setup_inputs(wacom); ++ if (error) ++ goto fail; ++ ++ if (features->type == HID_GENERIC) ++ connect_mask |= HID_CONNECT_DRIVER; ++ ++ /* Regular HID work starts now */ ++ error = hid_hw_start(hdev, connect_mask); ++ if (error) { ++ hid_err(hdev, "hw start failed\n"); ++ goto fail; ++ } ++ + error = wacom_register_inputs(wacom); + if (error) + goto fail; +@@ -2390,16 +2423,6 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) + goto fail; + } + +- if (features->type == HID_GENERIC) +- connect_mask |= HID_CONNECT_DRIVER; +- +- /* Regular HID work starts now */ +- error = hid_hw_start(hdev, connect_mask); +- if (error) { +- hid_err(hdev, "hw start failed\n"); +- goto fail; +- } +- + if (!wireless) { + /* Note that if query fails it is not a hard failure */ + wacom_query_tablet_data(wacom); +diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c +index 8289ce7637044..002cbaa16bd16 100644 +--- a/drivers/hid/wacom_wac.c ++++ b/drivers/hid/wacom_wac.c +@@ -2574,7 +2574,14 @@ static void wacom_wac_pen_report(struct hid_device *hdev, + wacom_wac->hid_data.tipswitch); + input_report_key(input, wacom_wac->tool[0], sense); + if (wacom_wac->serial[0]) { +- input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]); ++ /* ++ * xf86-input-wacom does not accept a serial number ++ * of '0'. Report the low 32 bits if possible, but ++ * if they are zero, report the upper ones instead. ++ */ ++ __u32 serial_lo = wacom_wac->serial[0] & 0xFFFFFFFFu; ++ __u32 serial_hi = wacom_wac->serial[0] >> 32; ++ input_event(input, EV_MSC, MSC_SERIAL, (int)(serial_lo ? serial_lo : serial_hi)); + input_report_abs(input, ABS_MISC, sense ? id : 0); + } + +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index af56fe2c75c09..9be9fdb07f3dc 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -90,10 +90,8 @@ obj-$(CONFIG_I2C_NPCM) += i2c-npcm7xx.o + obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o + obj-$(CONFIG_I2C_OMAP) += i2c-omap.o + obj-$(CONFIG_I2C_OWL) += i2c-owl.o +-i2c-pasemi-objs := i2c-pasemi-core.o i2c-pasemi-pci.o +-obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o +-i2c-apple-objs := i2c-pasemi-core.o i2c-pasemi-platform.o +-obj-$(CONFIG_I2C_APPLE) += i2c-apple.o ++obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi-core.o i2c-pasemi-pci.o ++obj-$(CONFIG_I2C_APPLE) += i2c-pasemi-core.o i2c-pasemi-platform.o + obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o + obj-$(CONFIG_I2C_PNX) += i2c-pnx.o + obj-$(CONFIG_I2C_PXA) += i2c-pxa.o +diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c +index a87e3c15e5fc6..f1c82b2016f30 100644 +--- a/drivers/i2c/busses/i2c-i801.c ++++ b/drivers/i2c/busses/i2c-i801.c +@@ -500,11 +500,10 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, + /* Set block buffer mode */ + outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); + +- inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ +- + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + outb_p(len, SMBHSTDAT0(priv)); ++ inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ + for (i = 0; i < len; i++) + outb_p(data->block[i+1], SMBBLKDAT(priv)); + } +@@ -522,6 +521,7 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, + } + + data->block[0] = len; ++ inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ + for (i = 0; i < len; i++) + data->block[i + 1] = inb_p(SMBBLKDAT(priv)); + } +diff --git a/drivers/i2c/busses/i2c-pasemi-core.c b/drivers/i2c/busses/i2c-pasemi-core.c +index 7d54a9f34c74b..bd8becbdeeb28 100644 +--- a/drivers/i2c/busses/i2c-pasemi-core.c ++++ b/drivers/i2c/busses/i2c-pasemi-core.c +@@ -369,6 +369,7 @@ int pasemi_i2c_common_probe(struct pasemi_smbus *smbus) + + return 0; + } ++EXPORT_SYMBOL_GPL(pasemi_i2c_common_probe); + + irqreturn_t pasemi_irq_handler(int irq, void *dev_id) + { +@@ -378,3 +379,8 @@ irqreturn_t pasemi_irq_handler(int irq, void *dev_id) + complete(&smbus->irq_completion); + return IRQ_HANDLED; + } ++EXPORT_SYMBOL_GPL(pasemi_irq_handler); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Olof Johansson <olof@lixom.net>"); ++MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); +diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c +index 0a9d389df301b..5cc32a465f12e 100644 +--- a/drivers/i2c/busses/i2c-qcom-geni.c ++++ b/drivers/i2c/busses/i2c-qcom-geni.c +@@ -613,20 +613,20 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i + + peripheral.addr = msgs[i].addr; + ++ ret = geni_i2c_gpi(gi2c, &msgs[i], &config, ++ &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c); ++ if (ret) ++ goto err; ++ + if (msgs[i].flags & I2C_M_RD) { + ret = geni_i2c_gpi(gi2c, &msgs[i], &config, + &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c); + if (ret) + goto err; +- } +- +- ret = geni_i2c_gpi(gi2c, &msgs[i], &config, +- &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c); +- if (ret) +- goto err; + +- if (msgs[i].flags & I2C_M_RD) + dma_async_issue_pending(gi2c->rx_c); ++ } ++ + dma_async_issue_pending(gi2c->tx_c); + + timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); +diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig +index b6b45d359f287..5c5876b4d3b62 100644 +--- a/drivers/iio/accel/Kconfig ++++ b/drivers/iio/accel/Kconfig +@@ -219,10 +219,12 @@ config BMA400 + + config BMA400_I2C + tristate ++ select REGMAP_I2C + depends on BMA400 + + config BMA400_SPI + tristate ++ select REGMAP_SPI + depends on BMA400 + + config BMC150_ACCEL +diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c +index 5a5dd5e87ffc4..e650ebd167b03 100644 +--- a/drivers/iio/adc/ad4130.c ++++ b/drivers/iio/adc/ad4130.c +@@ -1826,7 +1826,7 @@ static int ad4130_setup_int_clk(struct ad4130_state *st) + { + struct device *dev = &st->spi->dev; + struct device_node *of_node = dev_of_node(dev); +- struct clk_init_data init; ++ struct clk_init_data init = {}; + const char *clk_name; + struct clk *clk; + int ret; +@@ -1900,10 +1900,14 @@ static int ad4130_setup(struct iio_dev *indio_dev) + return ret; + + /* +- * Configure all GPIOs for output. If configured, the interrupt function +- * of P2 takes priority over the GPIO out function. ++ * Configure unused GPIOs for output. If configured, the interrupt ++ * function of P2 takes priority over the GPIO out function. + */ +- val = AD4130_IO_CONTROL_GPIO_CTRL_MASK; ++ val = 0; ++ for (i = 0; i < AD4130_MAX_GPIOS; i++) ++ if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) ++ val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); ++ + val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel); + + ret = regmap_write(st->regmap, AD4130_IO_CONTROL_REG, val); +diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig +index 83e53acfbe880..c7f5866a177d9 100644 +--- a/drivers/iio/imu/bno055/Kconfig ++++ b/drivers/iio/imu/bno055/Kconfig +@@ -8,6 +8,7 @@ config BOSCH_BNO055 + config BOSCH_BNO055_SERIAL + tristate "Bosch BNO055 attached via UART" + depends on SERIAL_DEV_BUS ++ select REGMAP + select BOSCH_BNO055 + help + Enable this to support Bosch BNO055 IMUs attached via UART. +diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c +index d752e9c0499b9..feec93adb0651 100644 +--- a/drivers/iio/industrialio-core.c ++++ b/drivers/iio/industrialio-core.c +@@ -1577,10 +1577,13 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) + ret = iio_device_register_sysfs_group(indio_dev, + &iio_dev_opaque->chan_attr_group); + if (ret) +- goto error_clear_attrs; ++ goto error_free_chan_attrs; + + return 0; + ++error_free_chan_attrs: ++ kfree(iio_dev_opaque->chan_attr_group.attrs); ++ iio_dev_opaque->chan_attr_group.attrs = NULL; + error_clear_attrs: + iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list); + +diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c +index eb1aedad7edcc..3c8b9aab5da7c 100644 +--- a/drivers/iio/light/hid-sensor-als.c ++++ b/drivers/iio/light/hid-sensor-als.c +@@ -226,6 +226,7 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, + case HID_USAGE_SENSOR_TIME_TIMESTAMP: + als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes, + *(s64 *)raw_data); ++ ret = 0; + break; + default: + break; +diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c +index 69938204456f8..42b70cd42b393 100644 +--- a/drivers/iio/magnetometer/rm3100-core.c ++++ b/drivers/iio/magnetometer/rm3100-core.c +@@ -530,6 +530,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) + struct rm3100_data *data; + unsigned int tmp; + int ret; ++ int samp_rate_index; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) +@@ -586,9 +587,14 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) + ret = regmap_read(regmap, RM3100_REG_TMRC, &tmp); + if (ret < 0) + return ret; ++ ++ samp_rate_index = tmp - RM3100_TMRC_OFFSET; ++ if (samp_rate_index < 0 || samp_rate_index >= RM3100_SAMP_NUM) { ++ dev_err(dev, "The value read from RM3100_REG_TMRC is invalid!\n"); ++ return -EINVAL; ++ } + /* Initializing max wait time, which is double conversion time. */ +- data->conversion_time = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][2] +- * 2; ++ data->conversion_time = rm3100_samp_rates[samp_rate_index][2] * 2; + + /* Cycle count values may not be what we want. */ + if ((tmp - RM3100_TMRC_OFFSET) == 0) +diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c +index 1dff9bb7c4e90..967de99c1bb97 100644 +--- a/drivers/iio/pressure/bmp280-spi.c ++++ b/drivers/iio/pressure/bmp280-spi.c +@@ -91,6 +91,7 @@ static const struct of_device_id bmp280_of_spi_match[] = { + MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); + + static const struct spi_device_id bmp280_spi_id[] = { ++ { "bmp085", (kernel_ulong_t)&bmp180_chip_info }, + { "bmp180", (kernel_ulong_t)&bmp180_chip_info }, + { "bmp181", (kernel_ulong_t)&bmp180_chip_info }, + { "bmp280", (kernel_ulong_t)&bmp280_chip_info }, +diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c +index bdd3471d4ac89..a741badaa966e 100644 +--- a/drivers/interconnect/qcom/sc8180x.c ++++ b/drivers/interconnect/qcom/sc8180x.c +@@ -1372,6 +1372,7 @@ static struct qcom_icc_bcm bcm_mm0 = { + + static struct qcom_icc_bcm bcm_co0 = { + .name = "CO0", ++ .keepalive = true, + .num_nodes = 1, + .nodes = { &slv_qns_cdsp_mem_noc } + }; +diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c +index a10c8b6549ee6..16b2dfd794b40 100644 +--- a/drivers/interconnect/qcom/sm8550.c ++++ b/drivers/interconnect/qcom/sm8550.c +@@ -2223,6 +2223,7 @@ static struct platform_driver qnoc_driver = { + .driver = { + .name = "qnoc-sm8550", + .of_match_table = qnoc_of_match, ++ .sync_state = icc_sync_state, + }, + }; + +diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c +index 5559c943f03f9..2b0b3175cea06 100644 +--- a/drivers/irqchip/irq-brcmstb-l2.c ++++ b/drivers/irqchip/irq-brcmstb-l2.c +@@ -2,7 +2,7 @@ + /* + * Generic Broadcom Set Top Box Level 2 Interrupt controller driver + * +- * Copyright (C) 2014-2017 Broadcom ++ * Copyright (C) 2014-2024 Broadcom + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -112,6 +112,9 @@ static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc) + generic_handle_domain_irq(b->domain, irq); + } while (status); + out: ++ /* Don't ack parent before all device writes are done */ ++ wmb(); ++ + chained_irq_exit(chip, desc); + } + +diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c +index 9a7a74239eabb..3632c92cd183c 100644 +--- a/drivers/irqchip/irq-gic-v3-its.c ++++ b/drivers/irqchip/irq-gic-v3-its.c +@@ -207,6 +207,11 @@ static bool require_its_list_vmovp(struct its_vm *vm, struct its_node *its) + return (gic_rdists->has_rvpeid || vm->vlpi_count[its->list_nr]); + } + ++static bool rdists_support_shareable(void) ++{ ++ return !(gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE); ++} ++ + static u16 get_its_list(struct its_vm *vm) + { + struct its_node *its; +@@ -2710,10 +2715,12 @@ static u64 inherit_vpe_l1_table_from_its(void) + break; + } + val |= FIELD_PREP(GICR_VPROPBASER_4_1_ADDR, addr >> 12); +- val |= FIELD_PREP(GICR_VPROPBASER_SHAREABILITY_MASK, +- FIELD_GET(GITS_BASER_SHAREABILITY_MASK, baser)); +- val |= FIELD_PREP(GICR_VPROPBASER_INNER_CACHEABILITY_MASK, +- FIELD_GET(GITS_BASER_INNER_CACHEABILITY_MASK, baser)); ++ if (rdists_support_shareable()) { ++ val |= FIELD_PREP(GICR_VPROPBASER_SHAREABILITY_MASK, ++ FIELD_GET(GITS_BASER_SHAREABILITY_MASK, baser)); ++ val |= FIELD_PREP(GICR_VPROPBASER_INNER_CACHEABILITY_MASK, ++ FIELD_GET(GITS_BASER_INNER_CACHEABILITY_MASK, baser)); ++ } + val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, GITS_BASER_NR_PAGES(baser) - 1); + + return val; +@@ -2936,8 +2943,10 @@ static int allocate_vpe_l1_table(void) + WARN_ON(!IS_ALIGNED(pa, psz)); + + val |= FIELD_PREP(GICR_VPROPBASER_4_1_ADDR, pa >> 12); +- val |= GICR_VPROPBASER_RaWb; +- val |= GICR_VPROPBASER_InnerShareable; ++ if (rdists_support_shareable()) { ++ val |= GICR_VPROPBASER_RaWb; ++ val |= GICR_VPROPBASER_InnerShareable; ++ } + val |= GICR_VPROPBASER_4_1_Z; + val |= GICR_VPROPBASER_4_1_VALID; + +@@ -3126,7 +3135,7 @@ static void its_cpu_init_lpis(void) + gicr_write_propbaser(val, rbase + GICR_PROPBASER); + tmp = gicr_read_propbaser(rbase + GICR_PROPBASER); + +- if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE) ++ if (!rdists_support_shareable()) + tmp &= ~GICR_PROPBASER_SHAREABILITY_MASK; + + if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { +@@ -3153,7 +3162,7 @@ static void its_cpu_init_lpis(void) + gicr_write_pendbaser(val, rbase + GICR_PENDBASER); + tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER); + +- if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE) ++ if (!rdists_support_shareable()) + tmp &= ~GICR_PENDBASER_SHAREABILITY_MASK; + + if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { +@@ -3817,8 +3826,9 @@ static int its_vpe_set_affinity(struct irq_data *d, + bool force) + { + struct its_vpe *vpe = irq_data_get_irq_chip_data(d); +- int from, cpu = cpumask_first(mask_val); ++ struct cpumask common, *table_mask; + unsigned long flags; ++ int from, cpu; + + /* + * Changing affinity is mega expensive, so let's be as lazy as +@@ -3834,19 +3844,22 @@ static int its_vpe_set_affinity(struct irq_data *d, + * taken on any vLPI handling path that evaluates vpe->col_idx. + */ + from = vpe_to_cpuid_lock(vpe, &flags); +- if (from == cpu) +- goto out; +- +- vpe->col_idx = cpu; ++ table_mask = gic_data_rdist_cpu(from)->vpe_table_mask; + + /* +- * GICv4.1 allows us to skip VMOVP if moving to a cpu whose RD +- * is sharing its VPE table with the current one. ++ * If we are offered another CPU in the same GICv4.1 ITS ++ * affinity, pick this one. Otherwise, any CPU will do. + */ +- if (gic_data_rdist_cpu(cpu)->vpe_table_mask && +- cpumask_test_cpu(from, gic_data_rdist_cpu(cpu)->vpe_table_mask)) ++ if (table_mask && cpumask_and(&common, mask_val, table_mask)) ++ cpu = cpumask_test_cpu(from, &common) ? from : cpumask_first(&common); ++ else ++ cpu = cpumask_first(mask_val); ++ ++ if (from == cpu) + goto out; + ++ vpe->col_idx = cpu; ++ + its_send_vmovp(vpe); + its_vpe_db_proxy_move(vpe, from, cpu); + +@@ -3880,14 +3893,18 @@ static void its_vpe_schedule(struct its_vpe *vpe) + val = virt_to_phys(page_address(vpe->its_vm->vprop_page)) & + GENMASK_ULL(51, 12); + val |= (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK; +- val |= GICR_VPROPBASER_RaWb; +- val |= GICR_VPROPBASER_InnerShareable; ++ if (rdists_support_shareable()) { ++ val |= GICR_VPROPBASER_RaWb; ++ val |= GICR_VPROPBASER_InnerShareable; ++ } + gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER); + + val = virt_to_phys(page_address(vpe->vpt_page)) & + GENMASK_ULL(51, 16); +- val |= GICR_VPENDBASER_RaWaWb; +- val |= GICR_VPENDBASER_InnerShareable; ++ if (rdists_support_shareable()) { ++ val |= GICR_VPENDBASER_RaWaWb; ++ val |= GICR_VPENDBASER_InnerShareable; ++ } + /* + * There is no good way of finding out if the pending table is + * empty as we can race against the doorbell interrupt very +@@ -5078,6 +5095,8 @@ static int __init its_probe_one(struct its_node *its) + u32 ctlr; + int err; + ++ its_enable_quirks(its); ++ + if (is_v4(its)) { + if (!(its->typer & GITS_TYPER_VMOVP)) { + err = its_compute_its_list_map(its); +@@ -5429,7 +5448,6 @@ static int __init its_of_probe(struct device_node *node) + if (!its) + return -ENOMEM; + +- its_enable_quirks(its); + err = its_probe_one(its); + if (err) { + its_node_destroy(its); +diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c +index 1623cd7791752..b3736bdd4b9f2 100644 +--- a/drivers/irqchip/irq-loongson-eiointc.c ++++ b/drivers/irqchip/irq-loongson-eiointc.c +@@ -241,7 +241,7 @@ static int eiointc_domain_alloc(struct irq_domain *domain, unsigned int virq, + int ret; + unsigned int i, type; + unsigned long hwirq = 0; +- struct eiointc *priv = domain->host_data; ++ struct eiointc_priv *priv = domain->host_data; + + ret = irq_domain_translate_onecell(domain, arg, &hwirq, &type); + if (ret) +diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h +index 095b9b49aa825..e6757a30dccad 100644 +--- a/drivers/md/dm-core.h ++++ b/drivers/md/dm-core.h +@@ -22,6 +22,8 @@ + #include "dm-ima.h" + + #define DM_RESERVED_MAX_IOS 1024 ++#define DM_MAX_TARGETS 1048576 ++#define DM_MAX_TARGET_PARAMS 1024 + + struct dm_io; + +diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c +index 17ffbf7fbe73e..1a539ec81bacc 100644 +--- a/drivers/md/dm-crypt.c ++++ b/drivers/md/dm-crypt.c +@@ -73,10 +73,8 @@ struct dm_crypt_io { + struct bio *base_bio; + u8 *integrity_metadata; + bool integrity_metadata_from_pool:1; +- bool in_tasklet:1; + + struct work_struct work; +- struct tasklet_struct tasklet; + + struct convert_context ctx; + +@@ -1768,7 +1766,6 @@ static void crypt_io_init(struct dm_crypt_io *io, struct crypt_config *cc, + io->ctx.r.req = NULL; + io->integrity_metadata = NULL; + io->integrity_metadata_from_pool = false; +- io->in_tasklet = false; + atomic_set(&io->io_pending, 0); + } + +@@ -1777,13 +1774,6 @@ static void crypt_inc_pending(struct dm_crypt_io *io) + atomic_inc(&io->io_pending); + } + +-static void kcryptd_io_bio_endio(struct work_struct *work) +-{ +- struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work); +- +- bio_endio(io->base_bio); +-} +- + /* + * One of the bios was finished. Check for completion of + * the whole request and correctly clean up the buffer. +@@ -1807,20 +1797,6 @@ static void crypt_dec_pending(struct dm_crypt_io *io) + + base_bio->bi_status = error; + +- /* +- * If we are running this function from our tasklet, +- * we can't call bio_endio() here, because it will call +- * clone_endio() from dm.c, which in turn will +- * free the current struct dm_crypt_io structure with +- * our tasklet. In this case we need to delay bio_endio() +- * execution to after the tasklet is done and dequeued. +- */ +- if (io->in_tasklet) { +- INIT_WORK(&io->work, kcryptd_io_bio_endio); +- queue_work(cc->io_queue, &io->work); +- return; +- } +- + bio_endio(base_bio); + } + +@@ -2252,11 +2228,6 @@ static void kcryptd_crypt(struct work_struct *work) + kcryptd_crypt_write_convert(io); + } + +-static void kcryptd_crypt_tasklet(unsigned long work) +-{ +- kcryptd_crypt((struct work_struct *)work); +-} +- + static void kcryptd_queue_crypt(struct dm_crypt_io *io) + { + struct crypt_config *cc = io->cc; +@@ -2268,15 +2239,10 @@ static void kcryptd_queue_crypt(struct dm_crypt_io *io) + * irqs_disabled(): the kernel may run some IO completion from the idle thread, but + * it is being executed with irqs disabled. + */ +- if (in_hardirq() || irqs_disabled()) { +- io->in_tasklet = true; +- tasklet_init(&io->tasklet, kcryptd_crypt_tasklet, (unsigned long)&io->work); +- tasklet_schedule(&io->tasklet); ++ if (!(in_hardirq() || irqs_disabled())) { ++ kcryptd_crypt(&io->work); + return; + } +- +- kcryptd_crypt(&io->work); +- return; + } + + INIT_WORK(&io->work, kcryptd_crypt); +diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c +index 21ebb6c39394b..3b8b2e886cf67 100644 +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -1941,7 +1941,8 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern + minimum_data_size - sizeof(param_kernel->version))) + return -EFAULT; + +- if (param_kernel->data_size < minimum_data_size) { ++ if (unlikely(param_kernel->data_size < minimum_data_size) || ++ unlikely(param_kernel->data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS)) { + DMERR("Invalid data size in the ioctl structure: %u", + param_kernel->data_size); + return -EINVAL; +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 37b48f63ae6a5..fd84e06670e8d 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -129,7 +129,12 @@ static int alloc_targets(struct dm_table *t, unsigned int num) + int dm_table_create(struct dm_table **result, blk_mode_t mode, + unsigned int num_targets, struct mapped_device *md) + { +- struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL); ++ struct dm_table *t; ++ ++ if (num_targets > DM_MAX_TARGETS) ++ return -EOVERFLOW; ++ ++ t = kzalloc(sizeof(*t), GFP_KERNEL); + + if (!t) + return -ENOMEM; +@@ -144,7 +149,7 @@ int dm_table_create(struct dm_table **result, blk_mode_t mode, + + if (!num_targets) { + kfree(t); +- return -ENOMEM; ++ return -EOVERFLOW; + } + + if (alloc_targets(t, num_targets)) { +diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c +index 14e58ae705218..82662f5769c4a 100644 +--- a/drivers/md/dm-verity-target.c ++++ b/drivers/md/dm-verity-target.c +@@ -645,23 +645,6 @@ static void verity_work(struct work_struct *w) + verity_finish_io(io, errno_to_blk_status(verity_verify_io(io))); + } + +-static void verity_tasklet(unsigned long data) +-{ +- struct dm_verity_io *io = (struct dm_verity_io *)data; +- int err; +- +- io->in_tasklet = true; +- err = verity_verify_io(io); +- if (err == -EAGAIN || err == -ENOMEM) { +- /* fallback to retrying with work-queue */ +- INIT_WORK(&io->work, verity_work); +- queue_work(io->v->verify_wq, &io->work); +- return; +- } +- +- verity_finish_io(io, errno_to_blk_status(err)); +-} +- + static void verity_end_io(struct bio *bio) + { + struct dm_verity_io *io = bio->bi_private; +@@ -674,13 +657,8 @@ static void verity_end_io(struct bio *bio) + return; + } + +- if (static_branch_unlikely(&use_tasklet_enabled) && io->v->use_tasklet) { +- tasklet_init(&io->tasklet, verity_tasklet, (unsigned long)io); +- tasklet_schedule(&io->tasklet); +- } else { +- INIT_WORK(&io->work, verity_work); +- queue_work(io->v->verify_wq, &io->work); +- } ++ INIT_WORK(&io->work, verity_work); ++ queue_work(io->v->verify_wq, &io->work); + } + + /* +diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h +index f9d522c870e61..f3f6070084196 100644 +--- a/drivers/md/dm-verity.h ++++ b/drivers/md/dm-verity.h +@@ -83,7 +83,6 @@ struct dm_verity_io { + struct bvec_iter iter; + + struct work_struct work; +- struct tasklet_struct tasklet; + + /* + * Three variably-size fields follow this struct: +diff --git a/drivers/md/md.c b/drivers/md/md.c +index dccf270aa1b4b..108590041db64 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -940,9 +940,10 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev, + return; + + bio = bio_alloc_bioset(rdev->meta_bdev ? rdev->meta_bdev : rdev->bdev, +- 1, +- REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH | REQ_FUA, +- GFP_NOIO, &mddev->sync_set); ++ 1, ++ REQ_OP_WRITE | REQ_SYNC | REQ_IDLE | REQ_META ++ | REQ_PREFLUSH | REQ_FUA, ++ GFP_NOIO, &mddev->sync_set); + + atomic_inc(&rdev->nr_pending); + +diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +index f96f821a7b50d..acc559652d6eb 100644 +--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c ++++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +@@ -559,7 +559,7 @@ static int rkisp1_probe(struct platform_device *pdev) + rkisp1->irqs[il] = irq; + } + +- ret = devm_request_irq(dev, irq, info->isrs[i].isr, 0, ++ ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, + dev_driver_string(dev), dev); + if (ret) { + dev_err(dev, "request irq failed: %d\n", ret); +diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c +index fe17c7f98e810..52d82cbe7685f 100644 +--- a/drivers/media/rc/bpf-lirc.c ++++ b/drivers/media/rc/bpf-lirc.c +@@ -253,7 +253,7 @@ int lirc_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog) + if (attr->attach_flags) + return -EINVAL; + +- rcdev = rc_dev_get_from_fd(attr->target_fd); ++ rcdev = rc_dev_get_from_fd(attr->target_fd, true); + if (IS_ERR(rcdev)) + return PTR_ERR(rcdev); + +@@ -278,7 +278,7 @@ int lirc_prog_detach(const union bpf_attr *attr) + if (IS_ERR(prog)) + return PTR_ERR(prog); + +- rcdev = rc_dev_get_from_fd(attr->target_fd); ++ rcdev = rc_dev_get_from_fd(attr->target_fd, true); + if (IS_ERR(rcdev)) { + bpf_prog_put(prog); + return PTR_ERR(rcdev); +@@ -303,7 +303,7 @@ int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) + if (attr->query.query_flags) + return -EINVAL; + +- rcdev = rc_dev_get_from_fd(attr->query.target_fd); ++ rcdev = rc_dev_get_from_fd(attr->query.target_fd, false); + if (IS_ERR(rcdev)) + return PTR_ERR(rcdev); + +diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c +index 1968067092594..69e630d85262f 100644 +--- a/drivers/media/rc/ir_toy.c ++++ b/drivers/media/rc/ir_toy.c +@@ -332,6 +332,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) + sizeof(COMMAND_SMODE_EXIT), STATE_COMMAND_NO_RESP); + if (err) { + dev_err(irtoy->dev, "exit sample mode: %d\n", err); ++ kfree(buf); + return err; + } + +@@ -339,6 +340,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) + sizeof(COMMAND_SMODE_ENTER), STATE_COMMAND); + if (err) { + dev_err(irtoy->dev, "enter sample mode: %d\n", err); ++ kfree(buf); + return err; + } + +diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c +index a537734832c50..caad59f76793f 100644 +--- a/drivers/media/rc/lirc_dev.c ++++ b/drivers/media/rc/lirc_dev.c +@@ -814,7 +814,7 @@ void __exit lirc_dev_exit(void) + unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX); + } + +-struct rc_dev *rc_dev_get_from_fd(int fd) ++struct rc_dev *rc_dev_get_from_fd(int fd, bool write) + { + struct fd f = fdget(fd); + struct lirc_fh *fh; +@@ -828,6 +828,9 @@ struct rc_dev *rc_dev_get_from_fd(int fd) + return ERR_PTR(-EINVAL); + } + ++ if (write && !(f.file->f_mode & FMODE_WRITE)) ++ return ERR_PTR(-EPERM); ++ + fh = f.file->private_data; + dev = fh->rc; + +diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h +index ef1e95e1af7fc..7df949fc65e2b 100644 +--- a/drivers/media/rc/rc-core-priv.h ++++ b/drivers/media/rc/rc-core-priv.h +@@ -325,7 +325,7 @@ void lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev); + void lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc); + int lirc_register(struct rc_dev *dev); + void lirc_unregister(struct rc_dev *dev); +-struct rc_dev *rc_dev_get_from_fd(int fd); ++struct rc_dev *rc_dev_get_from_fd(int fd, bool write); + #else + static inline int lirc_dev_init(void) { return 0; } + static inline void lirc_dev_exit(void) {} +diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c +index 1c6c62a7f7f55..03319a1fa97fd 100644 +--- a/drivers/misc/fastrpc.c ++++ b/drivers/misc/fastrpc.c +@@ -2191,7 +2191,7 @@ static int fastrpc_cb_remove(struct platform_device *pdev) + int i; + + spin_lock_irqsave(&cctx->lock, flags); +- for (i = 1; i < FASTRPC_MAX_SESSIONS; i++) { ++ for (i = 0; i < FASTRPC_MAX_SESSIONS; i++) { + if (cctx->session[i].sid == sess->sid) { + cctx->session[i].valid = false; + cctx->sesscount--; +diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c +index 2a2d949a9344e..39f45c2b6de8a 100644 +--- a/drivers/mmc/core/slot-gpio.c ++++ b/drivers/mmc/core/slot-gpio.c +@@ -75,11 +75,15 @@ EXPORT_SYMBOL(mmc_gpio_set_cd_irq); + int mmc_gpio_get_ro(struct mmc_host *host) + { + struct mmc_gpio *ctx = host->slot.handler_priv; ++ int cansleep; + + if (!ctx || !ctx->ro_gpio) + return -ENOSYS; + +- return gpiod_get_value_cansleep(ctx->ro_gpio); ++ cansleep = gpiod_cansleep(ctx->ro_gpio); ++ return cansleep ? ++ gpiod_get_value_cansleep(ctx->ro_gpio) : ++ gpiod_get_value(ctx->ro_gpio); + } + EXPORT_SYMBOL(mmc_gpio_get_ro); + +diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c +index 7bfee28116af1..d4a02184784a3 100644 +--- a/drivers/mmc/host/sdhci-pci-o2micro.c ++++ b/drivers/mmc/host/sdhci-pci-o2micro.c +@@ -693,6 +693,35 @@ static int sdhci_pci_o2_init_sd_express(struct mmc_host *mmc, struct mmc_ios *io + return 0; + } + ++static void sdhci_pci_o2_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) ++{ ++ struct sdhci_pci_chip *chip; ++ struct sdhci_pci_slot *slot = sdhci_priv(host); ++ u32 scratch_32 = 0; ++ u8 scratch_8 = 0; ++ ++ chip = slot->chip; ++ ++ if (mode == MMC_POWER_OFF) { ++ /* UnLock WP */ ++ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8); ++ scratch_8 &= 0x7f; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); ++ ++ /* Set PCR 0x354[16] to switch Clock Source back to OPE Clock */ ++ pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &scratch_32); ++ scratch_32 &= ~(O2_SD_SEL_DLL); ++ pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, scratch_32); ++ ++ /* Lock WP */ ++ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8); ++ scratch_8 |= 0x80; ++ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); ++ } ++ ++ sdhci_set_power(host, mode, vdd); ++} ++ + static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) + { + struct sdhci_pci_chip *chip; +@@ -1051,6 +1080,7 @@ static const struct sdhci_ops sdhci_pci_o2_ops = { + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .set_power = sdhci_pci_o2_set_power, + }; + + const struct sdhci_pci_fixes sdhci_o2 = { +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 8e6cc0e133b7f..6cf7f364704e8 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1819,6 +1819,8 @@ void bond_xdp_set_features(struct net_device *bond_dev) + bond_for_each_slave(bond, slave, iter) + val &= slave->dev->xdp_features; + ++ val &= ~NETDEV_XDP_ACT_XSK_ZEROCOPY; ++ + xdp_set_features_flag(bond_dev, val); + } + +@@ -5934,9 +5936,6 @@ void bond_setup(struct net_device *bond_dev) + if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) + bond_dev->features |= BOND_XFRM_FEATURES; + #endif /* CONFIG_XFRM_OFFLOAD */ +- +- if (bond_xdp_check(bond)) +- bond_dev->xdp_features = NETDEV_XDP_ACT_MASK; + } + + /* Destroy a bonding device. +diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c +index 036d85ef07f5b..dfdc039d92a6c 100644 +--- a/drivers/net/can/dev/netlink.c ++++ b/drivers/net/can/dev/netlink.c +@@ -346,7 +346,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], + /* Neither of TDC parameters nor TDC flags are + * provided: do calculation + */ +- can_calc_tdco(&priv->tdc, priv->tdc_const, &priv->data_bittiming, ++ can_calc_tdco(&priv->tdc, priv->tdc_const, &dbt, + &priv->ctrlmode, priv->ctrlmode_supported); + } /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly + * turned off. TDC is disabled: do nothing +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index dc7f9b99f409f..5ad51271a5349 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -3545,7 +3545,7 @@ static int mv88e6xxx_mdio_read_c45(struct mii_bus *bus, int phy, int devad, + int err; + + if (!chip->info->ops->phy_read_c45) +- return -EOPNOTSUPP; ++ return 0xffff; + + mv88e6xxx_reg_lock(chip); + err = chip->info->ops->phy_read_c45(chip, bus, phy, devad, reg, &val); +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index aad39ebff4aba..9d37c0374c75e 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -5351,7 +5351,7 @@ static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf) + { + int v, ret = 0; + +- for (v = 0; v < pf->hw.func_caps.num_vsis; v++) { ++ for (v = 0; v < pf->num_alloc_vsi; v++) { + if (pf->vsi[v]) { + ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]); + if (ret) +diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +index cc4c53470db2c..082c099209995 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +@@ -2848,6 +2848,24 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg) + (u8 *)&stats, sizeof(stats)); + } + ++/** ++ * i40e_can_vf_change_mac ++ * @vf: pointer to the VF info ++ * ++ * Return true if the VF is allowed to change its MAC filters, false otherwise ++ */ ++static bool i40e_can_vf_change_mac(struct i40e_vf *vf) ++{ ++ /* If the VF MAC address has been set administratively (via the ++ * ndo_set_vf_mac command), then deny permission to the VF to ++ * add/delete unicast MAC addresses, unless the VF is trusted ++ */ ++ if (vf->pf_set_mac && !vf->trusted) ++ return false; ++ ++ return true; ++} ++ + #define I40E_MAX_MACVLAN_PER_HW 3072 + #define I40E_MAX_MACVLAN_PER_PF(num_ports) (I40E_MAX_MACVLAN_PER_HW / \ + (num_ports)) +@@ -2907,8 +2925,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, + * The VF may request to set the MAC address filter already + * assigned to it so do not return an error in that case. + */ +- if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) && +- !is_multicast_ether_addr(addr) && vf->pf_set_mac && ++ if (!i40e_can_vf_change_mac(vf) && ++ !is_multicast_ether_addr(addr) && + !ether_addr_equal(addr, vf->default_lan_addr.addr)) { + dev_err(&pf->pdev->dev, + "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n"); +@@ -3114,19 +3132,29 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg) + ret = -EINVAL; + goto error_param; + } +- if (ether_addr_equal(al->list[i].addr, vf->default_lan_addr.addr)) +- was_unimac_deleted = true; + } + vsi = pf->vsi[vf->lan_vsi_idx]; + + spin_lock_bh(&vsi->mac_filter_hash_lock); + /* delete addresses from the list */ +- for (i = 0; i < al->num_elements; i++) ++ for (i = 0; i < al->num_elements; i++) { ++ const u8 *addr = al->list[i].addr; ++ ++ /* Allow to delete VF primary MAC only if it was not set ++ * administratively by PF or if VF is trusted. ++ */ ++ if (ether_addr_equal(addr, vf->default_lan_addr.addr) && ++ i40e_can_vf_change_mac(vf)) ++ was_unimac_deleted = true; ++ else ++ continue; ++ + if (i40e_del_mac_filter(vsi, al->list[i].addr)) { + ret = -EINVAL; + spin_unlock_bh(&vsi->mac_filter_hash_lock); + goto error_param; + } ++ } + + spin_unlock_bh(&vsi->mac_filter_hash_lock); + +diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c b/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c +index 41fa2523d91d3..5f2cd9a8cf8fb 100644 +--- a/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c ++++ b/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c +@@ -37,19 +37,24 @@ static void lan966x_lag_set_aggr_pgids(struct lan966x *lan966x) + + /* Now, set PGIDs for each active LAG */ + for (lag = 0; lag < lan966x->num_phys_ports; ++lag) { +- struct net_device *bond = lan966x->ports[lag]->bond; ++ struct lan966x_port *port = lan966x->ports[lag]; + int num_active_ports = 0; ++ struct net_device *bond; + unsigned long bond_mask; + u8 aggr_idx[16]; + +- if (!bond || (visited & BIT(lag))) ++ if (!port || !port->bond || (visited & BIT(lag))) + continue; + ++ bond = port->bond; + bond_mask = lan966x_lag_get_mask(lan966x, bond); + + for_each_set_bit(p, &bond_mask, lan966x->num_phys_ports) { + struct lan966x_port *port = lan966x->ports[p]; + ++ if (!port) ++ continue; ++ + lan_wr(ANA_PGID_PGID_SET(bond_mask), + lan966x, ANA_PGID(p)); + if (port->lag_tx_active) +diff --git a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c +index 2967bab725056..15180538b80a1 100644 +--- a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c ++++ b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c +@@ -1424,10 +1424,30 @@ static void nfp_nft_ct_translate_mangle_action(struct flow_action_entry *mangle_ + mangle_action->mangle.mask = (__force u32)cpu_to_be32(mangle_action->mangle.mask); + return; + ++ /* Both struct tcphdr and struct udphdr start with ++ * __be16 source; ++ * __be16 dest; ++ * so we can use the same code for both. ++ */ + case FLOW_ACT_MANGLE_HDR_TYPE_TCP: + case FLOW_ACT_MANGLE_HDR_TYPE_UDP: +- mangle_action->mangle.val = (__force u16)cpu_to_be16(mangle_action->mangle.val); +- mangle_action->mangle.mask = (__force u16)cpu_to_be16(mangle_action->mangle.mask); ++ if (mangle_action->mangle.offset == offsetof(struct tcphdr, source)) { ++ mangle_action->mangle.val = ++ (__force u32)cpu_to_be32(mangle_action->mangle.val << 16); ++ /* The mask of mangle action is inverse mask, ++ * so clear the dest tp port with 0xFFFF to ++ * instead of rotate-left operation. ++ */ ++ mangle_action->mangle.mask = ++ (__force u32)cpu_to_be32(mangle_action->mangle.mask << 16 | 0xFFFF); ++ } ++ if (mangle_action->mangle.offset == offsetof(struct tcphdr, dest)) { ++ mangle_action->mangle.offset = 0; ++ mangle_action->mangle.val = ++ (__force u32)cpu_to_be32(mangle_action->mangle.val); ++ mangle_action->mangle.mask = ++ (__force u32)cpu_to_be32(mangle_action->mangle.mask); ++ } + return; + + default: +@@ -1864,10 +1884,30 @@ int nfp_fl_ct_handle_post_ct(struct nfp_flower_priv *priv, + { + struct flow_rule *rule = flow_cls_offload_flow_rule(flow); + struct nfp_fl_ct_flow_entry *ct_entry; ++ struct flow_action_entry *ct_goto; + struct nfp_fl_ct_zone_entry *zt; ++ struct flow_action_entry *act; + bool wildcarded = false; + struct flow_match_ct ct; +- struct flow_action_entry *ct_goto; ++ int i; ++ ++ flow_action_for_each(i, act, &rule->action) { ++ switch (act->id) { ++ case FLOW_ACTION_REDIRECT: ++ case FLOW_ACTION_REDIRECT_INGRESS: ++ case FLOW_ACTION_MIRRED: ++ case FLOW_ACTION_MIRRED_INGRESS: ++ if (act->dev->rtnl_link_ops && ++ !strcmp(act->dev->rtnl_link_ops->kind, "openvswitch")) { ++ NL_SET_ERR_MSG_MOD(extack, ++ "unsupported offload: out port is openvswitch internal port"); ++ return -EOPNOTSUPP; ++ } ++ break; ++ default: ++ break; ++ } ++ } + + flow_rule_match_ct(rule, &ct); + if (!ct.mask->ct_zone) { +diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +index e522845c7c211..0d7d138d6e0d7 100644 +--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c ++++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +@@ -1084,7 +1084,7 @@ nfp_tunnel_add_shared_mac(struct nfp_app *app, struct net_device *netdev, + u16 nfp_mac_idx = 0; + + entry = nfp_tunnel_lookup_offloaded_macs(app, netdev->dev_addr); +- if (entry && nfp_tunnel_is_mac_idx_global(entry->index)) { ++ if (entry && (nfp_tunnel_is_mac_idx_global(entry->index) || netif_is_lag_port(netdev))) { + if (entry->bridge_count || + !nfp_flower_is_supported_bridge(netdev)) { + nfp_tunnel_offloaded_macs_inc_ref_and_link(entry, +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +index de0a5d5ded305..f2085340a1cfe 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +@@ -2588,6 +2588,7 @@ static void nfp_net_netdev_init(struct nfp_net *nn) + case NFP_NFD_VER_NFD3: + netdev->netdev_ops = &nfp_nfd3_netdev_ops; + netdev->xdp_features |= NETDEV_XDP_ACT_XSK_ZEROCOPY; ++ netdev->xdp_features |= NETDEV_XDP_ACT_REDIRECT; + break; + case NFP_NFD_VER_NFDK: + netdev->netdev_ops = &nfp_nfdk_netdev_ops; +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +index 33b4c28563162..3f10c5365c80e 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +@@ -537,11 +537,13 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) + const u32 barcfg_msix_general = + NFP_PCIE_BAR_PCIE2CPP_MapType( + NFP_PCIE_BAR_PCIE2CPP_MapType_GENERAL) | +- NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT; ++ NFP_PCIE_BAR_PCIE2CPP_LengthSelect( ++ NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT); + const u32 barcfg_msix_xpb = + NFP_PCIE_BAR_PCIE2CPP_MapType( + NFP_PCIE_BAR_PCIE2CPP_MapType_BULK) | +- NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT | ++ NFP_PCIE_BAR_PCIE2CPP_LengthSelect( ++ NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT) | + NFP_PCIE_BAR_PCIE2CPP_Target_BaseAddress( + NFP_CPP_TARGET_ISLAND_XPB); + const u32 barcfg_explicit[4] = { +diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h +index 3d4f34e178a88..b0dd8adce3560 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/common.h ++++ b/drivers/net/ethernet/stmicro/stmmac/common.h +@@ -59,28 +59,51 @@ + #undef FRAME_FILTER_DEBUG + /* #define FRAME_FILTER_DEBUG */ + ++struct stmmac_q_tx_stats { ++ u64_stats_t tx_bytes; ++ u64_stats_t tx_set_ic_bit; ++ u64_stats_t tx_tso_frames; ++ u64_stats_t tx_tso_nfrags; ++}; ++ ++struct stmmac_napi_tx_stats { ++ u64_stats_t tx_packets; ++ u64_stats_t tx_pkt_n; ++ u64_stats_t poll; ++ u64_stats_t tx_clean; ++ u64_stats_t tx_set_ic_bit; ++}; ++ + struct stmmac_txq_stats { +- u64 tx_bytes; +- u64 tx_packets; +- u64 tx_pkt_n; +- u64 tx_normal_irq_n; +- u64 napi_poll; +- u64 tx_clean; +- u64 tx_set_ic_bit; +- u64 tx_tso_frames; +- u64 tx_tso_nfrags; +- struct u64_stats_sync syncp; ++ /* Updates protected by tx queue lock. */ ++ struct u64_stats_sync q_syncp; ++ struct stmmac_q_tx_stats q; ++ ++ /* Updates protected by NAPI poll logic. */ ++ struct u64_stats_sync napi_syncp; ++ struct stmmac_napi_tx_stats napi; + } ____cacheline_aligned_in_smp; + ++struct stmmac_napi_rx_stats { ++ u64_stats_t rx_bytes; ++ u64_stats_t rx_packets; ++ u64_stats_t rx_pkt_n; ++ u64_stats_t poll; ++}; ++ + struct stmmac_rxq_stats { +- u64 rx_bytes; +- u64 rx_packets; +- u64 rx_pkt_n; +- u64 rx_normal_irq_n; +- u64 napi_poll; +- struct u64_stats_sync syncp; ++ /* Updates protected by NAPI poll logic. */ ++ struct u64_stats_sync napi_syncp; ++ struct stmmac_napi_rx_stats napi; + } ____cacheline_aligned_in_smp; + ++/* Updates on each CPU protected by not allowing nested irqs. */ ++struct stmmac_pcpu_stats { ++ struct u64_stats_sync syncp; ++ u64_stats_t rx_normal_irq_n[MTL_MAX_TX_QUEUES]; ++ u64_stats_t tx_normal_irq_n[MTL_MAX_RX_QUEUES]; ++}; ++ + /* Extra statistic and debug information exposed by ethtool */ + struct stmmac_extra_stats { + /* Transmit errors */ +@@ -205,6 +228,7 @@ struct stmmac_extra_stats { + /* per queue statistics */ + struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; + struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; ++ struct stmmac_pcpu_stats __percpu *pcpu_stats; + unsigned long rx_dropped; + unsigned long rx_errors; + unsigned long tx_dropped; +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +index 465ff1fd47855..51f121f867457 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +@@ -441,8 +441,7 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, + struct stmmac_extra_stats *x, u32 chan, + u32 dir) + { +- struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; +- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; ++ struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); + int ret = 0; + u32 v; + +@@ -455,9 +454,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, + + if (v & EMAC_TX_INT) { + ret |= handle_tx; +- u64_stats_update_begin(&txq_stats->syncp); +- txq_stats->tx_normal_irq_n++; +- u64_stats_update_end(&txq_stats->syncp); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->tx_normal_irq_n[chan]); ++ u64_stats_update_end(&stats->syncp); + } + + if (v & EMAC_TX_DMA_STOP_INT) +@@ -479,9 +478,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, + + if (v & EMAC_RX_INT) { + ret |= handle_rx; +- u64_stats_update_begin(&rxq_stats->syncp); +- rxq_stats->rx_normal_irq_n++; +- u64_stats_update_end(&rxq_stats->syncp); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->rx_normal_irq_n[chan]); ++ u64_stats_update_end(&stats->syncp); + } + + if (v & EMAC_RX_BUF_UA_INT) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +index 9470d3fd2dede..0d185e54eb7e2 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +@@ -171,8 +171,7 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, + const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; + u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan)); + u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); +- struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; +- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; ++ struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); + int ret = 0; + + if (dir == DMA_DIR_RX) +@@ -201,15 +200,15 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, + } + /* TX/RX NORMAL interrupts */ + if (likely(intr_status & DMA_CHAN_STATUS_RI)) { +- u64_stats_update_begin(&rxq_stats->syncp); +- rxq_stats->rx_normal_irq_n++; +- u64_stats_update_end(&rxq_stats->syncp); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->rx_normal_irq_n[chan]); ++ u64_stats_update_end(&stats->syncp); + ret |= handle_rx; + } + if (likely(intr_status & DMA_CHAN_STATUS_TI)) { +- u64_stats_update_begin(&txq_stats->syncp); +- txq_stats->tx_normal_irq_n++; +- u64_stats_update_end(&txq_stats->syncp); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->tx_normal_irq_n[chan]); ++ u64_stats_update_end(&stats->syncp); + ret |= handle_tx; + } + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +index 7907d62d34375..85e18f9a22f92 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +@@ -162,8 +162,7 @@ static void show_rx_process_state(unsigned int status) + int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, + struct stmmac_extra_stats *x, u32 chan, u32 dir) + { +- struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; +- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; ++ struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); + int ret = 0; + /* read the status register (CSR5) */ + u32 intr_status = readl(ioaddr + DMA_STATUS); +@@ -215,16 +214,16 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, + u32 value = readl(ioaddr + DMA_INTR_ENA); + /* to schedule NAPI on real RIE event. */ + if (likely(value & DMA_INTR_ENA_RIE)) { +- u64_stats_update_begin(&rxq_stats->syncp); +- rxq_stats->rx_normal_irq_n++; +- u64_stats_update_end(&rxq_stats->syncp); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->rx_normal_irq_n[chan]); ++ u64_stats_update_end(&stats->syncp); + ret |= handle_rx; + } + } + if (likely(intr_status & DMA_STATUS_TI)) { +- u64_stats_update_begin(&txq_stats->syncp); +- txq_stats->tx_normal_irq_n++; +- u64_stats_update_end(&txq_stats->syncp); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->tx_normal_irq_n[chan]); ++ u64_stats_update_end(&stats->syncp); + ret |= handle_tx; + } + if (unlikely(intr_status & DMA_STATUS_ERI)) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +index 3cde695fec91b..dd2ab6185c40e 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +@@ -337,8 +337,7 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, + struct stmmac_extra_stats *x, u32 chan, + u32 dir) + { +- struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; +- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; ++ struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats); + u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan)); + u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); + int ret = 0; +@@ -367,15 +366,15 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, + /* TX/RX NORMAL interrupts */ + if (likely(intr_status & XGMAC_NIS)) { + if (likely(intr_status & XGMAC_RI)) { +- u64_stats_update_begin(&rxq_stats->syncp); +- rxq_stats->rx_normal_irq_n++; +- u64_stats_update_end(&rxq_stats->syncp); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->rx_normal_irq_n[chan]); ++ u64_stats_update_end(&stats->syncp); + ret |= handle_rx; + } + if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) { +- u64_stats_update_begin(&txq_stats->syncp); +- txq_stats->tx_normal_irq_n++; +- u64_stats_update_end(&txq_stats->syncp); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->tx_normal_irq_n[chan]); ++ u64_stats_update_end(&stats->syncp); + ret |= handle_tx; + } + } +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +index 69c8c25285243..521b1b5ffebb4 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +@@ -539,44 +539,79 @@ stmmac_set_pauseparam(struct net_device *netdev, + } + } + ++static u64 stmmac_get_rx_normal_irq_n(struct stmmac_priv *priv, int q) ++{ ++ u64 total; ++ int cpu; ++ ++ total = 0; ++ for_each_possible_cpu(cpu) { ++ struct stmmac_pcpu_stats *pcpu; ++ unsigned int start; ++ u64 irq_n; ++ ++ pcpu = per_cpu_ptr(priv->xstats.pcpu_stats, cpu); ++ do { ++ start = u64_stats_fetch_begin(&pcpu->syncp); ++ irq_n = u64_stats_read(&pcpu->rx_normal_irq_n[q]); ++ } while (u64_stats_fetch_retry(&pcpu->syncp, start)); ++ total += irq_n; ++ } ++ return total; ++} ++ ++static u64 stmmac_get_tx_normal_irq_n(struct stmmac_priv *priv, int q) ++{ ++ u64 total; ++ int cpu; ++ ++ total = 0; ++ for_each_possible_cpu(cpu) { ++ struct stmmac_pcpu_stats *pcpu; ++ unsigned int start; ++ u64 irq_n; ++ ++ pcpu = per_cpu_ptr(priv->xstats.pcpu_stats, cpu); ++ do { ++ start = u64_stats_fetch_begin(&pcpu->syncp); ++ irq_n = u64_stats_read(&pcpu->tx_normal_irq_n[q]); ++ } while (u64_stats_fetch_retry(&pcpu->syncp, start)); ++ total += irq_n; ++ } ++ return total; ++} ++ + static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data) + { + u32 tx_cnt = priv->plat->tx_queues_to_use; + u32 rx_cnt = priv->plat->rx_queues_to_use; + unsigned int start; +- int q, stat; +- char *p; ++ int q; + + for (q = 0; q < tx_cnt; q++) { + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q]; +- struct stmmac_txq_stats snapshot; ++ u64 pkt_n; + + do { +- start = u64_stats_fetch_begin(&txq_stats->syncp); +- snapshot = *txq_stats; +- } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); ++ start = u64_stats_fetch_begin(&txq_stats->napi_syncp); ++ pkt_n = u64_stats_read(&txq_stats->napi.tx_pkt_n); ++ } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start)); + +- p = (char *)&snapshot + offsetof(struct stmmac_txq_stats, tx_pkt_n); +- for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) { +- *data++ = (*(u64 *)p); +- p += sizeof(u64); +- } ++ *data++ = pkt_n; ++ *data++ = stmmac_get_tx_normal_irq_n(priv, q); + } + + for (q = 0; q < rx_cnt; q++) { + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q]; +- struct stmmac_rxq_stats snapshot; ++ u64 pkt_n; + + do { +- start = u64_stats_fetch_begin(&rxq_stats->syncp); +- snapshot = *rxq_stats; +- } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); ++ start = u64_stats_fetch_begin(&rxq_stats->napi_syncp); ++ pkt_n = u64_stats_read(&rxq_stats->napi.rx_pkt_n); ++ } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start)); + +- p = (char *)&snapshot + offsetof(struct stmmac_rxq_stats, rx_pkt_n); +- for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) { +- *data++ = (*(u64 *)p); +- p += sizeof(u64); +- } ++ *data++ = pkt_n; ++ *data++ = stmmac_get_rx_normal_irq_n(priv, q); + } + } + +@@ -635,39 +670,49 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, + pos = j; + for (i = 0; i < rx_queues_count; i++) { + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[i]; +- struct stmmac_rxq_stats snapshot; ++ struct stmmac_napi_rx_stats snapshot; ++ u64 n_irq; + + j = pos; + do { +- start = u64_stats_fetch_begin(&rxq_stats->syncp); +- snapshot = *rxq_stats; +- } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); +- +- data[j++] += snapshot.rx_pkt_n; +- data[j++] += snapshot.rx_normal_irq_n; +- normal_irq_n += snapshot.rx_normal_irq_n; +- napi_poll += snapshot.napi_poll; ++ start = u64_stats_fetch_begin(&rxq_stats->napi_syncp); ++ snapshot = rxq_stats->napi; ++ } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start)); ++ ++ data[j++] += u64_stats_read(&snapshot.rx_pkt_n); ++ n_irq = stmmac_get_rx_normal_irq_n(priv, i); ++ data[j++] += n_irq; ++ normal_irq_n += n_irq; ++ napi_poll += u64_stats_read(&snapshot.poll); + } + + pos = j; + for (i = 0; i < tx_queues_count; i++) { + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[i]; +- struct stmmac_txq_stats snapshot; ++ struct stmmac_napi_tx_stats napi_snapshot; ++ struct stmmac_q_tx_stats q_snapshot; ++ u64 n_irq; + + j = pos; + do { +- start = u64_stats_fetch_begin(&txq_stats->syncp); +- snapshot = *txq_stats; +- } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); +- +- data[j++] += snapshot.tx_pkt_n; +- data[j++] += snapshot.tx_normal_irq_n; +- normal_irq_n += snapshot.tx_normal_irq_n; +- data[j++] += snapshot.tx_clean; +- data[j++] += snapshot.tx_set_ic_bit; +- data[j++] += snapshot.tx_tso_frames; +- data[j++] += snapshot.tx_tso_nfrags; +- napi_poll += snapshot.napi_poll; ++ start = u64_stats_fetch_begin(&txq_stats->q_syncp); ++ q_snapshot = txq_stats->q; ++ } while (u64_stats_fetch_retry(&txq_stats->q_syncp, start)); ++ do { ++ start = u64_stats_fetch_begin(&txq_stats->napi_syncp); ++ napi_snapshot = txq_stats->napi; ++ } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start)); ++ ++ data[j++] += u64_stats_read(&napi_snapshot.tx_pkt_n); ++ n_irq = stmmac_get_tx_normal_irq_n(priv, i); ++ data[j++] += n_irq; ++ normal_irq_n += n_irq; ++ data[j++] += u64_stats_read(&napi_snapshot.tx_clean); ++ data[j++] += u64_stats_read(&q_snapshot.tx_set_ic_bit) + ++ u64_stats_read(&napi_snapshot.tx_set_ic_bit); ++ data[j++] += u64_stats_read(&q_snapshot.tx_tso_frames); ++ data[j++] += u64_stats_read(&q_snapshot.tx_tso_nfrags); ++ napi_poll += u64_stats_read(&napi_snapshot.poll); + } + normal_irq_n += priv->xstats.rx_early_irq; + data[j++] = normal_irq_n; +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 292857c0e601f..f1614ad2daaa7 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -2442,7 +2442,6 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) + struct xdp_desc xdp_desc; + bool work_done = true; + u32 tx_set_ic_bit = 0; +- unsigned long flags; + + /* Avoids TX time-out as we are sharing with slow path */ + txq_trans_cond_update(nq); +@@ -2515,9 +2514,9 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) + tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + entry = tx_q->cur_tx; + } +- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); +- txq_stats->tx_set_ic_bit += tx_set_ic_bit; +- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); ++ u64_stats_update_begin(&txq_stats->napi_syncp); ++ u64_stats_add(&txq_stats->napi.tx_set_ic_bit, tx_set_ic_bit); ++ u64_stats_update_end(&txq_stats->napi_syncp); + + if (tx_desc) { + stmmac_flush_tx_descriptors(priv, queue); +@@ -2561,7 +2560,6 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) + unsigned int bytes_compl = 0, pkts_compl = 0; + unsigned int entry, xmits = 0, count = 0; + u32 tx_packets = 0, tx_errors = 0; +- unsigned long flags; + + __netif_tx_lock_bh(netdev_get_tx_queue(priv->dev, queue)); + +@@ -2717,11 +2715,11 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) + if (tx_q->dirty_tx != tx_q->cur_tx) + stmmac_tx_timer_arm(priv, queue); + +- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); +- txq_stats->tx_packets += tx_packets; +- txq_stats->tx_pkt_n += tx_packets; +- txq_stats->tx_clean++; +- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); ++ u64_stats_update_begin(&txq_stats->napi_syncp); ++ u64_stats_add(&txq_stats->napi.tx_packets, tx_packets); ++ u64_stats_add(&txq_stats->napi.tx_pkt_n, tx_packets); ++ u64_stats_inc(&txq_stats->napi.tx_clean); ++ u64_stats_update_end(&txq_stats->napi_syncp); + + priv->xstats.tx_errors += tx_errors; + +@@ -3853,6 +3851,9 @@ static int __stmmac_open(struct net_device *dev, + priv->rx_copybreak = STMMAC_RX_COPYBREAK; + + buf_sz = dma_conf->dma_buf_sz; ++ for (int i = 0; i < MTL_MAX_TX_QUEUES; i++) ++ if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_EN) ++ dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs; + memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf)); + + stmmac_reset_queues_param(priv); +@@ -4131,7 +4132,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) + struct stmmac_tx_queue *tx_q; + bool has_vlan, set_ic; + u8 proto_hdr_len, hdr; +- unsigned long flags; + u32 pay_len, mss; + dma_addr_t des; + int i; +@@ -4296,13 +4296,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) + netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); + } + +- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); +- txq_stats->tx_bytes += skb->len; +- txq_stats->tx_tso_frames++; +- txq_stats->tx_tso_nfrags += nfrags; ++ u64_stats_update_begin(&txq_stats->q_syncp); ++ u64_stats_add(&txq_stats->q.tx_bytes, skb->len); ++ u64_stats_inc(&txq_stats->q.tx_tso_frames); ++ u64_stats_add(&txq_stats->q.tx_tso_nfrags, nfrags); + if (set_ic) +- txq_stats->tx_set_ic_bit++; +- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); ++ u64_stats_inc(&txq_stats->q.tx_set_ic_bit); ++ u64_stats_update_end(&txq_stats->q_syncp); + + if (priv->sarc_type) + stmmac_set_desc_sarc(priv, first, priv->sarc_type); +@@ -4401,7 +4401,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) + struct stmmac_tx_queue *tx_q; + bool has_vlan, set_ic; + int entry, first_tx; +- unsigned long flags; + dma_addr_t des; + + tx_q = &priv->dma_conf.tx_queue[queue]; +@@ -4571,11 +4570,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) + netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); + } + +- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); +- txq_stats->tx_bytes += skb->len; ++ u64_stats_update_begin(&txq_stats->q_syncp); ++ u64_stats_add(&txq_stats->q.tx_bytes, skb->len); + if (set_ic) +- txq_stats->tx_set_ic_bit++; +- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); ++ u64_stats_inc(&txq_stats->q.tx_set_ic_bit); ++ u64_stats_update_end(&txq_stats->q_syncp); + + if (priv->sarc_type) + stmmac_set_desc_sarc(priv, first, priv->sarc_type); +@@ -4839,12 +4838,11 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, + set_ic = false; + + if (set_ic) { +- unsigned long flags; + tx_q->tx_count_frames = 0; + stmmac_set_tx_ic(priv, tx_desc); +- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); +- txq_stats->tx_set_ic_bit++; +- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); ++ u64_stats_update_begin(&txq_stats->q_syncp); ++ u64_stats_inc(&txq_stats->q.tx_set_ic_bit); ++ u64_stats_update_end(&txq_stats->q_syncp); + } + + stmmac_enable_dma_transmission(priv, priv->ioaddr); +@@ -4994,7 +4992,6 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue, + unsigned int len = xdp->data_end - xdp->data; + enum pkt_hash_types hash_type; + int coe = priv->hw->rx_csum; +- unsigned long flags; + struct sk_buff *skb; + u32 hash; + +@@ -5019,10 +5016,10 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue, + skb_record_rx_queue(skb, queue); + napi_gro_receive(&ch->rxtx_napi, skb); + +- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); +- rxq_stats->rx_pkt_n++; +- rxq_stats->rx_bytes += len; +- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); ++ u64_stats_update_begin(&rxq_stats->napi_syncp); ++ u64_stats_inc(&rxq_stats->napi.rx_pkt_n); ++ u64_stats_add(&rxq_stats->napi.rx_bytes, len); ++ u64_stats_update_end(&rxq_stats->napi_syncp); + } + + static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget) +@@ -5104,7 +5101,6 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) + unsigned int desc_size; + struct bpf_prog *prog; + bool failure = false; +- unsigned long flags; + int xdp_status = 0; + int status = 0; + +@@ -5259,9 +5255,9 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) + + stmmac_finalize_xdp_rx(priv, xdp_status); + +- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); +- rxq_stats->rx_pkt_n += count; +- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); ++ u64_stats_update_begin(&rxq_stats->napi_syncp); ++ u64_stats_add(&rxq_stats->napi.rx_pkt_n, count); ++ u64_stats_update_end(&rxq_stats->napi_syncp); + + priv->xstats.rx_dropped += rx_dropped; + priv->xstats.rx_errors += rx_errors; +@@ -5299,7 +5295,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) + unsigned int desc_size; + struct sk_buff *skb = NULL; + struct stmmac_xdp_buff ctx; +- unsigned long flags; + int xdp_status = 0; + int buf_sz; + +@@ -5552,11 +5547,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) + + stmmac_rx_refill(priv, queue); + +- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); +- rxq_stats->rx_packets += rx_packets; +- rxq_stats->rx_bytes += rx_bytes; +- rxq_stats->rx_pkt_n += count; +- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); ++ u64_stats_update_begin(&rxq_stats->napi_syncp); ++ u64_stats_add(&rxq_stats->napi.rx_packets, rx_packets); ++ u64_stats_add(&rxq_stats->napi.rx_bytes, rx_bytes); ++ u64_stats_add(&rxq_stats->napi.rx_pkt_n, count); ++ u64_stats_update_end(&rxq_stats->napi_syncp); + + priv->xstats.rx_dropped += rx_dropped; + priv->xstats.rx_errors += rx_errors; +@@ -5571,13 +5566,12 @@ static int stmmac_napi_poll_rx(struct napi_struct *napi, int budget) + struct stmmac_priv *priv = ch->priv_data; + struct stmmac_rxq_stats *rxq_stats; + u32 chan = ch->index; +- unsigned long flags; + int work_done; + + rxq_stats = &priv->xstats.rxq_stats[chan]; +- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); +- rxq_stats->napi_poll++; +- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); ++ u64_stats_update_begin(&rxq_stats->napi_syncp); ++ u64_stats_inc(&rxq_stats->napi.poll); ++ u64_stats_update_end(&rxq_stats->napi_syncp); + + work_done = stmmac_rx(priv, budget, chan); + if (work_done < budget && napi_complete_done(napi, work_done)) { +@@ -5598,13 +5592,12 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget) + struct stmmac_priv *priv = ch->priv_data; + struct stmmac_txq_stats *txq_stats; + u32 chan = ch->index; +- unsigned long flags; + int work_done; + + txq_stats = &priv->xstats.txq_stats[chan]; +- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); +- txq_stats->napi_poll++; +- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); ++ u64_stats_update_begin(&txq_stats->napi_syncp); ++ u64_stats_inc(&txq_stats->napi.poll); ++ u64_stats_update_end(&txq_stats->napi_syncp); + + work_done = stmmac_tx_clean(priv, budget, chan); + work_done = min(work_done, budget); +@@ -5629,17 +5622,16 @@ static int stmmac_napi_poll_rxtx(struct napi_struct *napi, int budget) + struct stmmac_rxq_stats *rxq_stats; + struct stmmac_txq_stats *txq_stats; + u32 chan = ch->index; +- unsigned long flags; + + rxq_stats = &priv->xstats.rxq_stats[chan]; +- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); +- rxq_stats->napi_poll++; +- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); ++ u64_stats_update_begin(&rxq_stats->napi_syncp); ++ u64_stats_inc(&rxq_stats->napi.poll); ++ u64_stats_update_end(&rxq_stats->napi_syncp); + + txq_stats = &priv->xstats.txq_stats[chan]; +- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); +- txq_stats->napi_poll++; +- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); ++ u64_stats_update_begin(&txq_stats->napi_syncp); ++ u64_stats_inc(&txq_stats->napi.poll); ++ u64_stats_update_end(&txq_stats->napi_syncp); + + tx_done = stmmac_tx_clean(priv, budget, chan); + tx_done = min(tx_done, budget); +@@ -6961,10 +6953,13 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64 + u64 tx_bytes; + + do { +- start = u64_stats_fetch_begin(&txq_stats->syncp); +- tx_packets = txq_stats->tx_packets; +- tx_bytes = txq_stats->tx_bytes; +- } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); ++ start = u64_stats_fetch_begin(&txq_stats->q_syncp); ++ tx_bytes = u64_stats_read(&txq_stats->q.tx_bytes); ++ } while (u64_stats_fetch_retry(&txq_stats->q_syncp, start)); ++ do { ++ start = u64_stats_fetch_begin(&txq_stats->napi_syncp); ++ tx_packets = u64_stats_read(&txq_stats->napi.tx_packets); ++ } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start)); + + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; +@@ -6976,10 +6971,10 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64 + u64 rx_bytes; + + do { +- start = u64_stats_fetch_begin(&rxq_stats->syncp); +- rx_packets = rxq_stats->rx_packets; +- rx_bytes = rxq_stats->rx_bytes; +- } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); ++ start = u64_stats_fetch_begin(&rxq_stats->napi_syncp); ++ rx_packets = u64_stats_read(&rxq_stats->napi.rx_packets); ++ rx_bytes = u64_stats_read(&rxq_stats->napi.rx_bytes); ++ } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; +@@ -7373,9 +7368,16 @@ int stmmac_dvr_probe(struct device *device, + priv->dev = ndev; + + for (i = 0; i < MTL_MAX_RX_QUEUES; i++) +- u64_stats_init(&priv->xstats.rxq_stats[i].syncp); +- for (i = 0; i < MTL_MAX_TX_QUEUES; i++) +- u64_stats_init(&priv->xstats.txq_stats[i].syncp); ++ u64_stats_init(&priv->xstats.rxq_stats[i].napi_syncp); ++ for (i = 0; i < MTL_MAX_TX_QUEUES; i++) { ++ u64_stats_init(&priv->xstats.txq_stats[i].q_syncp); ++ u64_stats_init(&priv->xstats.txq_stats[i].napi_syncp); ++ } ++ ++ priv->xstats.pcpu_stats = ++ devm_netdev_alloc_pcpu_stats(device, struct stmmac_pcpu_stats); ++ if (!priv->xstats.pcpu_stats) ++ return -ENOMEM; + + stmmac_set_ethtool_ops(ndev); + priv->pause = pause; +diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c +index ca4d4548f85e3..2ed165dcdbdcf 100644 +--- a/drivers/net/ethernet/ti/cpsw.c ++++ b/drivers/net/ethernet/ti/cpsw.c +@@ -631,6 +631,8 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) + } + } + ++ phy->mac_managed_pm = true; ++ + slave->phy = phy; + + phy_attached_info(slave->phy); +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index 0e4f526b17532..9061dca97fcbf 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -773,6 +773,9 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) + slave->slave_num); + return; + } ++ ++ phy->mac_managed_pm = true; ++ + slave->phy = phy; + + phy_attached_info(slave->phy); +diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c +index 82e9796c8f5e5..4f9658a741024 100644 +--- a/drivers/net/hyperv/netvsc.c ++++ b/drivers/net/hyperv/netvsc.c +@@ -708,7 +708,10 @@ void netvsc_device_remove(struct hv_device *device) + /* Disable NAPI and disassociate its context from the device. */ + for (i = 0; i < net_device->num_chn; i++) { + /* See also vmbus_reset_channel_cb(). */ +- napi_disable(&net_device->chan_table[i].napi); ++ /* only disable enabled NAPI channel */ ++ if (i < ndev->real_num_rx_queues) ++ napi_disable(&net_device->chan_table[i].napi); ++ + netif_napi_del(&net_device->chan_table[i].napi); + } + +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index cd15d7b380ab5..9d2d66a4aafd5 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -42,6 +42,10 @@ + #define LINKCHANGE_INT (2 * HZ) + #define VF_TAKEOVER_INT (HZ / 10) + ++/* Macros to define the context of vf registration */ ++#define VF_REG_IN_PROBE 1 ++#define VF_REG_IN_NOTIFIER 2 ++ + static unsigned int ring_size __ro_after_init = 128; + module_param(ring_size, uint, 0444); + MODULE_PARM_DESC(ring_size, "Ring buffer size (# of 4K pages)"); +@@ -2183,7 +2187,7 @@ static rx_handler_result_t netvsc_vf_handle_frame(struct sk_buff **pskb) + } + + static int netvsc_vf_join(struct net_device *vf_netdev, +- struct net_device *ndev) ++ struct net_device *ndev, int context) + { + struct net_device_context *ndev_ctx = netdev_priv(ndev); + int ret; +@@ -2206,7 +2210,11 @@ static int netvsc_vf_join(struct net_device *vf_netdev, + goto upper_link_failed; + } + +- schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT); ++ /* If this registration is called from probe context vf_takeover ++ * is taken care of later in probe itself. ++ */ ++ if (context == VF_REG_IN_NOTIFIER) ++ schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT); + + call_netdevice_notifiers(NETDEV_JOIN, vf_netdev); + +@@ -2344,7 +2352,7 @@ static int netvsc_prepare_bonding(struct net_device *vf_netdev) + return NOTIFY_DONE; + } + +-static int netvsc_register_vf(struct net_device *vf_netdev) ++static int netvsc_register_vf(struct net_device *vf_netdev, int context) + { + struct net_device_context *net_device_ctx; + struct netvsc_device *netvsc_dev; +@@ -2384,7 +2392,7 @@ static int netvsc_register_vf(struct net_device *vf_netdev) + + netdev_info(ndev, "VF registering: %s\n", vf_netdev->name); + +- if (netvsc_vf_join(vf_netdev, ndev) != 0) ++ if (netvsc_vf_join(vf_netdev, ndev, context) != 0) + return NOTIFY_DONE; + + dev_hold(vf_netdev); +@@ -2482,10 +2490,31 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev) + return NOTIFY_OK; + } + ++static int check_dev_is_matching_vf(struct net_device *event_ndev) ++{ ++ /* Skip NetVSC interfaces */ ++ if (event_ndev->netdev_ops == &device_ops) ++ return -ENODEV; ++ ++ /* Avoid non-Ethernet type devices */ ++ if (event_ndev->type != ARPHRD_ETHER) ++ return -ENODEV; ++ ++ /* Avoid Vlan dev with same MAC registering as VF */ ++ if (is_vlan_dev(event_ndev)) ++ return -ENODEV; ++ ++ /* Avoid Bonding master dev with same MAC registering as VF */ ++ if (netif_is_bond_master(event_ndev)) ++ return -ENODEV; ++ ++ return 0; ++} ++ + static int netvsc_probe(struct hv_device *dev, + const struct hv_vmbus_device_id *dev_id) + { +- struct net_device *net = NULL; ++ struct net_device *net = NULL, *vf_netdev; + struct net_device_context *net_device_ctx; + struct netvsc_device_info *device_info = NULL; + struct netvsc_device *nvdev; +@@ -2597,6 +2626,30 @@ static int netvsc_probe(struct hv_device *dev, + } + + list_add(&net_device_ctx->list, &netvsc_dev_list); ++ ++ /* When the hv_netvsc driver is unloaded and reloaded, the ++ * NET_DEVICE_REGISTER for the vf device is replayed before probe ++ * is complete. This is because register_netdevice_notifier() gets ++ * registered before vmbus_driver_register() so that callback func ++ * is set before probe and we don't miss events like NETDEV_POST_INIT ++ * So, in this section we try to register the matching vf device that ++ * is present as a netdevice, knowing that its register call is not ++ * processed in the netvsc_netdev_notifier(as probing is progress and ++ * get_netvsc_byslot fails). ++ */ ++ for_each_netdev(dev_net(net), vf_netdev) { ++ ret = check_dev_is_matching_vf(vf_netdev); ++ if (ret != 0) ++ continue; ++ ++ if (net != get_netvsc_byslot(vf_netdev)) ++ continue; ++ ++ netvsc_prepare_bonding(vf_netdev); ++ netvsc_register_vf(vf_netdev, VF_REG_IN_PROBE); ++ __netvsc_vf_setup(net, vf_netdev); ++ break; ++ } + rtnl_unlock(); + + netvsc_devinfo_put(device_info); +@@ -2752,28 +2805,17 @@ static int netvsc_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) + { + struct net_device *event_dev = netdev_notifier_info_to_dev(ptr); ++ int ret = 0; + +- /* Skip our own events */ +- if (event_dev->netdev_ops == &device_ops) +- return NOTIFY_DONE; +- +- /* Avoid non-Ethernet type devices */ +- if (event_dev->type != ARPHRD_ETHER) +- return NOTIFY_DONE; +- +- /* Avoid Vlan dev with same MAC registering as VF */ +- if (is_vlan_dev(event_dev)) +- return NOTIFY_DONE; +- +- /* Avoid Bonding master dev with same MAC registering as VF */ +- if (netif_is_bond_master(event_dev)) ++ ret = check_dev_is_matching_vf(event_dev); ++ if (ret != 0) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_POST_INIT: + return netvsc_prepare_bonding(event_dev); + case NETDEV_REGISTER: +- return netvsc_register_vf(event_dev); ++ return netvsc_register_vf(event_dev, VF_REG_IN_NOTIFIER); + case NETDEV_UNREGISTER: + return netvsc_unregister_vf(event_dev); + case NETDEV_UP: +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +index b26f90e522564..359397a617153 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c ++++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +@@ -618,7 +618,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { +- ret = PTR_ERR(wifi_pkg); ++ ret = -EINVAL; + goto out_free; + } + +@@ -634,7 +634,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 1) { +- ret = PTR_ERR(wifi_pkg); ++ ret = -EINVAL; + goto out_free; + } + +@@ -650,7 +650,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0) { +- ret = PTR_ERR(wifi_pkg); ++ ret = -EINVAL; + goto out_free; + } + +@@ -707,7 +707,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { +- ret = PTR_ERR(wifi_pkg); ++ ret = -EINVAL; + goto out_free; + } + +@@ -723,7 +723,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 1) { +- ret = PTR_ERR(wifi_pkg); ++ ret = -EINVAL; + goto out_free; + } + +@@ -739,7 +739,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0) { +- ret = PTR_ERR(wifi_pkg); ++ ret = -EINVAL; + goto out_free; + } + +@@ -1088,6 +1088,9 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) + goto read_table; + } + ++ ret = PTR_ERR(wifi_pkg); ++ goto out_free; ++ + read_table: + fwrt->ppag_ver = tbl_rev; + flags = &wifi_pkg->package.elements[1]; +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +index fb5e254757e71..8faf4e7872bb9 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +@@ -128,6 +128,7 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) + kfree(drv->fw.ucode_capa.cmd_versions); + kfree(drv->fw.phy_integration_ver); + kfree(drv->trans->dbg.pc_data); ++ drv->trans->dbg.pc_data = NULL; + + for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) + iwl_free_fw_img(drv, drv->fw.img + i); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +index a25ea638229b0..0aeca64725da6 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +@@ -3666,6 +3666,9 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, + NL80211_TDLS_SETUP); + } + ++ if (ret) ++ return ret; ++ + for_each_sta_active_link(vif, sta, link_sta, i) + link_sta->agg.max_rc_amsdu_len = 1; + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +index 8d1e44fd9de73..82b4d4d01097a 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +@@ -503,6 +503,10 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, + return false; + + mvm_sta = iwl_mvm_sta_from_mac80211(sta); ++ ++ if (WARN_ON_ONCE(!mvm_sta->dup_data)) ++ return false; ++ + dup_data = &mvm_sta->dup_data[queue]; + + /* +diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c +index d7503aef599f0..fab361a250d60 100644 +--- a/drivers/net/xen-netback/netback.c ++++ b/drivers/net/xen-netback/netback.c +@@ -104,13 +104,12 @@ bool provides_xdp_headroom = true; + module_param(provides_xdp_headroom, bool, 0644); + + static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, +- u8 status); ++ s8 status); + + static void make_tx_response(struct xenvif_queue *queue, +- struct xen_netif_tx_request *txp, ++ const struct xen_netif_tx_request *txp, + unsigned int extra_count, +- s8 st); +-static void push_tx_responses(struct xenvif_queue *queue); ++ s8 status); + + static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx); + +@@ -208,13 +207,9 @@ static void xenvif_tx_err(struct xenvif_queue *queue, + unsigned int extra_count, RING_IDX end) + { + RING_IDX cons = queue->tx.req_cons; +- unsigned long flags; + + do { +- spin_lock_irqsave(&queue->response_lock, flags); + make_tx_response(queue, txp, extra_count, XEN_NETIF_RSP_ERROR); +- push_tx_responses(queue); +- spin_unlock_irqrestore(&queue->response_lock, flags); + if (cons == end) + break; + RING_COPY_REQUEST(&queue->tx, cons++, txp); +@@ -465,12 +460,7 @@ static void xenvif_get_requests(struct xenvif_queue *queue, + for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS; + nr_slots--) { + if (unlikely(!txp->size)) { +- unsigned long flags; +- +- spin_lock_irqsave(&queue->response_lock, flags); + make_tx_response(queue, txp, 0, XEN_NETIF_RSP_OKAY); +- push_tx_responses(queue); +- spin_unlock_irqrestore(&queue->response_lock, flags); + ++txp; + continue; + } +@@ -496,14 +486,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue, + + for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots; ++txp) { + if (unlikely(!txp->size)) { +- unsigned long flags; +- +- spin_lock_irqsave(&queue->response_lock, flags); + make_tx_response(queue, txp, 0, + XEN_NETIF_RSP_OKAY); +- push_tx_responses(queue); +- spin_unlock_irqrestore(&queue->response_lock, +- flags); + continue; + } + +@@ -995,7 +979,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, + (ret == 0) ? + XEN_NETIF_RSP_OKAY : + XEN_NETIF_RSP_ERROR); +- push_tx_responses(queue); + continue; + } + +@@ -1007,7 +990,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, + + make_tx_response(queue, &txreq, extra_count, + XEN_NETIF_RSP_OKAY); +- push_tx_responses(queue); + continue; + } + +@@ -1433,8 +1415,35 @@ int xenvif_tx_action(struct xenvif_queue *queue, int budget) + return work_done; + } + ++static void _make_tx_response(struct xenvif_queue *queue, ++ const struct xen_netif_tx_request *txp, ++ unsigned int extra_count, ++ s8 status) ++{ ++ RING_IDX i = queue->tx.rsp_prod_pvt; ++ struct xen_netif_tx_response *resp; ++ ++ resp = RING_GET_RESPONSE(&queue->tx, i); ++ resp->id = txp->id; ++ resp->status = status; ++ ++ while (extra_count-- != 0) ++ RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL; ++ ++ queue->tx.rsp_prod_pvt = ++i; ++} ++ ++static void push_tx_responses(struct xenvif_queue *queue) ++{ ++ int notify; ++ ++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify); ++ if (notify) ++ notify_remote_via_irq(queue->tx_irq); ++} ++ + static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, +- u8 status) ++ s8 status) + { + struct pending_tx_info *pending_tx_info; + pending_ring_idx_t index; +@@ -1444,8 +1453,8 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, + + spin_lock_irqsave(&queue->response_lock, flags); + +- make_tx_response(queue, &pending_tx_info->req, +- pending_tx_info->extra_count, status); ++ _make_tx_response(queue, &pending_tx_info->req, ++ pending_tx_info->extra_count, status); + + /* Release the pending index before pusing the Tx response so + * its available before a new Tx request is pushed by the +@@ -1459,32 +1468,19 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, + spin_unlock_irqrestore(&queue->response_lock, flags); + } + +- + static void make_tx_response(struct xenvif_queue *queue, +- struct xen_netif_tx_request *txp, ++ const struct xen_netif_tx_request *txp, + unsigned int extra_count, +- s8 st) ++ s8 status) + { +- RING_IDX i = queue->tx.rsp_prod_pvt; +- struct xen_netif_tx_response *resp; +- +- resp = RING_GET_RESPONSE(&queue->tx, i); +- resp->id = txp->id; +- resp->status = st; +- +- while (extra_count-- != 0) +- RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL; ++ unsigned long flags; + +- queue->tx.rsp_prod_pvt = ++i; +-} ++ spin_lock_irqsave(&queue->response_lock, flags); + +-static void push_tx_responses(struct xenvif_queue *queue) +-{ +- int notify; ++ _make_tx_response(queue, txp, extra_count, status); ++ push_tx_responses(queue); + +- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify); +- if (notify) +- notify_remote_via_irq(queue->tx_irq); ++ spin_unlock_irqrestore(&queue->response_lock, flags); + } + + static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx) +diff --git a/drivers/of/property.c b/drivers/of/property.c +index cf8dacf3e3b84..e1a2cb5ef401c 100644 +--- a/drivers/of/property.c ++++ b/drivers/of/property.c +@@ -762,7 +762,9 @@ struct device_node *of_graph_get_port_parent(struct device_node *node) + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && node; depth--) { + node = of_get_next_parent(node); +- if (depth == 2 && !of_node_name_eq(node, "ports")) ++ if (depth == 2 && !of_node_name_eq(node, "ports") && ++ !of_node_name_eq(node, "in-ports") && ++ !of_node_name_eq(node, "out-ports")) + break; + } + return node; +@@ -1062,36 +1064,6 @@ of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + return of_device_get_match_data(dev); + } + +-static struct device_node *of_get_compat_node(struct device_node *np) +-{ +- of_node_get(np); +- +- while (np) { +- if (!of_device_is_available(np)) { +- of_node_put(np); +- np = NULL; +- } +- +- if (of_property_present(np, "compatible")) +- break; +- +- np = of_get_next_parent(np); +- } +- +- return np; +-} +- +-static struct device_node *of_get_compat_node_parent(struct device_node *np) +-{ +- struct device_node *parent, *node; +- +- parent = of_get_parent(np); +- node = of_get_compat_node(parent); +- of_node_put(parent); +- +- return node; +-} +- + static void of_link_to_phandle(struct device_node *con_np, + struct device_node *sup_np) + { +@@ -1221,10 +1193,10 @@ static struct device_node *parse_##fname(struct device_node *np, \ + * @parse_prop.prop_name: Name of property holding a phandle value + * @parse_prop.index: For properties holding a list of phandles, this is the + * index into the list ++ * @get_con_dev: If the consumer node containing the property is never converted ++ * to a struct device, implement this ops so fw_devlink can use it ++ * to find the true consumer. + * @optional: Describes whether a supplier is mandatory or not +- * @node_not_dev: The consumer node containing the property is never converted +- * to a struct device. Instead, parse ancestor nodes for the +- * compatible property to find a node corresponding to a device. + * + * Returns: + * parse_prop() return values are +@@ -1235,15 +1207,15 @@ static struct device_node *parse_##fname(struct device_node *np, \ + struct supplier_bindings { + struct device_node *(*parse_prop)(struct device_node *np, + const char *prop_name, int index); ++ struct device_node *(*get_con_dev)(struct device_node *np); + bool optional; +- bool node_not_dev; + }; + + DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells") + DEFINE_SIMPLE_PROP(interconnects, "interconnects", "#interconnect-cells") + DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells") + DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells") +-DEFINE_SIMPLE_PROP(io_channels, "io-channel", "#io-channel-cells") ++DEFINE_SIMPLE_PROP(io_channels, "io-channels", "#io-channel-cells") + DEFINE_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL) + DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells") + DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells") +@@ -1261,7 +1233,6 @@ DEFINE_SIMPLE_PROP(pinctrl5, "pinctrl-5", NULL) + DEFINE_SIMPLE_PROP(pinctrl6, "pinctrl-6", NULL) + DEFINE_SIMPLE_PROP(pinctrl7, "pinctrl-7", NULL) + DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL) +-DEFINE_SIMPLE_PROP(remote_endpoint, "remote-endpoint", NULL) + DEFINE_SIMPLE_PROP(pwms, "pwms", "#pwm-cells") + DEFINE_SIMPLE_PROP(resets, "resets", "#reset-cells") + DEFINE_SIMPLE_PROP(leds, "leds", NULL) +@@ -1326,6 +1297,17 @@ static struct device_node *parse_interrupts(struct device_node *np, + return of_irq_parse_one(np, index, &sup_args) ? NULL : sup_args.np; + } + ++static struct device_node *parse_remote_endpoint(struct device_node *np, ++ const char *prop_name, ++ int index) ++{ ++ /* Return NULL for index > 0 to signify end of remote-endpoints. */ ++ if (!index || strcmp(prop_name, "remote-endpoint")) ++ return NULL; ++ ++ return of_graph_get_remote_port_parent(np); ++} ++ + static const struct supplier_bindings of_supplier_bindings[] = { + { .parse_prop = parse_clocks, }, + { .parse_prop = parse_interconnects, }, +@@ -1350,7 +1332,10 @@ static const struct supplier_bindings of_supplier_bindings[] = { + { .parse_prop = parse_pinctrl6, }, + { .parse_prop = parse_pinctrl7, }, + { .parse_prop = parse_pinctrl8, }, +- { .parse_prop = parse_remote_endpoint, .node_not_dev = true, }, ++ { ++ .parse_prop = parse_remote_endpoint, ++ .get_con_dev = of_graph_get_port_parent, ++ }, + { .parse_prop = parse_pwms, }, + { .parse_prop = parse_resets, }, + { .parse_prop = parse_leds, }, +@@ -1400,8 +1385,8 @@ static int of_link_property(struct device_node *con_np, const char *prop_name) + while ((phandle = s->parse_prop(con_np, prop_name, i))) { + struct device_node *con_dev_np; + +- con_dev_np = s->node_not_dev +- ? of_get_compat_node_parent(con_np) ++ con_dev_np = s->get_con_dev ++ ? s->get_con_dev(con_np) + : of_node_get(con_np); + matched = true; + i++; +diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c +index f278def7ef038..4f58345b5c683 100644 +--- a/drivers/of/unittest.c ++++ b/drivers/of/unittest.c +@@ -50,6 +50,12 @@ static struct unittest_results { + failed; \ + }) + ++#ifdef CONFIG_OF_KOBJ ++#define OF_KREF_READ(NODE) kref_read(&(NODE)->kobj.kref) ++#else ++#define OF_KREF_READ(NODE) 1 ++#endif ++ + /* + * Expected message may have a message level other than KERN_INFO. + * Print the expected message only if the current loglevel will allow +@@ -570,7 +576,7 @@ static void __init of_unittest_parse_phandle_with_args_map(void) + pr_err("missing testcase data\n"); + return; + } +- prefs[i] = kref_read(&p[i]->kobj.kref); ++ prefs[i] = OF_KREF_READ(p[i]); + } + + rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells"); +@@ -693,9 +699,9 @@ static void __init of_unittest_parse_phandle_with_args_map(void) + unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); + + for (i = 0; i < ARRAY_SIZE(p); ++i) { +- unittest(prefs[i] == kref_read(&p[i]->kobj.kref), ++ unittest(prefs[i] == OF_KREF_READ(p[i]), + "provider%d: expected:%d got:%d\n", +- i, prefs[i], kref_read(&p[i]->kobj.kref)); ++ i, prefs[i], OF_KREF_READ(p[i])); + of_node_put(p[i]); + } + } +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 59d6cb1a3a9d5..06fc6f532d6c4 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -2434,29 +2434,36 @@ static void pci_pme_list_scan(struct work_struct *work) + if (pdev->pme_poll) { + struct pci_dev *bridge = pdev->bus->self; + struct device *dev = &pdev->dev; +- int pm_status; ++ struct device *bdev = bridge ? &bridge->dev : NULL; ++ int bref = 0; + + /* +- * If bridge is in low power state, the +- * configuration space of subordinate devices +- * may be not accessible ++ * If we have a bridge, it should be in an active/D0 ++ * state or the configuration space of subordinate ++ * devices may not be accessible or stable over the ++ * course of the call. + */ +- if (bridge && bridge->current_state != PCI_D0) +- continue; ++ if (bdev) { ++ bref = pm_runtime_get_if_active(bdev, true); ++ if (!bref) ++ continue; ++ ++ if (bridge->current_state != PCI_D0) ++ goto put_bridge; ++ } + + /* +- * If the device is in a low power state it +- * should not be polled either. ++ * The device itself should be suspended but config ++ * space must be accessible, therefore it cannot be in ++ * D3cold. + */ +- pm_status = pm_runtime_get_if_active(dev, true); +- if (!pm_status) +- continue; +- +- if (pdev->current_state != PCI_D3cold) ++ if (pm_runtime_suspended(dev) && ++ pdev->current_state != PCI_D3cold) + pci_pme_wakeup(pdev, NULL); + +- if (pm_status > 0) +- pm_runtime_put(dev); ++put_bridge: ++ if (bref > 0) ++ pm_runtime_put(bdev); + } else { + list_del(&pme_dev->list); + kfree(pme_dev); +diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c +index 365d964b0f6a6..bc0d414a6aff9 100644 +--- a/drivers/perf/cxl_pmu.c ++++ b/drivers/perf/cxl_pmu.c +@@ -419,7 +419,7 @@ static struct attribute *cxl_pmu_event_attrs[] = { + CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmp, CXL_PMU_GID_S2M_NDR, BIT(0)), + CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmps, CXL_PMU_GID_S2M_NDR, BIT(1)), + CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmpe, CXL_PMU_GID_S2M_NDR, BIT(2)), +- CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_biconflictack, CXL_PMU_GID_S2M_NDR, BIT(3)), ++ CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_biconflictack, CXL_PMU_GID_S2M_NDR, BIT(4)), + /* CXL rev 3.0 Table 3-46 S2M DRS opcodes */ + CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdata, CXL_PMU_GID_S2M_DRS, BIT(0)), + CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdatanxm, CXL_PMU_GID_S2M_DRS, BIT(1)), +diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c +index ee962804b8303..edded392950ce 100644 +--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c ++++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c +@@ -508,6 +508,11 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren + goto err_put_node; + } + ++ /* recursive call to add all subdomains */ ++ ret = scpsys_add_subdomain(scpsys, child); ++ if (ret) ++ goto err_put_node; ++ + ret = pm_genpd_add_subdomain(parent_pd, child_pd); + if (ret) { + dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n", +@@ -517,11 +522,6 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren + dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name, + child_pd->name); + } +- +- /* recursive call to add all subdomains */ +- ret = scpsys_add_subdomain(scpsys, child); +- if (ret) +- goto err_put_node; + } + + return 0; +@@ -535,9 +535,6 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd) + { + int ret; + +- if (scpsys_domain_is_on(pd)) +- scpsys_power_off(&pd->genpd); +- + /* + * We're in the error cleanup already, so we only complain, + * but won't emit another error on top of the original one. +@@ -547,6 +544,8 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd) + dev_err(pd->scpsys->dev, + "failed to remove domain '%s' : %d - state may be inconsistent\n", + pd->genpd.name, ret); ++ if (scpsys_domain_is_on(pd)) ++ scpsys_power_off(&pd->genpd); + + clk_bulk_put(pd->num_clks, pd->clks); + clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); +diff --git a/drivers/pmdomain/renesas/r8a77980-sysc.c b/drivers/pmdomain/renesas/r8a77980-sysc.c +index 39ca84a67daad..621e411fc9991 100644 +--- a/drivers/pmdomain/renesas/r8a77980-sysc.c ++++ b/drivers/pmdomain/renesas/r8a77980-sysc.c +@@ -25,7 +25,8 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = { + PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A77980_PD_CA53_CPU3, R8A77980_PD_CA53_SCU, + PD_CPU_NOCR }, +- { "cr7", 0x240, 0, R8A77980_PD_CR7, R8A77980_PD_ALWAYS_ON }, ++ { "cr7", 0x240, 0, R8A77980_PD_CR7, R8A77980_PD_ALWAYS_ON, ++ PD_CPU_NOCR }, + { "a3ir", 0x180, 0, R8A77980_PD_A3IR, R8A77980_PD_ALWAYS_ON }, + { "a2ir0", 0x400, 0, R8A77980_PD_A2IR0, R8A77980_PD_A3IR }, + { "a2ir1", 0x400, 1, R8A77980_PD_A2IR1, R8A77980_PD_A3IR }, +diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c +index b92a32b4b1141..04c64ce0a1ca1 100644 +--- a/drivers/s390/net/qeth_l3_main.c ++++ b/drivers/s390/net/qeth_l3_main.c +@@ -255,9 +255,10 @@ static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover) + if (!recover) { + hash_del(&addr->hnode); + kfree(addr); +- continue; ++ } else { ++ /* prepare for recovery */ ++ addr->disp_flag = QETH_DISP_ADDR_ADD; + } +- addr->disp_flag = QETH_DISP_ADDR_ADD; + } + + mutex_unlock(&card->ip_lock); +@@ -278,9 +279,11 @@ static void qeth_l3_recover_ip(struct qeth_card *card) + if (addr->disp_flag == QETH_DISP_ADDR_ADD) { + rc = qeth_l3_register_addr_entry(card, addr); + +- if (!rc) { ++ if (!rc || rc == -EADDRINUSE || rc == -ENETDOWN) { ++ /* keep it in the records */ + addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; + } else { ++ /* bad address */ + hash_del(&addr->hnode); + kfree(addr); + } +diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c +index 19eee108db021..5c8d1ba3f8f3c 100644 +--- a/drivers/scsi/fcoe/fcoe_ctlr.c ++++ b/drivers/scsi/fcoe/fcoe_ctlr.c +@@ -319,17 +319,16 @@ static void fcoe_ctlr_announce(struct fcoe_ctlr *fip) + { + struct fcoe_fcf *sel; + struct fcoe_fcf *fcf; +- unsigned long flags; + + mutex_lock(&fip->ctlr_mutex); +- spin_lock_irqsave(&fip->ctlr_lock, flags); ++ spin_lock_bh(&fip->ctlr_lock); + + kfree_skb(fip->flogi_req); + fip->flogi_req = NULL; + list_for_each_entry(fcf, &fip->fcfs, list) + fcf->flogi_sent = 0; + +- spin_unlock_irqrestore(&fip->ctlr_lock, flags); ++ spin_unlock_bh(&fip->ctlr_lock); + sel = fip->sel_fcf; + + if (sel && ether_addr_equal(sel->fcf_mac, fip->dest_addr)) +@@ -700,7 +699,6 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, + { + struct fc_frame *fp; + struct fc_frame_header *fh; +- unsigned long flags; + u16 old_xid; + u8 op; + u8 mac[ETH_ALEN]; +@@ -734,11 +732,11 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, + op = FIP_DT_FLOGI; + if (fip->mode == FIP_MODE_VN2VN) + break; +- spin_lock_irqsave(&fip->ctlr_lock, flags); ++ spin_lock_bh(&fip->ctlr_lock); + kfree_skb(fip->flogi_req); + fip->flogi_req = skb; + fip->flogi_req_send = 1; +- spin_unlock_irqrestore(&fip->ctlr_lock, flags); ++ spin_unlock_bh(&fip->ctlr_lock); + schedule_work(&fip->timer_work); + return -EINPROGRESS; + case ELS_FDISC: +@@ -1707,11 +1705,10 @@ static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip) + static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) + { + struct fcoe_fcf *fcf; +- unsigned long flags; + int error; + + mutex_lock(&fip->ctlr_mutex); +- spin_lock_irqsave(&fip->ctlr_lock, flags); ++ spin_lock_bh(&fip->ctlr_lock); + LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n"); + fcf = fcoe_ctlr_select(fip); + if (!fcf || fcf->flogi_sent) { +@@ -1722,7 +1719,7 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) + fcoe_ctlr_solicit(fip, NULL); + error = fcoe_ctlr_flogi_send_locked(fip); + } +- spin_unlock_irqrestore(&fip->ctlr_lock, flags); ++ spin_unlock_bh(&fip->ctlr_lock); + mutex_unlock(&fip->ctlr_mutex); + return error; + } +@@ -1739,9 +1736,8 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) + static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip) + { + struct fcoe_fcf *fcf; +- unsigned long flags; + +- spin_lock_irqsave(&fip->ctlr_lock, flags); ++ spin_lock_bh(&fip->ctlr_lock); + fcf = fip->sel_fcf; + if (!fcf || !fip->flogi_req_send) + goto unlock; +@@ -1768,7 +1764,7 @@ static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip) + } else /* XXX */ + LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n"); + unlock: +- spin_unlock_irqrestore(&fip->ctlr_lock, flags); ++ spin_unlock_bh(&fip->ctlr_lock); + } + + /** +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index a95936b18f695..7ceb982040a5d 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -330,6 +330,7 @@ enum storvsc_request_type { + */ + + static int storvsc_ringbuffer_size = (128 * 1024); ++static int aligned_ringbuffer_size; + static u32 max_outstanding_req_per_channel; + static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth); + +@@ -687,8 +688,8 @@ static void handle_sc_creation(struct vmbus_channel *new_sc) + new_sc->next_request_id_callback = storvsc_next_request_id; + + ret = vmbus_open(new_sc, +- storvsc_ringbuffer_size, +- storvsc_ringbuffer_size, ++ aligned_ringbuffer_size, ++ aligned_ringbuffer_size, + (void *)&props, + sizeof(struct vmstorage_channel_properties), + storvsc_on_channel_callback, new_sc); +@@ -1973,7 +1974,7 @@ static int storvsc_probe(struct hv_device *device, + dma_set_min_align_mask(&device->device, HV_HYP_PAGE_SIZE - 1); + + stor_device->port_number = host->host_no; +- ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc); ++ ret = storvsc_connect_to_vsp(device, aligned_ringbuffer_size, is_fc); + if (ret) + goto err_out1; + +@@ -2164,7 +2165,7 @@ static int storvsc_resume(struct hv_device *hv_dev) + { + int ret; + +- ret = storvsc_connect_to_vsp(hv_dev, storvsc_ringbuffer_size, ++ ret = storvsc_connect_to_vsp(hv_dev, aligned_ringbuffer_size, + hv_dev_is_fc(hv_dev)); + return ret; + } +@@ -2198,8 +2199,9 @@ static int __init storvsc_drv_init(void) + * the ring buffer indices) by the max request size (which is + * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) + */ ++ aligned_ringbuffer_size = VMBUS_RING_SIZE(storvsc_ringbuffer_size); + max_outstanding_req_per_channel = +- ((storvsc_ringbuffer_size - PAGE_SIZE) / ++ ((aligned_ringbuffer_size - PAGE_SIZE) / + ALIGN(MAX_MULTIPAGE_BUFFER_PACKET + + sizeof(struct vstor_packet) + sizeof(u64), + sizeof(u64))); +diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c +index 272bc871a848b..e2d3e3ec13789 100644 +--- a/drivers/spi/spi-imx.c ++++ b/drivers/spi/spi-imx.c +@@ -2,6 +2,7 @@ + // Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + // Copyright (C) 2008 Juergen Beisert + ++#include <linux/bits.h> + #include <linux/clk.h> + #include <linux/completion.h> + #include <linux/delay.h> +@@ -660,15 +661,15 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, + << MX51_ECSPI_CTRL_BL_OFFSET; + else { + if (spi_imx->usedma) { +- ctrl |= (spi_imx->bits_per_word * +- spi_imx_bytes_per_word(spi_imx->bits_per_word) - 1) ++ ctrl |= (spi_imx->bits_per_word - 1) + << MX51_ECSPI_CTRL_BL_OFFSET; + } else { + if (spi_imx->count >= MX51_ECSPI_CTRL_MAX_BURST) +- ctrl |= (MX51_ECSPI_CTRL_MAX_BURST - 1) ++ ctrl |= (MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1) + << MX51_ECSPI_CTRL_BL_OFFSET; + else +- ctrl |= (spi_imx->count * spi_imx->bits_per_word - 1) ++ ctrl |= spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word, ++ BITS_PER_BYTE) * spi_imx->bits_per_word + << MX51_ECSPI_CTRL_BL_OFFSET; + } + } +diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c +index 03aab661be9d3..e982d3189fdce 100644 +--- a/drivers/spi/spi-ppc4xx.c ++++ b/drivers/spi/spi-ppc4xx.c +@@ -166,10 +166,8 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t) + int scr; + u8 cdm = 0; + u32 speed; +- u8 bits_per_word; + + /* Start with the generic configuration for this device. */ +- bits_per_word = spi->bits_per_word; + speed = spi->max_speed_hz; + + /* +@@ -177,9 +175,6 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t) + * the transfer to overwrite the generic configuration with zeros. + */ + if (t) { +- if (t->bits_per_word) +- bits_per_word = t->bits_per_word; +- + if (t->speed_hz) + speed = min(t->speed_hz, spi->max_speed_hz); + } +diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c +index 46db6d91542a4..2d0883a640827 100644 +--- a/drivers/staging/iio/impedance-analyzer/ad5933.c ++++ b/drivers/staging/iio/impedance-analyzer/ad5933.c +@@ -608,7 +608,7 @@ static void ad5933_work(struct work_struct *work) + struct ad5933_state, work.work); + struct iio_dev *indio_dev = i2c_get_clientdata(st->client); + __be16 buf[2]; +- int val[2]; ++ u16 val[2]; + unsigned char status; + int ret; + +diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h +index cf9f2370878a8..580277dc91152 100644 +--- a/drivers/thunderbolt/tb_regs.h ++++ b/drivers/thunderbolt/tb_regs.h +@@ -203,7 +203,7 @@ struct tb_regs_switch_header { + #define ROUTER_CS_5_WOP BIT(1) + #define ROUTER_CS_5_WOU BIT(2) + #define ROUTER_CS_5_WOD BIT(3) +-#define ROUTER_CS_5_C3S BIT(23) ++#define ROUTER_CS_5_CNS BIT(23) + #define ROUTER_CS_5_PTO BIT(24) + #define ROUTER_CS_5_UTO BIT(25) + #define ROUTER_CS_5_HCO BIT(26) +diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c +index 05ddb224c4649..13c779e23011b 100644 +--- a/drivers/thunderbolt/usb4.c ++++ b/drivers/thunderbolt/usb4.c +@@ -290,7 +290,7 @@ int usb4_switch_setup(struct tb_switch *sw) + } + + /* TBT3 supported by the CM */ +- val |= ROUTER_CS_5_C3S; ++ val &= ~ROUTER_CS_5_CNS; + + return tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); + } +diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c +index db3204d2a3053..3865c7f6dba8a 100644 +--- a/drivers/tty/serial/max310x.c ++++ b/drivers/tty/serial/max310x.c +@@ -237,6 +237,14 @@ + #define MAX310x_REV_MASK (0xf8) + #define MAX310X_WRITE_BIT 0x80 + ++/* Port startup definitions */ ++#define MAX310X_PORT_STARTUP_WAIT_RETRIES 20 /* Number of retries */ ++#define MAX310X_PORT_STARTUP_WAIT_DELAY_MS 10 /* Delay between retries */ ++ ++/* Crystal-related definitions */ ++#define MAX310X_XTAL_WAIT_RETRIES 20 /* Number of retries */ ++#define MAX310X_XTAL_WAIT_DELAY_MS 10 /* Delay between retries */ ++ + /* MAX3107 specific */ + #define MAX3107_REV_ID (0xa0) + +@@ -583,7 +591,7 @@ static int max310x_update_best_err(unsigned long f, long *besterr) + return 1; + } + +-static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, ++static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, + unsigned long freq, bool xtal) + { + unsigned int div, clksrc, pllcfg = 0; +@@ -641,12 +649,20 @@ static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, + + /* Wait for crystal */ + if (xtal) { +- unsigned int val; +- msleep(10); +- regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &val); +- if (!(val & MAX310X_STS_CLKREADY_BIT)) { +- dev_warn(dev, "clock is not stable yet\n"); +- } ++ bool stable = false; ++ unsigned int try = 0, val = 0; ++ ++ do { ++ msleep(MAX310X_XTAL_WAIT_DELAY_MS); ++ regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &val); ++ ++ if (val & MAX310X_STS_CLKREADY_BIT) ++ stable = true; ++ } while (!stable && (++try < MAX310X_XTAL_WAIT_RETRIES)); ++ ++ if (!stable) ++ return dev_err_probe(dev, -EAGAIN, ++ "clock is not stable\n"); + } + + return bestfreq; +@@ -1271,7 +1287,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty + { + int i, ret, fmin, fmax, freq; + struct max310x_port *s; +- u32 uartclk = 0; ++ s32 uartclk = 0; + bool xtal; + + for (i = 0; i < devtype->nr; i++) +@@ -1334,6 +1350,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty + goto out_clk; + + for (i = 0; i < devtype->nr; i++) { ++ bool started = false; ++ unsigned int try = 0, val = 0; ++ + /* Reset port */ + regmap_write(regmaps[i], MAX310X_MODE2_REG, + MAX310X_MODE2_RST_BIT); +@@ -1342,13 +1361,27 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty + + /* Wait for port startup */ + do { +- regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &ret); +- } while (ret != 0x01); ++ msleep(MAX310X_PORT_STARTUP_WAIT_DELAY_MS); ++ regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &val); ++ ++ if (val == 0x01) ++ started = true; ++ } while (!started && (++try < MAX310X_PORT_STARTUP_WAIT_RETRIES)); ++ ++ if (!started) { ++ ret = dev_err_probe(dev, -EAGAIN, "port reset failed\n"); ++ goto out_uart; ++ } + + regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1); + } + + uartclk = max310x_set_ref_clk(dev, s, freq, xtal); ++ if (uartclk < 0) { ++ ret = uartclk; ++ goto out_uart; ++ } ++ + dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); + + for (i = 0; i < devtype->nr; i++) { +diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c +index 8eeecf8ad3596..380a8b0590e34 100644 +--- a/drivers/tty/serial/mxs-auart.c ++++ b/drivers/tty/serial/mxs-auart.c +@@ -605,13 +605,16 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s) + return; + } + +- pending = uart_port_tx(&s->port, ch, ++ pending = uart_port_tx_flags(&s->port, ch, UART_TX_NOSTOP, + !(mxs_read(s, REG_STAT) & AUART_STAT_TXFF), + mxs_write(ch, s, REG_DATA)); + if (pending) + mxs_set(AUART_INTR_TXIEN, s, REG_INTR); + else + mxs_clr(AUART_INTR_TXIEN, s, REG_INTR); ++ ++ if (uart_tx_stopped(&s->port)) ++ mxs_auart_stop_tx(&s->port); + } + + static void mxs_auart_rx_char(struct mxs_auart_port *s) +diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h +index d9bb3d3f026e6..2a38e1eb65466 100644 +--- a/drivers/usb/chipidea/ci.h ++++ b/drivers/usb/chipidea/ci.h +@@ -176,6 +176,7 @@ struct hw_bank { + * @enabled_otg_timer_bits: bits of enabled otg timers + * @next_otg_timer: next nearest enabled timer to be expired + * @work: work for role changing ++ * @power_lost_work: work for power lost handling + * @wq: workqueue thread + * @qh_pool: allocation pool for queue heads + * @td_pool: allocation pool for transfer descriptors +@@ -226,6 +227,7 @@ struct ci_hdrc { + enum otg_fsm_timer next_otg_timer; + struct usb_role_switch *role_switch; + struct work_struct work; ++ struct work_struct power_lost_work; + struct workqueue_struct *wq; + + struct dma_pool *qh_pool; +diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c +index 85e9c3ab66e94..ca71df4f32e4c 100644 +--- a/drivers/usb/chipidea/core.c ++++ b/drivers/usb/chipidea/core.c +@@ -856,6 +856,27 @@ static int ci_extcon_register(struct ci_hdrc *ci) + return 0; + } + ++static void ci_power_lost_work(struct work_struct *work) ++{ ++ struct ci_hdrc *ci = container_of(work, struct ci_hdrc, power_lost_work); ++ enum ci_role role; ++ ++ disable_irq_nosync(ci->irq); ++ pm_runtime_get_sync(ci->dev); ++ if (!ci_otg_is_fsm_mode(ci)) { ++ role = ci_get_role(ci); ++ ++ if (ci->role != role) { ++ ci_handle_id_switch(ci); ++ } else if (role == CI_ROLE_GADGET) { ++ if (ci->is_otg && hw_read_otgsc(ci, OTGSC_BSV)) ++ usb_gadget_vbus_connect(&ci->gadget); ++ } ++ } ++ pm_runtime_put_sync(ci->dev); ++ enable_irq(ci->irq); ++} ++ + static DEFINE_IDA(ci_ida); + + struct platform_device *ci_hdrc_add_device(struct device *dev, +@@ -1045,6 +1066,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) + + spin_lock_init(&ci->lock); + mutex_init(&ci->mutex); ++ INIT_WORK(&ci->power_lost_work, ci_power_lost_work); ++ + ci->dev = dev; + ci->platdata = dev_get_platdata(dev); + ci->imx28_write_fix = !!(ci->platdata->flags & +@@ -1396,25 +1419,6 @@ static int ci_suspend(struct device *dev) + return 0; + } + +-static void ci_handle_power_lost(struct ci_hdrc *ci) +-{ +- enum ci_role role; +- +- disable_irq_nosync(ci->irq); +- if (!ci_otg_is_fsm_mode(ci)) { +- role = ci_get_role(ci); +- +- if (ci->role != role) { +- ci_handle_id_switch(ci); +- } else if (role == CI_ROLE_GADGET) { +- if (ci->is_otg && hw_read_otgsc(ci, OTGSC_BSV)) +- usb_gadget_vbus_connect(&ci->gadget); +- } +- } +- +- enable_irq(ci->irq); +-} +- + static int ci_resume(struct device *dev) + { + struct ci_hdrc *ci = dev_get_drvdata(dev); +@@ -1446,7 +1450,7 @@ static int ci_resume(struct device *dev) + ci_role(ci)->resume(ci, power_lost); + + if (power_lost) +- ci_handle_power_lost(ci); ++ queue_work(system_freezable_wq, &ci->power_lost_work); + + if (ci->supports_runtime_pm) { + pm_runtime_disable(dev); +diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c +index 84d91b1c1eed5..0886b19d2e1c8 100644 +--- a/drivers/usb/common/ulpi.c ++++ b/drivers/usb/common/ulpi.c +@@ -301,7 +301,7 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi) + return ret; + } + +- root = debugfs_create_dir(dev_name(dev), ulpi_root); ++ root = debugfs_create_dir(dev_name(&ulpi->dev), ulpi_root); + debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_fops); + + dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n", +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index bd27741327dfb..71635dfa741d2 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2047,9 +2047,19 @@ static void update_port_device_state(struct usb_device *udev) + + if (udev->parent) { + hub = usb_hub_to_struct_hub(udev->parent); +- port_dev = hub->ports[udev->portnum - 1]; +- WRITE_ONCE(port_dev->state, udev->state); +- sysfs_notify_dirent(port_dev->state_kn); ++ ++ /* ++ * The Link Layer Validation System Driver (lvstest) ++ * has a test step to unbind the hub before running the ++ * rest of the procedure. This triggers hub_disconnect ++ * which will set the hub's maxchild to 0, further ++ * resulting in usb_hub_to_struct_hub returning NULL. ++ */ ++ if (hub) { ++ port_dev = hub->ports[udev->portnum - 1]; ++ WRITE_ONCE(port_dev->state, udev->state); ++ sysfs_notify_dirent(port_dev->state_kn); ++ } + } + } + +@@ -2380,17 +2390,25 @@ static int usb_enumerate_device_otg(struct usb_device *udev) + } + } else if (desc->bLength == sizeof + (struct usb_otg_descriptor)) { +- /* Set a_alt_hnp_support for legacy otg device */ +- err = usb_control_msg(udev, +- usb_sndctrlpipe(udev, 0), +- USB_REQ_SET_FEATURE, 0, +- USB_DEVICE_A_ALT_HNP_SUPPORT, +- 0, NULL, 0, +- USB_CTRL_SET_TIMEOUT); +- if (err < 0) +- dev_err(&udev->dev, +- "set a_alt_hnp_support failed: %d\n", +- err); ++ /* ++ * We are operating on a legacy OTP device ++ * These should be told that they are operating ++ * on the wrong port if we have another port that does ++ * support HNP ++ */ ++ if (bus->otg_port != 0) { ++ /* Set a_alt_hnp_support for legacy otg device */ ++ err = usb_control_msg(udev, ++ usb_sndctrlpipe(udev, 0), ++ USB_REQ_SET_FEATURE, 0, ++ USB_DEVICE_A_ALT_HNP_SUPPORT, ++ 0, NULL, 0, ++ USB_CTRL_SET_TIMEOUT); ++ if (err < 0) ++ dev_err(&udev->dev, ++ "set a_alt_hnp_support failed: %d\n", ++ err); ++ } + } + } + #endif +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 89de363ecf8bb..4c8dd67246788 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -4703,15 +4703,13 @@ int dwc3_gadget_suspend(struct dwc3 *dwc) + unsigned long flags; + int ret; + +- if (!dwc->gadget_driver) +- return 0; +- + ret = dwc3_gadget_soft_disconnect(dwc); + if (ret) + goto err; + + spin_lock_irqsave(&dwc->lock, flags); +- dwc3_disconnect_gadget(dwc); ++ if (dwc->gadget_driver) ++ dwc3_disconnect_gadget(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c +index 722a3ab2b3379..c265a1f62fc14 100644 +--- a/drivers/usb/gadget/function/f_mass_storage.c ++++ b/drivers/usb/gadget/function/f_mass_storage.c +@@ -545,21 +545,37 @@ static int start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, + + static bool start_in_transfer(struct fsg_common *common, struct fsg_buffhd *bh) + { ++ int rc; ++ + if (!fsg_is_set(common)) + return false; + bh->state = BUF_STATE_SENDING; +- if (start_transfer(common->fsg, common->fsg->bulk_in, bh->inreq)) ++ rc = start_transfer(common->fsg, common->fsg->bulk_in, bh->inreq); ++ if (rc) { + bh->state = BUF_STATE_EMPTY; ++ if (rc == -ESHUTDOWN) { ++ common->running = 0; ++ return false; ++ } ++ } + return true; + } + + static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh) + { ++ int rc; ++ + if (!fsg_is_set(common)) + return false; + bh->state = BUF_STATE_RECEIVING; +- if (start_transfer(common->fsg, common->fsg->bulk_out, bh->outreq)) ++ rc = start_transfer(common->fsg, common->fsg->bulk_out, bh->outreq); ++ if (rc) { + bh->state = BUF_STATE_FULL; ++ if (rc == -ESHUTDOWN) { ++ common->running = 0; ++ return false; ++ } ++ } + return true; + } + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 47ae2d520fda5..6d455ca76125e 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -4862,7 +4862,8 @@ static void run_state_machine(struct tcpm_port *port) + break; + case PORT_RESET: + tcpm_reset_port(port); +- tcpm_set_cc(port, TYPEC_CC_OPEN); ++ tcpm_set_cc(port, tcpm_default_state(port) == SNK_UNATTACHED ? ++ TYPEC_CC_RD : tcpm_rp_cc(port)); + tcpm_set_state(port, PORT_RESET_WAIT_OFF, + PD_T_ERROR_RECOVERY); + break; +diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c +index 61b64558f96c5..8f9dff993b3da 100644 +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -935,7 +935,9 @@ static void ucsi_handle_connector_change(struct work_struct *work) + + clear_bit(EVENT_PENDING, &con->ucsi->flags); + ++ mutex_lock(&ucsi->ppm_lock); + ret = ucsi_acknowledge_connector_change(ucsi); ++ mutex_unlock(&ucsi->ppm_lock); + if (ret) + dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret); + +diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c +index 6bbf490ac4010..fa222080887d5 100644 +--- a/drivers/usb/typec/ucsi/ucsi_acpi.c ++++ b/drivers/usb/typec/ucsi/ucsi_acpi.c +@@ -73,9 +73,13 @@ static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) + { + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); ++ bool ack = UCSI_COMMAND(*(u64 *)val) == UCSI_ACK_CC_CI; + int ret; + +- set_bit(COMMAND_PENDING, &ua->flags); ++ if (ack) ++ set_bit(ACK_PENDING, &ua->flags); ++ else ++ set_bit(COMMAND_PENDING, &ua->flags); + + ret = ucsi_acpi_async_write(ucsi, offset, val, val_len); + if (ret) +@@ -85,7 +89,10 @@ static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset, + ret = -ETIMEDOUT; + + out_clear_bit: +- clear_bit(COMMAND_PENDING, &ua->flags); ++ if (ack) ++ clear_bit(ACK_PENDING, &ua->flags); ++ else ++ clear_bit(COMMAND_PENDING, &ua->flags); + + return ret; + } +@@ -142,8 +149,10 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) + if (UCSI_CCI_CONNECTOR(cci)) + ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci)); + +- if (test_bit(COMMAND_PENDING, &ua->flags) && +- cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE)) ++ if (cci & UCSI_CCI_ACK_COMPLETE && test_bit(ACK_PENDING, &ua->flags)) ++ complete(&ua->complete); ++ if (cci & UCSI_CCI_COMMAND_COMPLETE && ++ test_bit(COMMAND_PENDING, &ua->flags)) + complete(&ua->complete); + } + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 5a97db9888107..3afd435dc2c7a 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -1467,6 +1467,7 @@ static bool clean_pinned_extents(struct btrfs_trans_handle *trans, + */ + void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) + { ++ LIST_HEAD(retry_list); + struct btrfs_block_group *block_group; + struct btrfs_space_info *space_info; + struct btrfs_trans_handle *trans; +@@ -1488,6 +1489,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) + + spin_lock(&fs_info->unused_bgs_lock); + while (!list_empty(&fs_info->unused_bgs)) { ++ u64 used; + int trimming; + + block_group = list_first_entry(&fs_info->unused_bgs, +@@ -1523,9 +1525,9 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) + goto next; + } + ++ spin_lock(&space_info->lock); + spin_lock(&block_group->lock); +- if (block_group->reserved || block_group->pinned || +- block_group->used || block_group->ro || ++ if (btrfs_is_block_group_used(block_group) || block_group->ro || + list_is_singular(&block_group->list)) { + /* + * We want to bail if we made new allocations or have +@@ -1535,10 +1537,49 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) + */ + trace_btrfs_skip_unused_block_group(block_group); + spin_unlock(&block_group->lock); ++ spin_unlock(&space_info->lock); ++ up_write(&space_info->groups_sem); ++ goto next; ++ } ++ ++ /* ++ * The block group may be unused but there may be space reserved ++ * accounting with the existence of that block group, that is, ++ * space_info->bytes_may_use was incremented by a task but no ++ * space was yet allocated from the block group by the task. ++ * That space may or may not be allocated, as we are generally ++ * pessimistic about space reservation for metadata as well as ++ * for data when using compression (as we reserve space based on ++ * the worst case, when data can't be compressed, and before ++ * actually attempting compression, before starting writeback). ++ * ++ * So check if the total space of the space_info minus the size ++ * of this block group is less than the used space of the ++ * space_info - if that's the case, then it means we have tasks ++ * that might be relying on the block group in order to allocate ++ * extents, and add back the block group to the unused list when ++ * we finish, so that we retry later in case no tasks ended up ++ * needing to allocate extents from the block group. ++ */ ++ used = btrfs_space_info_used(space_info, true); ++ if (space_info->total_bytes - block_group->length < used) { ++ /* ++ * Add a reference for the list, compensate for the ref ++ * drop under the "next" label for the ++ * fs_info->unused_bgs list. ++ */ ++ btrfs_get_block_group(block_group); ++ list_add_tail(&block_group->bg_list, &retry_list); ++ ++ trace_btrfs_skip_unused_block_group(block_group); ++ spin_unlock(&block_group->lock); ++ spin_unlock(&space_info->lock); + up_write(&space_info->groups_sem); + goto next; + } ++ + spin_unlock(&block_group->lock); ++ spin_unlock(&space_info->lock); + + /* We don't want to force the issue, only flip if it's ok. */ + ret = inc_block_group_ro(block_group, 0); +@@ -1662,12 +1703,16 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) + btrfs_put_block_group(block_group); + spin_lock(&fs_info->unused_bgs_lock); + } ++ list_splice_tail(&retry_list, &fs_info->unused_bgs); + spin_unlock(&fs_info->unused_bgs_lock); + mutex_unlock(&fs_info->reclaim_bgs_lock); + return; + + flip_async: + btrfs_end_transaction(trans); ++ spin_lock(&fs_info->unused_bgs_lock); ++ list_splice_tail(&retry_list, &fs_info->unused_bgs); ++ spin_unlock(&fs_info->unused_bgs_lock); + mutex_unlock(&fs_info->reclaim_bgs_lock); + btrfs_put_block_group(block_group); + btrfs_discard_punt_unused_bgs_list(fs_info); +diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h +index 2bdbcb834f954..089979981e4aa 100644 +--- a/fs/btrfs/block-group.h ++++ b/fs/btrfs/block-group.h +@@ -255,6 +255,13 @@ static inline u64 btrfs_block_group_end(struct btrfs_block_group *block_group) + return (block_group->start + block_group->length); + } + ++static inline bool btrfs_is_block_group_used(const struct btrfs_block_group *bg) ++{ ++ lockdep_assert_held(&bg->lock); ++ ++ return (bg->used > 0 || bg->reserved > 0 || bg->pinned > 0); ++} ++ + static inline bool btrfs_is_block_group_data_only( + struct btrfs_block_group *block_group) + { +diff --git a/fs/btrfs/delalloc-space.c b/fs/btrfs/delalloc-space.c +index eef341bbcc60e..4a7aefa5f9cf9 100644 +--- a/fs/btrfs/delalloc-space.c ++++ b/fs/btrfs/delalloc-space.c +@@ -245,7 +245,6 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, + struct btrfs_block_rsv *block_rsv = &inode->block_rsv; + u64 reserve_size = 0; + u64 qgroup_rsv_size = 0; +- u64 csum_leaves; + unsigned outstanding_extents; + + lockdep_assert_held(&inode->lock); +@@ -260,10 +259,12 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, + outstanding_extents); + reserve_size += btrfs_calc_metadata_size(fs_info, 1); + } +- csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, +- inode->csum_bytes); +- reserve_size += btrfs_calc_insert_metadata_size(fs_info, +- csum_leaves); ++ if (!(inode->flags & BTRFS_INODE_NODATASUM)) { ++ u64 csum_leaves; ++ ++ csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, inode->csum_bytes); ++ reserve_size += btrfs_calc_insert_metadata_size(fs_info, csum_leaves); ++ } + /* + * For qgroup rsv, the calculation is very simple: + * account one nodesize for each outstanding extent +@@ -278,14 +279,20 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, + spin_unlock(&block_rsv->lock); + } + +-static void calc_inode_reservations(struct btrfs_fs_info *fs_info, ++static void calc_inode_reservations(struct btrfs_inode *inode, + u64 num_bytes, u64 disk_num_bytes, + u64 *meta_reserve, u64 *qgroup_reserve) + { ++ struct btrfs_fs_info *fs_info = inode->root->fs_info; + u64 nr_extents = count_max_extents(fs_info, num_bytes); +- u64 csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, disk_num_bytes); ++ u64 csum_leaves; + u64 inode_update = btrfs_calc_metadata_size(fs_info, 1); + ++ if (inode->flags & BTRFS_INODE_NODATASUM) ++ csum_leaves = 0; ++ else ++ csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, disk_num_bytes); ++ + *meta_reserve = btrfs_calc_insert_metadata_size(fs_info, + nr_extents + csum_leaves); + +@@ -337,7 +344,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes, + * everything out and try again, which is bad. This way we just + * over-reserve slightly, and clean up the mess when we are done. + */ +- calc_inode_reservations(fs_info, num_bytes, disk_num_bytes, ++ calc_inode_reservations(inode, num_bytes, disk_num_bytes, + &meta_reserve, &qgroup_reserve); + ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true, + noflush); +@@ -358,7 +365,8 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes, + nr_extents = count_max_extents(fs_info, num_bytes); + spin_lock(&inode->lock); + btrfs_mod_outstanding_extents(inode, nr_extents); +- inode->csum_bytes += disk_num_bytes; ++ if (!(inode->flags & BTRFS_INODE_NODATASUM)) ++ inode->csum_bytes += disk_num_bytes; + btrfs_calculate_inode_block_rsv_size(fs_info, inode); + spin_unlock(&inode->lock); + +@@ -392,7 +400,8 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes, + + num_bytes = ALIGN(num_bytes, fs_info->sectorsize); + spin_lock(&inode->lock); +- inode->csum_bytes -= num_bytes; ++ if (!(inode->flags & BTRFS_INODE_NODATASUM)) ++ inode->csum_bytes -= num_bytes; + btrfs_calculate_inode_block_rsv_size(fs_info, inode); + spin_unlock(&inode->lock); + +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index b79781df70714..ffb9ae303f2a3 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -1311,8 +1311,17 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info, + again: + root = btrfs_lookup_fs_root(fs_info, objectid); + if (root) { +- /* Shouldn't get preallocated anon_dev for cached roots */ +- ASSERT(!anon_dev); ++ /* ++ * Some other caller may have read out the newly inserted ++ * subvolume already (for things like backref walk etc). Not ++ * that common but still possible. In that case, we just need ++ * to free the anon_dev. ++ */ ++ if (unlikely(anon_dev)) { ++ free_anon_bdev(anon_dev); ++ anon_dev = 0; ++ } ++ + if (check_ref && btrfs_root_refs(&root->root_item) == 0) { + btrfs_put_root(root); + return ERR_PTR(-ENOENT); +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index f250e2083c7eb..ca79c2b8adc46 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -3168,8 +3168,23 @@ int btrfs_finish_one_ordered(struct btrfs_ordered_extent *ordered_extent) + unwritten_start += logical_len; + clear_extent_uptodate(io_tree, unwritten_start, end, NULL); + +- /* Drop extent maps for the part of the extent we didn't write. */ +- btrfs_drop_extent_map_range(inode, unwritten_start, end, false); ++ /* ++ * Drop extent maps for the part of the extent we didn't write. ++ * ++ * We have an exception here for the free_space_inode, this is ++ * because when we do btrfs_get_extent() on the free space inode ++ * we will search the commit root. If this is a new block group ++ * we won't find anything, and we will trip over the assert in ++ * writepage where we do ASSERT(em->block_start != ++ * EXTENT_MAP_HOLE). ++ * ++ * Theoretically we could also skip this for any NOCOW extent as ++ * we don't mess with the extent map tree in the NOCOW case, but ++ * for now simply skip this if we are the free space inode. ++ */ ++ if (!btrfs_is_free_space_inode(inode)) ++ btrfs_drop_extent_map_range(inode, unwritten_start, ++ end, false); + + /* + * If the ordered extent had an IOERR or something else went +@@ -10223,6 +10238,13 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from, + if (encoded->encryption != BTRFS_ENCODED_IO_ENCRYPTION_NONE) + return -EINVAL; + ++ /* ++ * Compressed extents should always have checksums, so error out if we ++ * have a NOCOW file or inode was created while mounted with NODATASUM. ++ */ ++ if (inode->flags & BTRFS_INODE_NODATASUM) ++ return -EINVAL; ++ + orig_count = iov_iter_count(from); + + /* The extent size must be sane. */ +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index 908215928d6a6..a26a909a5ad16 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -3810,6 +3810,11 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) + goto out; + } + ++ if (sa->create && is_fstree(sa->qgroupid)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index a006f5160e6b4..9acdd0f91a5ae 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1659,6 +1659,15 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) + return ret; + } + ++static bool qgroup_has_usage(struct btrfs_qgroup *qgroup) ++{ ++ return (qgroup->rfer > 0 || qgroup->rfer_cmpr > 0 || ++ qgroup->excl > 0 || qgroup->excl_cmpr > 0 || ++ qgroup->rsv.values[BTRFS_QGROUP_RSV_DATA] > 0 || ++ qgroup->rsv.values[BTRFS_QGROUP_RSV_META_PREALLOC] > 0 || ++ qgroup->rsv.values[BTRFS_QGROUP_RSV_META_PERTRANS] > 0); ++} ++ + int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) + { + struct btrfs_fs_info *fs_info = trans->fs_info; +@@ -1678,6 +1687,11 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) + goto out; + } + ++ if (is_fstree(qgroupid) && qgroup_has_usage(qgroup)) { ++ ret = -EBUSY; ++ goto out; ++ } ++ + /* Check if there are no children of this qgroup */ + if (!list_empty(&qgroup->members)) { + ret = -EBUSY; +diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c +index db94eefda27e2..994c0be8055c6 100644 +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -8111,7 +8111,7 @@ long btrfs_ioctl_send(struct inode *inode, struct btrfs_ioctl_send_args *arg) + } + + if (arg->flags & ~BTRFS_SEND_FLAG_MASK) { +- ret = -EINVAL; ++ ret = -EOPNOTSUPP; + goto out; + } + +diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c +index 7f7e5f5d643c6..fc9f8f1a9036d 100644 +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -1415,7 +1415,7 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap, + if (flushing & CEPH_CAP_XATTR_EXCL) { + arg->old_xattr_buf = __ceph_build_xattrs_blob(ci); + arg->xattr_version = ci->i_xattrs.version; +- arg->xattr_buf = ci->i_xattrs.blob; ++ arg->xattr_buf = ceph_buffer_get(ci->i_xattrs.blob); + } else { + arg->xattr_buf = NULL; + arg->old_xattr_buf = NULL; +@@ -1513,6 +1513,7 @@ static void __send_cap(struct cap_msg_args *arg, struct ceph_inode_info *ci) + encode_cap_msg(msg, arg); + ceph_con_send(&arg->session->s_con, msg); + ceph_buffer_put(arg->old_xattr_buf); ++ ceph_buffer_put(arg->xattr_buf); + if (arg->wake) + wake_up_all(&ci->i_cap_wq); + } +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 529ca47da0353..7a2d42a84807a 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -1909,11 +1909,6 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, + mb_check_buddy(e4b); + mb_free_blocks_double(inode, e4b, first, count); + +- this_cpu_inc(discard_pa_seq); +- e4b->bd_info->bb_free += count; +- if (first < e4b->bd_info->bb_first_free) +- e4b->bd_info->bb_first_free = first; +- + /* access memory sequentially: check left neighbour, + * clear range and then check right neighbour + */ +@@ -1927,23 +1922,31 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, + struct ext4_sb_info *sbi = EXT4_SB(sb); + ext4_fsblk_t blocknr; + ++ /* ++ * Fastcommit replay can free already freed blocks which ++ * corrupts allocation info. Regenerate it. ++ */ ++ if (sbi->s_mount_state & EXT4_FC_REPLAY) { ++ mb_regenerate_buddy(e4b); ++ goto check; ++ } ++ + blocknr = ext4_group_first_block_no(sb, e4b->bd_group); + blocknr += EXT4_C2B(sbi, block); +- if (!(sbi->s_mount_state & EXT4_FC_REPLAY)) { +- ext4_grp_locked_error(sb, e4b->bd_group, +- inode ? inode->i_ino : 0, +- blocknr, +- "freeing already freed block (bit %u); block bitmap corrupt.", +- block); +- ext4_mark_group_bitmap_corrupted( +- sb, e4b->bd_group, ++ ext4_grp_locked_error(sb, e4b->bd_group, ++ inode ? inode->i_ino : 0, blocknr, ++ "freeing already freed block (bit %u); block bitmap corrupt.", ++ block); ++ ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group, + EXT4_GROUP_INFO_BBITMAP_CORRUPT); +- } else { +- mb_regenerate_buddy(e4b); +- } +- goto done; ++ return; + } + ++ this_cpu_inc(discard_pa_seq); ++ e4b->bd_info->bb_free += count; ++ if (first < e4b->bd_info->bb_first_free) ++ e4b->bd_info->bb_first_free = first; ++ + /* let's maintain fragments counter */ + if (left_is_free && right_is_free) + e4b->bd_info->bb_fragments--; +@@ -1968,9 +1971,9 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, + if (first <= last) + mb_buddy_mark_free(e4b, first >> 1, last >> 1); + +-done: + mb_set_largest_free_order(sb, e4b->bd_info); + mb_update_avg_fragment_size(sb, e4b->bd_info); ++check: + mb_check_buddy(e4b); + } + +diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c +index 18a9e7c479754..e6976716e85d4 100644 +--- a/fs/ext4/move_extent.c ++++ b/fs/ext4/move_extent.c +@@ -619,6 +619,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, + goto out; + o_end = o_start + len; + ++ *moved_len = 0; + while (o_start < o_end) { + struct ext4_extent *ex; + ext4_lblk_t cur_blk, next_blk; +@@ -673,7 +674,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, + */ + ext4_double_up_write_data_sem(orig_inode, donor_inode); + /* Swap original branches with new branches */ +- move_extent_per_page(o_filp, donor_inode, ++ *moved_len += move_extent_per_page(o_filp, donor_inode, + orig_page_index, donor_page_index, + offset_in_page, cur_len, + unwritten, &ret); +@@ -683,9 +684,6 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, + o_start += cur_len; + d_start += cur_len; + } +- *moved_len = o_start - orig_blk; +- if (*moved_len > len) +- *moved_len = len; + + out: + if (*moved_len) { +diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c +index 60fce26ff9378..ac519515ef6c0 100644 +--- a/fs/hugetlbfs/inode.c ++++ b/fs/hugetlbfs/inode.c +@@ -123,6 +123,7 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) + loff_t len, vma_len; + int ret; + struct hstate *h = hstate_file(file); ++ vm_flags_t vm_flags; + + /* + * vma address alignment (but not the pgoff alignment) has +@@ -164,10 +165,20 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) + file_accessed(file); + + ret = -ENOMEM; ++ ++ vm_flags = vma->vm_flags; ++ /* ++ * for SHM_HUGETLB, the pages are reserved in the shmget() call so skip ++ * reserving here. Note: only for SHM hugetlbfs file, the inode ++ * flag S_PRIVATE is set. ++ */ ++ if (inode->i_flags & S_PRIVATE) ++ vm_flags |= VM_NORESERVE; ++ + if (!hugetlb_reserve_pages(inode, + vma->vm_pgoff >> huge_page_order(h), + len >> huge_page_shift(h), vma, +- vma->vm_flags)) ++ vm_flags)) + goto out; + + ret = 0; +@@ -1390,6 +1401,7 @@ static int hugetlbfs_parse_param(struct fs_context *fc, struct fs_parameter *par + { + struct hugetlbfs_fs_context *ctx = fc->fs_private; + struct fs_parse_result result; ++ struct hstate *h; + char *rest; + unsigned long ps; + int opt; +@@ -1434,11 +1446,12 @@ static int hugetlbfs_parse_param(struct fs_context *fc, struct fs_parameter *par + + case Opt_pagesize: + ps = memparse(param->string, &rest); +- ctx->hstate = size_to_hstate(ps); +- if (!ctx->hstate) { ++ h = size_to_hstate(ps); ++ if (!h) { + pr_err("Unsupported page size %lu MB\n", ps / SZ_1M); + return -EINVAL; + } ++ ctx->hstate = h; + return 0; + + case Opt_min_size: +diff --git a/fs/namespace.c b/fs/namespace.c +index bfc5cff0e196f..e6c61d4997ccf 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -4470,10 +4470,15 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr) + /* + * If this is an attached mount make sure it's located in the callers + * mount namespace. If it's not don't let the caller interact with it. +- * If this is a detached mount make sure it has an anonymous mount +- * namespace attached to it, i.e. we've created it via OPEN_TREE_CLONE. ++ * ++ * If this mount doesn't have a parent it's most often simply a ++ * detached mount with an anonymous mount namespace. IOW, something ++ * that's simply not attached yet. But there are apparently also users ++ * that do change mount properties on the rootfs itself. That obviously ++ * neither has a parent nor is it a detached mount so we cannot ++ * unconditionally check for detached mounts. + */ +- if (!(mnt_has_parent(mnt) ? check_mnt(mnt) : is_anon_ns(mnt->mnt_ns))) ++ if ((mnt_has_parent(mnt) || !is_anon_ns(mnt->mnt_ns)) && !check_mnt(mnt)) + goto out; + + /* +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index f4cccbf664ceb..522596060252f 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4944,10 +4944,8 @@ nfsd_break_deleg_cb(struct file_lock *fl) + */ + fl->fl_break_time = 0; + +- spin_lock(&fp->fi_lock); + fp->fi_had_conflict = true; + nfsd_break_one_deleg(dp); +- spin_unlock(&fp->fi_lock); + return false; + } + +@@ -5556,12 +5554,13 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, + if (status) + goto out_unlock; + ++ status = -EAGAIN; ++ if (fp->fi_had_conflict) ++ goto out_unlock; ++ + spin_lock(&state_lock); + spin_lock(&fp->fi_lock); +- if (fp->fi_had_conflict) +- status = -EAGAIN; +- else +- status = hash_delegation_locked(dp, fp); ++ status = hash_delegation_locked(dp, fp); + spin_unlock(&fp->fi_lock); + spin_unlock(&state_lock); + +diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c +index 740ce26d1e765..0505feef79f4a 100644 +--- a/fs/nilfs2/file.c ++++ b/fs/nilfs2/file.c +@@ -105,7 +105,13 @@ static vm_fault_t nilfs_page_mkwrite(struct vm_fault *vmf) + nilfs_transaction_commit(inode->i_sb); + + mapped: +- wait_for_stable_page(page); ++ /* ++ * Since checksumming including data blocks is performed to determine ++ * the validity of the log to be written and used for recovery, it is ++ * necessary to wait for writeback to finish here, regardless of the ++ * stable write requirement of the backing device. ++ */ ++ wait_on_page_writeback(page); + out: + sb_end_pagefault(inode->i_sb); + return vmf_fs_error(ret); +diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c +index 0955b657938ff..a9b8d77c8c1d5 100644 +--- a/fs/nilfs2/recovery.c ++++ b/fs/nilfs2/recovery.c +@@ -472,9 +472,10 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, + + static int nilfs_recovery_copy_block(struct the_nilfs *nilfs, + struct nilfs_recovery_block *rb, +- struct page *page) ++ loff_t pos, struct page *page) + { + struct buffer_head *bh_org; ++ size_t from = pos & ~PAGE_MASK; + void *kaddr; + + bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize); +@@ -482,7 +483,7 @@ static int nilfs_recovery_copy_block(struct the_nilfs *nilfs, + return -EIO; + + kaddr = kmap_atomic(page); +- memcpy(kaddr + bh_offset(bh_org), bh_org->b_data, bh_org->b_size); ++ memcpy(kaddr + from, bh_org->b_data, bh_org->b_size); + kunmap_atomic(kaddr); + brelse(bh_org); + return 0; +@@ -521,7 +522,7 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs, + goto failed_inode; + } + +- err = nilfs_recovery_copy_block(nilfs, rb, page); ++ err = nilfs_recovery_copy_block(nilfs, rb, pos, page); + if (unlikely(err)) + goto failed_page; + +diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c +index 7ec16879756e8..a03e37207f487 100644 +--- a/fs/nilfs2/segment.c ++++ b/fs/nilfs2/segment.c +@@ -1704,7 +1704,6 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci) + + list_for_each_entry(bh, &segbuf->sb_payload_buffers, + b_assoc_buffers) { +- set_buffer_async_write(bh); + if (bh == segbuf->sb_super_root) { + if (bh->b_page != bd_page) { + lock_page(bd_page); +@@ -1715,6 +1714,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci) + } + break; + } ++ set_buffer_async_write(bh); + if (bh->b_page != fs_page) { + nilfs_begin_page_io(fs_page); + fs_page = bh->b_page; +@@ -1800,7 +1800,6 @@ static void nilfs_abort_logs(struct list_head *logs, int err) + + list_for_each_entry(bh, &segbuf->sb_payload_buffers, + b_assoc_buffers) { +- clear_buffer_async_write(bh); + if (bh == segbuf->sb_super_root) { + clear_buffer_uptodate(bh); + if (bh->b_page != bd_page) { +@@ -1809,6 +1808,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err) + } + break; + } ++ clear_buffer_async_write(bh); + if (bh->b_page != fs_page) { + nilfs_end_page_io(fs_page, err); + fs_page = bh->b_page; +@@ -1896,8 +1896,9 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) + BIT(BH_Delay) | BIT(BH_NILFS_Volatile) | + BIT(BH_NILFS_Redirected)); + +- set_mask_bits(&bh->b_state, clear_bits, set_bits); + if (bh == segbuf->sb_super_root) { ++ set_buffer_uptodate(bh); ++ clear_buffer_dirty(bh); + if (bh->b_page != bd_page) { + end_page_writeback(bd_page); + bd_page = bh->b_page; +@@ -1905,6 +1906,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) + update_sr = true; + break; + } ++ set_mask_bits(&bh->b_state, clear_bits, set_bits); + if (bh->b_page != fs_page) { + nilfs_end_page_io(fs_page, 0); + fs_page = bh->b_page; +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 2c2efbe685d87..37b8061d84bb7 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -511,7 +511,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + + sigemptyset(&sigign); + sigemptyset(&sigcatch); +- cutime = cstime = utime = stime = 0; ++ cutime = cstime = 0; + cgtime = gtime = 0; + + if (lock_task_sighand(task, &flags)) { +@@ -545,7 +545,6 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + + min_flt += sig->min_flt; + maj_flt += sig->maj_flt; +- thread_group_cputime_adjusted(task, &utime, &stime); + gtime += sig->gtime; + + if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED)) +@@ -561,10 +560,13 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + + if (permitted && (!whole || num_threads < 2)) + wchan = !task_is_running(task); +- if (!whole) { ++ ++ if (whole) { ++ thread_group_cputime_adjusted(task, &utime, &stime); ++ } else { ++ task_cputime_adjusted(task, &utime, &stime); + min_flt = task->min_flt; + maj_flt = task->maj_flt; +- task_cputime_adjusted(task, &utime, &stime); + gtime = task_gtime(task); + } + +diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c +index 0ed6eb915c6ab..19440255944b0 100644 +--- a/fs/smb/client/connect.c ++++ b/fs/smb/client/connect.c +@@ -3426,8 +3426,18 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx) + * the user on mount + */ + if ((cifs_sb->ctx->wsize == 0) || +- (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) +- cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx); ++ (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) { ++ cifs_sb->ctx->wsize = ++ round_down(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE); ++ /* ++ * in the very unlikely event that the server sent a max write size under PAGE_SIZE, ++ * (which would get rounded down to 0) then reset wsize to absolute minimum eg 4096 ++ */ ++ if (cifs_sb->ctx->wsize == 0) { ++ cifs_sb->ctx->wsize = PAGE_SIZE; ++ cifs_dbg(VFS, "wsize too small, reset to minimum ie PAGE_SIZE, usually 4096\n"); ++ } ++ } + if ((cifs_sb->ctx->rsize == 0) || + (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx))) + cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx); +diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c +index a3493da12ad1e..75f2c8734ff56 100644 +--- a/fs/smb/client/fs_context.c ++++ b/fs/smb/client/fs_context.c +@@ -1107,6 +1107,17 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, + case Opt_wsize: + ctx->wsize = result.uint_32; + ctx->got_wsize = true; ++ if (ctx->wsize % PAGE_SIZE != 0) { ++ ctx->wsize = round_down(ctx->wsize, PAGE_SIZE); ++ if (ctx->wsize == 0) { ++ ctx->wsize = PAGE_SIZE; ++ cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE); ++ } else { ++ cifs_dbg(VFS, ++ "wsize rounded down to %d to multiple of PAGE_SIZE %ld\n", ++ ctx->wsize, PAGE_SIZE); ++ } ++ } + break; + case Opt_acregmax: + ctx->acregmax = HZ * result.uint_32; +diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c +index a6968573b775e..4a517b280f2b7 100644 +--- a/fs/smb/client/namespace.c ++++ b/fs/smb/client/namespace.c +@@ -168,6 +168,21 @@ static char *automount_fullpath(struct dentry *dentry, void *page) + return s; + } + ++static void fs_context_set_ids(struct smb3_fs_context *ctx) ++{ ++ kuid_t uid = current_fsuid(); ++ kgid_t gid = current_fsgid(); ++ ++ if (ctx->multiuser) { ++ if (!ctx->uid_specified) ++ ctx->linux_uid = uid; ++ if (!ctx->gid_specified) ++ ctx->linux_gid = gid; ++ } ++ if (!ctx->cruid_specified) ++ ctx->cred_uid = uid; ++} ++ + /* + * Create a vfsmount that we can automount + */ +@@ -205,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path) + tmp.leaf_fullpath = NULL; + tmp.UNC = tmp.prepath = NULL; + tmp.dfs_root_ses = NULL; ++ fs_context_set_ids(&tmp); + + rc = smb3_fs_context_dup(ctx, &tmp); + if (rc) { +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index e33ed0fbc318e..5850f861e7e13 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -619,7 +619,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, + goto out; + } + +- while (bytes_left >= sizeof(*p)) { ++ while (bytes_left >= (ssize_t)sizeof(*p)) { + memset(&tmp_iface, 0, sizeof(tmp_iface)); + tmp_iface.speed = le64_to_cpu(p->LinkSpeed); + tmp_iface.rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0; +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 6ddfe3fef55f3..3e885cdc5ffc7 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -6173,8 +6173,10 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work) + err = ksmbd_iov_pin_rsp_read(work, (void *)rsp, + offsetof(struct smb2_read_rsp, Buffer), + aux_payload_buf, nbytes); +- if (err) ++ if (err) { ++ kvfree(aux_payload_buf); + goto out; ++ } + kvfree(rpc_resp); + } else { + err = ksmbd_iov_pin_rsp(work, (void *)rsp, +@@ -6384,8 +6386,10 @@ int smb2_read(struct ksmbd_work *work) + err = ksmbd_iov_pin_rsp_read(work, (void *)rsp, + offsetof(struct smb2_read_rsp, Buffer), + aux_payload_buf, nbytes); +- if (err) ++ if (err) { ++ kvfree(aux_payload_buf); + goto out; ++ } + ksmbd_fd_put(work, fp); + return 0; + +diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c +index efbdc47c74dcf..110e8a2721890 100644 +--- a/fs/tracefs/event_inode.c ++++ b/fs/tracefs/event_inode.c +@@ -2,8 +2,9 @@ + /* + * event_inode.c - part of tracefs, a pseudo file system for activating tracing + * +- * Copyright (C) 2020-23 VMware Inc, author: Steven Rostedt (VMware) <rostedt@goodmis.org> ++ * Copyright (C) 2020-23 VMware Inc, author: Steven Rostedt <rostedt@goodmis.org> + * Copyright (C) 2020-23 VMware Inc, author: Ajay Kaher <akaher@vmware.com> ++ * Copyright (C) 2023 Google, author: Steven Rostedt <rostedt@goodmis.org> + * + * eventfs is used to dynamically create inodes and dentries based on the + * meta data provided by the tracing system. +@@ -23,51 +24,32 @@ + #include <linux/delay.h> + #include "internal.h" + +-struct eventfs_inode { +- struct list_head e_top_files; +-}; +- + /* +- * struct eventfs_file - hold the properties of the eventfs files and +- * directories. +- * @name: the name of the file or directory to create +- * @d_parent: holds parent's dentry +- * @dentry: once accessed holds dentry +- * @list: file or directory to be added to parent directory +- * @ei: list of files and directories within directory +- * @fop: file_operations for file or directory +- * @iop: inode_operations for file or directory +- * @data: something that the caller will want to get to later on +- * @is_freed: Flag set if the eventfs is on its way to be freed +- * @mode: the permission that the file or directory should have +- * @uid: saved uid if changed +- * @gid: saved gid if changed ++ * eventfs_mutex protects the eventfs_inode (ei) dentry. Any access ++ * to the ei->dentry must be done under this mutex and after checking ++ * if ei->is_freed is not set. When ei->is_freed is set, the dentry ++ * is on its way to being freed after the last dput() is made on it. + */ +-struct eventfs_file { +- const char *name; +- struct dentry *d_parent; +- struct dentry *dentry; +- struct list_head list; +- struct eventfs_inode *ei; +- const struct file_operations *fop; +- const struct inode_operations *iop; +- /* +- * Union - used for deletion +- * @llist: for calling dput() if needed after RCU +- * @rcu: eventfs_file to delete in RCU +- */ +- union { +- struct llist_node llist; +- struct rcu_head rcu; +- }; +- void *data; +- unsigned int is_freed:1; +- unsigned int mode:31; +- kuid_t uid; +- kgid_t gid; +-}; +- + static DEFINE_MUTEX(eventfs_mutex); ++ ++/* Choose something "unique" ;-) */ ++#define EVENTFS_FILE_INODE_INO 0x12c4e37 ++ ++/* Just try to make something consistent and unique */ ++static int eventfs_dir_ino(struct eventfs_inode *ei) ++{ ++ if (!ei->ino) ++ ei->ino = get_next_ino(); ++ ++ return ei->ino; ++} ++ ++/* ++ * The eventfs_inode (ei) itself is protected by SRCU. It is released from ++ * its parent's list and will have is_freed set (under eventfs_mutex). ++ * After the SRCU grace period is over and the last dput() is called ++ * the ei is freed. ++ */ + DEFINE_STATIC_SRCU(eventfs_srcu); + + /* Mode is unsigned short, use the upper bits for flags */ +@@ -75,60 +57,202 @@ enum { + EVENTFS_SAVE_MODE = BIT(16), + EVENTFS_SAVE_UID = BIT(17), + EVENTFS_SAVE_GID = BIT(18), ++ EVENTFS_TOPLEVEL = BIT(19), + }; + + #define EVENTFS_MODE_MASK (EVENTFS_SAVE_MODE - 1) + ++/* ++ * eventfs_inode reference count management. ++ * ++ * NOTE! We count only references from dentries, in the ++ * form 'dentry->d_fsdata'. There are also references from ++ * directory inodes ('ti->private'), but the dentry reference ++ * count is always a superset of the inode reference count. ++ */ ++static void release_ei(struct kref *ref) ++{ ++ struct eventfs_inode *ei = container_of(ref, struct eventfs_inode, kref); ++ ++ WARN_ON_ONCE(!ei->is_freed); ++ ++ kfree(ei->entry_attrs); ++ kfree_const(ei->name); ++ kfree_rcu(ei, rcu); ++} ++ ++static inline void put_ei(struct eventfs_inode *ei) ++{ ++ if (ei) ++ kref_put(&ei->kref, release_ei); ++} ++ ++static inline void free_ei(struct eventfs_inode *ei) ++{ ++ if (ei) { ++ ei->is_freed = 1; ++ put_ei(ei); ++ } ++} ++ ++static inline struct eventfs_inode *get_ei(struct eventfs_inode *ei) ++{ ++ if (ei) ++ kref_get(&ei->kref); ++ return ei; ++} ++ + static struct dentry *eventfs_root_lookup(struct inode *dir, + struct dentry *dentry, + unsigned int flags); +-static int dcache_dir_open_wrapper(struct inode *inode, struct file *file); +-static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx); +-static int eventfs_release(struct inode *inode, struct file *file); ++static int eventfs_iterate(struct file *file, struct dir_context *ctx); + +-static void update_attr(struct eventfs_file *ef, struct iattr *iattr) ++static void update_attr(struct eventfs_attr *attr, struct iattr *iattr) + { + unsigned int ia_valid = iattr->ia_valid; + + if (ia_valid & ATTR_MODE) { +- ef->mode = (ef->mode & ~EVENTFS_MODE_MASK) | ++ attr->mode = (attr->mode & ~EVENTFS_MODE_MASK) | + (iattr->ia_mode & EVENTFS_MODE_MASK) | + EVENTFS_SAVE_MODE; + } + if (ia_valid & ATTR_UID) { +- ef->mode |= EVENTFS_SAVE_UID; +- ef->uid = iattr->ia_uid; ++ attr->mode |= EVENTFS_SAVE_UID; ++ attr->uid = iattr->ia_uid; + } + if (ia_valid & ATTR_GID) { +- ef->mode |= EVENTFS_SAVE_GID; +- ef->gid = iattr->ia_gid; ++ attr->mode |= EVENTFS_SAVE_GID; ++ attr->gid = iattr->ia_gid; + } + } + + static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry, +- struct iattr *iattr) ++ struct iattr *iattr) + { +- struct eventfs_file *ef; ++ const struct eventfs_entry *entry; ++ struct eventfs_inode *ei; ++ const char *name; + int ret; + + mutex_lock(&eventfs_mutex); +- ef = dentry->d_fsdata; +- if (ef && ef->is_freed) { ++ ei = dentry->d_fsdata; ++ if (ei->is_freed) { + /* Do not allow changes if the event is about to be removed. */ + mutex_unlock(&eventfs_mutex); + return -ENODEV; + } + ++ /* Preallocate the children mode array if necessary */ ++ if (!(dentry->d_inode->i_mode & S_IFDIR)) { ++ if (!ei->entry_attrs) { ++ ei->entry_attrs = kcalloc(ei->nr_entries, sizeof(*ei->entry_attrs), ++ GFP_NOFS); ++ if (!ei->entry_attrs) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ } ++ } ++ + ret = simple_setattr(idmap, dentry, iattr); +- if (!ret && ef) +- update_attr(ef, iattr); ++ if (ret < 0) ++ goto out; ++ ++ /* ++ * If this is a dir, then update the ei cache, only the file ++ * mode is saved in the ei->m_children, and the ownership is ++ * determined by the parent directory. ++ */ ++ if (dentry->d_inode->i_mode & S_IFDIR) { ++ /* ++ * The events directory dentry is never freed, unless its ++ * part of an instance that is deleted. It's attr is the ++ * default for its child files and directories. ++ * Do not update it. It's not used for its own mode or ownership. ++ */ ++ if (ei->is_events) { ++ /* But it still needs to know if it was modified */ ++ if (iattr->ia_valid & ATTR_UID) ++ ei->attr.mode |= EVENTFS_SAVE_UID; ++ if (iattr->ia_valid & ATTR_GID) ++ ei->attr.mode |= EVENTFS_SAVE_GID; ++ } else { ++ update_attr(&ei->attr, iattr); ++ } ++ ++ } else { ++ name = dentry->d_name.name; ++ ++ for (int i = 0; i < ei->nr_entries; i++) { ++ entry = &ei->entries[i]; ++ if (strcmp(name, entry->name) == 0) { ++ update_attr(&ei->entry_attrs[i], iattr); ++ break; ++ } ++ } ++ } ++ out: + mutex_unlock(&eventfs_mutex); + return ret; + } + ++static void update_top_events_attr(struct eventfs_inode *ei, struct super_block *sb) ++{ ++ struct inode *root; ++ ++ /* Only update if the "events" was on the top level */ ++ if (!ei || !(ei->attr.mode & EVENTFS_TOPLEVEL)) ++ return; ++ ++ /* Get the tracefs root inode. */ ++ root = d_inode(sb->s_root); ++ ei->attr.uid = root->i_uid; ++ ei->attr.gid = root->i_gid; ++} ++ ++static void set_top_events_ownership(struct inode *inode) ++{ ++ struct tracefs_inode *ti = get_tracefs(inode); ++ struct eventfs_inode *ei = ti->private; ++ ++ /* The top events directory doesn't get automatically updated */ ++ if (!ei || !ei->is_events || !(ei->attr.mode & EVENTFS_TOPLEVEL)) ++ return; ++ ++ update_top_events_attr(ei, inode->i_sb); ++ ++ if (!(ei->attr.mode & EVENTFS_SAVE_UID)) ++ inode->i_uid = ei->attr.uid; ++ ++ if (!(ei->attr.mode & EVENTFS_SAVE_GID)) ++ inode->i_gid = ei->attr.gid; ++} ++ ++static int eventfs_get_attr(struct mnt_idmap *idmap, ++ const struct path *path, struct kstat *stat, ++ u32 request_mask, unsigned int flags) ++{ ++ struct dentry *dentry = path->dentry; ++ struct inode *inode = d_backing_inode(dentry); ++ ++ set_top_events_ownership(inode); ++ ++ generic_fillattr(idmap, request_mask, inode, stat); ++ return 0; ++} ++ ++static int eventfs_permission(struct mnt_idmap *idmap, ++ struct inode *inode, int mask) ++{ ++ set_top_events_ownership(inode); ++ return generic_permission(idmap, inode, mask); ++} ++ + static const struct inode_operations eventfs_root_dir_inode_operations = { + .lookup = eventfs_root_lookup, + .setattr = eventfs_set_attr, ++ .getattr = eventfs_get_attr, ++ .permission = eventfs_permission, + }; + + static const struct inode_operations eventfs_file_inode_operations = { +@@ -136,764 +260,548 @@ static const struct inode_operations eventfs_file_inode_operations = { + }; + + static const struct file_operations eventfs_file_operations = { +- .open = dcache_dir_open_wrapper, + .read = generic_read_dir, +- .iterate_shared = dcache_readdir_wrapper, ++ .iterate_shared = eventfs_iterate, + .llseek = generic_file_llseek, +- .release = eventfs_release, + }; + +-static void update_inode_attr(struct inode *inode, struct eventfs_file *ef) ++/* Return the evenfs_inode of the "events" directory */ ++static struct eventfs_inode *eventfs_find_events(struct dentry *dentry) ++{ ++ struct eventfs_inode *ei; ++ ++ do { ++ // The parent is stable because we do not do renames ++ dentry = dentry->d_parent; ++ // ... and directories always have d_fsdata ++ ei = dentry->d_fsdata; ++ ++ /* ++ * If the ei is being freed, the ownership of the children ++ * doesn't matter. ++ */ ++ if (ei->is_freed) { ++ ei = NULL; ++ break; ++ } ++ // Walk upwards until you find the events inode ++ } while (!ei->is_events); ++ ++ update_top_events_attr(ei, dentry->d_sb); ++ ++ return ei; ++} ++ ++static void update_inode_attr(struct dentry *dentry, struct inode *inode, ++ struct eventfs_attr *attr, umode_t mode) + { +- inode->i_mode = ef->mode & EVENTFS_MODE_MASK; ++ struct eventfs_inode *events_ei = eventfs_find_events(dentry); ++ ++ if (!events_ei) ++ return; ++ ++ inode->i_mode = mode; ++ inode->i_uid = events_ei->attr.uid; ++ inode->i_gid = events_ei->attr.gid; ++ ++ if (!attr) ++ return; ++ ++ if (attr->mode & EVENTFS_SAVE_MODE) ++ inode->i_mode = attr->mode & EVENTFS_MODE_MASK; + +- if (ef->mode & EVENTFS_SAVE_UID) +- inode->i_uid = ef->uid; ++ if (attr->mode & EVENTFS_SAVE_UID) ++ inode->i_uid = attr->uid; + +- if (ef->mode & EVENTFS_SAVE_GID) +- inode->i_gid = ef->gid; ++ if (attr->mode & EVENTFS_SAVE_GID) ++ inode->i_gid = attr->gid; + } + + /** +- * create_file - create a file in the tracefs filesystem +- * @ef: the eventfs_file +- * @parent: parent dentry for this file. ++ * lookup_file - look up a file in the tracefs filesystem ++ * @dentry: the dentry to look up ++ * @mode: the permission that the file should have. ++ * @attr: saved attributes changed by user + * @data: something that the caller will want to get to later on. + * @fop: struct file_operations that should be used for this file. + * +- * This is the basic "create a file" function for tracefs. It allows for a +- * wide range of flexibility in creating a file. +- * +- * This function will return a pointer to a dentry if it succeeds. This +- * pointer must be passed to the tracefs_remove() function when the file is +- * to be removed (no automatic cleanup happens if your module is unloaded, +- * you are responsible here.) If an error occurs, %NULL will be returned. +- * +- * If tracefs is not enabled in the kernel, the value -%ENODEV will be +- * returned. ++ * This function creates a dentry that represents a file in the eventsfs_inode ++ * directory. The inode.i_private pointer will point to @data in the open() ++ * call. + */ +-static struct dentry *create_file(struct eventfs_file *ef, +- struct dentry *parent, void *data, ++static struct dentry *lookup_file(struct eventfs_inode *parent_ei, ++ struct dentry *dentry, ++ umode_t mode, ++ struct eventfs_attr *attr, ++ void *data, + const struct file_operations *fop) + { + struct tracefs_inode *ti; +- struct dentry *dentry; + struct inode *inode; + +- if (!(ef->mode & S_IFMT)) +- ef->mode |= S_IFREG; +- +- if (WARN_ON_ONCE(!S_ISREG(ef->mode))) +- return NULL; +- +- dentry = eventfs_start_creating(ef->name, parent); ++ if (!(mode & S_IFMT)) ++ mode |= S_IFREG; + +- if (IS_ERR(dentry)) +- return dentry; ++ if (WARN_ON_ONCE(!S_ISREG(mode))) ++ return ERR_PTR(-EIO); + + inode = tracefs_get_inode(dentry->d_sb); + if (unlikely(!inode)) +- return eventfs_failed_creating(dentry); ++ return ERR_PTR(-ENOMEM); + + /* If the user updated the directory's attributes, use them */ +- update_inode_attr(inode, ef); ++ update_inode_attr(dentry, inode, attr, mode); + + inode->i_op = &eventfs_file_inode_operations; + inode->i_fop = fop; + inode->i_private = data; + ++ /* All files will have the same inode number */ ++ inode->i_ino = EVENTFS_FILE_INODE_INO; ++ + ti = get_tracefs(inode); + ti->flags |= TRACEFS_EVENT_INODE; +- d_instantiate(dentry, inode); +- fsnotify_create(dentry->d_parent->d_inode, dentry); +- return eventfs_end_creating(dentry); ++ ++ // Files have their parent's ei as their fsdata ++ dentry->d_fsdata = get_ei(parent_ei); ++ ++ d_add(dentry, inode); ++ return NULL; + }; + + /** +- * create_dir - create a dir in the tracefs filesystem ++ * lookup_dir_entry - look up a dir in the tracefs filesystem ++ * @dentry: the directory to look up + * @ei: the eventfs_inode that represents the directory to create +- * @parent: parent dentry for this file. +- * @data: something that the caller will want to get to later on. + * +- * This is the basic "create a dir" function for eventfs. It allows for a +- * wide range of flexibility in creating a dir. +- * +- * This function will return a pointer to a dentry if it succeeds. This +- * pointer must be passed to the tracefs_remove() function when the file is +- * to be removed (no automatic cleanup happens if your module is unloaded, +- * you are responsible here.) If an error occurs, %NULL will be returned. +- * +- * If tracefs is not enabled in the kernel, the value -%ENODEV will be +- * returned. ++ * This function will look up a dentry for a directory represented by ++ * a eventfs_inode. + */ +-static struct dentry *create_dir(struct eventfs_file *ef, +- struct dentry *parent, void *data) ++static struct dentry *lookup_dir_entry(struct dentry *dentry, ++ struct eventfs_inode *pei, struct eventfs_inode *ei) + { + struct tracefs_inode *ti; +- struct dentry *dentry; + struct inode *inode; + +- dentry = eventfs_start_creating(ef->name, parent); +- if (IS_ERR(dentry)) +- return dentry; +- + inode = tracefs_get_inode(dentry->d_sb); + if (unlikely(!inode)) +- return eventfs_failed_creating(dentry); ++ return ERR_PTR(-ENOMEM); + +- update_inode_attr(inode, ef); ++ /* If the user updated the directory's attributes, use them */ ++ update_inode_attr(dentry, inode, &ei->attr, ++ S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); + + inode->i_op = &eventfs_root_dir_inode_operations; + inode->i_fop = &eventfs_file_operations; +- inode->i_private = data; ++ ++ /* All directories will have the same inode number */ ++ inode->i_ino = eventfs_dir_ino(ei); + + ti = get_tracefs(inode); + ti->flags |= TRACEFS_EVENT_INODE; ++ /* Only directories have ti->private set to an ei, not files */ ++ ti->private = ei; + +- inc_nlink(inode); +- d_instantiate(dentry, inode); +- inc_nlink(dentry->d_parent->d_inode); +- fsnotify_mkdir(dentry->d_parent->d_inode, dentry); +- return eventfs_end_creating(dentry); +-} ++ dentry->d_fsdata = get_ei(ei); + +-static void free_ef(struct eventfs_file *ef) +-{ +- kfree(ef->name); +- kfree(ef->ei); +- kfree(ef); ++ d_add(dentry, inode); ++ return NULL; + } + +-/** +- * eventfs_set_ef_status_free - set the ef->status to free +- * @ti: the tracefs_inode of the dentry +- * @dentry: dentry who's status to be freed +- * +- * eventfs_set_ef_status_free will be called if no more +- * references remain +- */ +-void eventfs_set_ef_status_free(struct tracefs_inode *ti, struct dentry *dentry) ++static inline struct eventfs_inode *alloc_ei(const char *name) + { +- struct eventfs_inode *ei; +- struct eventfs_file *ef; ++ struct eventfs_inode *ei = kzalloc(sizeof(*ei), GFP_KERNEL); + +- /* The top level events directory may be freed by this */ +- if (unlikely(ti->flags & TRACEFS_EVENT_TOP_INODE)) { +- mutex_lock(&eventfs_mutex); +- ei = ti->private; +- +- /* Nothing should access this, but just in case! */ +- ti->private = NULL; +- mutex_unlock(&eventfs_mutex); +- +- ef = dentry->d_fsdata; +- if (ef) +- free_ef(ef); +- return; +- } +- +- mutex_lock(&eventfs_mutex); +- +- ef = dentry->d_fsdata; +- if (!ef) +- goto out; ++ if (!ei) ++ return NULL; + +- if (ef->is_freed) { +- free_ef(ef); +- } else { +- ef->dentry = NULL; ++ ei->name = kstrdup_const(name, GFP_KERNEL); ++ if (!ei->name) { ++ kfree(ei); ++ return NULL; + } +- +- dentry->d_fsdata = NULL; +-out: +- mutex_unlock(&eventfs_mutex); ++ kref_init(&ei->kref); ++ return ei; + } + + /** +- * eventfs_post_create_dir - post create dir routine +- * @ef: eventfs_file of recently created dir ++ * eventfs_d_release - dentry is going away ++ * @dentry: dentry which has the reference to remove. + * +- * Map the meta-data of files within an eventfs dir to their parent dentry ++ * Remove the association between a dentry from an eventfs_inode. + */ +-static void eventfs_post_create_dir(struct eventfs_file *ef) ++void eventfs_d_release(struct dentry *dentry) + { +- struct eventfs_file *ef_child; +- struct tracefs_inode *ti; +- +- /* srcu lock already held */ +- /* fill parent-child relation */ +- list_for_each_entry_srcu(ef_child, &ef->ei->e_top_files, list, +- srcu_read_lock_held(&eventfs_srcu)) { +- ef_child->d_parent = ef->dentry; +- } +- +- ti = get_tracefs(ef->dentry->d_inode); +- ti->private = ef->ei; ++ put_ei(dentry->d_fsdata); + } + + /** +- * create_dentry - helper function to create dentry +- * @ef: eventfs_file of file or directory to create +- * @parent: parent dentry +- * @lookup: true if called from lookup routine ++ * lookup_file_dentry - create a dentry for a file of an eventfs_inode ++ * @ei: the eventfs_inode that the file will be created under ++ * @idx: the index into the entry_attrs[] of the @ei ++ * @parent: The parent dentry of the created file. ++ * @name: The name of the file to create ++ * @mode: The mode of the file. ++ * @data: The data to use to set the inode of the file with on open() ++ * @fops: The fops of the file to be created. + * +- * Used to create a dentry for file/dir, executes post dentry creation routine ++ * Create a dentry for a file of an eventfs_inode @ei and place it into the ++ * address located at @e_dentry. + */ + static struct dentry * +-create_dentry(struct eventfs_file *ef, struct dentry *parent, bool lookup) ++lookup_file_dentry(struct dentry *dentry, ++ struct eventfs_inode *ei, int idx, ++ umode_t mode, void *data, ++ const struct file_operations *fops) + { +- bool invalidate = false; +- struct dentry *dentry; ++ struct eventfs_attr *attr = NULL; + +- mutex_lock(&eventfs_mutex); +- if (ef->is_freed) { +- mutex_unlock(&eventfs_mutex); +- return NULL; +- } +- if (ef->dentry) { +- dentry = ef->dentry; +- /* On dir open, up the ref count */ +- if (!lookup) +- dget(dentry); +- mutex_unlock(&eventfs_mutex); +- return dentry; +- } +- mutex_unlock(&eventfs_mutex); +- +- if (!lookup) +- inode_lock(parent->d_inode); +- +- if (ef->ei) +- dentry = create_dir(ef, parent, ef->data); +- else +- dentry = create_file(ef, parent, ef->data, ef->fop); ++ if (ei->entry_attrs) ++ attr = &ei->entry_attrs[idx]; + +- if (!lookup) +- inode_unlock(parent->d_inode); +- +- mutex_lock(&eventfs_mutex); +- if (IS_ERR_OR_NULL(dentry)) { +- /* If the ef was already updated get it */ +- dentry = ef->dentry; +- if (dentry && !lookup) +- dget(dentry); +- mutex_unlock(&eventfs_mutex); +- return dentry; +- } +- +- if (!ef->dentry && !ef->is_freed) { +- ef->dentry = dentry; +- if (ef->ei) +- eventfs_post_create_dir(ef); +- dentry->d_fsdata = ef; +- } else { +- /* A race here, should try again (unless freed) */ +- invalidate = true; +- +- /* +- * Should never happen unless we get here due to being freed. +- * Otherwise it means two dentries exist with the same name. +- */ +- WARN_ON_ONCE(!ef->is_freed); +- } +- mutex_unlock(&eventfs_mutex); +- if (invalidate) +- d_invalidate(dentry); +- +- if (lookup || invalidate) +- dput(dentry); +- +- return invalidate ? NULL : dentry; +-} +- +-static bool match_event_file(struct eventfs_file *ef, const char *name) +-{ +- bool ret; +- +- mutex_lock(&eventfs_mutex); +- ret = !ef->is_freed && strcmp(ef->name, name) == 0; +- mutex_unlock(&eventfs_mutex); +- +- return ret; ++ return lookup_file(ei, dentry, mode, attr, data, fops); + } + + /** + * eventfs_root_lookup - lookup routine to create file/dir + * @dir: in which a lookup is being done + * @dentry: file/dir dentry +- * @flags: to pass as flags parameter to simple lookup ++ * @flags: Just passed to simple_lookup() + * +- * Used to create a dynamic file/dir within @dir. Use the eventfs_inode +- * list of meta data to find the information needed to create the file/dir. ++ * Used to create dynamic file/dir with-in @dir, search with-in @ei ++ * list, if @dentry found go ahead and create the file/dir + */ ++ + static struct dentry *eventfs_root_lookup(struct inode *dir, + struct dentry *dentry, + unsigned int flags) + { ++ struct eventfs_inode *ei_child; + struct tracefs_inode *ti; + struct eventfs_inode *ei; +- struct eventfs_file *ef; +- struct dentry *ret = NULL; +- int idx; ++ const char *name = dentry->d_name.name; ++ struct dentry *result = NULL; + + ti = get_tracefs(dir); + if (!(ti->flags & TRACEFS_EVENT_INODE)) +- return NULL; ++ return ERR_PTR(-EIO); ++ ++ mutex_lock(&eventfs_mutex); + + ei = ti->private; +- idx = srcu_read_lock(&eventfs_srcu); +- list_for_each_entry_srcu(ef, &ei->e_top_files, list, +- srcu_read_lock_held(&eventfs_srcu)) { +- if (!match_event_file(ef, dentry->d_name.name)) ++ if (!ei || ei->is_freed) ++ goto out; ++ ++ list_for_each_entry(ei_child, &ei->children, list) { ++ if (strcmp(ei_child->name, name) != 0) + continue; +- ret = simple_lookup(dir, dentry, flags); +- create_dentry(ef, ef->d_parent, true); +- break; ++ if (ei_child->is_freed) ++ goto out; ++ result = lookup_dir_entry(dentry, ei, ei_child); ++ goto out; + } +- srcu_read_unlock(&eventfs_srcu, idx); +- return ret; +-} + +-struct dentry_list { +- void *cursor; +- struct dentry **dentries; +-}; +- +-/** +- * eventfs_release - called to release eventfs file/dir +- * @inode: inode to be released +- * @file: file to be released (not used) +- */ +-static int eventfs_release(struct inode *inode, struct file *file) +-{ +- struct tracefs_inode *ti; +- struct dentry_list *dlist = file->private_data; +- void *cursor; +- int i; ++ for (int i = 0; i < ei->nr_entries; i++) { ++ void *data; ++ umode_t mode; ++ const struct file_operations *fops; ++ const struct eventfs_entry *entry = &ei->entries[i]; + +- ti = get_tracefs(inode); +- if (!(ti->flags & TRACEFS_EVENT_INODE)) +- return -EINVAL; ++ if (strcmp(name, entry->name) != 0) ++ continue; + +- if (WARN_ON_ONCE(!dlist)) +- return -EINVAL; ++ data = ei->data; ++ if (entry->callback(name, &mode, &data, &fops) <= 0) ++ goto out; + +- for (i = 0; dlist->dentries && dlist->dentries[i]; i++) { +- dput(dlist->dentries[i]); ++ result = lookup_file_dentry(dentry, ei, i, mode, data, fops); ++ goto out; + } +- +- cursor = dlist->cursor; +- kfree(dlist->dentries); +- kfree(dlist); +- file->private_data = cursor; +- return dcache_dir_close(inode, file); ++ out: ++ mutex_unlock(&eventfs_mutex); ++ return result; + } + +-/** +- * dcache_dir_open_wrapper - eventfs open wrapper +- * @inode: not used +- * @file: dir to be opened (to create its child) +- * +- * Used to dynamically create the file/dir within @file. @file is really a +- * directory and all the files/dirs of the children within @file will be +- * created. If any of the files/dirs have already been created, their +- * reference count will be incremented. ++/* ++ * Walk the children of a eventfs_inode to fill in getdents(). + */ +-static int dcache_dir_open_wrapper(struct inode *inode, struct file *file) ++static int eventfs_iterate(struct file *file, struct dir_context *ctx) + { ++ const struct file_operations *fops; ++ struct inode *f_inode = file_inode(file); ++ const struct eventfs_entry *entry; ++ struct eventfs_inode *ei_child; + struct tracefs_inode *ti; + struct eventfs_inode *ei; +- struct eventfs_file *ef; +- struct dentry_list *dlist; +- struct dentry **dentries = NULL; +- struct dentry *dentry = file_dentry(file); +- struct dentry *d; +- struct inode *f_inode = file_inode(file); +- int cnt = 0; ++ const char *name; ++ umode_t mode; + int idx; +- int ret; ++ int ret = -EINVAL; ++ int ino; ++ int i, r, c; ++ ++ if (!dir_emit_dots(file, ctx)) ++ return 0; + + ti = get_tracefs(f_inode); + if (!(ti->flags & TRACEFS_EVENT_INODE)) + return -EINVAL; + +- if (WARN_ON_ONCE(file->private_data)) +- return -EINVAL; +- +- dlist = kmalloc(sizeof(*dlist), GFP_KERNEL); +- if (!dlist) +- return -ENOMEM; ++ c = ctx->pos - 2; + +- ei = ti->private; + idx = srcu_read_lock(&eventfs_srcu); +- list_for_each_entry_srcu(ef, &ei->e_top_files, list, +- srcu_read_lock_held(&eventfs_srcu)) { +- d = create_dentry(ef, dentry, false); +- if (d) { +- struct dentry **tmp; + ++ mutex_lock(&eventfs_mutex); ++ ei = READ_ONCE(ti->private); ++ if (ei && ei->is_freed) ++ ei = NULL; ++ mutex_unlock(&eventfs_mutex); + +- tmp = krealloc(dentries, sizeof(d) * (cnt + 2), GFP_KERNEL); +- if (!tmp) +- break; +- tmp[cnt] = d; +- tmp[cnt + 1] = NULL; +- cnt++; +- dentries = tmp; +- } +- } +- srcu_read_unlock(&eventfs_srcu, idx); +- ret = dcache_dir_open(inode, file); ++ if (!ei) ++ goto out; + + /* +- * dcache_dir_open() sets file->private_data to a dentry cursor. +- * Need to save that but also save all the dentries that were +- * opened by this function. ++ * Need to create the dentries and inodes to have a consistent ++ * inode number. + */ +- dlist->cursor = file->private_data; +- dlist->dentries = dentries; +- file->private_data = dlist; +- return ret; +-} ++ ret = 0; + +-/* +- * This just sets the file->private_data back to the cursor and back. +- */ +-static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx) +-{ +- struct dentry_list *dlist = file->private_data; +- int ret; ++ /* Start at 'c' to jump over already read entries */ ++ for (i = c; i < ei->nr_entries; i++, ctx->pos++) { ++ void *cdata = ei->data; + +- file->private_data = dlist->cursor; +- ret = dcache_readdir(file, ctx); +- dlist->cursor = file->private_data; +- file->private_data = dlist; +- return ret; +-} ++ entry = &ei->entries[i]; ++ name = entry->name; + +-/** +- * eventfs_prepare_ef - helper function to prepare eventfs_file +- * @name: the name of the file/directory to create. +- * @mode: the permission that the file should have. +- * @fop: struct file_operations that should be used for this file/directory. +- * @iop: struct inode_operations that should be used for this file/directory. +- * @data: something that the caller will want to get to later on. The +- * inode.i_private pointer will point to this value on the open() call. +- * +- * This function allocates and fills the eventfs_file structure. +- */ +-static struct eventfs_file *eventfs_prepare_ef(const char *name, umode_t mode, +- const struct file_operations *fop, +- const struct inode_operations *iop, +- void *data) +-{ +- struct eventfs_file *ef; ++ mutex_lock(&eventfs_mutex); ++ /* If ei->is_freed then just bail here, nothing more to do */ ++ if (ei->is_freed) { ++ mutex_unlock(&eventfs_mutex); ++ goto out; ++ } ++ r = entry->callback(name, &mode, &cdata, &fops); ++ mutex_unlock(&eventfs_mutex); ++ if (r <= 0) ++ continue; + +- ef = kzalloc(sizeof(*ef), GFP_KERNEL); +- if (!ef) +- return ERR_PTR(-ENOMEM); ++ ino = EVENTFS_FILE_INODE_INO; + +- ef->name = kstrdup(name, GFP_KERNEL); +- if (!ef->name) { +- kfree(ef); +- return ERR_PTR(-ENOMEM); ++ if (!dir_emit(ctx, name, strlen(name), ino, DT_REG)) ++ goto out; + } + +- if (S_ISDIR(mode)) { +- ef->ei = kzalloc(sizeof(*ef->ei), GFP_KERNEL); +- if (!ef->ei) { +- kfree(ef->name); +- kfree(ef); +- return ERR_PTR(-ENOMEM); +- } +- INIT_LIST_HEAD(&ef->ei->e_top_files); +- ef->mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; +- } else { +- ef->ei = NULL; +- ef->mode = mode; +- } ++ /* Subtract the skipped entries above */ ++ c -= min((unsigned int)c, (unsigned int)ei->nr_entries); + +- ef->iop = iop; +- ef->fop = fop; +- ef->data = data; +- return ef; +-} ++ list_for_each_entry_srcu(ei_child, &ei->children, list, ++ srcu_read_lock_held(&eventfs_srcu)) { + +-/** +- * eventfs_create_events_dir - create the trace event structure +- * @name: the name of the directory to create. +- * @parent: parent dentry for this file. This should be a directory dentry +- * if set. If this parameter is NULL, then the directory will be +- * created in the root of the tracefs filesystem. +- * +- * This function creates the top of the trace event directory. +- */ +-struct dentry *eventfs_create_events_dir(const char *name, +- struct dentry *parent) +-{ +- struct dentry *dentry = tracefs_start_creating(name, parent); +- struct eventfs_inode *ei; +- struct tracefs_inode *ti; +- struct inode *inode; ++ if (c > 0) { ++ c--; ++ continue; ++ } + +- if (security_locked_down(LOCKDOWN_TRACEFS)) +- return NULL; ++ ctx->pos++; + +- if (IS_ERR(dentry)) +- return dentry; ++ if (ei_child->is_freed) ++ continue; + +- ei = kzalloc(sizeof(*ei), GFP_KERNEL); +- if (!ei) +- return ERR_PTR(-ENOMEM); +- inode = tracefs_get_inode(dentry->d_sb); +- if (unlikely(!inode)) { +- kfree(ei); +- tracefs_failed_creating(dentry); +- return ERR_PTR(-ENOMEM); +- } ++ name = ei_child->name; + +- INIT_LIST_HEAD(&ei->e_top_files); ++ ino = eventfs_dir_ino(ei_child); + +- ti = get_tracefs(inode); +- ti->flags |= TRACEFS_EVENT_INODE | TRACEFS_EVENT_TOP_INODE; +- ti->private = ei; ++ if (!dir_emit(ctx, name, strlen(name), ino, DT_DIR)) ++ goto out_dec; ++ } ++ ret = 1; ++ out: ++ srcu_read_unlock(&eventfs_srcu, idx); + +- inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; +- inode->i_op = &eventfs_root_dir_inode_operations; +- inode->i_fop = &eventfs_file_operations; ++ return ret; + +- /* directory inodes start off with i_nlink == 2 (for "." entry) */ +- inc_nlink(inode); +- d_instantiate(dentry, inode); +- inc_nlink(dentry->d_parent->d_inode); +- fsnotify_mkdir(dentry->d_parent->d_inode, dentry); +- return tracefs_end_creating(dentry); ++ out_dec: ++ /* Incremented ctx->pos without adding something, reset it */ ++ ctx->pos--; ++ goto out; + } + + /** +- * eventfs_add_subsystem_dir - add eventfs subsystem_dir to list to create later +- * @name: the name of the file to create. +- * @parent: parent dentry for this dir. ++ * eventfs_create_dir - Create the eventfs_inode for this directory ++ * @name: The name of the directory to create. ++ * @parent: The eventfs_inode of the parent directory. ++ * @entries: A list of entries that represent the files under this directory ++ * @size: The number of @entries ++ * @data: The default data to pass to the files (an entry may override it). ++ * ++ * This function creates the descriptor to represent a directory in the ++ * eventfs. This descriptor is an eventfs_inode, and it is returned to be ++ * used to create other children underneath. ++ * ++ * The @entries is an array of eventfs_entry structures which has: ++ * const char *name ++ * eventfs_callback callback; ++ * ++ * The name is the name of the file, and the callback is a pointer to a function ++ * that will be called when the file is reference (either by lookup or by ++ * reading a directory). The callback is of the prototype: ++ * ++ * int callback(const char *name, umode_t *mode, void **data, ++ * const struct file_operations **fops); ++ * ++ * When a file needs to be created, this callback will be called with ++ * name = the name of the file being created (so that the same callback ++ * may be used for multiple files). ++ * mode = a place to set the file's mode ++ * data = A pointer to @data, and the callback may replace it, which will ++ * cause the file created to pass the new data to the open() call. ++ * fops = the fops to use for the created file. + * +- * This function adds eventfs subsystem dir to list. +- * And all these dirs are created on the fly when they are looked up, +- * and the dentry and inodes will be removed when they are done. ++ * NB. @callback is called while holding internal locks of the eventfs ++ * system. The callback must not call any code that might also call into ++ * the tracefs or eventfs system or it will risk creating a deadlock. + */ +-struct eventfs_file *eventfs_add_subsystem_dir(const char *name, +- struct dentry *parent) ++struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode *parent, ++ const struct eventfs_entry *entries, ++ int size, void *data) + { +- struct tracefs_inode *ti_parent; +- struct eventfs_inode *ei_parent; +- struct eventfs_file *ef; +- +- if (security_locked_down(LOCKDOWN_TRACEFS)) +- return NULL; ++ struct eventfs_inode *ei; + + if (!parent) + return ERR_PTR(-EINVAL); + +- ti_parent = get_tracefs(parent->d_inode); +- ei_parent = ti_parent->private; ++ ei = alloc_ei(name); ++ if (!ei) ++ return ERR_PTR(-ENOMEM); + +- ef = eventfs_prepare_ef(name, S_IFDIR, NULL, NULL, NULL); +- if (IS_ERR(ef)) +- return ef; ++ ei->entries = entries; ++ ei->nr_entries = size; ++ ei->data = data; ++ INIT_LIST_HEAD(&ei->children); ++ INIT_LIST_HEAD(&ei->list); + + mutex_lock(&eventfs_mutex); +- list_add_tail(&ef->list, &ei_parent->e_top_files); +- ef->d_parent = parent; ++ if (!parent->is_freed) ++ list_add_tail(&ei->list, &parent->children); + mutex_unlock(&eventfs_mutex); +- return ef; +-} +- +-/** +- * eventfs_add_dir - add eventfs dir to list to create later +- * @name: the name of the file to create. +- * @ef_parent: parent eventfs_file for this dir. +- * +- * This function adds eventfs dir to list. +- * And all these dirs are created on the fly when they are looked up, +- * and the dentry and inodes will be removed when they are done. +- */ +-struct eventfs_file *eventfs_add_dir(const char *name, +- struct eventfs_file *ef_parent) +-{ +- struct eventfs_file *ef; +- +- if (security_locked_down(LOCKDOWN_TRACEFS)) +- return NULL; +- +- if (!ef_parent) +- return ERR_PTR(-EINVAL); +- +- ef = eventfs_prepare_ef(name, S_IFDIR, NULL, NULL, NULL); +- if (IS_ERR(ef)) +- return ef; + +- mutex_lock(&eventfs_mutex); +- list_add_tail(&ef->list, &ef_parent->ei->e_top_files); +- ef->d_parent = ef_parent->dentry; +- mutex_unlock(&eventfs_mutex); +- return ef; ++ /* Was the parent freed? */ ++ if (list_empty(&ei->list)) { ++ free_ei(ei); ++ ei = NULL; ++ } ++ return ei; + } + + /** +- * eventfs_add_events_file - add the data needed to create a file for later reference +- * @name: the name of the file to create. +- * @mode: the permission that the file should have. +- * @parent: parent dentry for this file. +- * @data: something that the caller will want to get to later on. +- * @fop: struct file_operations that should be used for this file. ++ * eventfs_create_events_dir - create the top level events directory ++ * @name: The name of the top level directory to create. ++ * @parent: Parent dentry for this file in the tracefs directory. ++ * @entries: A list of entries that represent the files under this directory ++ * @size: The number of @entries ++ * @data: The default data to pass to the files (an entry may override it). + * +- * This function is used to add the information needed to create a +- * dentry/inode within the top level events directory. The file created +- * will have the @mode permissions. The @data will be used to fill the +- * inode.i_private when the open() call is done. The dentry and inodes are +- * all created when they are referenced, and removed when they are no +- * longer referenced. ++ * This function creates the top of the trace event directory. ++ * ++ * See eventfs_create_dir() for use of @entries. + */ +-int eventfs_add_events_file(const char *name, umode_t mode, +- struct dentry *parent, void *data, +- const struct file_operations *fop) ++struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry *parent, ++ const struct eventfs_entry *entries, ++ int size, void *data) + { +- struct tracefs_inode *ti; ++ struct dentry *dentry = tracefs_start_creating(name, parent); + struct eventfs_inode *ei; +- struct eventfs_file *ef; ++ struct tracefs_inode *ti; ++ struct inode *inode; ++ kuid_t uid; ++ kgid_t gid; + + if (security_locked_down(LOCKDOWN_TRACEFS)) +- return -ENODEV; +- +- if (!parent) +- return -EINVAL; +- +- if (!(mode & S_IFMT)) +- mode |= S_IFREG; +- +- if (!parent->d_inode) +- return -EINVAL; +- +- ti = get_tracefs(parent->d_inode); +- if (!(ti->flags & TRACEFS_EVENT_INODE)) +- return -EINVAL; +- +- ei = ti->private; +- ef = eventfs_prepare_ef(name, mode, fop, NULL, data); +- +- if (IS_ERR(ef)) +- return -ENOMEM; +- +- mutex_lock(&eventfs_mutex); +- list_add_tail(&ef->list, &ei->e_top_files); +- ef->d_parent = parent; +- mutex_unlock(&eventfs_mutex); +- return 0; +-} +- +-/** +- * eventfs_add_file - add eventfs file to list to create later +- * @name: the name of the file to create. +- * @mode: the permission that the file should have. +- * @ef_parent: parent eventfs_file for this file. +- * @data: something that the caller will want to get to later on. +- * @fop: struct file_operations that should be used for this file. +- * +- * This function is used to add the information needed to create a +- * file within a subdirectory of the events directory. The file created +- * will have the @mode permissions. The @data will be used to fill the +- * inode.i_private when the open() call is done. The dentry and inodes are +- * all created when they are referenced, and removed when they are no +- * longer referenced. +- */ +-int eventfs_add_file(const char *name, umode_t mode, +- struct eventfs_file *ef_parent, +- void *data, +- const struct file_operations *fop) +-{ +- struct eventfs_file *ef; ++ return NULL; + +- if (security_locked_down(LOCKDOWN_TRACEFS)) +- return -ENODEV; ++ if (IS_ERR(dentry)) ++ return ERR_CAST(dentry); + +- if (!ef_parent) +- return -EINVAL; ++ ei = alloc_ei(name); ++ if (!ei) ++ goto fail; + +- if (!(mode & S_IFMT)) +- mode |= S_IFREG; ++ inode = tracefs_get_inode(dentry->d_sb); ++ if (unlikely(!inode)) ++ goto fail; + +- ef = eventfs_prepare_ef(name, mode, fop, NULL, data); +- if (IS_ERR(ef)) +- return -ENOMEM; ++ // Note: we have a ref to the dentry from tracefs_start_creating() ++ ei->events_dir = dentry; ++ ei->entries = entries; ++ ei->nr_entries = size; ++ ei->is_events = 1; ++ ei->data = data; + +- mutex_lock(&eventfs_mutex); +- list_add_tail(&ef->list, &ef_parent->ei->e_top_files); +- ef->d_parent = ef_parent->dentry; +- mutex_unlock(&eventfs_mutex); +- return 0; +-} ++ /* Save the ownership of this directory */ ++ uid = d_inode(dentry->d_parent)->i_uid; ++ gid = d_inode(dentry->d_parent)->i_gid; + +-static LLIST_HEAD(free_list); ++ /* ++ * If the events directory is of the top instance, then parent ++ * is NULL. Set the attr.mode to reflect this and its permissions will ++ * default to the tracefs root dentry. ++ */ ++ if (!parent) ++ ei->attr.mode = EVENTFS_TOPLEVEL; + +-static void eventfs_workfn(struct work_struct *work) +-{ +- struct eventfs_file *ef, *tmp; +- struct llist_node *llnode; +- +- llnode = llist_del_all(&free_list); +- llist_for_each_entry_safe(ef, tmp, llnode, llist) { +- /* This should only get here if it had a dentry */ +- if (!WARN_ON_ONCE(!ef->dentry)) +- dput(ef->dentry); +- } +-} ++ /* This is used as the default ownership of the files and directories */ ++ ei->attr.uid = uid; ++ ei->attr.gid = gid; + +-static DECLARE_WORK(eventfs_work, eventfs_workfn); ++ INIT_LIST_HEAD(&ei->children); ++ INIT_LIST_HEAD(&ei->list); + +-static void free_rcu_ef(struct rcu_head *head) +-{ +- struct eventfs_file *ef = container_of(head, struct eventfs_file, rcu); ++ ti = get_tracefs(inode); ++ ti->flags |= TRACEFS_EVENT_INODE | TRACEFS_EVENT_TOP_INODE; ++ ti->private = ei; + +- if (ef->dentry) { +- /* Do not free the ef until all references of dentry are gone */ +- if (llist_add(&ef->llist, &free_list)) +- queue_work(system_unbound_wq, &eventfs_work); +- return; +- } ++ inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; ++ inode->i_uid = uid; ++ inode->i_gid = gid; ++ inode->i_op = &eventfs_root_dir_inode_operations; ++ inode->i_fop = &eventfs_file_operations; + +- free_ef(ef); +-} ++ dentry->d_fsdata = get_ei(ei); + +-static void unhook_dentry(struct dentry *dentry) +-{ +- if (!dentry) +- return; + /* +- * Need to add a reference to the dentry that is expected by +- * simple_recursive_removal(), which will include a dput(). ++ * Keep all eventfs directories with i_nlink == 1. ++ * Due to the dynamic nature of the dentry creations and not ++ * wanting to add a pointer to the parent eventfs_inode in the ++ * eventfs_inode structure, keeping the i_nlink in sync with the ++ * number of directories would cause too much complexity for ++ * something not worth much. Keeping directory links at 1 ++ * tells userspace not to trust the link number. + */ +- dget(dentry); ++ d_instantiate(dentry, inode); ++ /* The dentry of the "events" parent does keep track though */ ++ inc_nlink(dentry->d_parent->d_inode); ++ fsnotify_mkdir(dentry->d_parent->d_inode, dentry); ++ tracefs_end_creating(dentry); + +- /* +- * Also add a reference for the dput() in eventfs_workfn(). +- * That is required as that dput() will free the ei after +- * the SRCU grace period is over. +- */ +- dget(dentry); ++ return ei; ++ ++ fail: ++ free_ei(ei); ++ tracefs_failed_creating(dentry); ++ return ERR_PTR(-ENOMEM); + } + + /** + * eventfs_remove_rec - remove eventfs dir or file from list +- * @ef: eventfs_file to be removed. +- * @level: to check recursion depth ++ * @ei: eventfs_inode to be removed. ++ * @level: prevent recursion from going more than 3 levels deep. + * +- * The helper function eventfs_remove_rec() is used to clean up and free the +- * associated data from eventfs for both of the added functions. ++ * This function recursively removes eventfs_inodes which ++ * contains info of files and/or directories. + */ +-static void eventfs_remove_rec(struct eventfs_file *ef, int level) ++static void eventfs_remove_rec(struct eventfs_inode *ei, int level) + { +- struct eventfs_file *ef_child; ++ struct eventfs_inode *ei_child; + +- if (!ef) +- return; + /* + * Check recursion depth. It should never be greater than 3: + * 0 - events/ +@@ -904,72 +812,54 @@ static void eventfs_remove_rec(struct eventfs_file *ef, int level) + if (WARN_ON_ONCE(level > 3)) + return; + +- if (ef->ei) { +- /* search for nested folders or files */ +- list_for_each_entry_srcu(ef_child, &ef->ei->e_top_files, list, +- lockdep_is_held(&eventfs_mutex)) { +- eventfs_remove_rec(ef_child, level + 1); +- } +- } +- +- ef->is_freed = 1; ++ /* search for nested folders or files */ ++ list_for_each_entry(ei_child, &ei->children, list) ++ eventfs_remove_rec(ei_child, level + 1); + +- unhook_dentry(ef->dentry); +- +- list_del_rcu(&ef->list); +- call_srcu(&eventfs_srcu, &ef->rcu, free_rcu_ef); ++ list_del(&ei->list); ++ free_ei(ei); + } + + /** +- * eventfs_remove - remove eventfs dir or file from list +- * @ef: eventfs_file to be removed. ++ * eventfs_remove_dir - remove eventfs dir or file from list ++ * @ei: eventfs_inode to be removed. + * + * This function acquire the eventfs_mutex lock and call eventfs_remove_rec() + */ +-void eventfs_remove(struct eventfs_file *ef) ++void eventfs_remove_dir(struct eventfs_inode *ei) + { +- struct dentry *dentry; +- +- if (!ef) ++ if (!ei) + return; + + mutex_lock(&eventfs_mutex); +- dentry = ef->dentry; +- eventfs_remove_rec(ef, 0); ++ eventfs_remove_rec(ei, 0); + mutex_unlock(&eventfs_mutex); +- +- /* +- * If any of the ei children has a dentry, then the ei itself +- * must have a dentry. +- */ +- if (dentry) +- simple_recursive_removal(dentry, NULL); + } + + /** +- * eventfs_remove_events_dir - remove eventfs dir or file from list +- * @dentry: events's dentry to be removed. ++ * eventfs_remove_events_dir - remove the top level eventfs directory ++ * @ei: the event_inode returned by eventfs_create_events_dir(). + * +- * This function remove events main directory ++ * This function removes the events main directory + */ +-void eventfs_remove_events_dir(struct dentry *dentry) ++void eventfs_remove_events_dir(struct eventfs_inode *ei) + { +- struct eventfs_file *ef_child; +- struct eventfs_inode *ei; +- struct tracefs_inode *ti; ++ struct dentry *dentry; + +- if (!dentry || !dentry->d_inode) ++ dentry = ei->events_dir; ++ if (!dentry) + return; + +- ti = get_tracefs(dentry->d_inode); +- if (!ti || !(ti->flags & TRACEFS_EVENT_INODE)) +- return; ++ ei->events_dir = NULL; ++ eventfs_remove_dir(ei); + +- mutex_lock(&eventfs_mutex); +- ei = ti->private; +- list_for_each_entry_srcu(ef_child, &ei->e_top_files, list, +- lockdep_is_held(&eventfs_mutex)) { +- eventfs_remove_rec(ef_child, 0); +- } +- mutex_unlock(&eventfs_mutex); ++ /* ++ * Matches the dget() done by tracefs_start_creating() ++ * in eventfs_create_events_dir() when it the dentry was ++ * created. In other words, it's a normal dentry that ++ * sticks around while the other ei->dentry are created ++ * and destroyed dynamically. ++ */ ++ d_invalidate(dentry); ++ dput(dentry); + } +diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c +index 0292c6a2bed9f..99caf1c3d0c41 100644 +--- a/fs/tracefs/inode.c ++++ b/fs/tracefs/inode.c +@@ -38,8 +38,6 @@ static struct inode *tracefs_alloc_inode(struct super_block *sb) + if (!ti) + return NULL; + +- ti->flags = 0; +- + return &ti->vfs_inode; + } + +@@ -91,6 +89,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, + struct inode *inode, struct dentry *dentry, + umode_t mode) + { ++ struct tracefs_inode *ti; + char *name; + int ret; + +@@ -98,6 +97,15 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, + if (!name) + return -ENOMEM; + ++ /* ++ * This is a new directory that does not take the default of ++ * the rootfs. It becomes the default permissions for all the ++ * files and directories underneath it. ++ */ ++ ti = get_tracefs(inode); ++ ti->flags |= TRACEFS_INSTANCE_INODE; ++ ti->private = inode; ++ + /* + * The mkdir call can call the generic functions that create + * the files within the tracefs system. It is up to the individual +@@ -141,10 +149,76 @@ static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry) + return ret; + } + +-static const struct inode_operations tracefs_dir_inode_operations = { ++static void set_tracefs_inode_owner(struct inode *inode) ++{ ++ struct tracefs_inode *ti = get_tracefs(inode); ++ struct inode *root_inode = ti->private; ++ ++ /* ++ * If this inode has never been referenced, then update ++ * the permissions to the superblock. ++ */ ++ if (!(ti->flags & TRACEFS_UID_PERM_SET)) ++ inode->i_uid = root_inode->i_uid; ++ ++ if (!(ti->flags & TRACEFS_GID_PERM_SET)) ++ inode->i_gid = root_inode->i_gid; ++} ++ ++static int tracefs_permission(struct mnt_idmap *idmap, ++ struct inode *inode, int mask) ++{ ++ set_tracefs_inode_owner(inode); ++ return generic_permission(idmap, inode, mask); ++} ++ ++static int tracefs_getattr(struct mnt_idmap *idmap, ++ const struct path *path, struct kstat *stat, ++ u32 request_mask, unsigned int flags) ++{ ++ struct inode *inode = d_backing_inode(path->dentry); ++ ++ set_tracefs_inode_owner(inode); ++ generic_fillattr(idmap, request_mask, inode, stat); ++ return 0; ++} ++ ++static int tracefs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, ++ struct iattr *attr) ++{ ++ unsigned int ia_valid = attr->ia_valid; ++ struct inode *inode = d_inode(dentry); ++ struct tracefs_inode *ti = get_tracefs(inode); ++ ++ if (ia_valid & ATTR_UID) ++ ti->flags |= TRACEFS_UID_PERM_SET; ++ ++ if (ia_valid & ATTR_GID) ++ ti->flags |= TRACEFS_GID_PERM_SET; ++ ++ return simple_setattr(idmap, dentry, attr); ++} ++ ++static const struct inode_operations tracefs_instance_dir_inode_operations = { + .lookup = simple_lookup, + .mkdir = tracefs_syscall_mkdir, + .rmdir = tracefs_syscall_rmdir, ++ .permission = tracefs_permission, ++ .getattr = tracefs_getattr, ++ .setattr = tracefs_setattr, ++}; ++ ++static const struct inode_operations tracefs_dir_inode_operations = { ++ .lookup = simple_lookup, ++ .permission = tracefs_permission, ++ .getattr = tracefs_getattr, ++ .setattr = tracefs_setattr, ++}; ++ ++static const struct inode_operations tracefs_file_inode_operations = { ++ .permission = tracefs_permission, ++ .getattr = tracefs_getattr, ++ .setattr = tracefs_setattr, + }; + + struct inode *tracefs_get_inode(struct super_block *sb) +@@ -183,77 +257,6 @@ struct tracefs_fs_info { + struct tracefs_mount_opts mount_opts; + }; + +-static void change_gid(struct dentry *dentry, kgid_t gid) +-{ +- if (!dentry->d_inode) +- return; +- dentry->d_inode->i_gid = gid; +-} +- +-/* +- * Taken from d_walk, but without he need for handling renames. +- * Nothing can be renamed while walking the list, as tracefs +- * does not support renames. This is only called when mounting +- * or remounting the file system, to set all the files to +- * the given gid. +- */ +-static void set_gid(struct dentry *parent, kgid_t gid) +-{ +- struct dentry *this_parent; +- struct list_head *next; +- +- this_parent = parent; +- spin_lock(&this_parent->d_lock); +- +- change_gid(this_parent, gid); +-repeat: +- next = this_parent->d_subdirs.next; +-resume: +- while (next != &this_parent->d_subdirs) { +- struct list_head *tmp = next; +- struct dentry *dentry = list_entry(tmp, struct dentry, d_child); +- next = tmp->next; +- +- spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); +- +- change_gid(dentry, gid); +- +- if (!list_empty(&dentry->d_subdirs)) { +- spin_unlock(&this_parent->d_lock); +- spin_release(&dentry->d_lock.dep_map, _RET_IP_); +- this_parent = dentry; +- spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); +- goto repeat; +- } +- spin_unlock(&dentry->d_lock); +- } +- /* +- * All done at this level ... ascend and resume the search. +- */ +- rcu_read_lock(); +-ascend: +- if (this_parent != parent) { +- struct dentry *child = this_parent; +- this_parent = child->d_parent; +- +- spin_unlock(&child->d_lock); +- spin_lock(&this_parent->d_lock); +- +- /* go into the first sibling still alive */ +- do { +- next = child->d_child.next; +- if (next == &this_parent->d_subdirs) +- goto ascend; +- child = list_entry(next, struct dentry, d_child); +- } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)); +- rcu_read_unlock(); +- goto resume; +- } +- rcu_read_unlock(); +- spin_unlock(&this_parent->d_lock); +- return; +-} +- + static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts) + { + substring_t args[MAX_OPT_ARGS]; +@@ -326,10 +329,8 @@ static int tracefs_apply_options(struct super_block *sb, bool remount) + if (!remount || opts->opts & BIT(Opt_uid)) + inode->i_uid = opts->uid; + +- if (!remount || opts->opts & BIT(Opt_gid)) { +- /* Set all the group ids to the mount option */ +- set_gid(sb->s_root, opts->gid); +- } ++ if (!remount || opts->opts & BIT(Opt_gid)) ++ inode->i_gid = opts->gid; + + return 0; + } +@@ -376,21 +377,30 @@ static const struct super_operations tracefs_super_operations = { + .show_options = tracefs_show_options, + }; + +-static void tracefs_dentry_iput(struct dentry *dentry, struct inode *inode) ++/* ++ * It would be cleaner if eventfs had its own dentry ops. ++ * ++ * Note that d_revalidate is called potentially under RCU, ++ * so it can't take the eventfs mutex etc. It's fine - if ++ * we open a file just as it's marked dead, things will ++ * still work just fine, and just see the old stale case. ++ */ ++static void tracefs_d_release(struct dentry *dentry) + { +- struct tracefs_inode *ti; ++ if (dentry->d_fsdata) ++ eventfs_d_release(dentry); ++} + +- if (!dentry || !inode) +- return; ++static int tracefs_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ struct eventfs_inode *ei = dentry->d_fsdata; + +- ti = get_tracefs(inode); +- if (ti && ti->flags & TRACEFS_EVENT_INODE) +- eventfs_set_ef_status_free(ti, dentry); +- iput(inode); ++ return !(ei && ei->is_freed); + } + + static const struct dentry_operations tracefs_dentry_operations = { +- .d_iput = tracefs_dentry_iput, ++ .d_revalidate = tracefs_d_revalidate, ++ .d_release = tracefs_d_release, + }; + + static int trace_fill_super(struct super_block *sb, void *data, int silent) +@@ -494,73 +504,24 @@ struct dentry *tracefs_end_creating(struct dentry *dentry) + return dentry; + } + +-/** +- * eventfs_start_creating - start the process of creating a dentry +- * @name: Name of the file created for the dentry +- * @parent: The parent dentry where this dentry will be created +- * +- * This is a simple helper function for the dynamically created eventfs +- * files. When the directory of the eventfs files are accessed, their +- * dentries are created on the fly. This function is used to start that +- * process. +- */ +-struct dentry *eventfs_start_creating(const char *name, struct dentry *parent) ++/* Find the inode that this will use for default */ ++static struct inode *instance_inode(struct dentry *parent, struct inode *inode) + { +- struct dentry *dentry; +- int error; +- +- /* Must always have a parent. */ +- if (WARN_ON_ONCE(!parent)) +- return ERR_PTR(-EINVAL); +- +- error = simple_pin_fs(&trace_fs_type, &tracefs_mount, +- &tracefs_mount_count); +- if (error) +- return ERR_PTR(error); ++ struct tracefs_inode *ti; + +- if (unlikely(IS_DEADDIR(parent->d_inode))) +- dentry = ERR_PTR(-ENOENT); +- else +- dentry = lookup_one_len(name, parent, strlen(name)); ++ /* If parent is NULL then use root inode */ ++ if (!parent) ++ return d_inode(inode->i_sb->s_root); + +- if (!IS_ERR(dentry) && dentry->d_inode) { +- dput(dentry); +- dentry = ERR_PTR(-EEXIST); ++ /* Find the inode that is flagged as an instance or the root inode */ ++ while (!IS_ROOT(parent)) { ++ ti = get_tracefs(d_inode(parent)); ++ if (ti->flags & TRACEFS_INSTANCE_INODE) ++ break; ++ parent = parent->d_parent; + } + +- if (IS_ERR(dentry)) +- simple_release_fs(&tracefs_mount, &tracefs_mount_count); +- +- return dentry; +-} +- +-/** +- * eventfs_failed_creating - clean up a failed eventfs dentry creation +- * @dentry: The dentry to clean up +- * +- * If after calling eventfs_start_creating(), a failure is detected, the +- * resources created by eventfs_start_creating() needs to be cleaned up. In +- * that case, this function should be called to perform that clean up. +- */ +-struct dentry *eventfs_failed_creating(struct dentry *dentry) +-{ +- dput(dentry); +- simple_release_fs(&tracefs_mount, &tracefs_mount_count); +- return NULL; +-} +- +-/** +- * eventfs_end_creating - Finish the process of creating a eventfs dentry +- * @dentry: The dentry that has successfully been created. +- * +- * This function is currently just a place holder to match +- * eventfs_start_creating(). In case any synchronization needs to be added, +- * this function will be used to implement that without having to modify +- * the callers of eventfs_start_creating(). +- */ +-struct dentry *eventfs_end_creating(struct dentry *dentry) +-{ +- return dentry; ++ return d_inode(parent); + } + + /** +@@ -593,6 +554,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops) + { ++ struct tracefs_inode *ti; + struct dentry *dentry; + struct inode *inode; + +@@ -611,7 +573,11 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, + if (unlikely(!inode)) + return tracefs_failed_creating(dentry); + ++ ti = get_tracefs(inode); ++ ti->private = instance_inode(parent, inode); ++ + inode->i_mode = mode; ++ inode->i_op = &tracefs_file_inode_operations; + inode->i_fop = fops ? fops : &tracefs_file_operations; + inode->i_private = data; + inode->i_uid = d_inode(dentry->d_parent)->i_uid; +@@ -624,6 +590,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, + static struct dentry *__create_dir(const char *name, struct dentry *parent, + const struct inode_operations *ops) + { ++ struct tracefs_inode *ti; + struct dentry *dentry = tracefs_start_creating(name, parent); + struct inode *inode; + +@@ -641,6 +608,9 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent, + inode->i_uid = d_inode(dentry->d_parent)->i_uid; + inode->i_gid = d_inode(dentry->d_parent)->i_gid; + ++ ti = get_tracefs(inode); ++ ti->private = instance_inode(parent, inode); ++ + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inc_nlink(inode); + d_instantiate(dentry, inode); +@@ -671,7 +641,7 @@ struct dentry *tracefs_create_dir(const char *name, struct dentry *parent) + if (security_locked_down(LOCKDOWN_TRACEFS)) + return NULL; + +- return __create_dir(name, parent, &simple_dir_inode_operations); ++ return __create_dir(name, parent, &tracefs_dir_inode_operations); + } + + /** +@@ -702,7 +672,7 @@ __init struct dentry *tracefs_create_instance_dir(const char *name, + if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir)) + return NULL; + +- dentry = __create_dir(name, parent, &tracefs_dir_inode_operations); ++ dentry = __create_dir(name, parent, &tracefs_instance_dir_inode_operations); + if (!dentry) + return NULL; + +@@ -747,7 +717,11 @@ static void init_once(void *foo) + { + struct tracefs_inode *ti = (struct tracefs_inode *) foo; + ++ /* inode_init_once() calls memset() on the vfs_inode portion */ + inode_init_once(&ti->vfs_inode); ++ ++ /* Zero out the rest */ ++ memset_after(ti, 0, vfs_inode); + } + + static int __init tracefs_init(void) +diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h +index 4f2e49e2197b1..beb3dcd0e4342 100644 +--- a/fs/tracefs/internal.h ++++ b/fs/tracefs/internal.h +@@ -5,12 +5,64 @@ + enum { + TRACEFS_EVENT_INODE = BIT(1), + TRACEFS_EVENT_TOP_INODE = BIT(2), ++ TRACEFS_GID_PERM_SET = BIT(3), ++ TRACEFS_UID_PERM_SET = BIT(4), ++ TRACEFS_INSTANCE_INODE = BIT(5), + }; + + struct tracefs_inode { ++ struct inode vfs_inode; ++ /* The below gets initialized with memset_after(ti, 0, vfs_inode) */ + unsigned long flags; + void *private; +- struct inode vfs_inode; ++}; ++ ++/* ++ * struct eventfs_attr - cache the mode and ownership of a eventfs entry ++ * @mode: saved mode plus flags of what is saved ++ * @uid: saved uid if changed ++ * @gid: saved gid if changed ++ */ ++struct eventfs_attr { ++ int mode; ++ kuid_t uid; ++ kgid_t gid; ++}; ++ ++/* ++ * struct eventfs_inode - hold the properties of the eventfs directories. ++ * @list: link list into the parent directory ++ * @rcu: Union with @list for freeing ++ * @children: link list into the child eventfs_inode ++ * @entries: the array of entries representing the files in the directory ++ * @name: the name of the directory to create ++ * @events_dir: the dentry of the events directory ++ * @entry_attrs: Saved mode and ownership of the @d_children ++ * @data: The private data to pass to the callbacks ++ * @attr: Saved mode and ownership of eventfs_inode itself ++ * @is_freed: Flag set if the eventfs is on its way to be freed ++ * Note if is_freed is set, then dentry is corrupted. ++ * @is_events: Flag set for only the top level "events" directory ++ * @nr_entries: The number of items in @entries ++ * @ino: The saved inode number ++ */ ++struct eventfs_inode { ++ union { ++ struct list_head list; ++ struct rcu_head rcu; ++ }; ++ struct list_head children; ++ const struct eventfs_entry *entries; ++ const char *name; ++ struct dentry *events_dir; ++ struct eventfs_attr *entry_attrs; ++ void *data; ++ struct eventfs_attr attr; ++ struct kref kref; ++ unsigned int is_freed:1; ++ unsigned int is_events:1; ++ unsigned int nr_entries:30; ++ unsigned int ino; + }; + + static inline struct tracefs_inode *get_tracefs(const struct inode *inode) +@@ -22,9 +74,7 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent); + struct dentry *tracefs_end_creating(struct dentry *dentry); + struct dentry *tracefs_failed_creating(struct dentry *dentry); + struct inode *tracefs_get_inode(struct super_block *sb); +-struct dentry *eventfs_start_creating(const char *name, struct dentry *parent); +-struct dentry *eventfs_failed_creating(struct dentry *dentry); +-struct dentry *eventfs_end_creating(struct dentry *dentry); +-void eventfs_set_ef_status_free(struct tracefs_inode *ti, struct dentry *dentry); ++ ++void eventfs_d_release(struct dentry *dentry); + + #endif /* _TRACEFS_INTERNAL_H */ +diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c +index b2c9b35df8f76..897b12ec61e29 100644 +--- a/fs/zonefs/file.c ++++ b/fs/zonefs/file.c +@@ -348,7 +348,12 @@ static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size, + struct zonefs_inode_info *zi = ZONEFS_I(inode); + + if (error) { +- zonefs_io_error(inode, true); ++ /* ++ * For Sync IOs, error recovery is called from ++ * zonefs_file_dio_write(). ++ */ ++ if (!is_sync_kiocb(iocb)) ++ zonefs_io_error(inode, true); + return error; + } + +@@ -491,6 +496,14 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from) + ret = -EINVAL; + goto inode_unlock; + } ++ /* ++ * Advance the zone write pointer offset. This assumes that the ++ * IO will succeed, which is OK to do because we do not allow ++ * partial writes (IOMAP_DIO_PARTIAL is not set) and if the IO ++ * fails, the error path will correct the write pointer offset. ++ */ ++ z->z_wpoffset += count; ++ zonefs_inode_account_active(inode); + mutex_unlock(&zi->i_truncate_mutex); + } + +@@ -504,20 +517,19 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from) + if (ret == -ENOTBLK) + ret = -EBUSY; + +- if (zonefs_zone_is_seq(z) && +- (ret > 0 || ret == -EIOCBQUEUED)) { +- if (ret > 0) +- count = ret; +- +- /* +- * Update the zone write pointer offset assuming the write +- * operation succeeded. If it did not, the error recovery path +- * will correct it. Also do active seq file accounting. +- */ +- mutex_lock(&zi->i_truncate_mutex); +- z->z_wpoffset += count; +- zonefs_inode_account_active(inode); +- mutex_unlock(&zi->i_truncate_mutex); ++ /* ++ * For a failed IO or partial completion, trigger error recovery ++ * to update the zone write pointer offset to a correct value. ++ * For asynchronous IOs, zonefs_file_write_dio_end_io() may already ++ * have executed error recovery if the IO already completed when we ++ * reach here. However, we cannot know that and execute error recovery ++ * again (that will not change anything). ++ */ ++ if (zonefs_zone_is_seq(z)) { ++ if (ret > 0 && ret != count) ++ ret = -EIO; ++ if (ret < 0 && ret != -EIOCBQUEUED) ++ zonefs_io_error(inode, true); + } + + inode_unlock: +diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c +index 9d1a9808fbbba..cc364669d723d 100644 +--- a/fs/zonefs/super.c ++++ b/fs/zonefs/super.c +@@ -246,16 +246,18 @@ static void zonefs_inode_update_mode(struct inode *inode) + z->z_mode = inode->i_mode; + } + +-struct zonefs_ioerr_data { +- struct inode *inode; +- bool write; +-}; +- + static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, + void *data) + { +- struct zonefs_ioerr_data *err = data; +- struct inode *inode = err->inode; ++ struct blk_zone *z = data; ++ ++ *z = *zone; ++ return 0; ++} ++ ++static void zonefs_handle_io_error(struct inode *inode, struct blk_zone *zone, ++ bool write) ++{ + struct zonefs_zone *z = zonefs_inode_zone(inode); + struct super_block *sb = inode->i_sb; + struct zonefs_sb_info *sbi = ZONEFS_SB(sb); +@@ -270,8 +272,8 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, + data_size = zonefs_check_zone_condition(sb, z, zone); + isize = i_size_read(inode); + if (!(z->z_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)) && +- !err->write && isize == data_size) +- return 0; ++ !write && isize == data_size) ++ return; + + /* + * At this point, we detected either a bad zone or an inconsistency +@@ -292,7 +294,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, + * In all cases, warn about inode size inconsistency and handle the + * IO error according to the zone condition and to the mount options. + */ +- if (zonefs_zone_is_seq(z) && isize != data_size) ++ if (isize != data_size) + zonefs_warn(sb, + "inode %lu: invalid size %lld (should be %lld)\n", + inode->i_ino, isize, data_size); +@@ -352,8 +354,6 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, + zonefs_i_size_write(inode, data_size); + z->z_wpoffset = data_size; + zonefs_inode_account_active(inode); +- +- return 0; + } + + /* +@@ -367,23 +367,25 @@ void __zonefs_io_error(struct inode *inode, bool write) + { + struct zonefs_zone *z = zonefs_inode_zone(inode); + struct super_block *sb = inode->i_sb; +- struct zonefs_sb_info *sbi = ZONEFS_SB(sb); + unsigned int noio_flag; +- unsigned int nr_zones = 1; +- struct zonefs_ioerr_data err = { +- .inode = inode, +- .write = write, +- }; ++ struct blk_zone zone; + int ret; + + /* +- * The only files that have more than one zone are conventional zone +- * files with aggregated conventional zones, for which the inode zone +- * size is always larger than the device zone size. ++ * Conventional zone have no write pointer and cannot become read-only ++ * or offline. So simply fake a report for a single or aggregated zone ++ * and let zonefs_handle_io_error() correct the zone inode information ++ * according to the mount options. + */ +- if (z->z_size > bdev_zone_sectors(sb->s_bdev)) +- nr_zones = z->z_size >> +- (sbi->s_zone_sectors_shift + SECTOR_SHIFT); ++ if (!zonefs_zone_is_seq(z)) { ++ zone.start = z->z_sector; ++ zone.len = z->z_size >> SECTOR_SHIFT; ++ zone.wp = zone.start + zone.len; ++ zone.type = BLK_ZONE_TYPE_CONVENTIONAL; ++ zone.cond = BLK_ZONE_COND_NOT_WP; ++ zone.capacity = zone.len; ++ goto handle_io_error; ++ } + + /* + * Memory allocations in blkdev_report_zones() can trigger a memory +@@ -394,12 +396,20 @@ void __zonefs_io_error(struct inode *inode, bool write) + * the GFP_NOIO context avoids both problems. + */ + noio_flag = memalloc_noio_save(); +- ret = blkdev_report_zones(sb->s_bdev, z->z_sector, nr_zones, +- zonefs_io_error_cb, &err); +- if (ret != nr_zones) ++ ret = blkdev_report_zones(sb->s_bdev, z->z_sector, 1, ++ zonefs_io_error_cb, &zone); ++ memalloc_noio_restore(noio_flag); ++ ++ if (ret != 1) { + zonefs_err(sb, "Get inode %lu zone information failed %d\n", + inode->i_ino, ret); +- memalloc_noio_restore(noio_flag); ++ zonefs_warn(sb, "remounting filesystem read-only\n"); ++ sb->s_flags |= SB_RDONLY; ++ return; ++ } ++ ++handle_io_error: ++ zonefs_handle_io_error(inode, &zone, write); + } + + static struct kmem_cache *zonefs_inode_cachep; +diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h +index 67d8dd2f1bdec..bae0fe4d499bc 100644 +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -356,7 +356,6 @@ + *(.ref.data) \ + *(.data..shared_aligned) /* percpu related */ \ + MEM_KEEP(init.data*) \ +- MEM_KEEP(exit.data*) \ + *(.data.unlikely) \ + __start_once = .; \ + *(.data.once) \ +@@ -521,7 +520,6 @@ + __init_rodata : AT(ADDR(__init_rodata) - LOAD_OFFSET) { \ + *(.ref.rodata) \ + MEM_KEEP(init.rodata) \ +- MEM_KEEP(exit.rodata) \ + } \ + \ + /* Built-in module parameters. */ \ +@@ -574,7 +572,6 @@ + *(.ref.text) \ + *(.text.asan.* .text.tsan.*) \ + MEM_KEEP(init.text*) \ +- MEM_KEEP(exit.text*) \ + + + /* sched.text is aling to function alignment to secure we have same +@@ -714,13 +711,10 @@ + *(.exit.data .exit.data.*) \ + *(.fini_array .fini_array.*) \ + *(.dtors .dtors.*) \ +- MEM_DISCARD(exit.data*) \ +- MEM_DISCARD(exit.rodata*) + + #define EXIT_TEXT \ + *(.exit.text) \ + *(.text.exit) \ +- MEM_DISCARD(exit.text) + + #define EXIT_CALL \ + *(.exitcall.exit) +diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h +index ae12696ec492c..2ad261082bba5 100644 +--- a/include/linux/backing-dev-defs.h ++++ b/include/linux/backing-dev-defs.h +@@ -141,8 +141,6 @@ struct bdi_writeback { + struct delayed_work dwork; /* work item used for writeback */ + struct delayed_work bw_dwork; /* work item used for bandwidth estimate */ + +- unsigned long dirty_sleep; /* last wait */ +- + struct list_head bdi_node; /* anchored at bdi->wb_list */ + + #ifdef CONFIG_CGROUP_WRITEBACK +@@ -179,6 +177,11 @@ struct backing_dev_info { + * any dirty wbs, which is depended upon by bdi_has_dirty(). + */ + atomic_long_t tot_write_bandwidth; ++ /* ++ * Jiffies when last process was dirty throttled on this bdi. Used by ++ * blk-wbt. ++ */ ++ unsigned long last_bdp_sleep; + + struct bdi_writeback wb; /* the root writeback info for this bdi */ + struct list_head wb_list; /* list of all wbs */ +diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h +index 7af9e34ec261b..8c9a095c17571 100644 +--- a/include/linux/compiler-gcc.h ++++ b/include/linux/compiler-gcc.h +@@ -66,6 +66,26 @@ + __builtin_unreachable(); \ + } while (0) + ++/* ++ * GCC 'asm goto' with outputs miscompiles certain code sequences: ++ * ++ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921 ++ * ++ * Work around it via the same compiler barrier quirk that we used ++ * to use for the old 'asm goto' workaround. ++ * ++ * Also, always mark such 'asm goto' statements as volatile: all ++ * asm goto statements are supposed to be volatile as per the ++ * documentation, but some versions of gcc didn't actually do ++ * that for asms with outputs: ++ * ++ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98619 ++ */ ++#ifdef CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND ++#define asm_goto_output(x...) \ ++ do { asm volatile goto(x); asm (""); } while (0) ++#endif ++ + #if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP) + #define __HAVE_BUILTIN_BSWAP32__ + #define __HAVE_BUILTIN_BSWAP64__ +diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h +index c523c6683789d..b2f9e2c409cf2 100644 +--- a/include/linux/compiler_types.h ++++ b/include/linux/compiler_types.h +@@ -352,8 +352,15 @@ struct ftrace_likely_data { + # define __realloc_size(x, ...) + #endif + +-#ifndef asm_volatile_goto +-#define asm_volatile_goto(x...) asm goto(x) ++/* ++ * Some versions of gcc do not mark 'asm goto' volatile: ++ * ++ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103979 ++ * ++ * We do it here by hand, because it doesn't hurt. ++ */ ++#ifndef asm_goto_output ++#define asm_goto_output(x...) asm volatile goto(x) + #endif + + #ifdef CONFIG_CC_HAS_ASM_INLINE +diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h +index 7852f6c9a714c..719cf9cc6e1ac 100644 +--- a/include/linux/iio/adc/ad_sigma_delta.h ++++ b/include/linux/iio/adc/ad_sigma_delta.h +@@ -8,6 +8,8 @@ + #ifndef __AD_SIGMA_DELTA_H__ + #define __AD_SIGMA_DELTA_H__ + ++#include <linux/iio/iio.h> ++ + enum ad_sigma_delta_mode { + AD_SD_MODE_CONTINUOUS = 0, + AD_SD_MODE_SINGLE = 1, +@@ -99,7 +101,7 @@ struct ad_sigma_delta { + * 'rx_buf' is up to 32 bits per sample + 64 bit timestamp, + * rounded to 16 bytes to take into account padding. + */ +- uint8_t tx_buf[4] ____cacheline_aligned; ++ uint8_t tx_buf[4] __aligned(IIO_DMA_MINALIGN); + uint8_t rx_buf[16] __aligned(8); + }; + +diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h +index 607c3a89a6471..f9ae5cdd884f5 100644 +--- a/include/linux/iio/common/st_sensors.h ++++ b/include/linux/iio/common/st_sensors.h +@@ -258,9 +258,9 @@ struct st_sensor_data { + bool hw_irq_trigger; + s64 hw_timestamp; + +- char buffer_data[ST_SENSORS_MAX_BUFFER_SIZE] ____cacheline_aligned; +- + struct mutex odr_lock; ++ ++ char buffer_data[ST_SENSORS_MAX_BUFFER_SIZE] __aligned(IIO_DMA_MINALIGN); + }; + + #ifdef CONFIG_IIO_BUFFER +diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h +index dc9ea299e0885..8898966bc0f08 100644 +--- a/include/linux/iio/imu/adis.h ++++ b/include/linux/iio/imu/adis.h +@@ -11,6 +11,7 @@ + + #include <linux/spi/spi.h> + #include <linux/interrupt.h> ++#include <linux/iio/iio.h> + #include <linux/iio/types.h> + + #define ADIS_WRITE_REG(reg) ((0x80 | (reg))) +@@ -131,7 +132,7 @@ struct adis { + unsigned long irq_flag; + void *buffer; + +- u8 tx[10] ____cacheline_aligned; ++ u8 tx[10] __aligned(IIO_DMA_MINALIGN); + u8 rx[4]; + }; + +diff --git a/include/linux/init.h b/include/linux/init.h +index 266c3e1640d47..01b52c9c75268 100644 +--- a/include/linux/init.h ++++ b/include/linux/init.h +@@ -89,9 +89,6 @@ + __latent_entropy + #define __meminitdata __section(".meminit.data") + #define __meminitconst __section(".meminit.rodata") +-#define __memexit __section(".memexit.text") __exitused __cold notrace +-#define __memexitdata __section(".memexit.data") +-#define __memexitconst __section(".memexit.rodata") + + /* For assembly routines */ + #define __HEAD .section ".head.text","ax" +diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h +index 74c60f9446f84..489362b0cd857 100644 +--- a/include/linux/lsm_hook_defs.h ++++ b/include/linux/lsm_hook_defs.h +@@ -311,9 +311,9 @@ LSM_HOOK(int, 0, socket_getsockopt, struct socket *sock, int level, int optname) + LSM_HOOK(int, 0, socket_setsockopt, struct socket *sock, int level, int optname) + LSM_HOOK(int, 0, socket_shutdown, struct socket *sock, int how) + LSM_HOOK(int, 0, socket_sock_rcv_skb, struct sock *sk, struct sk_buff *skb) +-LSM_HOOK(int, 0, socket_getpeersec_stream, struct socket *sock, ++LSM_HOOK(int, -ENOPROTOOPT, socket_getpeersec_stream, struct socket *sock, + sockptr_t optval, sockptr_t optlen, unsigned int len) +-LSM_HOOK(int, 0, socket_getpeersec_dgram, struct socket *sock, ++LSM_HOOK(int, -ENOPROTOOPT, socket_getpeersec_dgram, struct socket *sock, + struct sk_buff *skb, u32 *secid) + LSM_HOOK(int, 0, sk_alloc_security, struct sock *sk, int family, gfp_t priority) + LSM_HOOK(void, LSM_RET_VOID, sk_free_security, struct sock *sk) +diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h +index e8c350a3ade15..e9f4f845d760a 100644 +--- a/include/linux/netfilter/ipset/ip_set.h ++++ b/include/linux/netfilter/ipset/ip_set.h +@@ -186,6 +186,8 @@ struct ip_set_type_variant { + /* Return true if "b" set is the same as "a" + * according to the create set parameters */ + bool (*same_set)(const struct ip_set *a, const struct ip_set *b); ++ /* Cancel ongoing garbage collectors before destroying the set*/ ++ void (*cancel_gc)(struct ip_set *set); + /* Region-locking is used */ + bool region_lock; + }; +@@ -242,6 +244,8 @@ extern void ip_set_type_unregister(struct ip_set_type *set_type); + + /* A generic IP set */ + struct ip_set { ++ /* For call_cru in destroy */ ++ struct rcu_head rcu; + /* The name of the set */ + char name[IPSET_MAXNAMELEN]; + /* Lock protecting the set data */ +diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h +index eaaef3ffec221..90507d4afcd6d 100644 +--- a/include/linux/ptrace.h ++++ b/include/linux/ptrace.h +@@ -393,6 +393,10 @@ static inline void user_single_step_report(struct pt_regs *regs) + #define current_user_stack_pointer() user_stack_pointer(current_pt_regs()) + #endif + ++#ifndef exception_ip ++#define exception_ip(x) instruction_pointer(x) ++#endif ++ + extern int task_current_syscall(struct task_struct *target, struct syscall_info *info); + + extern void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact); +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index bbbafc0feb5b0..27a26092493ad 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -748,8 +748,17 @@ struct uart_driver { + + void uart_write_wakeup(struct uart_port *port); + +-#define __uart_port_tx(uport, ch, tx_ready, put_char, tx_done, for_test, \ +- for_post) \ ++/** ++ * enum UART_TX_FLAGS -- flags for uart_port_tx_flags() ++ * ++ * @UART_TX_NOSTOP: don't call port->ops->stop_tx() on empty buffer ++ */ ++enum UART_TX_FLAGS { ++ UART_TX_NOSTOP = BIT(0), ++}; ++ ++#define __uart_port_tx(uport, ch, flags, tx_ready, put_char, tx_done, \ ++ for_test, for_post) \ + ({ \ + struct uart_port *__port = (uport); \ + struct circ_buf *xmit = &__port->state->xmit; \ +@@ -777,7 +786,7 @@ void uart_write_wakeup(struct uart_port *port); + if (pending < WAKEUP_CHARS) { \ + uart_write_wakeup(__port); \ + \ +- if (pending == 0) \ ++ if (!((flags) & UART_TX_NOSTOP) && pending == 0) \ + __port->ops->stop_tx(__port); \ + } \ + \ +@@ -812,7 +821,7 @@ void uart_write_wakeup(struct uart_port *port); + */ + #define uart_port_tx_limited(port, ch, count, tx_ready, put_char, tx_done) ({ \ + unsigned int __count = (count); \ +- __uart_port_tx(port, ch, tx_ready, put_char, tx_done, __count, \ ++ __uart_port_tx(port, ch, 0, tx_ready, put_char, tx_done, __count, \ + __count--); \ + }) + +@@ -826,8 +835,21 @@ void uart_write_wakeup(struct uart_port *port); + * See uart_port_tx_limited() for more details. + */ + #define uart_port_tx(port, ch, tx_ready, put_char) \ +- __uart_port_tx(port, ch, tx_ready, put_char, ({}), true, ({})) ++ __uart_port_tx(port, ch, 0, tx_ready, put_char, ({}), true, ({})) ++ + ++/** ++ * uart_port_tx_flags -- transmit helper for uart_port with flags ++ * @port: uart port ++ * @ch: variable to store a character to be written to the HW ++ * @flags: %UART_TX_NOSTOP or similar ++ * @tx_ready: can HW accept more data function ++ * @put_char: function to write a character ++ * ++ * See uart_port_tx_limited() for more details. ++ */ ++#define uart_port_tx_flags(port, ch, flags, tx_ready, put_char) \ ++ __uart_port_tx(port, ch, flags, tx_ready, put_char, ({}), true, ({})) + /* + * Baud rate helpers. + */ +diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h +index cf9f0c61796e1..696f8dc4aa53c 100644 +--- a/include/linux/trace_events.h ++++ b/include/linux/trace_events.h +@@ -652,7 +652,7 @@ struct trace_event_file { + struct list_head list; + struct trace_event_call *event_call; + struct event_filter __rcu *filter; +- struct eventfs_file *ef; ++ struct eventfs_inode *ei; + struct trace_array *tr; + struct trace_subsystem_dir *system; + struct list_head triggers; +diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h +index 009072792fa36..7a5fe17b6bf9c 100644 +--- a/include/linux/tracefs.h ++++ b/include/linux/tracefs.h +@@ -23,26 +23,69 @@ struct file_operations; + + struct eventfs_file; + +-struct dentry *eventfs_create_events_dir(const char *name, +- struct dentry *parent); +- +-struct eventfs_file *eventfs_add_subsystem_dir(const char *name, +- struct dentry *parent); ++/** ++ * eventfs_callback - A callback function to create dynamic files in eventfs ++ * @name: The name of the file that is to be created ++ * @mode: return the file mode for the file (RW access, etc) ++ * @data: data to pass to the created file ops ++ * @fops: the file operations of the created file ++ * ++ * The evetnfs files are dynamically created. The struct eventfs_entry array ++ * is passed to eventfs_create_dir() or eventfs_create_events_dir() that will ++ * be used to create the files within those directories. When a lookup ++ * or access to a file within the directory is made, the struct eventfs_entry ++ * array is used to find a callback() with the matching name that is being ++ * referenced (for lookups, the entire array is iterated and each callback ++ * will be called). ++ * ++ * The callback will be called with @name for the name of the file to create. ++ * The callback can return less than 1 to indicate that no file should be ++ * created. ++ * ++ * If a file is to be created, then @mode should be populated with the file ++ * mode (permissions) for which the file is created for. This would be ++ * used to set the created inode i_mode field. ++ * ++ * The @data should be set to the data passed to the other file operations ++ * (read, write, etc). Note, @data will also point to the data passed in ++ * to eventfs_create_dir() or eventfs_create_events_dir(), but the callback ++ * can replace the data if it chooses to. Otherwise, the original data ++ * will be used for the file operation functions. ++ * ++ * The @fops should be set to the file operations that will be used to create ++ * the inode. ++ * ++ * NB. This callback is called while holding internal locks of the eventfs ++ * system. The callback must not call any code that might also call into ++ * the tracefs or eventfs system or it will risk creating a deadlock. ++ */ ++typedef int (*eventfs_callback)(const char *name, umode_t *mode, void **data, ++ const struct file_operations **fops); + +-struct eventfs_file *eventfs_add_dir(const char *name, +- struct eventfs_file *ef_parent); ++/** ++ * struct eventfs_entry - dynamically created eventfs file call back handler ++ * @name: Then name of the dynamic file in an eventfs directory ++ * @callback: The callback to get the fops of the file when it is created ++ * ++ * See evenfs_callback() typedef for how to set up @callback. ++ */ ++struct eventfs_entry { ++ const char *name; ++ eventfs_callback callback; ++}; + +-int eventfs_add_file(const char *name, umode_t mode, +- struct eventfs_file *ef_parent, void *data, +- const struct file_operations *fops); ++struct eventfs_inode; + +-int eventfs_add_events_file(const char *name, umode_t mode, +- struct dentry *parent, void *data, +- const struct file_operations *fops); ++struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry *parent, ++ const struct eventfs_entry *entries, ++ int size, void *data); + +-void eventfs_remove(struct eventfs_file *ef); ++struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode *parent, ++ const struct eventfs_entry *entries, ++ int size, void *data); + +-void eventfs_remove_events_dir(struct dentry *dentry); ++void eventfs_remove_events_dir(struct eventfs_inode *ei); ++void eventfs_remove_dir(struct eventfs_inode *ei); + + struct dentry *tracefs_create_file(const char *name, umode_t mode, + struct dentry *parent, void *data, +diff --git a/include/net/tls.h b/include/net/tls.h +index a2b44578dcb75..5fdd5dd251df2 100644 +--- a/include/net/tls.h ++++ b/include/net/tls.h +@@ -96,9 +96,6 @@ struct tls_sw_context_tx { + struct tls_rec *open_rec; + struct list_head tx_list; + atomic_t encrypt_pending; +- /* protect crypto_wait with encrypt_pending */ +- spinlock_t encrypt_compl_lock; +- int async_notify; + u8 async_capable:1; + + #define BIT_TX_SCHEDULED 0 +@@ -135,8 +132,6 @@ struct tls_sw_context_rx { + struct tls_strparser strp; + + atomic_t decrypt_pending; +- /* protect crypto_wait with decrypt_pending*/ +- spinlock_t decrypt_compl_lock; + struct sk_buff_head async_hold; + struct wait_queue_head wq; + }; +diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h +index a6c808b223183..475294c853aa4 100644 +--- a/include/sound/tas2781.h ++++ b/include/sound/tas2781.h +@@ -135,6 +135,7 @@ struct tasdevice_priv { + + void tas2781_reset(struct tasdevice_priv *tas_dev); + int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, ++ struct module *module, + void (*cont)(const struct firmware *fw, void *context)); + struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c); + int tasdevice_init(struct tasdevice_priv *tas_priv); +diff --git a/init/Kconfig b/init/Kconfig +index 6d35728b94b2b..18fece8fe0857 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -89,6 +89,15 @@ config CC_HAS_ASM_GOTO_TIED_OUTPUT + # Detect buggy gcc and clang, fixed in gcc-11 clang-14. + def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null) + ++config GCC_ASM_GOTO_OUTPUT_WORKAROUND ++ bool ++ depends on CC_IS_GCC && CC_HAS_ASM_GOTO_OUTPUT ++ # Fixed in GCC 14, 13.3, 12.4 and 11.5 ++ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921 ++ default y if GCC_VERSION < 110500 ++ default y if GCC_VERSION >= 120000 && GCC_VERSION < 120400 ++ default y if GCC_VERSION >= 130000 && GCC_VERSION < 130300 ++ + config TOOLS_SUPPORT_RELR + def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh) + +diff --git a/io_uring/net.c b/io_uring/net.c +index 43bc9a5f96f9d..161622029147c 100644 +--- a/io_uring/net.c ++++ b/io_uring/net.c +@@ -1372,7 +1372,7 @@ int io_accept(struct io_kiocb *req, unsigned int issue_flags) + * has already been done + */ + if (issue_flags & IO_URING_F_MULTISHOT) +- ret = IOU_ISSUE_SKIP_COMPLETE; ++ return IOU_ISSUE_SKIP_COMPLETE; + return ret; + } + if (ret == -ERESTARTSYS) +@@ -1397,7 +1397,8 @@ int io_accept(struct io_kiocb *req, unsigned int issue_flags) + ret, IORING_CQE_F_MORE)) + goto retry; + +- return -ECANCELED; ++ io_req_set_res(req, ret, 0); ++ return IOU_STOP_MULTISHOT; + } + + int io_socket_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) +diff --git a/kernel/sched/membarrier.c b/kernel/sched/membarrier.c +index 2ad881d07752c..4e715b9b278e7 100644 +--- a/kernel/sched/membarrier.c ++++ b/kernel/sched/membarrier.c +@@ -162,6 +162,9 @@ + | MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK \ + | MEMBARRIER_CMD_GET_REGISTRATIONS) + ++static DEFINE_MUTEX(membarrier_ipi_mutex); ++#define SERIALIZE_IPI() guard(mutex)(&membarrier_ipi_mutex) ++ + static void ipi_mb(void *info) + { + smp_mb(); /* IPIs should be serializing but paranoid. */ +@@ -259,6 +262,7 @@ static int membarrier_global_expedited(void) + if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL)) + return -ENOMEM; + ++ SERIALIZE_IPI(); + cpus_read_lock(); + rcu_read_lock(); + for_each_online_cpu(cpu) { +@@ -347,6 +351,7 @@ static int membarrier_private_expedited(int flags, int cpu_id) + if (cpu_id < 0 && !zalloc_cpumask_var(&tmpmask, GFP_KERNEL)) + return -ENOMEM; + ++ SERIALIZE_IPI(); + cpus_read_lock(); + + if (cpu_id >= 0) { +@@ -460,6 +465,7 @@ static int sync_runqueues_membarrier_state(struct mm_struct *mm) + * between threads which are users of @mm has its membarrier state + * updated. + */ ++ SERIALIZE_IPI(); + cpus_read_lock(); + rcu_read_lock(); + for_each_online_cpu(cpu) { +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index b01ae7d360218..83ba342aef31f 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -5325,7 +5325,17 @@ static LIST_HEAD(ftrace_direct_funcs); + + static int register_ftrace_function_nolock(struct ftrace_ops *ops); + ++/* ++ * If there are multiple ftrace_ops, use SAVE_REGS by default, so that direct ++ * call will be jumped from ftrace_regs_caller. Only if the architecture does ++ * not support ftrace_regs_caller but direct_call, use SAVE_ARGS so that it ++ * jumps from ftrace_caller for multiple ftrace_ops. ++ */ ++#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS + #define MULTI_FLAGS (FTRACE_OPS_FL_DIRECT | FTRACE_OPS_FL_SAVE_ARGS) ++#else ++#define MULTI_FLAGS (FTRACE_OPS_FL_DIRECT | FTRACE_OPS_FL_SAVE_REGS) ++#endif + + static int check_direct_multi(struct ftrace_ops *ops) + { +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index f232cf56fa057..1ac6637895a44 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -1091,7 +1091,7 @@ __poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu, + full = 0; + } else { + if (!cpumask_test_cpu(cpu, buffer->cpumask)) +- return -EINVAL; ++ return EPOLLERR; + + cpu_buffer = buffer->buffers[cpu]; + work = &cpu_buffer->irq_work; +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index fc00356a5a0a1..82e28777cacf5 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -39,6 +39,7 @@ + #include <linux/ctype.h> + #include <linux/init.h> + #include <linux/panic_notifier.h> ++#include <linux/kmemleak.h> + #include <linux/poll.h> + #include <linux/nmi.h> + #include <linux/fs.h> +@@ -2311,7 +2312,7 @@ struct saved_cmdlines_buffer { + unsigned *map_cmdline_to_pid; + unsigned cmdline_num; + int cmdline_idx; +- char *saved_cmdlines; ++ char saved_cmdlines[]; + }; + static struct saved_cmdlines_buffer *savedcmd; + +@@ -2325,47 +2326,60 @@ static inline void set_cmdline(int idx, const char *cmdline) + strncpy(get_saved_cmdlines(idx), cmdline, TASK_COMM_LEN); + } + +-static int allocate_cmdlines_buffer(unsigned int val, +- struct saved_cmdlines_buffer *s) ++static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) ++{ ++ int order = get_order(sizeof(*s) + s->cmdline_num * TASK_COMM_LEN); ++ ++ kfree(s->map_cmdline_to_pid); ++ kmemleak_free(s); ++ free_pages((unsigned long)s, order); ++} ++ ++static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val) + { ++ struct saved_cmdlines_buffer *s; ++ struct page *page; ++ int orig_size, size; ++ int order; ++ ++ /* Figure out how much is needed to hold the given number of cmdlines */ ++ orig_size = sizeof(*s) + val * TASK_COMM_LEN; ++ order = get_order(orig_size); ++ size = 1 << (order + PAGE_SHIFT); ++ page = alloc_pages(GFP_KERNEL, order); ++ if (!page) ++ return NULL; ++ ++ s = page_address(page); ++ kmemleak_alloc(s, size, 1, GFP_KERNEL); ++ memset(s, 0, sizeof(*s)); ++ ++ /* Round up to actual allocation */ ++ val = (size - sizeof(*s)) / TASK_COMM_LEN; ++ s->cmdline_num = val; ++ + s->map_cmdline_to_pid = kmalloc_array(val, + sizeof(*s->map_cmdline_to_pid), + GFP_KERNEL); +- if (!s->map_cmdline_to_pid) +- return -ENOMEM; +- +- s->saved_cmdlines = kmalloc_array(TASK_COMM_LEN, val, GFP_KERNEL); +- if (!s->saved_cmdlines) { +- kfree(s->map_cmdline_to_pid); +- return -ENOMEM; ++ if (!s->map_cmdline_to_pid) { ++ free_saved_cmdlines_buffer(s); ++ return NULL; + } + + s->cmdline_idx = 0; +- s->cmdline_num = val; + memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP, + sizeof(s->map_pid_to_cmdline)); + memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP, + val * sizeof(*s->map_cmdline_to_pid)); + +- return 0; ++ return s; + } + + static int trace_create_savedcmd(void) + { +- int ret; ++ savedcmd = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT); + +- savedcmd = kmalloc(sizeof(*savedcmd), GFP_KERNEL); +- if (!savedcmd) +- return -ENOMEM; +- +- ret = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT, savedcmd); +- if (ret < 0) { +- kfree(savedcmd); +- savedcmd = NULL; +- return -ENOMEM; +- } +- +- return 0; ++ return savedcmd ? 0 : -ENOMEM; + } + + int is_tracing_stopped(void) +@@ -6056,26 +6070,14 @@ tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf, + return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); + } + +-static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) +-{ +- kfree(s->saved_cmdlines); +- kfree(s->map_cmdline_to_pid); +- kfree(s); +-} +- + static int tracing_resize_saved_cmdlines(unsigned int val) + { + struct saved_cmdlines_buffer *s, *savedcmd_temp; + +- s = kmalloc(sizeof(*s), GFP_KERNEL); ++ s = allocate_cmdlines_buffer(val); + if (!s) + return -ENOMEM; + +- if (allocate_cmdlines_buffer(val, s) < 0) { +- kfree(s); +- return -ENOMEM; +- } +- + preempt_disable(); + arch_spin_lock(&trace_cmdline_lock); + savedcmd_temp = savedcmd; +@@ -9758,7 +9760,6 @@ static __init void create_trace_instances(struct dentry *d_tracer) + static void + init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer) + { +- struct trace_event_file *file; + int cpu; + + trace_create_file("available_tracers", TRACE_MODE_READ, d_tracer, +@@ -9791,11 +9792,7 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer) + trace_create_file("trace_marker", 0220, d_tracer, + tr, &tracing_mark_fops); + +- file = __find_event_file(tr, "ftrace", "print"); +- if (file && file->ef) +- eventfs_add_file("trigger", TRACE_MODE_WRITE, file->ef, +- file, &event_trigger_fops); +- tr->trace_marker_file = file; ++ tr->trace_marker_file = __find_event_file(tr, "ftrace", "print"); + + trace_create_file("trace_marker_raw", 0220, d_tracer, + tr, &tracing_mark_raw_fops); +diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h +index 51c0a970339e2..02b727a54648f 100644 +--- a/kernel/trace/trace.h ++++ b/kernel/trace/trace.h +@@ -381,7 +381,7 @@ struct trace_array { + struct dentry *dir; + struct dentry *options; + struct dentry *percpu_dir; +- struct dentry *event_dir; ++ struct eventfs_inode *event_dir; + struct trace_options *topts; + struct list_head systems; + struct list_head events; +@@ -1345,7 +1345,7 @@ struct trace_subsystem_dir { + struct list_head list; + struct event_subsystem *subsystem; + struct trace_array *tr; +- struct eventfs_file *ef; ++ struct eventfs_inode *ei; + int ref_count; + int nr_events; + }; +diff --git a/kernel/trace/trace_btf.c b/kernel/trace/trace_btf.c +index ca224d53bfdcd..5bbdbcbbde3cd 100644 +--- a/kernel/trace/trace_btf.c ++++ b/kernel/trace/trace_btf.c +@@ -91,8 +91,8 @@ const struct btf_member *btf_find_struct_member(struct btf *btf, + for_each_member(i, type, member) { + if (!member->name_off) { + /* Anonymous union/struct: push it for later use */ +- type = btf_type_skip_modifiers(btf, member->type, &tid); +- if (type && top < BTF_ANON_STACK_MAX) { ++ if (btf_type_skip_modifiers(btf, member->type, &tid) && ++ top < BTF_ANON_STACK_MAX) { + anon_stack[top].tid = tid; + anon_stack[top++].offset = + cur_offset + member->offset; +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 82cb22ad6d617..941a394d39118 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -984,7 +984,7 @@ static void remove_subsystem(struct trace_subsystem_dir *dir) + return; + + if (!--dir->nr_events) { +- eventfs_remove(dir->ef); ++ eventfs_remove_dir(dir->ei); + list_del(&dir->list); + __put_system_dir(dir); + } +@@ -1013,7 +1013,7 @@ void event_file_put(struct trace_event_file *file) + + static void remove_event_file_dir(struct trace_event_file *file) + { +- eventfs_remove(file->ef); ++ eventfs_remove_dir(file->ei); + list_del(&file->list); + remove_subsystem(file->system); + free_event_filter(file->filter); +@@ -2302,14 +2302,40 @@ create_new_subsystem(const char *name) + return NULL; + } + +-static struct eventfs_file * ++static int system_callback(const char *name, umode_t *mode, void **data, ++ const struct file_operations **fops) ++{ ++ if (strcmp(name, "filter") == 0) ++ *fops = &ftrace_subsystem_filter_fops; ++ ++ else if (strcmp(name, "enable") == 0) ++ *fops = &ftrace_system_enable_fops; ++ ++ else ++ return 0; ++ ++ *mode = TRACE_MODE_WRITE; ++ return 1; ++} ++ ++static struct eventfs_inode * + event_subsystem_dir(struct trace_array *tr, const char *name, +- struct trace_event_file *file, struct dentry *parent) ++ struct trace_event_file *file, struct eventfs_inode *parent) + { + struct event_subsystem *system, *iter; + struct trace_subsystem_dir *dir; +- struct eventfs_file *ef; +- int res; ++ struct eventfs_inode *ei; ++ int nr_entries; ++ static struct eventfs_entry system_entries[] = { ++ { ++ .name = "filter", ++ .callback = system_callback, ++ }, ++ { ++ .name = "enable", ++ .callback = system_callback, ++ } ++ }; + + /* First see if we did not already create this dir */ + list_for_each_entry(dir, &tr->systems, list) { +@@ -2317,7 +2343,7 @@ event_subsystem_dir(struct trace_array *tr, const char *name, + if (strcmp(system->name, name) == 0) { + dir->nr_events++; + file->system = dir; +- return dir->ef; ++ return dir->ei; + } + } + +@@ -2341,39 +2367,29 @@ event_subsystem_dir(struct trace_array *tr, const char *name, + } else + __get_system(system); + +- ef = eventfs_add_subsystem_dir(name, parent); +- if (IS_ERR(ef)) { ++ /* ftrace only has directories no files */ ++ if (strcmp(name, "ftrace") == 0) ++ nr_entries = 0; ++ else ++ nr_entries = ARRAY_SIZE(system_entries); ++ ++ ei = eventfs_create_dir(name, parent, system_entries, nr_entries, dir); ++ if (IS_ERR(ei)) { + pr_warn("Failed to create system directory %s\n", name); + __put_system(system); + goto out_free; + } + +- dir->ef = ef; ++ dir->ei = ei; + dir->tr = tr; + dir->ref_count = 1; + dir->nr_events = 1; + dir->subsystem = system; + file->system = dir; + +- /* the ftrace system is special, do not create enable or filter files */ +- if (strcmp(name, "ftrace") != 0) { +- +- res = eventfs_add_file("filter", TRACE_MODE_WRITE, +- dir->ef, dir, +- &ftrace_subsystem_filter_fops); +- if (res) { +- kfree(system->filter); +- system->filter = NULL; +- pr_warn("Could not create tracefs '%s/filter' entry\n", name); +- } +- +- eventfs_add_file("enable", TRACE_MODE_WRITE, dir->ef, dir, +- &ftrace_system_enable_fops); +- } +- + list_add(&dir->list, &tr->systems); + +- return dir->ef; ++ return dir->ei; + + out_free: + kfree(dir); +@@ -2422,15 +2438,134 @@ event_define_fields(struct trace_event_call *call) + return ret; + } + ++static int event_callback(const char *name, umode_t *mode, void **data, ++ const struct file_operations **fops) ++{ ++ struct trace_event_file *file = *data; ++ struct trace_event_call *call = file->event_call; ++ ++ if (strcmp(name, "format") == 0) { ++ *mode = TRACE_MODE_READ; ++ *fops = &ftrace_event_format_fops; ++ *data = call; ++ return 1; ++ } ++ ++ /* ++ * Only event directories that can be enabled should have ++ * triggers or filters, with the exception of the "print" ++ * event that can have a "trigger" file. ++ */ ++ if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) { ++ if (call->class->reg && strcmp(name, "enable") == 0) { ++ *mode = TRACE_MODE_WRITE; ++ *fops = &ftrace_enable_fops; ++ return 1; ++ } ++ ++ if (strcmp(name, "filter") == 0) { ++ *mode = TRACE_MODE_WRITE; ++ *fops = &ftrace_event_filter_fops; ++ return 1; ++ } ++ } ++ ++ if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE) || ++ strcmp(trace_event_name(call), "print") == 0) { ++ if (strcmp(name, "trigger") == 0) { ++ *mode = TRACE_MODE_WRITE; ++ *fops = &event_trigger_fops; ++ return 1; ++ } ++ } ++ ++#ifdef CONFIG_PERF_EVENTS ++ if (call->event.type && call->class->reg && ++ strcmp(name, "id") == 0) { ++ *mode = TRACE_MODE_READ; ++ *data = (void *)(long)call->event.type; ++ *fops = &ftrace_event_id_fops; ++ return 1; ++ } ++#endif ++ ++#ifdef CONFIG_HIST_TRIGGERS ++ if (strcmp(name, "hist") == 0) { ++ *mode = TRACE_MODE_READ; ++ *fops = &event_hist_fops; ++ return 1; ++ } ++#endif ++#ifdef CONFIG_HIST_TRIGGERS_DEBUG ++ if (strcmp(name, "hist_debug") == 0) { ++ *mode = TRACE_MODE_READ; ++ *fops = &event_hist_debug_fops; ++ return 1; ++ } ++#endif ++#ifdef CONFIG_TRACE_EVENT_INJECT ++ if (call->event.type && call->class->reg && ++ strcmp(name, "inject") == 0) { ++ *mode = 0200; ++ *fops = &event_inject_fops; ++ return 1; ++ } ++#endif ++ return 0; ++} ++ + static int +-event_create_dir(struct dentry *parent, struct trace_event_file *file) ++event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file) + { + struct trace_event_call *call = file->event_call; +- struct eventfs_file *ef_subsystem = NULL; + struct trace_array *tr = file->tr; +- struct eventfs_file *ef; ++ struct eventfs_inode *e_events; ++ struct eventfs_inode *ei; + const char *name; ++ int nr_entries; + int ret; ++ static struct eventfs_entry event_entries[] = { ++ { ++ .name = "enable", ++ .callback = event_callback, ++ }, ++ { ++ .name = "filter", ++ .callback = event_callback, ++ }, ++ { ++ .name = "trigger", ++ .callback = event_callback, ++ }, ++ { ++ .name = "format", ++ .callback = event_callback, ++ }, ++#ifdef CONFIG_PERF_EVENTS ++ { ++ .name = "id", ++ .callback = event_callback, ++ }, ++#endif ++#ifdef CONFIG_HIST_TRIGGERS ++ { ++ .name = "hist", ++ .callback = event_callback, ++ }, ++#endif ++#ifdef CONFIG_HIST_TRIGGERS_DEBUG ++ { ++ .name = "hist_debug", ++ .callback = event_callback, ++ }, ++#endif ++#ifdef CONFIG_TRACE_EVENT_INJECT ++ { ++ .name = "inject", ++ .callback = event_callback, ++ }, ++#endif ++ }; + + /* + * If the trace point header did not define TRACE_SYSTEM +@@ -2440,29 +2575,20 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file) + if (WARN_ON_ONCE(strcmp(call->class->system, TRACE_SYSTEM) == 0)) + return -ENODEV; + +- ef_subsystem = event_subsystem_dir(tr, call->class->system, file, parent); +- if (!ef_subsystem) ++ e_events = event_subsystem_dir(tr, call->class->system, file, parent); ++ if (!e_events) + return -ENOMEM; + ++ nr_entries = ARRAY_SIZE(event_entries); ++ + name = trace_event_name(call); +- ef = eventfs_add_dir(name, ef_subsystem); +- if (IS_ERR(ef)) { ++ ei = eventfs_create_dir(name, e_events, event_entries, nr_entries, file); ++ if (IS_ERR(ei)) { + pr_warn("Could not create tracefs '%s' directory\n", name); + return -1; + } + +- file->ef = ef; +- +- if (call->class->reg && !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) +- eventfs_add_file("enable", TRACE_MODE_WRITE, file->ef, file, +- &ftrace_enable_fops); +- +-#ifdef CONFIG_PERF_EVENTS +- if (call->event.type && call->class->reg) +- eventfs_add_file("id", TRACE_MODE_READ, file->ef, +- (void *)(long)call->event.type, +- &ftrace_event_id_fops); +-#endif ++ file->ei = ei; + + ret = event_define_fields(call); + if (ret < 0) { +@@ -2470,35 +2596,6 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file) + return ret; + } + +- /* +- * Only event directories that can be enabled should have +- * triggers or filters. +- */ +- if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) { +- eventfs_add_file("filter", TRACE_MODE_WRITE, file->ef, +- file, &ftrace_event_filter_fops); +- +- eventfs_add_file("trigger", TRACE_MODE_WRITE, file->ef, +- file, &event_trigger_fops); +- } +- +-#ifdef CONFIG_HIST_TRIGGERS +- eventfs_add_file("hist", TRACE_MODE_READ, file->ef, file, +- &event_hist_fops); +-#endif +-#ifdef CONFIG_HIST_TRIGGERS_DEBUG +- eventfs_add_file("hist_debug", TRACE_MODE_READ, file->ef, file, +- &event_hist_debug_fops); +-#endif +- eventfs_add_file("format", TRACE_MODE_READ, file->ef, call, +- &ftrace_event_format_fops); +- +-#ifdef CONFIG_TRACE_EVENT_INJECT +- if (call->event.type && call->class->reg) +- eventfs_add_file("inject", 0200, file->ef, file, +- &event_inject_fops); +-#endif +- + return 0; + } + +@@ -3644,30 +3741,65 @@ static __init int setup_trace_event(char *str) + } + __setup("trace_event=", setup_trace_event); + ++static int events_callback(const char *name, umode_t *mode, void **data, ++ const struct file_operations **fops) ++{ ++ if (strcmp(name, "enable") == 0) { ++ *mode = TRACE_MODE_WRITE; ++ *fops = &ftrace_tr_enable_fops; ++ return 1; ++ } ++ ++ if (strcmp(name, "header_page") == 0) ++ *data = ring_buffer_print_page_header; ++ ++ else if (strcmp(name, "header_event") == 0) ++ *data = ring_buffer_print_entry_header; ++ ++ else ++ return 0; ++ ++ *mode = TRACE_MODE_READ; ++ *fops = &ftrace_show_header_fops; ++ return 1; ++} ++ + /* Expects to have event_mutex held when called */ + static int + create_event_toplevel_files(struct dentry *parent, struct trace_array *tr) + { +- struct dentry *d_events; ++ struct eventfs_inode *e_events; + struct dentry *entry; +- int error = 0; ++ int nr_entries; ++ static struct eventfs_entry events_entries[] = { ++ { ++ .name = "enable", ++ .callback = events_callback, ++ }, ++ { ++ .name = "header_page", ++ .callback = events_callback, ++ }, ++ { ++ .name = "header_event", ++ .callback = events_callback, ++ }, ++ }; + + entry = trace_create_file("set_event", TRACE_MODE_WRITE, parent, + tr, &ftrace_set_event_fops); + if (!entry) + return -ENOMEM; + +- d_events = eventfs_create_events_dir("events", parent); +- if (IS_ERR(d_events)) { ++ nr_entries = ARRAY_SIZE(events_entries); ++ ++ e_events = eventfs_create_events_dir("events", parent, events_entries, ++ nr_entries, tr); ++ if (IS_ERR(e_events)) { + pr_warn("Could not create tracefs 'events' directory\n"); + return -ENOMEM; + } + +- error = eventfs_add_events_file("enable", TRACE_MODE_WRITE, d_events, +- tr, &ftrace_tr_enable_fops); +- if (error) +- return -ENOMEM; +- + /* There are not as crucial, just warn if they are not created */ + + trace_create_file("set_event_pid", TRACE_MODE_WRITE, parent, +@@ -3677,16 +3809,7 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr) + TRACE_MODE_WRITE, parent, tr, + &ftrace_set_event_notrace_pid_fops); + +- /* ring buffer internal formats */ +- eventfs_add_events_file("header_page", TRACE_MODE_READ, d_events, +- ring_buffer_print_page_header, +- &ftrace_show_header_fops); +- +- eventfs_add_events_file("header_event", TRACE_MODE_READ, d_events, +- ring_buffer_print_entry_header, +- &ftrace_show_header_fops); +- +- tr->event_dir = d_events; ++ tr->event_dir = e_events; + + return 0; + } +diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c +index 846e02c0fb59a..624e0867316d0 100644 +--- a/kernel/trace/trace_events_synth.c ++++ b/kernel/trace/trace_events_synth.c +@@ -441,8 +441,9 @@ static unsigned int trace_string(struct synth_trace_event *entry, + if (is_dynamic) { + union trace_synth_field *data = &entry->fields[*n_u64]; + ++ len = fetch_store_strlen((unsigned long)str_val); + data->as_dynamic.offset = struct_size(entry, fields, event->n_u64) + data_size; +- data->as_dynamic.len = fetch_store_strlen((unsigned long)str_val); ++ data->as_dynamic.len = len; + + ret = fetch_store_string((unsigned long)str_val, &entry->fields[*n_u64], entry); + +diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c +index 46439e3bcec4d..b33c3861fbbbf 100644 +--- a/kernel/trace/trace_events_trigger.c ++++ b/kernel/trace/trace_events_trigger.c +@@ -1470,8 +1470,10 @@ register_snapshot_trigger(char *glob, + struct event_trigger_data *data, + struct trace_event_file *file) + { +- if (tracing_alloc_snapshot_instance(file->tr) != 0) +- return 0; ++ int ret = tracing_alloc_snapshot_instance(file->tr); ++ ++ if (ret < 0) ++ return ret; + + return register_trigger(glob, data, file); + } +diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c +index bd0d01d00fb9d..a8e28f9b9271c 100644 +--- a/kernel/trace/trace_osnoise.c ++++ b/kernel/trace/trace_osnoise.c +@@ -2444,6 +2444,9 @@ static int timerlat_fd_open(struct inode *inode, struct file *file) + tlat = this_cpu_tmr_var(); + tlat->count = 0; + ++ hrtimer_init(&tlat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD); ++ tlat->timer.function = timerlat_irq; ++ + migrate_enable(); + return 0; + }; +@@ -2526,9 +2529,6 @@ timerlat_fd_read(struct file *file, char __user *ubuf, size_t count, + tlat->tracing_thread = false; + tlat->kthread = current; + +- hrtimer_init(&tlat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD); +- tlat->timer.function = timerlat_irq; +- + /* Annotate now to drift new period */ + tlat->abs_period = hrtimer_cb_get_time(&tlat->timer); + +diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c +index 4dc74d73fc1df..34289f9c67076 100644 +--- a/kernel/trace/trace_probe.c ++++ b/kernel/trace/trace_probe.c +@@ -1159,9 +1159,12 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, + if (!(ctx->flags & TPARG_FL_TEVENT) && + (strcmp(arg, "$comm") == 0 || strcmp(arg, "$COMM") == 0 || + strncmp(arg, "\\\"", 2) == 0)) { +- /* The type of $comm must be "string", and not an array. */ +- if (parg->count || (t && strcmp(t, "string"))) ++ /* The type of $comm must be "string", and not an array type. */ ++ if (parg->count || (t && strcmp(t, "string"))) { ++ trace_probe_log_err(ctx->offset + (t ? (t - arg) : 0), ++ NEED_STRING_TYPE); + goto out; ++ } + parg->type = find_fetch_type("string", ctx->flags); + } else + parg->type = find_fetch_type(t, ctx->flags); +@@ -1169,18 +1172,6 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, + trace_probe_log_err(ctx->offset + (t ? (t - arg) : 0), BAD_TYPE); + goto out; + } +- parg->offset = *size; +- *size += parg->type->size * (parg->count ?: 1); +- +- ret = -ENOMEM; +- if (parg->count) { +- len = strlen(parg->type->fmttype) + 6; +- parg->fmt = kmalloc(len, GFP_KERNEL); +- if (!parg->fmt) +- goto out; +- snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype, +- parg->count); +- } + + code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL); + if (!code) +@@ -1204,6 +1195,19 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, + goto fail; + } + } ++ parg->offset = *size; ++ *size += parg->type->size * (parg->count ?: 1); ++ ++ if (parg->count) { ++ len = strlen(parg->type->fmttype) + 6; ++ parg->fmt = kmalloc(len, GFP_KERNEL); ++ if (!parg->fmt) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype, ++ parg->count); ++ } + + ret = -EINVAL; + /* Store operation */ +diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h +index 850d9ecb6765a..c1877d0182691 100644 +--- a/kernel/trace/trace_probe.h ++++ b/kernel/trace/trace_probe.h +@@ -515,7 +515,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, + C(BAD_HYPHEN, "Failed to parse single hyphen. Forgot '>'?"), \ + C(NO_BTF_FIELD, "This field is not found."), \ + C(BAD_BTF_TID, "Failed to get BTF type info."),\ +- C(BAD_TYPE4STR, "This type does not fit for string."), ++ C(BAD_TYPE4STR, "This type does not fit for string."),\ ++ C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"), + + #undef C + #define C(a, b) TP_ERR_##a +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index e6a95bb74e228..fd7b84b06d926 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -5793,13 +5793,9 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask) + list_for_each_entry(wq, &workqueues, list) { + if (!(wq->flags & WQ_UNBOUND)) + continue; +- + /* creating multiple pwqs breaks ordering guarantee */ +- if (!list_empty(&wq->pwqs)) { +- if (wq->flags & __WQ_ORDERED_EXPLICIT) +- continue; +- wq->flags &= ~__WQ_ORDERED; +- } ++ if (wq->flags & __WQ_ORDERED) ++ continue; + + ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs, unbound_cpumask); + if (IS_ERR(ctx)) { +diff --git a/lib/kobject.c b/lib/kobject.c +index 59dbcbdb1c916..72fa20f405f15 100644 +--- a/lib/kobject.c ++++ b/lib/kobject.c +@@ -74,10 +74,12 @@ static int create_dir(struct kobject *kobj) + if (error) + return error; + +- error = sysfs_create_groups(kobj, ktype->default_groups); +- if (error) { +- sysfs_remove_dir(kobj); +- return error; ++ if (ktype) { ++ error = sysfs_create_groups(kobj, ktype->default_groups); ++ if (error) { ++ sysfs_remove_dir(kobj); ++ return error; ++ } + } + + /* +@@ -589,7 +591,8 @@ static void __kobject_del(struct kobject *kobj) + sd = kobj->sd; + ktype = get_ktype(kobj); + +- sysfs_remove_groups(kobj, ktype->default_groups); ++ if (ktype) ++ sysfs_remove_groups(kobj, ktype->default_groups); + + /* send "remove" if the caller did not do it but sent "add" */ + if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) { +@@ -666,6 +669,10 @@ static void kobject_cleanup(struct kobject *kobj) + pr_debug("'%s' (%p): %s, parent %p\n", + kobject_name(kobj), kobj, __func__, kobj->parent); + ++ if (t && !t->release) ++ pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n", ++ kobject_name(kobj), kobj); ++ + /* remove from sysfs if the caller did not do it */ + if (kobj->state_in_sysfs) { + pr_debug("'%s' (%p): auto cleanup kobject_del\n", +@@ -676,13 +683,10 @@ static void kobject_cleanup(struct kobject *kobj) + parent = NULL; + } + +- if (t->release) { ++ if (t && t->release) { + pr_debug("'%s' (%p): calling ktype release\n", + kobject_name(kobj), kobj); + t->release(kobj); +- } else { +- pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n", +- kobject_name(kobj), kobj); + } + + /* free name if we allocated it */ +@@ -1056,7 +1060,7 @@ const struct kobj_ns_type_operations *kobj_child_ns_ops(const struct kobject *pa + { + const struct kobj_ns_type_operations *ops = NULL; + +- if (parent && parent->ktype->child_ns_type) ++ if (parent && parent->ktype && parent->ktype->child_ns_type) + ops = parent->ktype->child_ns_type(parent); + + return ops; +diff --git a/mm/backing-dev.c b/mm/backing-dev.c +index 1e3447bccdb14..e039d05304dd9 100644 +--- a/mm/backing-dev.c ++++ b/mm/backing-dev.c +@@ -436,7 +436,6 @@ static int wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi, + INIT_LIST_HEAD(&wb->work_list); + INIT_DELAYED_WORK(&wb->dwork, wb_workfn); + INIT_DELAYED_WORK(&wb->bw_dwork, wb_update_bandwidth_workfn); +- wb->dirty_sleep = jiffies; + + err = fprop_local_init_percpu(&wb->completions, gfp); + if (err) +@@ -921,6 +920,7 @@ int bdi_init(struct backing_dev_info *bdi) + INIT_LIST_HEAD(&bdi->bdi_list); + INIT_LIST_HEAD(&bdi->wb_list); + init_waitqueue_head(&bdi->wb_waitq); ++ bdi->last_bdp_sleep = jiffies; + + return cgwb_bdi_init(bdi); + } +diff --git a/mm/memory.c b/mm/memory.c +index dccf9203dd536..b3be18f1f1206 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -5315,7 +5315,7 @@ static inline bool get_mmap_lock_carefully(struct mm_struct *mm, struct pt_regs + return true; + + if (regs && !user_mode(regs)) { +- unsigned long ip = instruction_pointer(regs); ++ unsigned long ip = exception_ip(regs); + if (!search_exception_tables(ip)) + return false; + } +@@ -5340,7 +5340,7 @@ static inline bool upgrade_mmap_lock_carefully(struct mm_struct *mm, struct pt_r + { + mmap_read_unlock(mm); + if (regs && !user_mode(regs)) { +- unsigned long ip = instruction_pointer(regs); ++ unsigned long ip = exception_ip(regs); + if (!search_exception_tables(ip)) + return false; + } +diff --git a/mm/page-writeback.c b/mm/page-writeback.c +index 4656534b8f5cc..a9303f8866399 100644 +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -1638,7 +1638,7 @@ static inline void wb_dirty_limits(struct dirty_throttle_control *dtc) + */ + dtc->wb_thresh = __wb_calc_thresh(dtc); + dtc->wb_bg_thresh = dtc->thresh ? +- div_u64((u64)dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0; ++ div64_u64(dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0; + + /* + * In order to avoid the stacked BDI deadlock we need +@@ -1921,7 +1921,7 @@ static int balance_dirty_pages(struct bdi_writeback *wb, + break; + } + __set_current_state(TASK_KILLABLE); +- wb->dirty_sleep = now; ++ bdi->last_bdp_sleep = jiffies; + io_schedule_timeout(pause); + + current->dirty_paused_when = now + pause; +diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c +index 96d9eae5c7cc8..cd5ad448ac2f0 100644 +--- a/mm/userfaultfd.c ++++ b/mm/userfaultfd.c +@@ -357,6 +357,7 @@ static __always_inline ssize_t mfill_atomic_hugetlb( + unsigned long dst_start, + unsigned long src_start, + unsigned long len, ++ atomic_t *mmap_changing, + uffd_flags_t flags) + { + struct mm_struct *dst_mm = dst_vma->vm_mm; +@@ -472,6 +473,15 @@ static __always_inline ssize_t mfill_atomic_hugetlb( + goto out; + } + mmap_read_lock(dst_mm); ++ /* ++ * If memory mappings are changing because of non-cooperative ++ * operation (e.g. mremap) running in parallel, bail out and ++ * request the user to retry later ++ */ ++ if (mmap_changing && atomic_read(mmap_changing)) { ++ err = -EAGAIN; ++ break; ++ } + + dst_vma = NULL; + goto retry; +@@ -506,6 +516,7 @@ extern ssize_t mfill_atomic_hugetlb(struct vm_area_struct *dst_vma, + unsigned long dst_start, + unsigned long src_start, + unsigned long len, ++ atomic_t *mmap_changing, + uffd_flags_t flags); + #endif /* CONFIG_HUGETLB_PAGE */ + +@@ -622,8 +633,8 @@ static __always_inline ssize_t mfill_atomic(struct mm_struct *dst_mm, + * If this is a HUGETLB vma, pass off to appropriate routine + */ + if (is_vm_hugetlb_page(dst_vma)) +- return mfill_atomic_hugetlb(dst_vma, dst_start, +- src_start, len, flags); ++ return mfill_atomic_hugetlb(dst_vma, dst_start, src_start, ++ len, mmap_changing, flags); + + if (!vma_is_anonymous(dst_vma) && !vma_is_shmem(dst_vma)) + goto out_unlock; +diff --git a/net/can/j1939/j1939-priv.h b/net/can/j1939/j1939-priv.h +index 16af1a7f80f60..31a93cae5111b 100644 +--- a/net/can/j1939/j1939-priv.h ++++ b/net/can/j1939/j1939-priv.h +@@ -86,7 +86,7 @@ struct j1939_priv { + unsigned int tp_max_packet_size; + + /* lock for j1939_socks list */ +- spinlock_t j1939_socks_lock; ++ rwlock_t j1939_socks_lock; + struct list_head j1939_socks; + + struct kref rx_kref; +@@ -301,6 +301,7 @@ struct j1939_sock { + + int ifindex; + struct j1939_addr addr; ++ spinlock_t filters_lock; + struct j1939_filter *filters; + int nfilters; + pgn_t pgn_rx_filter; +diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c +index ecff1c947d683..a6fb89fa62785 100644 +--- a/net/can/j1939/main.c ++++ b/net/can/j1939/main.c +@@ -274,7 +274,7 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev) + return ERR_PTR(-ENOMEM); + + j1939_tp_init(priv); +- spin_lock_init(&priv->j1939_socks_lock); ++ rwlock_init(&priv->j1939_socks_lock); + INIT_LIST_HEAD(&priv->j1939_socks); + + mutex_lock(&j1939_netdev_lock); +diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c +index b28c976f52a0a..1f49d6164ea1d 100644 +--- a/net/can/j1939/socket.c ++++ b/net/can/j1939/socket.c +@@ -80,16 +80,16 @@ static void j1939_jsk_add(struct j1939_priv *priv, struct j1939_sock *jsk) + jsk->state |= J1939_SOCK_BOUND; + j1939_priv_get(priv); + +- spin_lock_bh(&priv->j1939_socks_lock); ++ write_lock_bh(&priv->j1939_socks_lock); + list_add_tail(&jsk->list, &priv->j1939_socks); +- spin_unlock_bh(&priv->j1939_socks_lock); ++ write_unlock_bh(&priv->j1939_socks_lock); + } + + static void j1939_jsk_del(struct j1939_priv *priv, struct j1939_sock *jsk) + { +- spin_lock_bh(&priv->j1939_socks_lock); ++ write_lock_bh(&priv->j1939_socks_lock); + list_del_init(&jsk->list); +- spin_unlock_bh(&priv->j1939_socks_lock); ++ write_unlock_bh(&priv->j1939_socks_lock); + + j1939_priv_put(priv); + jsk->state &= ~J1939_SOCK_BOUND; +@@ -262,12 +262,17 @@ static bool j1939_sk_match_dst(struct j1939_sock *jsk, + static bool j1939_sk_match_filter(struct j1939_sock *jsk, + const struct j1939_sk_buff_cb *skcb) + { +- const struct j1939_filter *f = jsk->filters; +- int nfilter = jsk->nfilters; ++ const struct j1939_filter *f; ++ int nfilter; ++ ++ spin_lock_bh(&jsk->filters_lock); ++ ++ f = jsk->filters; ++ nfilter = jsk->nfilters; + + if (!nfilter) + /* receive all when no filters are assigned */ +- return true; ++ goto filter_match_found; + + for (; nfilter; ++f, --nfilter) { + if ((skcb->addr.pgn & f->pgn_mask) != f->pgn) +@@ -276,9 +281,15 @@ static bool j1939_sk_match_filter(struct j1939_sock *jsk, + continue; + if ((skcb->addr.src_name & f->name_mask) != f->name) + continue; +- return true; ++ goto filter_match_found; + } ++ ++ spin_unlock_bh(&jsk->filters_lock); + return false; ++ ++filter_match_found: ++ spin_unlock_bh(&jsk->filters_lock); ++ return true; + } + + static bool j1939_sk_recv_match_one(struct j1939_sock *jsk, +@@ -329,13 +340,13 @@ bool j1939_sk_recv_match(struct j1939_priv *priv, struct j1939_sk_buff_cb *skcb) + struct j1939_sock *jsk; + bool match = false; + +- spin_lock_bh(&priv->j1939_socks_lock); ++ read_lock_bh(&priv->j1939_socks_lock); + list_for_each_entry(jsk, &priv->j1939_socks, list) { + match = j1939_sk_recv_match_one(jsk, skcb); + if (match) + break; + } +- spin_unlock_bh(&priv->j1939_socks_lock); ++ read_unlock_bh(&priv->j1939_socks_lock); + + return match; + } +@@ -344,11 +355,11 @@ void j1939_sk_recv(struct j1939_priv *priv, struct sk_buff *skb) + { + struct j1939_sock *jsk; + +- spin_lock_bh(&priv->j1939_socks_lock); ++ read_lock_bh(&priv->j1939_socks_lock); + list_for_each_entry(jsk, &priv->j1939_socks, list) { + j1939_sk_recv_one(jsk, skb); + } +- spin_unlock_bh(&priv->j1939_socks_lock); ++ read_unlock_bh(&priv->j1939_socks_lock); + } + + static void j1939_sk_sock_destruct(struct sock *sk) +@@ -401,6 +412,7 @@ static int j1939_sk_init(struct sock *sk) + atomic_set(&jsk->skb_pending, 0); + spin_lock_init(&jsk->sk_session_queue_lock); + INIT_LIST_HEAD(&jsk->sk_session_queue); ++ spin_lock_init(&jsk->filters_lock); + + /* j1939_sk_sock_destruct() depends on SOCK_RCU_FREE flag */ + sock_set_flag(sk, SOCK_RCU_FREE); +@@ -703,9 +715,11 @@ static int j1939_sk_setsockopt(struct socket *sock, int level, int optname, + } + + lock_sock(&jsk->sk); ++ spin_lock_bh(&jsk->filters_lock); + ofilters = jsk->filters; + jsk->filters = filters; + jsk->nfilters = count; ++ spin_unlock_bh(&jsk->filters_lock); + release_sock(&jsk->sk); + kfree(ofilters); + return 0; +@@ -1080,12 +1094,12 @@ void j1939_sk_errqueue(struct j1939_session *session, + } + + /* spread RX notifications to all sockets subscribed to this session */ +- spin_lock_bh(&priv->j1939_socks_lock); ++ read_lock_bh(&priv->j1939_socks_lock); + list_for_each_entry(jsk, &priv->j1939_socks, list) { + if (j1939_sk_recv_match_one(jsk, &session->skcb)) + __j1939_sk_errqueue(session, &jsk->sk, type); + } +- spin_unlock_bh(&priv->j1939_socks_lock); ++ read_unlock_bh(&priv->j1939_socks_lock); + }; + + void j1939_sk_send_loop_abort(struct sock *sk, int err) +@@ -1273,7 +1287,7 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv) + struct j1939_sock *jsk; + int error_code = ENETDOWN; + +- spin_lock_bh(&priv->j1939_socks_lock); ++ read_lock_bh(&priv->j1939_socks_lock); + list_for_each_entry(jsk, &priv->j1939_socks, list) { + jsk->sk.sk_err = error_code; + if (!sock_flag(&jsk->sk, SOCK_DEAD)) +@@ -1281,7 +1295,7 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv) + + j1939_sk_queue_drop_all(priv, jsk, error_code); + } +- spin_unlock_bh(&priv->j1939_socks_lock); ++ read_unlock_bh(&priv->j1939_socks_lock); + } + + static int j1939_sk_no_ioctlcmd(struct socket *sock, unsigned int cmd, +diff --git a/net/handshake/handshake-test.c b/net/handshake/handshake-test.c +index 16ed7bfd29e4f..34fd1d9b2db86 100644 +--- a/net/handshake/handshake-test.c ++++ b/net/handshake/handshake-test.c +@@ -471,7 +471,10 @@ static void handshake_req_destroy_test1(struct kunit *test) + handshake_req_cancel(sock->sk); + + /* Act */ +- fput(filp); ++ /* Ensure the close/release/put process has run to ++ * completion before checking the result. ++ */ ++ __fput_sync(filp); + + /* Assert */ + KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req); +diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c +index 306f942c3b28a..dd4b5f0aa1318 100644 +--- a/net/hsr/hsr_device.c ++++ b/net/hsr/hsr_device.c +@@ -291,7 +291,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master, + + skb = hsr_init_skb(master); + if (!skb) { +- WARN_ONCE(1, "HSR: Could not send supervision frame\n"); ++ netdev_warn_once(master->dev, "HSR: Could not send supervision frame\n"); + return; + } + +@@ -338,7 +338,7 @@ static void send_prp_supervision_frame(struct hsr_port *master, + + skb = hsr_init_skb(master); + if (!skb) { +- WARN_ONCE(1, "PRP: Could not send supervision frame\n"); ++ netdev_warn_once(master->dev, "PRP: Could not send supervision frame\n"); + return; + } + +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index 5481acbfc1d43..5ab9594ae119e 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -5,7 +5,7 @@ + * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * Copyright 2013-2014 Intel Mobile Communications GmbH +- * Copyright (C) 2018-2022 Intel Corporation ++ * Copyright (C) 2018-2024 Intel Corporation + * + * Transmit and frame generation functions. + */ +@@ -3913,6 +3913,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, + goto begin; + + skb = __skb_dequeue(&tx.skbs); ++ info = IEEE80211_SKB_CB(skb); + + if (!skb_queue_empty(&tx.skbs)) { + spin_lock_bh(&fq->lock); +@@ -3957,7 +3958,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, + } + + encap_out: +- IEEE80211_SKB_CB(skb)->control.vif = vif; ++ info->control.vif = vif; + + if (tx.sta && + wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { +diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c +index d042d32beb4df..c1717322c8922 100644 +--- a/net/mptcp/pm_userspace.c ++++ b/net/mptcp/pm_userspace.c +@@ -130,10 +130,21 @@ int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, + int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, + struct mptcp_addr_info *skc) + { +- struct mptcp_pm_addr_entry new_entry; ++ struct mptcp_pm_addr_entry *entry = NULL, *e, new_entry; + __be16 msk_sport = ((struct inet_sock *) + inet_sk((struct sock *)msk))->inet_sport; + ++ spin_lock_bh(&msk->pm.lock); ++ list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) { ++ if (mptcp_addresses_equal(&e->addr, skc, false)) { ++ entry = e; ++ break; ++ } ++ } ++ spin_unlock_bh(&msk->pm.lock); ++ if (entry) ++ return entry->addr.id; ++ + memset(&new_entry, 0, sizeof(struct mptcp_pm_addr_entry)); + new_entry.addr = *skc; + new_entry.addr.id = 0; +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index 5c003a0f0fe5b..9d4d5dbdbb53b 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -1522,8 +1522,11 @@ static void mptcp_update_post_push(struct mptcp_sock *msk, + + void mptcp_check_and_set_pending(struct sock *sk) + { +- if (mptcp_send_head(sk)) +- mptcp_sk(sk)->push_pending |= BIT(MPTCP_PUSH_PENDING); ++ if (mptcp_send_head(sk)) { ++ mptcp_data_lock(sk); ++ mptcp_sk(sk)->cb_flags |= BIT(MPTCP_PUSH_PENDING); ++ mptcp_data_unlock(sk); ++ } + } + + static int __subflow_push_pending(struct sock *sk, struct sock *ssk, +@@ -1964,6 +1967,9 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) + if (copied <= 0) + return; + ++ if (!msk->rcvspace_init) ++ mptcp_rcv_space_init(msk, msk->first); ++ + msk->rcvq_space.copied += copied; + + mstamp = div_u64(tcp_clock_ns(), NSEC_PER_USEC); +@@ -2318,9 +2324,6 @@ bool __mptcp_retransmit_pending_data(struct sock *sk) + if (__mptcp_check_fallback(msk)) + return false; + +- if (tcp_rtx_and_write_queues_empty(sk)) +- return false; +- + /* the closing socket has some data untransmitted and/or unacked: + * some data in the mptcp rtx queue has not really xmitted yet. + * keep it simple and re-inject the whole mptcp level rtx queue +@@ -3137,7 +3140,6 @@ static int mptcp_disconnect(struct sock *sk, int flags) + mptcp_destroy_common(msk, MPTCP_CF_FASTCLOSE); + WRITE_ONCE(msk->flags, 0); + msk->cb_flags = 0; +- msk->push_pending = 0; + msk->recovery = false; + msk->can_ack = false; + msk->fully_established = false; +@@ -3152,6 +3154,7 @@ static int mptcp_disconnect(struct sock *sk, int flags) + msk->bytes_received = 0; + msk->bytes_sent = 0; + msk->bytes_retrans = 0; ++ msk->rcvspace_init = 0; + + WRITE_ONCE(sk->sk_shutdown, 0); + sk_error_report(sk); +@@ -3239,6 +3242,7 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) + { + const struct tcp_sock *tp = tcp_sk(ssk); + ++ msk->rcvspace_init = 1; + msk->rcvq_space.copied = 0; + msk->rcvq_space.rtt_us = 0; + +@@ -3249,8 +3253,6 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) + TCP_INIT_CWND * tp->advmss); + if (msk->rcvq_space.space == 0) + msk->rcvq_space.space = TCP_INIT_CWND * TCP_MSS_DEFAULT; +- +- WRITE_ONCE(msk->wnd_end, msk->snd_nxt + tcp_sk(ssk)->snd_wnd); + } + + static struct sock *mptcp_accept(struct sock *ssk, int flags, int *err, +@@ -3362,8 +3364,7 @@ static void mptcp_release_cb(struct sock *sk) + struct mptcp_sock *msk = mptcp_sk(sk); + + for (;;) { +- unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED) | +- msk->push_pending; ++ unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED); + struct list_head join_list; + + if (!flags) +@@ -3379,7 +3380,6 @@ static void mptcp_release_cb(struct sock *sk) + * datapath acquires the msk socket spinlock while helding + * the subflow socket lock + */ +- msk->push_pending = 0; + msk->cb_flags &= ~flags; + spin_unlock_bh(&sk->sk_lock.slock); + +@@ -3510,10 +3510,9 @@ void mptcp_finish_connect(struct sock *ssk) + WRITE_ONCE(msk->write_seq, subflow->idsn + 1); + WRITE_ONCE(msk->snd_nxt, msk->write_seq); + WRITE_ONCE(msk->snd_una, msk->write_seq); ++ WRITE_ONCE(msk->wnd_end, msk->snd_nxt + tcp_sk(ssk)->snd_wnd); + + mptcp_pm_new_connection(msk, ssk, 0); +- +- mptcp_rcv_space_init(msk, ssk); + } + + void mptcp_sock_graft(struct sock *sk, struct socket *parent) +diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h +index 07c5ac37d092b..094d3fd47a92f 100644 +--- a/net/mptcp/protocol.h ++++ b/net/mptcp/protocol.h +@@ -283,7 +283,6 @@ struct mptcp_sock { + int rmem_released; + unsigned long flags; + unsigned long cb_flags; +- unsigned long push_pending; + bool recovery; /* closing subflow write queue reinjected */ + bool can_ack; + bool fully_established; +@@ -302,7 +301,8 @@ struct mptcp_sock { + nodelay:1, + fastopening:1, + in_accept_queue:1, +- free_first:1; ++ free_first:1, ++ rcvspace_init:1; + struct work_struct work; + struct sk_buff *ooo_last_skb; + struct rb_root out_of_order_queue; +@@ -1104,7 +1104,8 @@ static inline bool subflow_simultaneous_connect(struct sock *sk) + { + struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); + +- return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1) && ++ return (1 << sk->sk_state) & ++ (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | TCPF_CLOSING) && + is_active_ssk(subflow) && + !subflow->conn_finished; + } +diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c +index d3c5ecf8ddf52..8c7e22a9a37bd 100644 +--- a/net/mptcp/subflow.c ++++ b/net/mptcp/subflow.c +@@ -424,6 +424,8 @@ void __mptcp_sync_state(struct sock *sk, int state) + struct mptcp_sock *msk = mptcp_sk(sk); + + __mptcp_propagate_sndbuf(sk, msk->first); ++ if (!msk->rcvspace_init) ++ mptcp_rcv_space_init(msk, msk->first); + if (sk->sk_state == TCP_SYN_SENT) { + inet_sk_state_store(sk, state); + sk->sk_state_change(sk); +@@ -545,7 +547,6 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) + } + } else if (mptcp_check_fallback(sk)) { + fallback: +- mptcp_rcv_space_init(msk, sk); + mptcp_propagate_state(parent, sk); + } + return; +@@ -1736,7 +1737,6 @@ static void subflow_state_change(struct sock *sk) + msk = mptcp_sk(parent); + if (subflow_simultaneous_connect(sk)) { + mptcp_do_fallback(sk); +- mptcp_rcv_space_init(msk, sk); + pr_fallback(msk); + subflow->conn_finished = 1; + mptcp_propagate_state(parent, sk); +diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h +index 26ab0e9612d82..9523104a90da4 100644 +--- a/net/netfilter/ipset/ip_set_bitmap_gen.h ++++ b/net/netfilter/ipset/ip_set_bitmap_gen.h +@@ -28,6 +28,7 @@ + #define mtype_del IPSET_TOKEN(MTYPE, _del) + #define mtype_list IPSET_TOKEN(MTYPE, _list) + #define mtype_gc IPSET_TOKEN(MTYPE, _gc) ++#define mtype_cancel_gc IPSET_TOKEN(MTYPE, _cancel_gc) + #define mtype MTYPE + + #define get_ext(set, map, id) ((map)->extensions + ((set)->dsize * (id))) +@@ -57,9 +58,6 @@ mtype_destroy(struct ip_set *set) + { + struct mtype *map = set->data; + +- if (SET_WITH_TIMEOUT(set)) +- del_timer_sync(&map->gc); +- + if (set->dsize && set->extensions & IPSET_EXT_DESTROY) + mtype_ext_cleanup(set); + ip_set_free(map->members); +@@ -288,6 +286,15 @@ mtype_gc(struct timer_list *t) + add_timer(&map->gc); + } + ++static void ++mtype_cancel_gc(struct ip_set *set) ++{ ++ struct mtype *map = set->data; ++ ++ if (SET_WITH_TIMEOUT(set)) ++ del_timer_sync(&map->gc); ++} ++ + static const struct ip_set_type_variant mtype = { + .kadt = mtype_kadt, + .uadt = mtype_uadt, +@@ -301,6 +308,7 @@ static const struct ip_set_type_variant mtype = { + .head = mtype_head, + .list = mtype_list, + .same_set = mtype_same_set, ++ .cancel_gc = mtype_cancel_gc, + }; + + #endif /* __IP_SET_BITMAP_IP_GEN_H */ +diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c +index 4c133e06be1de..3184cc6be4c9d 100644 +--- a/net/netfilter/ipset/ip_set_core.c ++++ b/net/netfilter/ipset/ip_set_core.c +@@ -1154,6 +1154,7 @@ static int ip_set_create(struct sk_buff *skb, const struct nfnl_info *info, + return ret; + + cleanup: ++ set->variant->cancel_gc(set); + set->variant->destroy(set); + put_out: + module_put(set->type->me); +@@ -1182,6 +1183,14 @@ ip_set_destroy_set(struct ip_set *set) + kfree(set); + } + ++static void ++ip_set_destroy_set_rcu(struct rcu_head *head) ++{ ++ struct ip_set *set = container_of(head, struct ip_set, rcu); ++ ++ ip_set_destroy_set(set); ++} ++ + static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, + const struct nlattr * const attr[]) + { +@@ -1193,8 +1202,6 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, + if (unlikely(protocol_min_failed(attr))) + return -IPSET_ERR_PROTOCOL; + +- /* Must wait for flush to be really finished in list:set */ +- rcu_barrier(); + + /* Commands are serialized and references are + * protected by the ip_set_ref_lock. +@@ -1206,8 +1213,10 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, + * counter, so if it's already zero, we can proceed + * without holding the lock. + */ +- read_lock_bh(&ip_set_ref_lock); + if (!attr[IPSET_ATTR_SETNAME]) { ++ /* Must wait for flush to be really finished in list:set */ ++ rcu_barrier(); ++ read_lock_bh(&ip_set_ref_lock); + for (i = 0; i < inst->ip_set_max; i++) { + s = ip_set(inst, i); + if (s && (s->ref || s->ref_netlink)) { +@@ -1221,6 +1230,8 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, + s = ip_set(inst, i); + if (s) { + ip_set(inst, i) = NULL; ++ /* Must cancel garbage collectors */ ++ s->variant->cancel_gc(s); + ip_set_destroy_set(s); + } + } +@@ -1228,6 +1239,9 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, + inst->is_destroyed = false; + } else { + u32 flags = flag_exist(info->nlh); ++ u16 features = 0; ++ ++ read_lock_bh(&ip_set_ref_lock); + s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), + &i); + if (!s) { +@@ -1238,10 +1252,16 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, + ret = -IPSET_ERR_BUSY; + goto out; + } ++ features = s->type->features; + ip_set(inst, i) = NULL; + read_unlock_bh(&ip_set_ref_lock); +- +- ip_set_destroy_set(s); ++ if (features & IPSET_TYPE_NAME) { ++ /* Must wait for flush to be really finished */ ++ rcu_barrier(); ++ } ++ /* Must cancel garbage collectors */ ++ s->variant->cancel_gc(s); ++ call_rcu(&s->rcu, ip_set_destroy_set_rcu); + } + return 0; + out: +@@ -1394,9 +1414,6 @@ static int ip_set_swap(struct sk_buff *skb, const struct nfnl_info *info, + ip_set(inst, to_id) = from; + write_unlock_bh(&ip_set_ref_lock); + +- /* Make sure all readers of the old set pointers are completed. */ +- synchronize_rcu(); +- + return 0; + } + +@@ -2362,6 +2379,7 @@ ip_set_net_exit(struct net *net) + set = ip_set(inst, i); + if (set) { + ip_set(inst, i) = NULL; ++ set->variant->cancel_gc(set); + ip_set_destroy_set(set); + } + } +@@ -2409,8 +2427,11 @@ ip_set_fini(void) + { + nf_unregister_sockopt(&so_set); + nfnetlink_subsys_unregister(&ip_set_netlink_subsys); +- + unregister_pernet_subsys(&ip_set_net_ops); ++ ++ /* Wait for call_rcu() in destroy */ ++ rcu_barrier(); ++ + pr_debug("these are the famous last words\n"); + } + +diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h +index 7c2399541771f..20aad81fcad7e 100644 +--- a/net/netfilter/ipset/ip_set_hash_gen.h ++++ b/net/netfilter/ipset/ip_set_hash_gen.h +@@ -221,6 +221,7 @@ static const union nf_inet_addr zeromask = {}; + #undef mtype_gc_do + #undef mtype_gc + #undef mtype_gc_init ++#undef mtype_cancel_gc + #undef mtype_variant + #undef mtype_data_match + +@@ -265,6 +266,7 @@ static const union nf_inet_addr zeromask = {}; + #define mtype_gc_do IPSET_TOKEN(MTYPE, _gc_do) + #define mtype_gc IPSET_TOKEN(MTYPE, _gc) + #define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init) ++#define mtype_cancel_gc IPSET_TOKEN(MTYPE, _cancel_gc) + #define mtype_variant IPSET_TOKEN(MTYPE, _variant) + #define mtype_data_match IPSET_TOKEN(MTYPE, _data_match) + +@@ -429,7 +431,7 @@ mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy) + u32 i; + + for (i = 0; i < jhash_size(t->htable_bits); i++) { +- n = __ipset_dereference(hbucket(t, i)); ++ n = (__force struct hbucket *)hbucket(t, i); + if (!n) + continue; + if (set->extensions & IPSET_EXT_DESTROY && ext_destroy) +@@ -449,10 +451,7 @@ mtype_destroy(struct ip_set *set) + struct htype *h = set->data; + struct list_head *l, *lt; + +- if (SET_WITH_TIMEOUT(set)) +- cancel_delayed_work_sync(&h->gc.dwork); +- +- mtype_ahash_destroy(set, ipset_dereference_nfnl(h->table), true); ++ mtype_ahash_destroy(set, (__force struct htable *)h->table, true); + list_for_each_safe(l, lt, &h->ad) { + list_del(l); + kfree(l); +@@ -598,6 +597,15 @@ mtype_gc_init(struct htable_gc *gc) + queue_delayed_work(system_power_efficient_wq, &gc->dwork, HZ); + } + ++static void ++mtype_cancel_gc(struct ip_set *set) ++{ ++ struct htype *h = set->data; ++ ++ if (SET_WITH_TIMEOUT(set)) ++ cancel_delayed_work_sync(&h->gc.dwork); ++} ++ + static int + mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, + struct ip_set_ext *mext, u32 flags); +@@ -1440,6 +1448,7 @@ static const struct ip_set_type_variant mtype_variant = { + .uref = mtype_uref, + .resize = mtype_resize, + .same_set = mtype_same_set, ++ .cancel_gc = mtype_cancel_gc, + .region_lock = true, + }; + +diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c +index e162636525cfb..6c3f28bc59b32 100644 +--- a/net/netfilter/ipset/ip_set_list_set.c ++++ b/net/netfilter/ipset/ip_set_list_set.c +@@ -426,9 +426,6 @@ list_set_destroy(struct ip_set *set) + struct list_set *map = set->data; + struct set_elem *e, *n; + +- if (SET_WITH_TIMEOUT(set)) +- timer_shutdown_sync(&map->gc); +- + list_for_each_entry_safe(e, n, &map->members, list) { + list_del(&e->list); + ip_set_put_byindex(map->net, e->id); +@@ -545,6 +542,15 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b) + a->extensions == b->extensions; + } + ++static void ++list_set_cancel_gc(struct ip_set *set) ++{ ++ struct list_set *map = set->data; ++ ++ if (SET_WITH_TIMEOUT(set)) ++ timer_shutdown_sync(&map->gc); ++} ++ + static const struct ip_set_type_variant set_variant = { + .kadt = list_set_kadt, + .uadt = list_set_uadt, +@@ -558,6 +564,7 @@ static const struct ip_set_type_variant set_variant = { + .head = list_set_head, + .list = list_set_list, + .same_set = list_set_same_set, ++ .cancel_gc = list_set_cancel_gc, + }; + + static void +diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c +index 90e275bb3e5d7..a3a8ddca99189 100644 +--- a/net/netfilter/nft_set_pipapo_avx2.c ++++ b/net/netfilter/nft_set_pipapo_avx2.c +@@ -57,7 +57,7 @@ + + /* Jump to label if @reg is zero */ + #define NFT_PIPAPO_AVX2_NOMATCH_GOTO(reg, label) \ +- asm_volatile_goto("vptest %%ymm" #reg ", %%ymm" #reg ";" \ ++ asm goto("vptest %%ymm" #reg ", %%ymm" #reg ";" \ + "je %l[" #label "]" : : : : label) + + /* Store 256 bits from YMM register into memory. Contrary to bucket load +diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c +index 6c9592d051206..12684d835cb53 100644 +--- a/net/nfc/nci/core.c ++++ b/net/nfc/nci/core.c +@@ -1208,6 +1208,10 @@ void nci_free_device(struct nci_dev *ndev) + { + nfc_free_device(ndev->nfc_dev); + nci_hci_deallocate(ndev); ++ ++ /* drop partial rx data packet if present */ ++ if (ndev->rx_data_reassembly) ++ kfree_skb(ndev->rx_data_reassembly); + kfree(ndev); + } + EXPORT_SYMBOL(nci_free_device); +diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c +index 88965e2068ac6..ebc5728aab4ea 100644 +--- a/net/openvswitch/flow_netlink.c ++++ b/net/openvswitch/flow_netlink.c +@@ -48,6 +48,7 @@ struct ovs_len_tbl { + + #define OVS_ATTR_NESTED -1 + #define OVS_ATTR_VARIABLE -2 ++#define OVS_COPY_ACTIONS_MAX_DEPTH 16 + + static bool actions_may_change_flow(const struct nlattr *actions) + { +@@ -2545,13 +2546,15 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log); ++ u32 mpls_label_count, bool log, ++ u32 depth); + + static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log, bool last) ++ u32 mpls_label_count, bool log, bool last, ++ u32 depth) + { + const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1]; + const struct nlattr *probability, *actions; +@@ -2602,7 +2605,8 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, + return err; + + err = __ovs_nla_copy_actions(net, actions, key, sfa, +- eth_type, vlan_tci, mpls_label_count, log); ++ eth_type, vlan_tci, mpls_label_count, log, ++ depth + 1); + + if (err) + return err; +@@ -2617,7 +2621,8 @@ static int validate_and_copy_dec_ttl(struct net *net, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log) ++ u32 mpls_label_count, bool log, ++ u32 depth) + { + const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1]; + int start, action_start, err, rem; +@@ -2660,7 +2665,8 @@ static int validate_and_copy_dec_ttl(struct net *net, + return action_start; + + err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type, +- vlan_tci, mpls_label_count, log); ++ vlan_tci, mpls_label_count, log, ++ depth + 1); + if (err) + return err; + +@@ -2674,7 +2680,8 @@ static int validate_and_copy_clone(struct net *net, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log, bool last) ++ u32 mpls_label_count, bool log, bool last, ++ u32 depth) + { + int start, err; + u32 exec; +@@ -2694,7 +2701,8 @@ static int validate_and_copy_clone(struct net *net, + return err; + + err = __ovs_nla_copy_actions(net, attr, key, sfa, +- eth_type, vlan_tci, mpls_label_count, log); ++ eth_type, vlan_tci, mpls_label_count, log, ++ depth + 1); + if (err) + return err; + +@@ -3063,7 +3071,7 @@ static int validate_and_copy_check_pkt_len(struct net *net, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, + u32 mpls_label_count, +- bool log, bool last) ++ bool log, bool last, u32 depth) + { + const struct nlattr *acts_if_greater, *acts_if_lesser_eq; + struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1]; +@@ -3111,7 +3119,8 @@ static int validate_and_copy_check_pkt_len(struct net *net, + return nested_acts_start; + + err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa, +- eth_type, vlan_tci, mpls_label_count, log); ++ eth_type, vlan_tci, mpls_label_count, log, ++ depth + 1); + + if (err) + return err; +@@ -3124,7 +3133,8 @@ static int validate_and_copy_check_pkt_len(struct net *net, + return nested_acts_start; + + err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa, +- eth_type, vlan_tci, mpls_label_count, log); ++ eth_type, vlan_tci, mpls_label_count, log, ++ depth + 1); + + if (err) + return err; +@@ -3152,12 +3162,16 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, + __be16 eth_type, __be16 vlan_tci, +- u32 mpls_label_count, bool log) ++ u32 mpls_label_count, bool log, ++ u32 depth) + { + u8 mac_proto = ovs_key_mac_proto(key); + const struct nlattr *a; + int rem, err; + ++ if (depth > OVS_COPY_ACTIONS_MAX_DEPTH) ++ return -EOVERFLOW; ++ + nla_for_each_nested(a, attr, rem) { + /* Expected argument lengths, (u32)-1 for variable length. */ + static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = { +@@ -3355,7 +3369,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + err = validate_and_copy_sample(net, a, key, sfa, + eth_type, vlan_tci, + mpls_label_count, +- log, last); ++ log, last, depth); + if (err) + return err; + skip_copy = true; +@@ -3426,7 +3440,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + err = validate_and_copy_clone(net, a, key, sfa, + eth_type, vlan_tci, + mpls_label_count, +- log, last); ++ log, last, depth); + if (err) + return err; + skip_copy = true; +@@ -3440,7 +3454,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + eth_type, + vlan_tci, + mpls_label_count, +- log, last); ++ log, last, ++ depth); + if (err) + return err; + skip_copy = true; +@@ -3450,7 +3465,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + case OVS_ACTION_ATTR_DEC_TTL: + err = validate_and_copy_dec_ttl(net, a, key, sfa, + eth_type, vlan_tci, +- mpls_label_count, log); ++ mpls_label_count, log, ++ depth); + if (err) + return err; + skip_copy = true; +@@ -3495,7 +3511,8 @@ int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, + + (*sfa)->orig_len = nla_len(attr); + err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type, +- key->eth.vlan.tci, mpls_label_count, log); ++ key->eth.vlan.tci, mpls_label_count, log, ++ 0); + if (err) + ovs_nla_free_flow_actions(*sfa); + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index dba523cdc73da..e1f8ff6e9a739 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -63,6 +63,7 @@ struct tls_decrypt_ctx { + u8 iv[MAX_IV_SIZE]; + u8 aad[TLS_MAX_AAD_SIZE]; + u8 tail; ++ bool free_sgout; + struct scatterlist sg[]; + }; + +@@ -187,7 +188,6 @@ static void tls_decrypt_done(void *data, int err) + struct aead_request *aead_req = data; + struct crypto_aead *aead = crypto_aead_reqtfm(aead_req); + struct scatterlist *sgout = aead_req->dst; +- struct scatterlist *sgin = aead_req->src; + struct tls_sw_context_rx *ctx; + struct tls_decrypt_ctx *dctx; + struct tls_context *tls_ctx; +@@ -196,6 +196,17 @@ static void tls_decrypt_done(void *data, int err) + struct sock *sk; + int aead_size; + ++ /* If requests get too backlogged crypto API returns -EBUSY and calls ++ * ->complete(-EINPROGRESS) immediately followed by ->complete(0) ++ * to make waiting for backlog to flush with crypto_wait_req() easier. ++ * First wait converts -EBUSY -> -EINPROGRESS, and the second one ++ * -EINPROGRESS -> 0. ++ * We have a single struct crypto_async_request per direction, this ++ * scheme doesn't help us, so just ignore the first ->complete(). ++ */ ++ if (err == -EINPROGRESS) ++ return; ++ + aead_size = sizeof(*aead_req) + crypto_aead_reqsize(aead); + aead_size = ALIGN(aead_size, __alignof__(*dctx)); + dctx = (void *)((u8 *)aead_req + aead_size); +@@ -213,7 +224,7 @@ static void tls_decrypt_done(void *data, int err) + } + + /* Free the destination pages if skb was not decrypted inplace */ +- if (sgout != sgin) { ++ if (dctx->free_sgout) { + /* Skip the first S/G entry as it points to AAD */ + for_each_sg(sg_next(sgout), sg, UINT_MAX, pages) { + if (!sg) +@@ -224,10 +235,17 @@ static void tls_decrypt_done(void *data, int err) + + kfree(aead_req); + +- spin_lock_bh(&ctx->decrypt_compl_lock); +- if (!atomic_dec_return(&ctx->decrypt_pending)) ++ if (atomic_dec_and_test(&ctx->decrypt_pending)) + complete(&ctx->async_wait.completion); +- spin_unlock_bh(&ctx->decrypt_compl_lock); ++} ++ ++static int tls_decrypt_async_wait(struct tls_sw_context_rx *ctx) ++{ ++ if (!atomic_dec_and_test(&ctx->decrypt_pending)) ++ crypto_wait_req(-EINPROGRESS, &ctx->async_wait); ++ atomic_inc(&ctx->decrypt_pending); ++ ++ return ctx->async_wait.err; + } + + static int tls_do_decryption(struct sock *sk, +@@ -253,6 +271,7 @@ static int tls_do_decryption(struct sock *sk, + aead_request_set_callback(aead_req, + CRYPTO_TFM_REQ_MAY_BACKLOG, + tls_decrypt_done, aead_req); ++ DEBUG_NET_WARN_ON_ONCE(atomic_read(&ctx->decrypt_pending) < 1); + atomic_inc(&ctx->decrypt_pending); + } else { + aead_request_set_callback(aead_req, +@@ -261,6 +280,10 @@ static int tls_do_decryption(struct sock *sk, + } + + ret = crypto_aead_decrypt(aead_req); ++ if (ret == -EBUSY) { ++ ret = tls_decrypt_async_wait(ctx); ++ ret = ret ?: -EINPROGRESS; ++ } + if (ret == -EINPROGRESS) { + if (darg->async) + return 0; +@@ -439,9 +462,10 @@ static void tls_encrypt_done(void *data, int err) + struct tls_rec *rec = data; + struct scatterlist *sge; + struct sk_msg *msg_en; +- bool ready = false; + struct sock *sk; +- int pending; ++ ++ if (err == -EINPROGRESS) /* see the comment in tls_decrypt_done() */ ++ return; + + msg_en = &rec->msg_encrypted; + +@@ -476,23 +500,25 @@ static void tls_encrypt_done(void *data, int err) + /* If received record is at head of tx_list, schedule tx */ + first_rec = list_first_entry(&ctx->tx_list, + struct tls_rec, list); +- if (rec == first_rec) +- ready = true; ++ if (rec == first_rec) { ++ /* Schedule the transmission */ ++ if (!test_and_set_bit(BIT_TX_SCHEDULED, ++ &ctx->tx_bitmask)) ++ schedule_delayed_work(&ctx->tx_work.work, 1); ++ } + } + +- spin_lock_bh(&ctx->encrypt_compl_lock); +- pending = atomic_dec_return(&ctx->encrypt_pending); +- +- if (!pending && ctx->async_notify) ++ if (atomic_dec_and_test(&ctx->encrypt_pending)) + complete(&ctx->async_wait.completion); +- spin_unlock_bh(&ctx->encrypt_compl_lock); ++} + +- if (!ready) +- return; ++static int tls_encrypt_async_wait(struct tls_sw_context_tx *ctx) ++{ ++ if (!atomic_dec_and_test(&ctx->encrypt_pending)) ++ crypto_wait_req(-EINPROGRESS, &ctx->async_wait); ++ atomic_inc(&ctx->encrypt_pending); + +- /* Schedule the transmission */ +- if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) +- schedule_delayed_work(&ctx->tx_work.work, 1); ++ return ctx->async_wait.err; + } + + static int tls_do_encryption(struct sock *sk, +@@ -541,9 +567,14 @@ static int tls_do_encryption(struct sock *sk, + + /* Add the record in tx_list */ + list_add_tail((struct list_head *)&rec->list, &ctx->tx_list); ++ DEBUG_NET_WARN_ON_ONCE(atomic_read(&ctx->encrypt_pending) < 1); + atomic_inc(&ctx->encrypt_pending); + + rc = crypto_aead_encrypt(aead_req); ++ if (rc == -EBUSY) { ++ rc = tls_encrypt_async_wait(ctx); ++ rc = rc ?: -EINPROGRESS; ++ } + if (!rc || rc != -EINPROGRESS) { + atomic_dec(&ctx->encrypt_pending); + sge->offset -= prot->prepend_size; +@@ -984,7 +1015,6 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg, + int num_zc = 0; + int orig_size; + int ret = 0; +- int pending; + + if (!eor && (msg->msg_flags & MSG_EOR)) + return -EINVAL; +@@ -1163,24 +1193,12 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg, + if (!num_async) { + goto send_end; + } else if (num_zc) { +- /* Wait for pending encryptions to get completed */ +- spin_lock_bh(&ctx->encrypt_compl_lock); +- ctx->async_notify = true; +- +- pending = atomic_read(&ctx->encrypt_pending); +- spin_unlock_bh(&ctx->encrypt_compl_lock); +- if (pending) +- crypto_wait_req(-EINPROGRESS, &ctx->async_wait); +- else +- reinit_completion(&ctx->async_wait.completion); +- +- /* There can be no concurrent accesses, since we have no +- * pending encrypt operations +- */ +- WRITE_ONCE(ctx->async_notify, false); ++ int err; + +- if (ctx->async_wait.err) { +- ret = ctx->async_wait.err; ++ /* Wait for pending encryptions to get completed */ ++ err = tls_encrypt_async_wait(ctx); ++ if (err) { ++ ret = err; + copied = 0; + } + } +@@ -1229,7 +1247,6 @@ void tls_sw_splice_eof(struct socket *sock) + ssize_t copied = 0; + bool retrying = false; + int ret = 0; +- int pending; + + if (!ctx->open_rec) + return; +@@ -1264,22 +1281,7 @@ void tls_sw_splice_eof(struct socket *sock) + } + + /* Wait for pending encryptions to get completed */ +- spin_lock_bh(&ctx->encrypt_compl_lock); +- ctx->async_notify = true; +- +- pending = atomic_read(&ctx->encrypt_pending); +- spin_unlock_bh(&ctx->encrypt_compl_lock); +- if (pending) +- crypto_wait_req(-EINPROGRESS, &ctx->async_wait); +- else +- reinit_completion(&ctx->async_wait.completion); +- +- /* There can be no concurrent accesses, since we have no pending +- * encrypt operations +- */ +- WRITE_ONCE(ctx->async_notify, false); +- +- if (ctx->async_wait.err) ++ if (tls_encrypt_async_wait(ctx)) + goto unlock; + + /* Transmit if any encryptions have completed */ +@@ -1581,6 +1583,7 @@ static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov, + } else if (out_sg) { + memcpy(sgout, out_sg, n_sgout * sizeof(*sgout)); + } ++ dctx->free_sgout = !!pages; + + /* Prepare and submit AEAD request */ + err = tls_do_decryption(sk, sgin, sgout, dctx->iv, +@@ -2109,16 +2112,10 @@ int tls_sw_recvmsg(struct sock *sk, + + recv_end: + if (async) { +- int ret, pending; ++ int ret; + + /* Wait for all previously submitted records to be decrypted */ +- spin_lock_bh(&ctx->decrypt_compl_lock); +- reinit_completion(&ctx->async_wait.completion); +- pending = atomic_read(&ctx->decrypt_pending); +- spin_unlock_bh(&ctx->decrypt_compl_lock); +- ret = 0; +- if (pending) +- ret = crypto_wait_req(-EINPROGRESS, &ctx->async_wait); ++ ret = tls_decrypt_async_wait(ctx); + __skb_queue_purge(&ctx->async_hold); + + if (ret) { +@@ -2135,7 +2132,6 @@ int tls_sw_recvmsg(struct sock *sk, + else + err = process_rx_list(ctx, msg, &control, 0, + async_copy_bytes, is_peek); +- decrypted += max(err, 0); + } + + copied += decrypted; +@@ -2435,16 +2431,9 @@ void tls_sw_release_resources_tx(struct sock *sk) + struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec, *tmp; +- int pending; + + /* Wait for any pending async encryptions to complete */ +- spin_lock_bh(&ctx->encrypt_compl_lock); +- ctx->async_notify = true; +- pending = atomic_read(&ctx->encrypt_pending); +- spin_unlock_bh(&ctx->encrypt_compl_lock); +- +- if (pending) +- crypto_wait_req(-EINPROGRESS, &ctx->async_wait); ++ tls_encrypt_async_wait(ctx); + + tls_tx_records(sk, -1); + +@@ -2597,6 +2586,48 @@ void tls_update_rx_zc_capable(struct tls_context *tls_ctx) + tls_ctx->prot_info.version != TLS_1_3_VERSION; + } + ++static struct tls_sw_context_tx *init_ctx_tx(struct tls_context *ctx, struct sock *sk) ++{ ++ struct tls_sw_context_tx *sw_ctx_tx; ++ ++ if (!ctx->priv_ctx_tx) { ++ sw_ctx_tx = kzalloc(sizeof(*sw_ctx_tx), GFP_KERNEL); ++ if (!sw_ctx_tx) ++ return NULL; ++ } else { ++ sw_ctx_tx = ctx->priv_ctx_tx; ++ } ++ ++ crypto_init_wait(&sw_ctx_tx->async_wait); ++ atomic_set(&sw_ctx_tx->encrypt_pending, 1); ++ INIT_LIST_HEAD(&sw_ctx_tx->tx_list); ++ INIT_DELAYED_WORK(&sw_ctx_tx->tx_work.work, tx_work_handler); ++ sw_ctx_tx->tx_work.sk = sk; ++ ++ return sw_ctx_tx; ++} ++ ++static struct tls_sw_context_rx *init_ctx_rx(struct tls_context *ctx) ++{ ++ struct tls_sw_context_rx *sw_ctx_rx; ++ ++ if (!ctx->priv_ctx_rx) { ++ sw_ctx_rx = kzalloc(sizeof(*sw_ctx_rx), GFP_KERNEL); ++ if (!sw_ctx_rx) ++ return NULL; ++ } else { ++ sw_ctx_rx = ctx->priv_ctx_rx; ++ } ++ ++ crypto_init_wait(&sw_ctx_rx->async_wait); ++ atomic_set(&sw_ctx_rx->decrypt_pending, 1); ++ init_waitqueue_head(&sw_ctx_rx->wq); ++ skb_queue_head_init(&sw_ctx_rx->rx_list); ++ skb_queue_head_init(&sw_ctx_rx->async_hold); ++ ++ return sw_ctx_rx; ++} ++ + int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) + { + struct tls_context *tls_ctx = tls_get_ctx(sk); +@@ -2618,48 +2649,22 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) + } + + if (tx) { +- if (!ctx->priv_ctx_tx) { +- sw_ctx_tx = kzalloc(sizeof(*sw_ctx_tx), GFP_KERNEL); +- if (!sw_ctx_tx) { +- rc = -ENOMEM; +- goto out; +- } +- ctx->priv_ctx_tx = sw_ctx_tx; +- } else { +- sw_ctx_tx = +- (struct tls_sw_context_tx *)ctx->priv_ctx_tx; +- } +- } else { +- if (!ctx->priv_ctx_rx) { +- sw_ctx_rx = kzalloc(sizeof(*sw_ctx_rx), GFP_KERNEL); +- if (!sw_ctx_rx) { +- rc = -ENOMEM; +- goto out; +- } +- ctx->priv_ctx_rx = sw_ctx_rx; +- } else { +- sw_ctx_rx = +- (struct tls_sw_context_rx *)ctx->priv_ctx_rx; +- } +- } ++ ctx->priv_ctx_tx = init_ctx_tx(ctx, sk); ++ if (!ctx->priv_ctx_tx) ++ return -ENOMEM; + +- if (tx) { +- crypto_init_wait(&sw_ctx_tx->async_wait); +- spin_lock_init(&sw_ctx_tx->encrypt_compl_lock); ++ sw_ctx_tx = ctx->priv_ctx_tx; + crypto_info = &ctx->crypto_send.info; + cctx = &ctx->tx; + aead = &sw_ctx_tx->aead_send; +- INIT_LIST_HEAD(&sw_ctx_tx->tx_list); +- INIT_DELAYED_WORK(&sw_ctx_tx->tx_work.work, tx_work_handler); +- sw_ctx_tx->tx_work.sk = sk; + } else { +- crypto_init_wait(&sw_ctx_rx->async_wait); +- spin_lock_init(&sw_ctx_rx->decrypt_compl_lock); +- init_waitqueue_head(&sw_ctx_rx->wq); ++ ctx->priv_ctx_rx = init_ctx_rx(ctx); ++ if (!ctx->priv_ctx_rx) ++ return -ENOMEM; ++ ++ sw_ctx_rx = ctx->priv_ctx_rx; + crypto_info = &ctx->crypto_recv.info; + cctx = &ctx->rx; +- skb_queue_head_init(&sw_ctx_rx->rx_list); +- skb_queue_head_init(&sw_ctx_rx->async_hold); + aead = &sw_ctx_rx->aead_recv; + } + +diff --git a/net/wireless/core.c b/net/wireless/core.c +index f6ada0a729778..ff743e1f2e2cb 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -1675,6 +1675,7 @@ void wiphy_delayed_work_queue(struct wiphy *wiphy, + unsigned long delay) + { + if (!delay) { ++ del_timer(&dwork->timer); + wiphy_work_queue(wiphy, &dwork->work); + return; + } +diff --git a/samples/bpf/asm_goto_workaround.h b/samples/bpf/asm_goto_workaround.h +index 7048bb3594d65..634e81d83efd9 100644 +--- a/samples/bpf/asm_goto_workaround.h ++++ b/samples/bpf/asm_goto_workaround.h +@@ -4,14 +4,14 @@ + #define __ASM_GOTO_WORKAROUND_H + + /* +- * This will bring in asm_volatile_goto and asm_inline macro definitions ++ * This will bring in asm_goto_output and asm_inline macro definitions + * if enabled by compiler and config options. + */ + #include <linux/types.h> + +-#ifdef asm_volatile_goto +-#undef asm_volatile_goto +-#define asm_volatile_goto(x...) asm volatile("invalid use of asm_volatile_goto") ++#ifdef asm_goto_output ++#undef asm_goto_output ++#define asm_goto_output(x...) asm volatile("invalid use of asm_goto_output") + #endif + + /* +diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh +index a432b171be826..7862a81017477 100755 +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -135,8 +135,13 @@ gen_btf() + ${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \ + --strip-all ${1} ${2} 2>/dev/null + # Change e_type to ET_REL so that it can be used to link final vmlinux. +- # Unlike GNU ld, lld does not allow an ET_EXEC input. +- printf '\1' | dd of=${2} conv=notrunc bs=1 seek=16 status=none ++ # GNU ld 2.35+ and lld do not allow an ET_EXEC input. ++ if is_enabled CONFIG_CPU_BIG_ENDIAN; then ++ et_rel='\0\1' ++ else ++ et_rel='\1\0' ++ fi ++ printf "${et_rel}" | dd of=${2} conv=notrunc bs=1 seek=16 status=none + } + + # Create ${2} .S file with all symbols from the ${1} object file +diff --git a/scripts/mksysmap b/scripts/mksysmap +index 9ba1c9da0a40f..57ff5656d566f 100755 +--- a/scripts/mksysmap ++++ b/scripts/mksysmap +@@ -48,17 +48,8 @@ ${NM} -n ${1} | sed >${2} -e " + / __kvm_nvhe_\\$/d + / __kvm_nvhe_\.L/d + +-# arm64 lld +-/ __AArch64ADRPThunk_/d +- +-# arm lld +-/ __ARMV5PILongThunk_/d +-/ __ARMV7PILongThunk_/d +-/ __ThumbV7PILongThunk_/d +- +-# mips lld +-/ __LA25Thunk_/d +-/ __microLA25Thunk_/d ++# lld arm/aarch64/mips thunks ++/ __[[:alnum:]]*Thunk_/d + + # CFI type identifiers + / __kcfi_typeid_/d +diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c +index ac4ef3e206bbd..5191fdbd3fa23 100644 +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -798,7 +798,7 @@ static void check_section(const char *modname, struct elf_info *elf, + #define ALL_INIT_TEXT_SECTIONS \ + ".init.text", ".meminit.text" + #define ALL_EXIT_TEXT_SECTIONS \ +- ".exit.text", ".memexit.text" ++ ".exit.text" + + #define ALL_PCI_INIT_SECTIONS \ + ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \ +@@ -806,14 +806,14 @@ static void check_section(const char *modname, struct elf_info *elf, + ".pci_fixup_resume_early", ".pci_fixup_suspend" + + #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS +-#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS + + #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS +-#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS ++#define ALL_EXIT_SECTIONS EXIT_SECTIONS + + #define DATA_SECTIONS ".data", ".data.rel" + #define TEXT_SECTIONS ".text", ".text.*", ".sched.text", \ +- ".kprobes.text", ".cpuidle.text", ".noinstr.text" ++ ".kprobes.text", ".cpuidle.text", ".noinstr.text", \ ++ ".ltext", ".ltext.*" + #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ + ".fixup", ".entry.text", ".exception.text", \ + ".coldtext", ".softirqentry.text" +@@ -822,7 +822,6 @@ static void check_section(const char *modname, struct elf_info *elf, + #define MEM_INIT_SECTIONS ".meminit.*" + + #define EXIT_SECTIONS ".exit.*" +-#define MEM_EXIT_SECTIONS ".memexit.*" + + #define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \ + TEXT_SECTIONS, OTHER_TEXT_SECTIONS +@@ -832,7 +831,6 @@ enum mismatch { + DATA_TO_ANY_INIT, + TEXTDATA_TO_ANY_EXIT, + XXXINIT_TO_SOME_INIT, +- XXXEXIT_TO_SOME_EXIT, + ANY_INIT_TO_ANY_EXIT, + ANY_EXIT_TO_ANY_INIT, + EXTABLE_TO_NON_TEXT, +@@ -883,12 +881,6 @@ static const struct sectioncheck sectioncheck[] = { + .bad_tosec = { INIT_SECTIONS, NULL }, + .mismatch = XXXINIT_TO_SOME_INIT, + }, +-/* Do not reference exit code/data from memexit code/data */ +-{ +- .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, +- .bad_tosec = { EXIT_SECTIONS, NULL }, +- .mismatch = XXXEXIT_TO_SOME_EXIT, +-}, + /* Do not use exit code/data from init code */ + { + .fromsec = { ALL_INIT_SECTIONS, NULL }, +@@ -1017,7 +1009,7 @@ static int secref_whitelist(const char *fromsec, const char *fromsym, + + /* symbols in data sections that may refer to meminit sections */ + if (match(fromsec, PATTERNS(DATA_SECTIONS)) && +- match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_XXXEXIT_SECTIONS)) && ++ match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS)) && + match(fromsym, PATTERNS("*driver"))) + return 0; + +diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c +index 31066bfdba04e..dc4878502276c 100644 +--- a/scripts/mod/sumversion.c ++++ b/scripts/mod/sumversion.c +@@ -326,7 +326,12 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) + + /* Sum all files in the same dir or subdirs. */ + while ((line = get_line(&pos))) { +- char* p = line; ++ char* p; ++ ++ /* trim the leading spaces away */ ++ while (isspace(*line)) ++ line++; ++ p = line; + + if (strncmp(line, "source_", sizeof("source_")-1) == 0) { + p = strrchr(line, ' '); +diff --git a/security/security.c b/security/security.c +index 840a3d58a2902..407b51719f797 100644 +--- a/security/security.c ++++ b/security/security.c +@@ -4030,7 +4030,19 @@ EXPORT_SYMBOL(security_inode_setsecctx); + */ + int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) + { +- return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen); ++ struct security_hook_list *hp; ++ int rc; ++ ++ /* ++ * Only one module will provide a security context. ++ */ ++ hlist_for_each_entry(hp, &security_hook_heads.inode_getsecctx, list) { ++ rc = hp->hook.inode_getsecctx(inode, ctx, ctxlen); ++ if (rc != LSM_RET_DEFAULT(inode_getsecctx)) ++ return rc; ++ } ++ ++ return LSM_RET_DEFAULT(inode_getsecctx); + } + EXPORT_SYMBOL(security_inode_getsecctx); + +@@ -4387,8 +4399,20 @@ EXPORT_SYMBOL(security_sock_rcv_skb); + int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, + sockptr_t optlen, unsigned int len) + { +- return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock, +- optval, optlen, len); ++ struct security_hook_list *hp; ++ int rc; ++ ++ /* ++ * Only one module will provide a security context. ++ */ ++ hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream, ++ list) { ++ rc = hp->hook.socket_getpeersec_stream(sock, optval, optlen, ++ len); ++ if (rc != LSM_RET_DEFAULT(socket_getpeersec_stream)) ++ return rc; ++ } ++ return LSM_RET_DEFAULT(socket_getpeersec_stream); + } + + /** +@@ -4408,8 +4432,19 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, + int security_socket_getpeersec_dgram(struct socket *sock, + struct sk_buff *skb, u32 *secid) + { +- return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock, +- skb, secid); ++ struct security_hook_list *hp; ++ int rc; ++ ++ /* ++ * Only one module will provide a security context. ++ */ ++ hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram, ++ list) { ++ rc = hp->hook.socket_getpeersec_dgram(sock, skb, secid); ++ if (rc != LSM_RET_DEFAULT(socket_getpeersec_dgram)) ++ return rc; ++ } ++ return LSM_RET_DEFAULT(socket_getpeersec_dgram); + } + EXPORT_SYMBOL(security_socket_getpeersec_dgram); + +diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig +index 0d7502d6e0604..21046f72cdca9 100644 +--- a/sound/pci/hda/Kconfig ++++ b/sound/pci/hda/Kconfig +@@ -140,7 +140,7 @@ config SND_HDA_SCODEC_CS35L56_I2C + depends on I2C + depends on ACPI || COMPILE_TEST + depends on SND_SOC +- select CS_DSP ++ select FW_CS_DSP + select SND_HDA_GENERIC + select SND_SOC_CS35L56_SHARED + select SND_HDA_SCODEC_CS35L56 +@@ -154,7 +154,7 @@ config SND_HDA_SCODEC_CS35L56_SPI + depends on SPI_MASTER + depends on ACPI || COMPILE_TEST + depends on SND_SOC +- select CS_DSP ++ select FW_CS_DSP + select SND_HDA_GENERIC + select SND_SOC_CS35L56_SHARED + select SND_HDA_SCODEC_CS35L56 +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index e8819e8a98763..e8209178d87bb 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -344,6 +344,7 @@ enum { + CXT_FIXUP_HP_ZBOOK_MUTE_LED, + CXT_FIXUP_HEADSET_MIC, + CXT_FIXUP_HP_MIC_NO_PRESENCE, ++ CXT_PINCFG_SWS_JS201D, + }; + + /* for hda_fixup_thinkpad_acpi() */ +@@ -841,6 +842,17 @@ static const struct hda_pintbl cxt_pincfg_lemote[] = { + {} + }; + ++/* SuoWoSi/South-holding JS201D with sn6140 */ ++static const struct hda_pintbl cxt_pincfg_sws_js201d[] = { ++ { 0x16, 0x03211040 }, /* hp out */ ++ { 0x17, 0x91170110 }, /* SPK/Class_D */ ++ { 0x18, 0x95a70130 }, /* Internal mic */ ++ { 0x19, 0x03a11020 }, /* Headset Mic */ ++ { 0x1a, 0x40f001f0 }, /* Not used */ ++ { 0x21, 0x40f001f0 }, /* Not used */ ++ {} ++}; ++ + static const struct hda_fixup cxt_fixups[] = { + [CXT_PINCFG_LENOVO_X200] = { + .type = HDA_FIXUP_PINS, +@@ -996,6 +1008,10 @@ static const struct hda_fixup cxt_fixups[] = { + .chained = true, + .chain_id = CXT_FIXUP_HEADSET_MIC, + }, ++ [CXT_PINCFG_SWS_JS201D] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = cxt_pincfg_sws_js201d, ++ }, + }; + + static const struct snd_pci_quirk cxt5045_fixups[] = { +@@ -1069,6 +1085,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { + SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), ++ SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D), + SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), + SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), + SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), +@@ -1109,6 +1126,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { + { .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" }, + { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" }, + { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" }, ++ { .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" }, + {} + }; + +diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c +index 627899959ffe8..e41316e2e9833 100644 +--- a/sound/pci/hda/patch_cs8409.c ++++ b/sound/pci/hda/patch_cs8409.c +@@ -1371,6 +1371,7 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac + spec->scodecs[CS8409_CODEC1] = &dolphin_cs42l42_1; + spec->scodecs[CS8409_CODEC1]->codec = codec; + spec->num_scodecs = 2; ++ spec->gen.suppress_vmaster = 1; + + codec->patch_ops = cs8409_dolphin_patch_ops; + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 375569d0864b3..0cb8ccdabc095 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -438,6 +438,10 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) + alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); + fallthrough; + case 0x10ec0215: ++ case 0x10ec0285: ++ case 0x10ec0289: ++ alc_update_coef_idx(codec, 0x36, 1<<13, 0); ++ fallthrough; + case 0x10ec0230: + case 0x10ec0233: + case 0x10ec0235: +@@ -451,9 +455,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) + case 0x10ec0283: + case 0x10ec0286: + case 0x10ec0288: +- case 0x10ec0285: + case 0x10ec0298: +- case 0x10ec0289: + case 0x10ec0300: + alc_update_coef_idx(codec, 0x10, 1<<9, 0); + break; +@@ -9479,7 +9481,7 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_i2c_two, + .chained = true, +- .chain_id = ALC269_FIXUP_THINKPAD_ACPI, ++ .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, + }, + [ALC287_FIXUP_TAS2781_I2C] = { + .type = HDA_FIXUP_FUNC, +@@ -9500,6 +9502,8 @@ static const struct hda_fixup alc269_fixups[] = { + [ALC287_FIXUP_THINKPAD_I2S_SPK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc287_fixup_bind_dacs, ++ .chained = true, ++ .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, + }, + [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = { + .type = HDA_FIXUP_FUNC, +@@ -9549,6 +9553,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS), + SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1025, 0x1269, "Acer SWIFT SF314-54", ALC256_FIXUP_ACER_HEADSET_MIC), ++ SND_PCI_QUIRK(0x1025, 0x126a, "Acer Swift SF114-32", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1025, 0x128f, "Acer Veriton Z6860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), +@@ -9626,6 +9631,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS), + SND_PCI_QUIRK(0x1028, 0x0beb, "Dell XPS 15 9530 (2023)", ALC289_FIXUP_DELL_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE), ++ SND_PCI_QUIRK(0x1028, 0x0c0b, "Dell Oasis 14 RPL-P", ALC289_FIXUP_RTK_AMP_DUAL_SPK), ++ SND_PCI_QUIRK(0x1028, 0x0c0d, "Dell Oasis", ALC289_FIXUP_RTK_AMP_DUAL_SPK), ++ SND_PCI_QUIRK(0x1028, 0x0c0e, "Dell Oasis 16", ALC289_FIXUP_RTK_AMP_DUAL_SPK), + SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS), + SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS), + SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS), +@@ -9745,6 +9753,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8786, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8787, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), ++ SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), +@@ -9814,6 +9823,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), ++ SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), +@@ -9821,6 +9831,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8b45, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8b46, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8b47, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), ++ SND_PCI_QUIRK(0x103c, 0x8b59, "HP Elite mt645 G7 Mobile Thin Client U89", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8b63, "HP Elite Dragonfly 13.5 inch G4", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), +@@ -9850,6 +9861,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), ++ SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED), ++ SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), +@@ -10200,6 +10213,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), + SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO), ++ SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME), + SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), + SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), + SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), +diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c +index 731664fc8b217..26928d5ae5f70 100644 +--- a/sound/pci/hda/tas2781_hda_i2c.c ++++ b/sound/pci/hda/tas2781_hda_i2c.c +@@ -627,7 +627,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, + + strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + +- ret = tascodec_init(tas_hda->priv, codec, tasdev_fw_ready); ++ ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready); + if (!ret) + comps->playback_hook = tas2781_hda_playback_hook; + +diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c +index d83cb6e4c62ae..80ad60d485ea0 100644 +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -248,6 +248,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "82YM"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "83AS"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +@@ -297,6 +304,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 B7ED"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7VF"), ++ } ++ }, + { + .driver_data = &acp6x_card, + .matches = { +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index edcb85bd8ea7f..ea08b7cfc31da 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3314,6 +3314,7 @@ static void rt5645_jack_detect_work(struct work_struct *work) + report, SND_JACK_HEADPHONE); + snd_soc_jack_report(rt5645->mic_jack, + report, SND_JACK_MICROPHONE); ++ mutex_unlock(&rt5645->jd_mutex); + return; + case 4: + val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; +diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c +index 00e35169ae495..add16302f711e 100644 +--- a/sound/soc/codecs/tas2781-comlib.c ++++ b/sound/soc/codecs/tas2781-comlib.c +@@ -267,6 +267,7 @@ void tas2781_reset(struct tasdevice_priv *tas_dev) + EXPORT_SYMBOL_GPL(tas2781_reset); + + int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, ++ struct module *module, + void (*cont)(const struct firmware *fw, void *context)) + { + int ret = 0; +@@ -280,7 +281,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, + tas_priv->dev_name, tas_priv->ndev); + crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL); + tas_priv->codec = codec; +- ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, ++ ret = request_firmware_nowait(module, FW_ACTION_UEVENT, + tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv, + cont); + if (ret) +diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c +index 917b1c15f71d4..2f7f8b18c36fa 100644 +--- a/sound/soc/codecs/tas2781-i2c.c ++++ b/sound/soc/codecs/tas2781-i2c.c +@@ -564,7 +564,7 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec) + { + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + +- return tascodec_init(tas_priv, codec, tasdevice_fw_ready); ++ return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready); + } + + static void tasdevice_deinit(void *context) +diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c +index 23d06338f716f..7df1719e07239 100644 +--- a/sound/soc/codecs/wcd938x.c ++++ b/sound/soc/codecs/wcd938x.c +@@ -3589,7 +3589,7 @@ static int wcd938x_probe(struct platform_device *pdev) + ret = wcd938x_populate_dt_data(wcd938x, dev); + if (ret) { + dev_err(dev, "%s: Fail to obtain platform data\n", __func__); +- return -EINVAL; ++ return ret; + } + + ret = wcd938x_add_slave_components(wcd938x, dev, &match); +diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c +index 2c7a5e7a364cf..d96555438c6bf 100644 +--- a/sound/soc/sof/ipc3-topology.c ++++ b/sound/soc/sof/ipc3-topology.c +@@ -2309,27 +2309,16 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) + return 0; + } + +-/* +- * For older firmware, this function doesn't free widgets for static pipelines during suspend. +- * It only resets use_count for all widgets. +- */ +-static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) ++static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler, ++ bool *dyn_widgets, bool verify) + { + struct sof_ipc_fw_version *v = &sdev->fw_ready.version; + struct snd_sof_widget *swidget; +- struct snd_sof_route *sroute; +- bool dyn_widgets = false; + int ret; + +- /* +- * This function is called during suspend and for one-time topology verification during +- * first boot. In both cases, there is no need to protect swidget->use_count and +- * sroute->setup because during suspend all running streams are suspended and during +- * topology loading the sound card unavailable to open PCMs. +- */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->dynamic_pipeline_widget) { +- dyn_widgets = true; ++ *dyn_widgets = true; + continue; + } + +@@ -2344,11 +2333,49 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif + continue; + } + ++ if (include_scheduler && swidget->id != snd_soc_dapm_scheduler) ++ continue; ++ ++ if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler) ++ continue; ++ + ret = sof_widget_free(sdev, swidget); + if (ret < 0) + return ret; + } + ++ return 0; ++} ++ ++/* ++ * For older firmware, this function doesn't free widgets for static pipelines during suspend. ++ * It only resets use_count for all widgets. ++ */ ++static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) ++{ ++ struct sof_ipc_fw_version *v = &sdev->fw_ready.version; ++ struct snd_sof_widget *swidget; ++ struct snd_sof_route *sroute; ++ bool dyn_widgets = false; ++ int ret; ++ ++ /* ++ * This function is called during suspend and for one-time topology verification during ++ * first boot. In both cases, there is no need to protect swidget->use_count and ++ * sroute->setup because during suspend all running streams are suspended and during ++ * topology loading the sound card unavailable to open PCMs. Do not free the scheduler ++ * widgets yet so that the secondary cores do not get powered down before all the widgets ++ * associated with the scheduler are freed. ++ */ ++ ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify); ++ if (ret < 0) ++ return ret; ++ ++ /* free all the scheduler widgets now */ ++ ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify); ++ if (ret < 0) ++ return ret; ++ + /* + * Tear down all pipelines associated with PCMs that did not get suspended + * and unset the prepare flag so that they can be set up again during resume. +diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c +index fb40378ad0840..c03dd513fbff1 100644 +--- a/sound/soc/sof/ipc3.c ++++ b/sound/soc/sof/ipc3.c +@@ -1067,7 +1067,7 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev) + return; + } + +- if (hdr.size < sizeof(hdr)) { ++ if (hdr.size < sizeof(hdr) || hdr.size > SOF_IPC_MSG_MAX_SIZE) { + dev_err(sdev->dev, "The received message size is invalid\n"); + return; + } +diff --git a/tools/arch/x86/include/asm/rmwcc.h b/tools/arch/x86/include/asm/rmwcc.h +index 11ff975242cac..e2ff22b379a44 100644 +--- a/tools/arch/x86/include/asm/rmwcc.h ++++ b/tools/arch/x86/include/asm/rmwcc.h +@@ -4,7 +4,7 @@ + + #define __GEN_RMWcc(fullop, var, cc, ...) \ + do { \ +- asm_volatile_goto (fullop "; j" cc " %l[cc_label]" \ ++ asm goto (fullop "; j" cc " %l[cc_label]" \ + : : "m" (var), ## __VA_ARGS__ \ + : "memory" : cc_label); \ + return 0; \ +diff --git a/tools/include/linux/compiler_types.h b/tools/include/linux/compiler_types.h +index 1bdd834bdd571..d09f9dc172a48 100644 +--- a/tools/include/linux/compiler_types.h ++++ b/tools/include/linux/compiler_types.h +@@ -36,8 +36,8 @@ + #include <linux/compiler-gcc.h> + #endif + +-#ifndef asm_volatile_goto +-#define asm_volatile_goto(x...) asm goto(x) ++#ifndef asm_goto_output ++#define asm_goto_output(x...) asm goto(x) + #endif + + #endif /* __LINUX_COMPILER_TYPES_H */ +diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c +index 936f3a8d1b83e..e96fababd3f06 100644 +--- a/tools/testing/selftests/kvm/dirty_log_test.c ++++ b/tools/testing/selftests/kvm/dirty_log_test.c +@@ -376,7 +376,10 @@ static void dirty_ring_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, + + cleared = kvm_vm_reset_dirty_ring(vcpu->vm); + +- /* Cleared pages should be the same as collected */ ++ /* ++ * Cleared pages should be the same as collected, as KVM is supposed to ++ * clear only the entries that have been harvested. ++ */ + TEST_ASSERT(cleared == count, "Reset dirty pages (%u) mismatch " + "with collected (%u)", cleared, count); + +@@ -415,12 +418,6 @@ static void dirty_ring_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) + } + } + +-static void dirty_ring_before_vcpu_join(void) +-{ +- /* Kick another round of vcpu just to make sure it will quit */ +- sem_post(&sem_vcpu_cont); +-} +- + struct log_mode { + const char *name; + /* Return true if this mode is supported, otherwise false */ +@@ -433,7 +430,6 @@ struct log_mode { + uint32_t *ring_buf_idx); + /* Hook to call when after each vcpu run */ + void (*after_vcpu_run)(struct kvm_vcpu *vcpu, int ret, int err); +- void (*before_vcpu_join) (void); + } log_modes[LOG_MODE_NUM] = { + { + .name = "dirty-log", +@@ -452,7 +448,6 @@ struct log_mode { + .supported = dirty_ring_supported, + .create_vm_done = dirty_ring_create_vm_done, + .collect_dirty_pages = dirty_ring_collect_dirty_pages, +- .before_vcpu_join = dirty_ring_before_vcpu_join, + .after_vcpu_run = dirty_ring_after_vcpu_run, + }, + }; +@@ -513,14 +508,6 @@ static void log_mode_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) + mode->after_vcpu_run(vcpu, ret, err); + } + +-static void log_mode_before_vcpu_join(void) +-{ +- struct log_mode *mode = &log_modes[host_log_mode]; +- +- if (mode->before_vcpu_join) +- mode->before_vcpu_join(); +-} +- + static void generate_random_array(uint64_t *guest_array, uint64_t size) + { + uint64_t i; +@@ -719,6 +706,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) + struct kvm_vm *vm; + unsigned long *bmap; + uint32_t ring_buf_idx = 0; ++ int sem_val; + + if (!log_mode_supported()) { + print_skip("Log mode '%s' not supported", +@@ -788,12 +776,22 @@ static void run_test(enum vm_guest_mode mode, void *arg) + /* Start the iterations */ + iteration = 1; + sync_global_to_guest(vm, iteration); +- host_quit = false; ++ WRITE_ONCE(host_quit, false); + host_dirty_count = 0; + host_clear_count = 0; + host_track_next_count = 0; + WRITE_ONCE(dirty_ring_vcpu_ring_full, false); + ++ /* ++ * Ensure the previous iteration didn't leave a dangling semaphore, i.e. ++ * that the main task and vCPU worker were synchronized and completed ++ * verification of all iterations. ++ */ ++ sem_getvalue(&sem_vcpu_stop, &sem_val); ++ TEST_ASSERT_EQ(sem_val, 0); ++ sem_getvalue(&sem_vcpu_cont, &sem_val); ++ TEST_ASSERT_EQ(sem_val, 0); ++ + pthread_create(&vcpu_thread, NULL, vcpu_worker, vcpu); + + while (iteration < p->iterations) { +@@ -819,15 +817,21 @@ static void run_test(enum vm_guest_mode mode, void *arg) + assert(host_log_mode == LOG_MODE_DIRTY_RING || + atomic_read(&vcpu_sync_stop_requested) == false); + vm_dirty_log_verify(mode, bmap); +- sem_post(&sem_vcpu_cont); + +- iteration++; ++ /* ++ * Set host_quit before sem_vcpu_cont in the final iteration to ++ * ensure that the vCPU worker doesn't resume the guest. As ++ * above, the dirty ring test may stop and wait even when not ++ * explicitly request to do so, i.e. would hang waiting for a ++ * "continue" if it's allowed to resume the guest. ++ */ ++ if (++iteration == p->iterations) ++ WRITE_ONCE(host_quit, true); ++ ++ sem_post(&sem_vcpu_cont); + sync_global_to_guest(vm, iteration); + } + +- /* Tell the vcpu thread to quit */ +- host_quit = true; +- log_mode_before_vcpu_join(); + pthread_join(vcpu_thread, NULL); + + pr_info("Total bits checked: dirty (%"PRIu64"), clear (%"PRIu64"), " +diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c +index 11329e5ff945e..309ee5c72b46a 100644 +--- a/tools/testing/selftests/kvm/x86_64/amx_test.c ++++ b/tools/testing/selftests/kvm/x86_64/amx_test.c +@@ -221,7 +221,7 @@ int main(int argc, char *argv[]) + vm_vaddr_t amx_cfg, tiledata, xstate; + struct ucall uc; + u32 amx_offset; +- int stage, ret; ++ int ret; + + /* + * Note, all off-by-default features must be enabled before anything +@@ -263,7 +263,7 @@ int main(int argc, char *argv[]) + memset(addr_gva2hva(vm, xstate), 0, PAGE_SIZE * DIV_ROUND_UP(XSAVE_SIZE, PAGE_SIZE)); + vcpu_args_set(vcpu, 3, amx_cfg, tiledata, xstate); + +- for (stage = 1; ; stage++) { ++ for (;;) { + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + +diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c +index 9f28aa276c4e2..a726831b80244 100644 +--- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c ++++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c +@@ -454,7 +454,7 @@ static void guest_test_msrs_access(void) + case 44: + /* MSR is not available when CPUID feature bit is unset */ + if (!has_invtsc) +- continue; ++ goto next_stage; + msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL; + msr->write = false; + msr->fault_expected = true; +@@ -462,7 +462,7 @@ static void guest_test_msrs_access(void) + case 45: + /* MSR is vailable when CPUID feature bit is set */ + if (!has_invtsc) +- continue; ++ goto next_stage; + vcpu_set_cpuid_feature(vcpu, HV_ACCESS_TSC_INVARIANT); + msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL; + msr->write = false; +@@ -471,7 +471,7 @@ static void guest_test_msrs_access(void) + case 46: + /* Writing bits other than 0 is forbidden */ + if (!has_invtsc) +- continue; ++ goto next_stage; + msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL; + msr->write = true; + msr->write_val = 0xdeadbeef; +@@ -480,7 +480,7 @@ static void guest_test_msrs_access(void) + case 47: + /* Setting bit 0 enables the feature */ + if (!has_invtsc) +- continue; ++ goto next_stage; + msr->idx = HV_X64_MSR_TSC_INVARIANT_CONTROL; + msr->write = true; + msr->write_val = 1; +@@ -513,6 +513,7 @@ static void guest_test_msrs_access(void) + return; + } + ++next_stage: + stage++; + kvm_vm_free(vm); + } +diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c +index 251594306d409..720bafa0f87be 100644 +--- a/tools/testing/selftests/landlock/fs_test.c ++++ b/tools/testing/selftests/landlock/fs_test.c +@@ -241,9 +241,11 @@ struct mnt_opt { + const char *const data; + }; + +-const struct mnt_opt mnt_tmp = { ++#define MNT_TMP_DATA "size=4m,mode=700" ++ ++static const struct mnt_opt mnt_tmp = { + .type = "tmpfs", +- .data = "size=4m,mode=700", ++ .data = MNT_TMP_DATA, + }; + + static int mount_opt(const struct mnt_opt *const mnt, const char *const target) +@@ -4523,7 +4525,10 @@ FIXTURE_VARIANT(layout3_fs) + /* clang-format off */ + FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) { + /* clang-format on */ +- .mnt = mnt_tmp, ++ .mnt = { ++ .type = "tmpfs", ++ .data = MNT_TMP_DATA, ++ }, + .file_path = file1_s1d1, + }; + +diff --git a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh +index 0899019a7fcb4..e14bdd4455f2d 100755 +--- a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh ++++ b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh +@@ -1,4 +1,4 @@ +-#!/bin/sh ++#!/bin/bash + # SPDX-License-Identifier: GPL-2.0 + + # Kselftest framework requirement - SKIP code is 4. +diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c +index 380b691d3eb9f..b748c48908d9d 100644 +--- a/tools/testing/selftests/mm/ksm_tests.c ++++ b/tools/testing/selftests/mm/ksm_tests.c +@@ -566,7 +566,7 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot, + if (map_ptr_orig == MAP_FAILED) + err(2, "initial mmap"); + +- if (madvise(map_ptr, len + HPAGE_SIZE, MADV_HUGEPAGE)) ++ if (madvise(map_ptr, len, MADV_HUGEPAGE)) + err(2, "MADV_HUGEPAGE"); + + pagemap_fd = open("/proc/self/pagemap", O_RDONLY); +diff --git a/tools/testing/selftests/mm/map_hugetlb.c b/tools/testing/selftests/mm/map_hugetlb.c +index 193281560b61b..86e8f2048a409 100644 +--- a/tools/testing/selftests/mm/map_hugetlb.c ++++ b/tools/testing/selftests/mm/map_hugetlb.c +@@ -15,6 +15,7 @@ + #include <unistd.h> + #include <sys/mman.h> + #include <fcntl.h> ++#include "vm_util.h" + + #define LENGTH (256UL*1024*1024) + #define PROTECTION (PROT_READ | PROT_WRITE) +@@ -58,10 +59,16 @@ int main(int argc, char **argv) + { + void *addr; + int ret; ++ size_t hugepage_size; + size_t length = LENGTH; + int flags = FLAGS; + int shift = 0; + ++ hugepage_size = default_huge_page_size(); ++ /* munmap with fail if the length is not page aligned */ ++ if (hugepage_size > length) ++ length = hugepage_size; ++ + if (argc > 1) + length = atol(argv[1]) << 20; + if (argc > 2) { +diff --git a/tools/testing/selftests/mm/va_high_addr_switch.sh b/tools/testing/selftests/mm/va_high_addr_switch.sh +index 45cae7cab27e1..a0a75f3029043 100755 +--- a/tools/testing/selftests/mm/va_high_addr_switch.sh ++++ b/tools/testing/selftests/mm/va_high_addr_switch.sh +@@ -29,9 +29,15 @@ check_supported_x86_64() + # See man 1 gzip under '-f'. + local pg_table_levels=$(gzip -dcfq "${config}" | grep PGTABLE_LEVELS | cut -d'=' -f 2) + ++ local cpu_supports_pl5=$(awk '/^flags/ {if (/la57/) {print 0;} ++ else {print 1}; exit}' /proc/cpuinfo 2>/dev/null) ++ + if [[ "${pg_table_levels}" -lt 5 ]]; then + echo "$0: PGTABLE_LEVELS=${pg_table_levels}, must be >= 5 to run this test" + exit $ksft_skip ++ elif [[ "${cpu_supports_pl5}" -ne 0 ]]; then ++ echo "$0: CPU does not have the necessary la57 flag to support page table level 5" ++ exit $ksft_skip + fi + } + +diff --git a/tools/testing/selftests/mm/write_hugetlb_memory.sh b/tools/testing/selftests/mm/write_hugetlb_memory.sh +index 70a02301f4c27..3d2d2eb9d6fff 100755 +--- a/tools/testing/selftests/mm/write_hugetlb_memory.sh ++++ b/tools/testing/selftests/mm/write_hugetlb_memory.sh +@@ -1,4 +1,4 @@ +-#!/bin/sh ++#!/bin/bash + # SPDX-License-Identifier: GPL-2.0 + + set -e +diff --git a/tools/testing/selftests/net/forwarding/bridge_locked_port.sh b/tools/testing/selftests/net/forwarding/bridge_locked_port.sh +index 9af9f6964808b..c62331b2e0060 100755 +--- a/tools/testing/selftests/net/forwarding/bridge_locked_port.sh ++++ b/tools/testing/selftests/net/forwarding/bridge_locked_port.sh +@@ -327,10 +327,10 @@ locked_port_mab_redirect() + RET=0 + check_port_mab_support || return 0 + +- bridge link set dev $swp1 learning on locked on mab on + tc qdisc add dev $swp1 clsact + tc filter add dev $swp1 ingress protocol all pref 1 handle 101 flower \ + action mirred egress redirect dev $swp2 ++ bridge link set dev $swp1 learning on locked on mab on + + ping_do $h1 192.0.2.2 + check_err $? "Ping did not work with redirection" +@@ -349,8 +349,8 @@ locked_port_mab_redirect() + check_err $? "Locked entry not created after deleting filter" + + bridge fdb del `mac_get $h1` vlan 1 dev $swp1 master +- tc qdisc del dev $swp1 clsact + bridge link set dev $swp1 learning off locked off mab off ++ tc qdisc del dev $swp1 clsact + + log_test "Locked port MAB redirect" + } +diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb.sh b/tools/testing/selftests/net/forwarding/bridge_mdb.sh +index d0c6c499d5dab..a3678dfe5848a 100755 +--- a/tools/testing/selftests/net/forwarding/bridge_mdb.sh ++++ b/tools/testing/selftests/net/forwarding/bridge_mdb.sh +@@ -145,14 +145,14 @@ cfg_test_host_common() + + # Check basic add, replace and delete behavior. + bridge mdb add dev br0 port br0 grp $grp $state vid 10 +- bridge mdb show dev br0 vid 10 | grep -q "$grp" ++ bridge mdb get dev br0 grp $grp vid 10 &> /dev/null + check_err $? "Failed to add $name host entry" + + bridge mdb replace dev br0 port br0 grp $grp $state vid 10 &> /dev/null + check_fail $? "Managed to replace $name host entry" + + bridge mdb del dev br0 port br0 grp $grp $state vid 10 +- bridge mdb show dev br0 vid 10 | grep -q "$grp" ++ bridge mdb get dev br0 grp $grp vid 10 &> /dev/null + check_fail $? "Failed to delete $name host entry" + + # Check error cases. +@@ -200,7 +200,7 @@ cfg_test_port_common() + + # Check basic add, replace and delete behavior. + bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10 +- bridge mdb show dev br0 vid 10 | grep -q "$grp_key" ++ bridge mdb get dev br0 $grp_key vid 10 &> /dev/null + check_err $? "Failed to add $name entry" + + bridge mdb replace dev br0 port $swp1 $grp_key permanent vid 10 \ +@@ -208,31 +208,31 @@ cfg_test_port_common() + check_err $? "Failed to replace $name entry" + + bridge mdb del dev br0 port $swp1 $grp_key permanent vid 10 +- bridge mdb show dev br0 vid 10 | grep -q "$grp_key" ++ bridge mdb get dev br0 $grp_key vid 10 &> /dev/null + check_fail $? "Failed to delete $name entry" + + # Check default protocol and replacement. + bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10 +- bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | grep -q "static" ++ bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "static" + check_err $? "$name entry not added with default \"static\" protocol" + + bridge mdb replace dev br0 port $swp1 $grp_key permanent vid 10 \ + proto 123 +- bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | grep -q "123" ++ bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "123" + check_err $? "Failed to replace protocol of $name entry" + bridge mdb del dev br0 port $swp1 $grp_key permanent vid 10 + + # Check behavior when VLAN is not specified. + bridge mdb add dev br0 port $swp1 $grp_key permanent +- bridge mdb show dev br0 vid 10 | grep -q "$grp_key" ++ bridge mdb get dev br0 $grp_key vid 10 &> /dev/null + check_err $? "$name entry with VLAN 10 not added when VLAN was not specified" +- bridge mdb show dev br0 vid 20 | grep -q "$grp_key" ++ bridge mdb get dev br0 $grp_key vid 20 &> /dev/null + check_err $? "$name entry with VLAN 20 not added when VLAN was not specified" + + bridge mdb del dev br0 port $swp1 $grp_key permanent +- bridge mdb show dev br0 vid 10 | grep -q "$grp_key" ++ bridge mdb get dev br0 $grp_key vid 10 &> /dev/null + check_fail $? "$name entry with VLAN 10 not deleted when VLAN was not specified" +- bridge mdb show dev br0 vid 20 | grep -q "$grp_key" ++ bridge mdb get dev br0 $grp_key vid 20 &> /dev/null + check_fail $? "$name entry with VLAN 20 not deleted when VLAN was not specified" + + # Check behavior when bridge port is down. +@@ -298,21 +298,21 @@ __cfg_test_port_ip_star_g() + RET=0 + + bridge mdb add dev br0 port $swp1 grp $grp vid 10 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "exclude" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "exclude" + check_err $? "Default filter mode is not \"exclude\"" + bridge mdb del dev br0 port $swp1 grp $grp vid 10 + + # Check basic add and delete behavior. + bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode exclude \ + source_list $src1 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q -v "src" ++ bridge -d mdb get dev br0 grp $grp vid 10 &> /dev/null + check_err $? "(*, G) entry not created" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src1" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 &> /dev/null + check_err $? "(S, G) entry not created" + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q -v "src" ++ bridge -d mdb get dev br0 grp $grp vid 10 &> /dev/null + check_fail $? "(*, G) entry not deleted" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src1" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 &> /dev/null + check_fail $? "(S, G) entry not deleted" + + ## State (permanent / temp) tests. +@@ -321,18 +321,15 @@ __cfg_test_port_ip_star_g() + bridge mdb add dev br0 port $swp1 grp $grp permanent vid 10 \ + filter_mode exclude source_list $src1 + +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "permanent" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "permanent" + check_err $? "(*, G) entry not added as \"permanent\" when should" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | \ + grep -q "permanent" + check_err $? "(S, G) entry not added as \"permanent\" when should" + +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q " 0.00" ++ bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00" + check_err $? "(*, G) \"permanent\" entry has a pending group timer" +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "\/0.00" ++ bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00" + check_err $? "\"permanent\" source entry has a pending source timer" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -342,18 +339,14 @@ __cfg_test_port_ip_star_g() + bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode exclude source_list $src1 + +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "temp" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "temp" + check_err $? "(*, G) EXCLUDE entry not added as \"temp\" when should" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "temp" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "temp" + check_err $? "(S, G) \"blocked\" entry not added as \"temp\" when should" + +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q " 0.00" ++ bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00" + check_fail $? "(*, G) EXCLUDE entry does not have a pending group timer" +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "\/0.00" ++ bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00" + check_err $? "\"blocked\" source entry has a pending source timer" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -363,18 +356,14 @@ __cfg_test_port_ip_star_g() + bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode include source_list $src1 + +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "temp" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "temp" + check_err $? "(*, G) INCLUDE entry not added as \"temp\" when should" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "temp" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "temp" + check_err $? "(S, G) entry not added as \"temp\" when should" + +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q " 0.00" ++ bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00" + check_err $? "(*, G) INCLUDE entry has a pending group timer" +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "\/0.00" ++ bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00" + check_fail $? "Source entry does not have a pending source timer" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -383,8 +372,7 @@ __cfg_test_port_ip_star_g() + bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode include source_list $src1 + +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q " 0.00" ++ bridge -d -s mdb get dev br0 grp $grp src $src1 vid 10 | grep -q " 0.00" + check_err $? "(S, G) entry has a pending group timer" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -396,11 +384,9 @@ __cfg_test_port_ip_star_g() + bridge mdb add dev br0 port $swp1 grp $grp vid 10 \ + filter_mode include source_list $src1 + +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "include" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "include" + check_err $? "(*, G) INCLUDE not added with \"include\" filter mode" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "blocked" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "blocked" + check_fail $? "(S, G) entry marked as \"blocked\" when should not" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -410,11 +396,9 @@ __cfg_test_port_ip_star_g() + bridge mdb add dev br0 port $swp1 grp $grp vid 10 \ + filter_mode exclude source_list $src1 + +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "exclude" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "exclude" + check_err $? "(*, G) EXCLUDE not added with \"exclude\" filter mode" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "blocked" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "blocked" + check_err $? "(S, G) entry not marked as \"blocked\" when should" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -426,11 +410,9 @@ __cfg_test_port_ip_star_g() + bridge mdb add dev br0 port $swp1 grp $grp vid 10 \ + filter_mode exclude source_list $src1 proto zebra + +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "zebra" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "zebra" + check_err $? "(*, G) entry not added with \"zebra\" protocol" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "zebra" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "zebra" + check_err $? "(S, G) entry not marked added with \"zebra\" protocol" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -443,20 +425,16 @@ __cfg_test_port_ip_star_g() + + bridge mdb replace dev br0 port $swp1 grp $grp permanent vid 10 \ + filter_mode exclude source_list $src1 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "permanent" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "permanent" + check_err $? "(*, G) entry not marked as \"permanent\" after replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "permanent" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "permanent" + check_err $? "(S, G) entry not marked as \"permanent\" after replace" + + bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode exclude source_list $src1 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "temp" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "temp" + check_err $? "(*, G) entry not marked as \"temp\" after replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "temp" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "temp" + check_err $? "(S, G) entry not marked as \"temp\" after replace" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -467,20 +445,16 @@ __cfg_test_port_ip_star_g() + + bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode include source_list $src1 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "include" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "include" + check_err $? "(*, G) not marked with \"include\" filter mode after replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "blocked" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "blocked" + check_fail $? "(S, G) marked as \"blocked\" after replace" + + bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode exclude source_list $src1 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "exclude" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "exclude" + check_err $? "(*, G) not marked with \"exclude\" filter mode after replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "blocked" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "blocked" + check_err $? "(S, G) not marked as \"blocked\" after replace" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -491,20 +465,20 @@ __cfg_test_port_ip_star_g() + + bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode exclude source_list $src1,$src2,$src3 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src1" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 &> /dev/null + check_err $? "(S, G) entry for source $src1 not created after replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src2" ++ bridge -d mdb get dev br0 grp $grp src $src2 vid 10 &> /dev/null + check_err $? "(S, G) entry for source $src2 not created after replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src3" ++ bridge -d mdb get dev br0 grp $grp src $src3 vid 10 &> /dev/null + check_err $? "(S, G) entry for source $src3 not created after replace" + + bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode exclude source_list $src1,$src3 +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src1" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 &> /dev/null + check_err $? "(S, G) entry for source $src1 not created after second replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src2" ++ bridge -d mdb get dev br0 grp $grp src $src2 vid 10 &> /dev/null + check_fail $? "(S, G) entry for source $src2 created after second replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src3" ++ bridge -d mdb get dev br0 grp $grp src $src3 vid 10 &> /dev/null + check_err $? "(S, G) entry for source $src3 not created after second replace" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -515,11 +489,9 @@ __cfg_test_port_ip_star_g() + + bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \ + filter_mode exclude source_list $src1 proto bgp +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \ +- grep -q "bgp" ++ bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "bgp" + check_err $? "(*, G) protocol not changed to \"bgp\" after replace" +- bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \ +- grep -q "bgp" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "bgp" + check_err $? "(S, G) protocol not changed to \"bgp\" after replace" + + bridge mdb del dev br0 port $swp1 grp $grp vid 10 +@@ -532,8 +504,8 @@ __cfg_test_port_ip_star_g() + bridge mdb add dev br0 port $swp2 grp $grp vid 10 \ + filter_mode include source_list $src1 + bridge mdb add dev br0 port $swp1 grp $grp vid 10 +- bridge -d mdb show dev br0 vid 10 | grep "$swp1" | grep "$grp" | \ +- grep "$src1" | grep -q "added_by_star_ex" ++ bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep "$swp1" | \ ++ grep -q "added_by_star_ex" + check_err $? "\"added_by_star_ex\" entry not created after adding (*, G) entry" + bridge mdb del dev br0 port $swp1 grp $grp vid 10 + bridge mdb del dev br0 port $swp2 grp $grp src $src1 vid 10 +@@ -606,27 +578,23 @@ __cfg_test_port_ip_sg() + RET=0 + + bridge mdb add dev br0 port $swp1 $grp_key vid 10 +- bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | grep -q "include" ++ bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "include" + check_err $? "Default filter mode is not \"include\"" + bridge mdb del dev br0 port $swp1 $grp_key vid 10 + + # Check that entries can be added as both permanent and temp and that + # group timer is set correctly. + bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10 +- bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q "permanent" ++ bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "permanent" + check_err $? "Entry not added as \"permanent\" when should" +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q " 0.00" ++ bridge -d -s mdb get dev br0 $grp_key vid 10 | grep -q " 0.00" + check_err $? "\"permanent\" entry has a pending group timer" + bridge mdb del dev br0 port $swp1 $grp_key vid 10 + + bridge mdb add dev br0 port $swp1 $grp_key temp vid 10 +- bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q "temp" ++ bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "temp" + check_err $? "Entry not added as \"temp\" when should" +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q " 0.00" ++ bridge -d -s mdb get dev br0 $grp_key vid 10 | grep -q " 0.00" + check_fail $? "\"temp\" entry has an unpending group timer" + bridge mdb del dev br0 port $swp1 $grp_key vid 10 + +@@ -650,24 +618,19 @@ __cfg_test_port_ip_sg() + # Check that we can replace available attributes. + bridge mdb add dev br0 port $swp1 $grp_key vid 10 proto 123 + bridge mdb replace dev br0 port $swp1 $grp_key vid 10 proto 111 +- bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q "111" ++ bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "111" + check_err $? "Failed to replace protocol" + + bridge mdb replace dev br0 port $swp1 $grp_key vid 10 permanent +- bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q "permanent" ++ bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "permanent" + check_err $? "Entry not marked as \"permanent\" after replace" +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q " 0.00" ++ bridge -d -s mdb get dev br0 $grp_key vid 10 | grep -q " 0.00" + check_err $? "Entry has a pending group timer after replace" + + bridge mdb replace dev br0 port $swp1 $grp_key vid 10 temp +- bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q "temp" ++ bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "temp" + check_err $? "Entry not marked as \"temp\" after replace" +- bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \ +- grep -q " 0.00" ++ bridge -d -s mdb get dev br0 $grp_key vid 10 | grep -q " 0.00" + check_fail $? "Entry has an unpending group timer after replace" + bridge mdb del dev br0 port $swp1 $grp_key vid 10 + +@@ -675,7 +638,7 @@ __cfg_test_port_ip_sg() + # (*, G) ports need to be added to it. + bridge mdb add dev br0 port $swp2 grp $grp vid 10 + bridge mdb add dev br0 port $swp1 $grp_key vid 10 +- bridge mdb show dev br0 vid 10 | grep "$grp_key" | grep $swp2 | \ ++ bridge mdb get dev br0 $grp_key vid 10 | grep $swp2 | \ + grep -q "added_by_star_ex" + check_err $? "\"added_by_star_ex\" entry not created after adding (S, G) entry" + bridge mdb del dev br0 port $swp1 $grp_key vid 10 +@@ -1102,14 +1065,17 @@ fwd_test() + echo + log_info "# Forwarding tests" + ++ # Set the Max Response Delay to 100 centiseconds (1 second) so that the ++ # bridge will start forwarding according to its MDB soon after a ++ # multicast querier is enabled. ++ ip link set dev br0 type bridge mcast_query_response_interval 100 ++ + # Forwarding according to MDB entries only takes place when the bridge + # detects that there is a valid querier in the network. Set the bridge + # as the querier and assign it a valid IPv6 link-local address to be + # used as the source address for MLD queries. + ip -6 address add fe80::1/64 nodad dev br0 + ip link set dev br0 type bridge mcast_querier 1 +- # Wait the default Query Response Interval (10 seconds) for the bridge +- # to determine that there are no other queriers in the network. + sleep 10 + + fwd_test_host +@@ -1117,6 +1083,7 @@ fwd_test() + + ip link set dev br0 type bridge mcast_querier 0 + ip -6 address del fe80::1/64 dev br0 ++ ip link set dev br0 type bridge mcast_query_response_interval 1000 + } + + ctrl_igmpv3_is_in_test() +@@ -1132,7 +1099,7 @@ ctrl_igmpv3_is_in_test() + $MZ $h1.10 -c 1 -a own -b 01:00:5e:01:01:01 -A 192.0.2.1 -B 239.1.1.1 \ + -t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q + +- bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | grep -q 192.0.2.2 ++ bridge mdb get dev br0 grp 239.1.1.1 src 192.0.2.2 vid 10 &> /dev/null + check_fail $? "Permanent entry affected by IGMP packet" + + # Replace the permanent entry with a temporary one and check that after +@@ -1145,12 +1112,10 @@ ctrl_igmpv3_is_in_test() + $MZ $h1.10 -a own -b 01:00:5e:01:01:01 -c 1 -A 192.0.2.1 -B 239.1.1.1 \ + -t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q + +- bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | grep -v "src" | \ +- grep -q 192.0.2.2 ++ bridge -d mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q 192.0.2.2 + check_err $? "Source not add to source list" + +- bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | \ +- grep -q "src 192.0.2.2" ++ bridge mdb get dev br0 grp 239.1.1.1 src 192.0.2.2 vid 10 &> /dev/null + check_err $? "(S, G) entry not created for new source" + + bridge mdb del dev br0 port $swp1 grp 239.1.1.1 vid 10 +@@ -1172,8 +1137,7 @@ ctrl_mldv2_is_in_test() + $MZ -6 $h1.10 -a own -b 33:33:00:00:00:01 -c 1 -A fe80::1 -B ff0e::1 \ + -t ip hop=1,next=0,p="$p" -q + +- bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | \ +- grep -q 2001:db8:1::2 ++ bridge mdb get dev br0 grp ff0e::1 src 2001:db8:1::2 vid 10 &> /dev/null + check_fail $? "Permanent entry affected by MLD packet" + + # Replace the permanent entry with a temporary one and check that after +@@ -1186,12 +1150,10 @@ ctrl_mldv2_is_in_test() + $MZ -6 $h1.10 -a own -b 33:33:00:00:00:01 -c 1 -A fe80::1 -B ff0e::1 \ + -t ip hop=1,next=0,p="$p" -q + +- bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | grep -v "src" | \ +- grep -q 2001:db8:1::2 ++ bridge -d mdb get dev br0 grp ff0e::1 vid 10 | grep -q 2001:db8:1::2 + check_err $? "Source not add to source list" + +- bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | \ +- grep -q "src 2001:db8:1::2" ++ bridge mdb get dev br0 grp ff0e::1 src 2001:db8:1::2 vid 10 &> /dev/null + check_err $? "(S, G) entry not created for new source" + + bridge mdb del dev br0 port $swp1 grp ff0e::1 vid 10 +@@ -1208,8 +1170,8 @@ ctrl_test() + ctrl_mldv2_is_in_test + } + +-if ! bridge mdb help 2>&1 | grep -q "replace"; then +- echo "SKIP: iproute2 too old, missing bridge mdb replace support" ++if ! bridge mdb help 2>&1 | grep -q "get"; then ++ echo "SKIP: iproute2 too old, missing bridge mdb get support" + exit $ksft_skip + fi + +diff --git a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh +index 20a7cb7222b8b..c2420bb72c128 100755 +--- a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh ++++ b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh +@@ -209,14 +209,17 @@ test_l2_miss_multicast() + # both registered and unregistered multicast traffic. + bridge link set dev $swp2 mcast_router 2 + ++ # Set the Max Response Delay to 100 centiseconds (1 second) so that the ++ # bridge will start forwarding according to its MDB soon after a ++ # multicast querier is enabled. ++ ip link set dev br1 type bridge mcast_query_response_interval 100 ++ + # Forwarding according to MDB entries only takes place when the bridge + # detects that there is a valid querier in the network. Set the bridge + # as the querier and assign it a valid IPv6 link-local address to be + # used as the source address for MLD queries. + ip link set dev br1 type bridge mcast_querier 1 + ip -6 address add fe80::1/64 nodad dev br1 +- # Wait the default Query Response Interval (10 seconds) for the bridge +- # to determine that there are no other queriers in the network. + sleep 10 + + test_l2_miss_multicast_ipv4 +@@ -224,6 +227,7 @@ test_l2_miss_multicast() + + ip -6 address del fe80::1/64 dev br1 + ip link set dev br1 type bridge mcast_querier 0 ++ ip link set dev br1 type bridge mcast_query_response_interval 1000 + bridge link set dev $swp2 mcast_router 1 + } + +diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config +index e317c2e44dae8..4f80014cae494 100644 +--- a/tools/testing/selftests/net/mptcp/config ++++ b/tools/testing/selftests/net/mptcp/config +@@ -22,8 +22,11 @@ CONFIG_NFT_TPROXY=m + CONFIG_NFT_SOCKET=m + CONFIG_IP_ADVANCED_ROUTER=y + CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_NF_FILTER=m ++CONFIG_IP_NF_MANGLE=m + CONFIG_IP_NF_TARGET_REJECT=m + CONFIG_IPV6_MULTIPLE_TABLES=y ++CONFIG_IP6_NF_FILTER=m + CONFIG_NET_ACT_CSUM=m + CONFIG_NET_ACT_PEDIT=m + CONFIG_NET_CLS_ACT=y +diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh +index 4632a954c73e6..67ca22856d54a 100755 +--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh +@@ -682,16 +682,10 @@ wait_mpj() + done + } + +-kill_wait() +-{ +- kill $1 > /dev/null 2>&1 +- wait $1 2>/dev/null +-} +- + kill_events_pids() + { +- kill_wait $evts_ns1_pid +- kill_wait $evts_ns2_pid ++ mptcp_lib_kill_wait $evts_ns1_pid ++ mptcp_lib_kill_wait $evts_ns2_pid + } + + kill_tests_wait() +diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh +index 92a5befe80394..4cd4297ca86de 100644 +--- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh +@@ -6,7 +6,7 @@ readonly KSFT_FAIL=1 + readonly KSFT_SKIP=4 + + # shellcheck disable=SC2155 # declare and assign separately +-readonly KSFT_TEST=$(basename "${0}" | sed 's/\.sh$//g') ++readonly KSFT_TEST="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}" + + MPTCP_LIB_SUBTESTS=() + +@@ -207,3 +207,12 @@ mptcp_lib_result_print_all_tap() { + printf "%s\n" "${subtest}" + done + } ++ ++# $1: PID ++mptcp_lib_kill_wait() { ++ [ "${1}" -eq 0 ] && return 0 ++ ++ kill -SIGUSR1 "${1}" > /dev/null 2>&1 ++ kill "${1}" > /dev/null 2>&1 ++ wait "${1}" 2>/dev/null ++} +diff --git a/tools/testing/selftests/net/mptcp/settings b/tools/testing/selftests/net/mptcp/settings +index 79b65bdf05db6..abc5648b59abd 100644 +--- a/tools/testing/selftests/net/mptcp/settings ++++ b/tools/testing/selftests/net/mptcp/settings +@@ -1 +1 @@ +-timeout=1200 ++timeout=1800 +diff --git a/tools/testing/selftests/net/mptcp/userspace_pm.sh b/tools/testing/selftests/net/mptcp/userspace_pm.sh +index b25a3e33eb253..c44bf5c7c6e04 100755 +--- a/tools/testing/selftests/net/mptcp/userspace_pm.sh ++++ b/tools/testing/selftests/net/mptcp/userspace_pm.sh +@@ -108,15 +108,6 @@ test_fail() + mptcp_lib_result_fail "${test_name}" + } + +-kill_wait() +-{ +- [ $1 -eq 0 ] && return 0 +- +- kill -SIGUSR1 $1 > /dev/null 2>&1 +- kill $1 > /dev/null 2>&1 +- wait $1 2>/dev/null +-} +- + # This function is used in the cleanup trap + #shellcheck disable=SC2317 + cleanup() +@@ -128,7 +119,7 @@ cleanup() + for pid in $client4_pid $server4_pid $client6_pid $server6_pid\ + $server_evts_pid $client_evts_pid + do +- kill_wait $pid ++ mptcp_lib_kill_wait $pid + done + + local netns +@@ -210,7 +201,7 @@ make_connection() + fi + :>"$client_evts" + if [ $client_evts_pid -ne 0 ]; then +- kill_wait $client_evts_pid ++ mptcp_lib_kill_wait $client_evts_pid + fi + ip netns exec "$ns2" ./pm_nl_ctl events >> "$client_evts" 2>&1 & + client_evts_pid=$! +@@ -219,7 +210,7 @@ make_connection() + fi + :>"$server_evts" + if [ $server_evts_pid -ne 0 ]; then +- kill_wait $server_evts_pid ++ mptcp_lib_kill_wait $server_evts_pid + fi + ip netns exec "$ns1" ./pm_nl_ctl events >> "$server_evts" 2>&1 & + server_evts_pid=$! +@@ -627,7 +618,7 @@ test_subflows() + "10.0.2.2" "$client4_port" "23" "$client_addr_id" "ns1" "ns2" + + # Delete the listener from the client ns, if one was created +- kill_wait $listener_pid ++ mptcp_lib_kill_wait $listener_pid + + local sport + sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") +@@ -666,7 +657,7 @@ test_subflows() + "$client_addr_id" "ns1" "ns2" + + # Delete the listener from the client ns, if one was created +- kill_wait $listener_pid ++ mptcp_lib_kill_wait $listener_pid + + sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") + +@@ -705,7 +696,7 @@ test_subflows() + "$client_addr_id" "ns1" "ns2" + + # Delete the listener from the client ns, if one was created +- kill_wait $listener_pid ++ mptcp_lib_kill_wait $listener_pid + + sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts") + +@@ -743,7 +734,7 @@ test_subflows() + "10.0.2.1" "$app4_port" "23" "$server_addr_id" "ns2" "ns1" + + # Delete the listener from the server ns, if one was created +- kill_wait $listener_pid ++ mptcp_lib_kill_wait $listener_pid + + sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") + +@@ -782,7 +773,7 @@ test_subflows() + "$server_addr_id" "ns2" "ns1" + + # Delete the listener from the server ns, if one was created +- kill_wait $listener_pid ++ mptcp_lib_kill_wait $listener_pid + + sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") + +@@ -819,7 +810,7 @@ test_subflows() + "10.0.2.2" "10.0.2.1" "$new4_port" "23" "$server_addr_id" "ns2" "ns1" + + # Delete the listener from the server ns, if one was created +- kill_wait $listener_pid ++ mptcp_lib_kill_wait $listener_pid + + sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") + +@@ -865,7 +856,7 @@ test_subflows_v4_v6_mix() + "$server_addr_id" "ns2" "ns1" + + # Delete the listener from the server ns, if one was created +- kill_wait $listener_pid ++ mptcp_lib_kill_wait $listener_pid + + sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts") + +@@ -982,7 +973,7 @@ test_listener() + sleep 0.5 + + # Delete the listener from the client ns, if one was created +- kill_wait $listener_pid ++ mptcp_lib_kill_wait $listener_pid + + sleep 0.5 + verify_listener_events $client_evts $LISTENER_CLOSED $AF_INET 10.0.2.2 $client4_port +diff --git a/tools/testing/selftests/net/test_bridge_backup_port.sh b/tools/testing/selftests/net/test_bridge_backup_port.sh +index 112cfd8a10ad9..1b3f89e2b86e6 100755 +--- a/tools/testing/selftests/net/test_bridge_backup_port.sh ++++ b/tools/testing/selftests/net/test_bridge_backup_port.sh +@@ -35,9 +35,8 @@ + # | sw1 | | sw2 | + # +------------------------------------+ +------------------------------------+ + ++source lib.sh + ret=0 +-# Kselftest framework requirement - SKIP code is 4. +-ksft_skip=4 + + # All tests in this script. Can be overridden with -t option. + TESTS=" +@@ -125,6 +124,16 @@ tc_check_packets() + [[ $pkts == $count ]] + } + ++bridge_link_check() ++{ ++ local ns=$1; shift ++ local dev=$1; shift ++ local state=$1; shift ++ ++ bridge -n $ns -d -j link show dev $dev | \ ++ jq -e ".[][\"state\"] == \"$state\"" &> /dev/null ++} ++ + ################################################################################ + # Setup + +@@ -132,9 +141,6 @@ setup_topo_ns() + { + local ns=$1; shift + +- ip netns add $ns +- ip -n $ns link set dev lo up +- + ip netns exec $ns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1 + ip netns exec $ns sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1 + ip netns exec $ns sysctl -qw net.ipv6.conf.all.accept_dad=0 +@@ -145,13 +151,14 @@ setup_topo() + { + local ns + +- for ns in sw1 sw2; do ++ setup_ns sw1 sw2 ++ for ns in $sw1 $sw2; do + setup_topo_ns $ns + done + + ip link add name veth0 type veth peer name veth1 +- ip link set dev veth0 netns sw1 name veth0 +- ip link set dev veth1 netns sw2 name veth0 ++ ip link set dev veth0 netns $sw1 name veth0 ++ ip link set dev veth1 netns $sw2 name veth0 + } + + setup_sw_common() +@@ -190,7 +197,7 @@ setup_sw_common() + + setup_sw1() + { +- local ns=sw1 ++ local ns=$sw1 + local local_addr=192.0.2.33 + local remote_addr=192.0.2.34 + local veth_addr=192.0.2.49 +@@ -203,7 +210,7 @@ setup_sw1() + + setup_sw2() + { +- local ns=sw2 ++ local ns=$sw2 + local local_addr=192.0.2.34 + local remote_addr=192.0.2.33 + local veth_addr=192.0.2.50 +@@ -229,11 +236,7 @@ setup() + + cleanup() + { +- local ns +- +- for ns in h1 h2 sw1 sw2; do +- ip netns del $ns &> /dev/null +- done ++ cleanup_ns $sw1 $sw2 + } + + ################################################################################ +@@ -248,85 +251,90 @@ backup_port() + echo "Backup port" + echo "-----------" + +- run_cmd "tc -n sw1 qdisc replace dev swp1 clsact" +- run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" ++ run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact" ++ run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + +- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" +- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" ++ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" ++ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + +- run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10" ++ run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10" + + # Initial state - check that packets are forwarded out of swp1 when it + # has a carrier and not forwarded out of any port when it does not have + # a carrier. +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 1 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 1 + log_test $? 0 "Forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 0 ++ tc_check_packets $sw1 "dev vx0 egress" 101 0 + log_test $? 0 "No forwarding out of vx0" + +- run_cmd "ip -n sw1 link set dev swp1 carrier off" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled + log_test $? 0 "swp1 carrier off" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 1 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 1 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 0 ++ tc_check_packets $sw1 "dev vx0 egress" 101 0 + log_test $? 0 "No forwarding out of vx0" + +- run_cmd "ip -n sw1 link set dev swp1 carrier on" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier on" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding + log_test $? 0 "swp1 carrier on" + + # Configure vx0 as the backup port of swp1 and check that packets are + # forwarded out of swp1 when it has a carrier and out of vx0 when swp1 + # does not have a carrier. +- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\"" + log_test $? 0 "vx0 configured as backup port of swp1" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 2 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 2 + log_test $? 0 "Forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 0 ++ tc_check_packets $sw1 "dev vx0 egress" 101 0 + log_test $? 0 "No forwarding out of vx0" + +- run_cmd "ip -n sw1 link set dev swp1 carrier off" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled + log_test $? 0 "swp1 carrier off" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 2 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 2 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 1 ++ tc_check_packets $sw1 "dev vx0 egress" 101 1 + log_test $? 0 "Forwarding out of vx0" + +- run_cmd "ip -n sw1 link set dev swp1 carrier on" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier on" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding + log_test $? 0 "swp1 carrier on" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 3 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 3 + log_test $? 0 "Forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 1 ++ tc_check_packets $sw1 "dev vx0 egress" 101 1 + log_test $? 0 "No forwarding out of vx0" + + # Remove vx0 as the backup port of swp1 and check that packets are no + # longer forwarded out of vx0 when swp1 does not have a carrier. +- run_cmd "bridge -n sw1 link set dev swp1 nobackup_port" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 nobackup_port" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\"" + log_test $? 1 "vx0 not configured as backup port of swp1" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 4 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 4 + log_test $? 0 "Forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 1 ++ tc_check_packets $sw1 "dev vx0 egress" 101 1 + log_test $? 0 "No forwarding out of vx0" + +- run_cmd "ip -n sw1 link set dev swp1 carrier off" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled + log_test $? 0 "swp1 carrier off" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 4 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 4 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 1 ++ tc_check_packets $sw1 "dev vx0 egress" 101 1 + log_test $? 0 "No forwarding out of vx0" + } + +@@ -339,125 +347,130 @@ backup_nhid() + echo "Backup nexthop ID" + echo "-----------------" + +- run_cmd "tc -n sw1 qdisc replace dev swp1 clsact" +- run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" ++ run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact" ++ run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + +- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" +- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" ++ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" ++ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + +- run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb" +- run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb" +- run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb" + +- run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10" +- run_cmd "bridge -n sw1 fdb replace $dmac dev vx0 self static dst 192.0.2.36 src_vni 10010" ++ run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10" ++ run_cmd "bridge -n $sw1 fdb replace $dmac dev vx0 self static dst 192.0.2.36 src_vni 10010" + +- run_cmd "ip -n sw2 address replace 192.0.2.36/32 dev lo" ++ run_cmd "ip -n $sw2 address replace 192.0.2.36/32 dev lo" + + # The first filter matches on packets forwarded using the backup + # nexthop ID and the second filter matches on packets forwarded using a + # regular VXLAN FDB entry. +- run_cmd "tc -n sw2 qdisc replace dev vx0 clsact" +- run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass" +- run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 102 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.36 action pass" ++ run_cmd "tc -n $sw2 qdisc replace dev vx0 clsact" ++ run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass" ++ run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 102 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.36 action pass" + + # Configure vx0 as the backup port of swp1 and check that packets are + # forwarded out of swp1 when it has a carrier and out of vx0 when swp1 + # does not have a carrier. When packets are forwarded out of vx0, check + # that they are forwarded by the VXLAN FDB entry. +- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\"" + log_test $? 0 "vx0 configured as backup port of swp1" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 1 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 1 + log_test $? 0 "Forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 0 ++ tc_check_packets $sw1 "dev vx0 egress" 101 0 + log_test $? 0 "No forwarding out of vx0" + +- run_cmd "ip -n sw1 link set dev swp1 carrier off" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled + log_test $? 0 "swp1 carrier off" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 1 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 1 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 1 ++ tc_check_packets $sw1 "dev vx0 egress" 101 1 + log_test $? 0 "Forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 0 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 0 + log_test $? 0 "No forwarding using backup nexthop ID" +- tc_check_packets sw2 "dev vx0 ingress" 102 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 102 1 + log_test $? 0 "Forwarding using VXLAN FDB entry" + +- run_cmd "ip -n sw1 link set dev swp1 carrier on" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier on" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding + log_test $? 0 "swp1 carrier on" + + # Configure nexthop ID 10 as the backup nexthop ID of swp1 and check + # that when packets are forwarded out of vx0, they are forwarded using + # the backup nexthop ID. +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 10\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 10\"" + log_test $? 0 "nexthop ID 10 configured as backup nexthop ID of swp1" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 2 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 2 + log_test $? 0 "Forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 1 ++ tc_check_packets $sw1 "dev vx0 egress" 101 1 + log_test $? 0 "No forwarding out of vx0" + +- run_cmd "ip -n sw1 link set dev swp1 carrier off" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled + log_test $? 0 "swp1 carrier off" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 2 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 2 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 2 ++ tc_check_packets $sw1 "dev vx0 egress" 101 2 + log_test $? 0 "Forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "Forwarding using backup nexthop ID" +- tc_check_packets sw2 "dev vx0 ingress" 102 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 102 1 + log_test $? 0 "No forwarding using VXLAN FDB entry" + +- run_cmd "ip -n sw1 link set dev swp1 carrier on" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier on" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 forwarding + log_test $? 0 "swp1 carrier on" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 3 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 3 + log_test $? 0 "Forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 2 ++ tc_check_packets $sw1 "dev vx0 egress" 101 2 + log_test $? 0 "No forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "No forwarding using backup nexthop ID" +- tc_check_packets sw2 "dev vx0 ingress" 102 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 102 1 + log_test $? 0 "No forwarding using VXLAN FDB entry" + + # Reset the backup nexthop ID to 0 and check that packets are no longer + # forwarded using the backup nexthop ID when swp1 does not have a + # carrier and are instead forwarded by the VXLAN FDB. +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 0" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 0" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid\"" + log_test $? 1 "No backup nexthop ID configured for swp1" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 4 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 4 + log_test $? 0 "Forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 2 ++ tc_check_packets $sw1 "dev vx0 egress" 101 2 + log_test $? 0 "No forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "No forwarding using backup nexthop ID" +- tc_check_packets sw2 "dev vx0 ingress" 102 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 102 1 + log_test $? 0 "No forwarding using VXLAN FDB entry" + +- run_cmd "ip -n sw1 link set dev swp1 carrier off" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled + log_test $? 0 "swp1 carrier off" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 4 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 4 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 3 ++ tc_check_packets $sw1 "dev vx0 egress" 101 3 + log_test $? 0 "Forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "No forwarding using backup nexthop ID" +- tc_check_packets sw2 "dev vx0 ingress" 102 2 ++ tc_check_packets $sw2 "dev vx0 ingress" 102 2 + log_test $? 0 "Forwarding using VXLAN FDB entry" + } + +@@ -475,109 +488,110 @@ backup_nhid_invalid() + # is forwarded out of the VXLAN port, but dropped by the VXLAN driver + # and does not crash the host. + +- run_cmd "tc -n sw1 qdisc replace dev swp1 clsact" +- run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" ++ run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact" ++ run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + +- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" +- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" ++ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact" ++ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass" + # Drop all other Tx traffic to avoid changes to Tx drop counter. +- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 2 handle 102 proto all matchall action drop" ++ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 2 handle 102 proto all matchall action drop" + +- tx_drop=$(ip -n sw1 -s -j link show dev vx0 | jq '.[]["stats64"]["tx"]["dropped"]') ++ tx_drop=$(ip -n $sw1 -s -j link show dev vx0 | jq '.[]["stats64"]["tx"]["dropped"]') + +- run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb" +- run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb" +- run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb" + +- run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10" ++ run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10" + +- run_cmd "tc -n sw2 qdisc replace dev vx0 clsact" +- run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass" ++ run_cmd "tc -n $sw2 qdisc replace dev vx0 clsact" ++ run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass" + + # First, check that redirection works. +- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\"" + log_test $? 0 "vx0 configured as backup port of swp1" + +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 10\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 10\"" + log_test $? 0 "Valid nexthop as backup nexthop" + +- run_cmd "ip -n sw1 link set dev swp1 carrier off" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled + log_test $? 0 "swp1 carrier off" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 0 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 0 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 1 ++ tc_check_packets $sw1 "dev vx0 egress" 101 1 + log_test $? 0 "Forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "Forwarding using backup nexthop ID" +- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $tx_drop'" ++ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $tx_drop'" + log_test $? 0 "No Tx drop increase" + + # Use a non-existent nexthop ID. +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 20" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 20\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 20" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 20\"" + log_test $? 0 "Non-existent nexthop as backup nexthop" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 0 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 0 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 2 ++ tc_check_packets $sw1 "dev vx0 egress" 101 2 + log_test $? 0 "Forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "No forwarding using backup nexthop ID" +- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 1))'" ++ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 1))'" + log_test $? 0 "Tx drop increased" + + # Use a blckhole nexthop. +- run_cmd "ip -n sw1 nexthop replace id 30 blackhole" +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 30" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 30\"" ++ run_cmd "ip -n $sw1 nexthop replace id 30 blackhole" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 30" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 30\"" + log_test $? 0 "Blackhole nexthop as backup nexthop" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 0 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 0 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 3 ++ tc_check_packets $sw1 "dev vx0 egress" 101 3 + log_test $? 0 "Forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "No forwarding using backup nexthop ID" +- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 2))'" ++ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 2))'" + log_test $? 0 "Tx drop increased" + + # Non-group FDB nexthop. +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 1" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 1\"" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 1" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 1\"" + log_test $? 0 "Non-group FDB nexthop as backup nexthop" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 0 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 0 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 4 ++ tc_check_packets $sw1 "dev vx0 egress" 101 4 + log_test $? 0 "Forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "No forwarding using backup nexthop ID" +- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 3))'" ++ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 3))'" + log_test $? 0 "Tx drop increased" + + # IPv6 address family nexthop. +- run_cmd "ip -n sw1 nexthop replace id 100 via 2001:db8:100::1 fdb" +- run_cmd "ip -n sw1 nexthop replace id 200 via 2001:db8:100::1 fdb" +- run_cmd "ip -n sw1 nexthop replace id 300 group 100/200 fdb" +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 300" +- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 300\"" ++ run_cmd "ip -n $sw1 nexthop replace id 100 via 2001:db8:100::1 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 200 via 2001:db8:100::1 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 300 group 100/200 fdb" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 300" ++ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 300\"" + log_test $? 0 "IPv6 address family nexthop as backup nexthop" + +- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" +- tc_check_packets sw1 "dev swp1 egress" 101 0 ++ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1" ++ tc_check_packets $sw1 "dev swp1 egress" 101 0 + log_test $? 0 "No forwarding out of swp1" +- tc_check_packets sw1 "dev vx0 egress" 101 5 ++ tc_check_packets $sw1 "dev vx0 egress" 101 5 + log_test $? 0 "Forwarding out of vx0" +- tc_check_packets sw2 "dev vx0 ingress" 101 1 ++ tc_check_packets $sw2 "dev vx0 ingress" 101 1 + log_test $? 0 "No forwarding using backup nexthop ID" +- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 4))'" ++ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 4))'" + log_test $? 0 "Tx drop increased" + } + +@@ -591,44 +605,46 @@ backup_nhid_ping() + echo "------------------------" + + # Test bidirectional traffic when traffic is redirected in both VTEPs. +- sw1_mac=$(ip -n sw1 -j -p link show br0.10 | jq -r '.[]["address"]') +- sw2_mac=$(ip -n sw2 -j -p link show br0.10 | jq -r '.[]["address"]') ++ sw1_mac=$(ip -n $sw1 -j -p link show br0.10 | jq -r '.[]["address"]') ++ sw2_mac=$(ip -n $sw2 -j -p link show br0.10 | jq -r '.[]["address"]') + +- run_cmd "bridge -n sw1 fdb replace $sw2_mac dev swp1 master static vlan 10" +- run_cmd "bridge -n sw2 fdb replace $sw1_mac dev swp1 master static vlan 10" ++ run_cmd "bridge -n $sw1 fdb replace $sw2_mac dev swp1 master static vlan 10" ++ run_cmd "bridge -n $sw2 fdb replace $sw1_mac dev swp1 master static vlan 10" + +- run_cmd "ip -n sw1 neigh replace 192.0.2.66 lladdr $sw2_mac nud perm dev br0.10" +- run_cmd "ip -n sw2 neigh replace 192.0.2.65 lladdr $sw1_mac nud perm dev br0.10" ++ run_cmd "ip -n $sw1 neigh replace 192.0.2.66 lladdr $sw2_mac nud perm dev br0.10" ++ run_cmd "ip -n $sw2 neigh replace 192.0.2.65 lladdr $sw1_mac nud perm dev br0.10" + +- run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb" +- run_cmd "ip -n sw2 nexthop replace id 1 via 192.0.2.33 fdb" +- run_cmd "ip -n sw1 nexthop replace id 10 group 1 fdb" +- run_cmd "ip -n sw2 nexthop replace id 10 group 1 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb" ++ run_cmd "ip -n $sw2 nexthop replace id 1 via 192.0.2.33 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 10 group 1 fdb" ++ run_cmd "ip -n $sw2 nexthop replace id 10 group 1 fdb" + +- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" +- run_cmd "bridge -n sw2 link set dev swp1 backup_port vx0" +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10" +- run_cmd "bridge -n sw2 link set dev swp1 backup_nhid 10" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" ++ run_cmd "bridge -n $sw2 link set dev swp1 backup_port vx0" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10" ++ run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 10" + +- run_cmd "ip -n sw1 link set dev swp1 carrier off" +- run_cmd "ip -n sw2 link set dev swp1 carrier off" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw1 swp1 disabled ++ run_cmd "ip -n $sw2 link set dev swp1 carrier off" ++ busywait $BUSYWAIT_TIMEOUT bridge_link_check $sw2 swp1 disabled + +- run_cmd "ip netns exec sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" ++ run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" + log_test $? 0 "Ping with backup nexthop ID" + + # Reset the backup nexthop ID to 0 and check that ping fails. +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 0" +- run_cmd "bridge -n sw2 link set dev swp1 backup_nhid 0" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 0" ++ run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 0" + +- run_cmd "ip netns exec sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" ++ run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66" + log_test $? 1 "Ping after disabling backup nexthop ID" + } + + backup_nhid_add_del_loop() + { + while true; do +- ip -n sw1 nexthop del id 10 +- ip -n sw1 nexthop replace id 10 group 1/2 fdb ++ ip -n $sw1 nexthop del id 10 ++ ip -n $sw1 nexthop replace id 10 group 1/2 fdb + done >/dev/null 2>&1 + } + +@@ -648,19 +664,19 @@ backup_nhid_torture() + # deleting the group. The test is considered successful if nothing + # crashed. + +- run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb" +- run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb" +- run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb" ++ run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb" + +- run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10" ++ run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10" + +- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0" +- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10" +- run_cmd "ip -n sw1 link set dev swp1 carrier off" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0" ++ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10" ++ run_cmd "ip -n $sw1 link set dev swp1 carrier off" + + backup_nhid_add_del_loop & + pid1=$! +- ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 0 & ++ ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 0 & + pid2=$! + + sleep 30 +diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile +index 2456a399eb9ae..afd18c678ff5a 100644 +--- a/tools/tracing/rtla/Makefile ++++ b/tools/tracing/rtla/Makefile +@@ -28,10 +28,15 @@ FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \ + -fasynchronous-unwind-tables -fstack-clash-protection + WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized + ++ifeq ($(CC),clang) ++ FOPTS := $(filter-out -ffat-lto-objects, $(FOPTS)) ++ WOPTS := $(filter-out -Wno-maybe-uninitialized, $(WOPTS)) ++endif ++ + TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs) + + CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS) +-LDFLAGS := -ggdb $(EXTRA_LDFLAGS) ++LDFLAGS := -flto=auto -ggdb $(EXTRA_LDFLAGS) + LIBS := $$($(PKG_CONFIG) --libs libtracefs) + + SRC := $(wildcard src/*.c) +diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c +index 8f81fa0073648..01870d50942a1 100644 +--- a/tools/tracing/rtla/src/osnoise_hist.c ++++ b/tools/tracing/rtla/src/osnoise_hist.c +@@ -135,8 +135,7 @@ static void osnoise_hist_update_multiple(struct osnoise_tool *tool, int cpu, + if (params->output_divisor) + duration = duration / params->output_divisor; + +- if (data->bucket_size) +- bucket = duration / data->bucket_size; ++ bucket = duration / data->bucket_size; + + total_duration = duration * count; + +@@ -480,7 +479,11 @@ static void osnoise_hist_usage(char *usage) + + for (i = 0; msg[i]; i++) + fprintf(stderr, "%s\n", msg[i]); +- exit(1); ++ ++ if (usage) ++ exit(EXIT_FAILURE); ++ ++ exit(EXIT_SUCCESS); + } + + /* +diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c +index f7c959be86777..457360db07673 100644 +--- a/tools/tracing/rtla/src/osnoise_top.c ++++ b/tools/tracing/rtla/src/osnoise_top.c +@@ -331,7 +331,11 @@ static void osnoise_top_usage(struct osnoise_top_params *params, char *usage) + + for (i = 0; msg[i]; i++) + fprintf(stderr, "%s\n", msg[i]); +- exit(1); ++ ++ if (usage) ++ exit(EXIT_FAILURE); ++ ++ exit(EXIT_SUCCESS); + } + + /* +diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c +index 47d3d8b53cb21..dbf154082f958 100644 +--- a/tools/tracing/rtla/src/timerlat_hist.c ++++ b/tools/tracing/rtla/src/timerlat_hist.c +@@ -178,8 +178,7 @@ timerlat_hist_update(struct osnoise_tool *tool, int cpu, + if (params->output_divisor) + latency = latency / params->output_divisor; + +- if (data->bucket_size) +- bucket = latency / data->bucket_size; ++ bucket = latency / data->bucket_size; + + if (!context) { + hist = data->hist[cpu].irq; +@@ -546,7 +545,11 @@ static void timerlat_hist_usage(char *usage) + + for (i = 0; msg[i]; i++) + fprintf(stderr, "%s\n", msg[i]); +- exit(1); ++ ++ if (usage) ++ exit(EXIT_FAILURE); ++ ++ exit(EXIT_SUCCESS); + } + + /* +diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c +index 1640f121baca5..3e9af2c386888 100644 +--- a/tools/tracing/rtla/src/timerlat_top.c ++++ b/tools/tracing/rtla/src/timerlat_top.c +@@ -375,7 +375,11 @@ static void timerlat_top_usage(char *usage) + + for (i = 0; msg[i]; i++) + fprintf(stderr, "%s\n", msg[i]); +- exit(1); ++ ++ if (usage) ++ exit(EXIT_FAILURE); ++ ++ exit(EXIT_SUCCESS); + } + + /* +diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c +index c769d7b3842c0..9ac71a66840c1 100644 +--- a/tools/tracing/rtla/src/utils.c ++++ b/tools/tracing/rtla/src/utils.c +@@ -238,12 +238,6 @@ static inline int sched_setattr(pid_t pid, const struct sched_attr *attr, + return syscall(__NR_sched_setattr, pid, attr, flags); + } + +-static inline int sched_getattr(pid_t pid, struct sched_attr *attr, +- unsigned int size, unsigned int flags) +-{ +- return syscall(__NR_sched_getattr, pid, attr, size, flags); +-} +- + int __set_sched_attr(int pid, struct sched_attr *attr) + { + int flags = 0; +@@ -479,13 +473,13 @@ int parse_prio(char *arg, struct sched_attr *sched_param) + if (prio == INVALID_VAL) + return -1; + +- if (prio < sched_get_priority_min(SCHED_OTHER)) ++ if (prio < MIN_NICE) + return -1; +- if (prio > sched_get_priority_max(SCHED_OTHER)) ++ if (prio > MAX_NICE) + return -1; + + sched_param->sched_policy = SCHED_OTHER; +- sched_param->sched_priority = prio; ++ sched_param->sched_nice = prio; + break; + default: + return -1; +@@ -536,7 +530,7 @@ int set_cpu_dma_latency(int32_t latency) + */ + static const int find_mount(const char *fs, char *mp, int sizeof_mp) + { +- char mount_point[MAX_PATH]; ++ char mount_point[MAX_PATH+1]; + char type[100]; + int found = 0; + FILE *fp; +diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h +index 04ed1e650495a..d44513e6c66a0 100644 +--- a/tools/tracing/rtla/src/utils.h ++++ b/tools/tracing/rtla/src/utils.h +@@ -9,6 +9,8 @@ + */ + #define BUFF_U64_STR_SIZE 24 + #define MAX_PATH 1024 ++#define MAX_NICE 20 ++#define MIN_NICE -19 + + #define container_of(ptr, type, member)({ \ + const typeof(((type *)0)->member) *__mptr = (ptr); \ +diff --git a/tools/verification/rv/Makefile b/tools/verification/rv/Makefile +index 3d0f3888a58c6..485f8aeddbe03 100644 +--- a/tools/verification/rv/Makefile ++++ b/tools/verification/rv/Makefile +@@ -28,10 +28,15 @@ FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \ + -fasynchronous-unwind-tables -fstack-clash-protection + WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized + ++ifeq ($(CC),clang) ++ FOPTS := $(filter-out -ffat-lto-objects, $(FOPTS)) ++ WOPTS := $(filter-out -Wno-maybe-uninitialized, $(WOPTS)) ++endif ++ + TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs) + + CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS) -I include +-LDFLAGS := -ggdb $(EXTRA_LDFLAGS) ++LDFLAGS := -flto=auto -ggdb $(EXTRA_LDFLAGS) + LIBS := $$($(PKG_CONFIG) --libs libtracefs) + + SRC := $(wildcard src/*.c) +diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/src/in_kernel.c +index ad28582bcf2b1..f04479ecc96c0 100644 +--- a/tools/verification/rv/src/in_kernel.c ++++ b/tools/verification/rv/src/in_kernel.c +@@ -210,9 +210,9 @@ static char *ikm_read_reactor(char *monitor_name) + static char *ikm_get_current_reactor(char *monitor_name) + { + char *reactors = ikm_read_reactor(monitor_name); ++ char *curr_reactor = NULL; + char *start; + char *end; +- char *curr_reactor; + + if (!reactors) + return NULL; |