From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org, akpm@linux-foundation.org,
torvalds@linux-foundation.org, stable@vger.kernel.org
Cc: lwn@lwn.net, jslaby@suse.cz,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: Re: Linux 6.18.23
Date: Sat, 18 Apr 2026 10:51:28 +0200 [thread overview]
Message-ID: <2026041828-perm-siesta-5f30@gregkh> (raw)
In-Reply-To: <2026041828-punch-tadpole-d578@gregkh>
diff --git a/Makefile b/Makefile
index 6fba60168bb9..84ef363e7af6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 18
-SUBLEVEL = 22
+SUBLEVEL = 23
EXTRAVERSION =
NAME = Baby Opossum Posse
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts
index 077c5cd2586f..4533a84fb0b9 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-r3.dts
@@ -7,7 +7,7 @@
&a53_opp_table {
opp-1000000000 {
- opp-microvolt = <950000>;
+ opp-microvolt = <1000000>;
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
index 9e0e2d7271ef..e5f228517b6d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
@@ -844,9 +844,9 @@ buck1_reg: BUCK1 {
regulator-max-microvolt = <1300000>;
regulator-boot-on;
regulator-ramp-delay = <1250>;
- rohm,dvs-run-voltage = <880000>;
- rohm,dvs-idle-voltage = <820000>;
- rohm,dvs-suspend-voltage = <810000>;
+ rohm,dvs-run-voltage = <900000>;
+ rohm,dvs-idle-voltage = <850000>;
+ rohm,dvs-suspend-voltage = <850000>;
regulator-always-on;
};
@@ -856,8 +856,8 @@ buck2_reg: BUCK2 {
regulator-max-microvolt = <1300000>;
regulator-boot-on;
regulator-ramp-delay = <1250>;
- rohm,dvs-run-voltage = <950000>;
- rohm,dvs-idle-voltage = <850000>;
+ rohm,dvs-run-voltage = <1000000>;
+ rohm,dvs-idle-voltage = <900000>;
regulator-always-on;
};
@@ -866,14 +866,14 @@ buck3_reg: BUCK3 {
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1300000>;
regulator-boot-on;
- rohm,dvs-run-voltage = <850000>;
+ rohm,dvs-run-voltage = <900000>;
};
buck4_reg: BUCK4 {
regulator-name = "buck4";
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1300000>;
- rohm,dvs-run-voltage = <930000>;
+ rohm,dvs-run-voltage = <1000000>;
};
buck5_reg: BUCK5 {
@@ -1407,13 +1407,3 @@ &wdog1 {
fsl,ext-reset-output;
status = "okay";
};
-
-&a53_opp_table {
- opp-1000000000 {
- opp-microvolt = <850000>;
- };
-
- opp-1500000000 {
- opp-microvolt = <950000>;
- };
-};
diff --git a/arch/arm64/boot/dts/hisilicon/hi3798cv200-poplar.dts b/arch/arm64/boot/dts/hisilicon/hi3798cv200-poplar.dts
index 7d370dac4c85..579d55daa7d0 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3798cv200-poplar.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi3798cv200-poplar.dts
@@ -179,7 +179,7 @@ &ohci {
};
&pcie {
- reset-gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio4 4 GPIO_ACTIVE_LOW>;
vpcie-supply = <®_pcie>;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi b/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi
index f6bc001c3832..2f4ad5da5e33 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi
@@ -122,6 +122,7 @@ soc: soc@f0000000 {
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x0 0xf0000000 0x10000000>;
+ dma-ranges = <0x0 0x0 0x0 0x40000000>;
crg: clock-reset-controller@8a22000 {
compatible = "hisilicon,hi3798cv200-crg", "syscon", "simple-mfd";
diff --git a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts
index ff07d984cbf2..812b133cf29e 100644
--- a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts
+++ b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts
@@ -118,6 +118,17 @@ memory@600000000 {
reg = <0x6 0x00000000 0x1 0x00000000>;
};
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ tfa@40000000 {
+ reg = <0x0 0x40000000 0x0 0x8000000>;
+ no-map;
+ };
+ };
+
/* Page 27 / DSI to Display */
dp-con {
compatible = "dp-connector";
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
index a6ac89567baf..54abe0585ec5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
@@ -879,12 +879,6 @@ vcc5v0_host_en_pin: vcc5v0-host-en-pin {
};
};
- wifi {
- wifi_host_wake_l: wifi-host-wake-l {
- rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
- };
- };
-
wireless-bluetooth {
bt_wake_pin: bt-wake-pin {
rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -942,19 +936,7 @@ &sdio0 {
pinctrl-names = "default";
pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
sd-uhs-sdr104;
- #address-cells = <1>;
- #size-cells = <0>;
status = "okay";
-
- brcmf: wifi@1 {
- compatible = "brcm,bcm4329-fmac";
- reg = <1>;
- interrupt-parent = <&gpio0>;
- interrupts = <RK_PA3 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "host-wake";
- pinctrl-names = "default";
- pinctrl-0 = <&wifi_host_wake_l>;
- };
};
&sdhci {
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 404390bb87ea..3f11e5218e6c 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -484,7 +484,6 @@
# endif
# ifndef cpu_vmbits
# define cpu_vmbits cpu_data[0].vmbits
-# define __NEED_VMBITS_PROBE
# endif
#endif
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h
index fd60837ce50b..211b578af6aa 100644
--- a/arch/mips/include/asm/cpu-info.h
+++ b/arch/mips/include/asm/cpu-info.h
@@ -80,9 +80,7 @@ struct cpuinfo_mips {
int srsets; /* Shadow register sets */
int package;/* physical package number */
unsigned int globalnumber;
-#ifdef CONFIG_64BIT
int vmbits; /* Virtual memory size in bits */
-#endif
void *data; /* Additional data */
unsigned int watch_reg_count; /* Number that exist */
unsigned int watch_reg_use_cnt; /* Usable by ptrace */
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index f799c0d723da..12a095dbf9e2 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -1871,6 +1871,8 @@ do { \
#define read_c0_entryhi() __read_ulong_c0_register($10, 0)
#define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val)
+#define read_c0_entryhi_64() __read_64bit_c0_register($10, 0)
+#define write_c0_entryhi_64(val) __write_64bit_c0_register($10, 0, val)
#define read_c0_guestctl1() __read_32bit_c0_register($10, 4)
#define write_c0_guestctl1(val) __write_32bit_c0_register($10, 4, val)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 1e49e05ac8b1..489612ed9d49 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -210,11 +210,14 @@ static inline void set_elf_base_platform(const char *plat)
static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
{
-#ifdef __NEED_VMBITS_PROBE
- write_c0_entryhi(0x3fffffffffffe000ULL);
- back_to_back_c0_hazard();
- c->vmbits = fls64(read_c0_entryhi() & 0x3fffffffffffe000ULL);
-#endif
+ int vmbits = 31;
+
+ if (cpu_has_64bits) {
+ write_c0_entryhi_64(0x3fffffffffffe000ULL);
+ back_to_back_c0_hazard();
+ vmbits = fls64(read_c0_entryhi_64() & 0x3fffffffffffe000ULL);
+ }
+ c->vmbits = vmbits;
}
static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
diff --git a/arch/mips/kernel/cpu-r3k-probe.c b/arch/mips/kernel/cpu-r3k-probe.c
index 0c826f729f75..edcf04de0a6f 100644
--- a/arch/mips/kernel/cpu-r3k-probe.c
+++ b/arch/mips/kernel/cpu-r3k-probe.c
@@ -137,6 +137,8 @@ void cpu_probe(void)
else
cpu_set_nofpu_opts(c);
+ c->vmbits = 31;
+
reserve_exception_space(0, 0x400);
}
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 645f77e09d5b..24fe85fa169d 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -13,6 +13,7 @@
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/memblock.h>
+#include <linux/minmax.h>
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/export.h>
@@ -24,6 +25,7 @@
#include <asm/hazards.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
+#include <asm/tlbdebug.h>
#include <asm/tlbex.h>
#include <asm/tlbmisc.h>
#include <asm/setup.h>
@@ -511,87 +513,259 @@ static int __init set_ntlb(char *str)
__setup("ntlb=", set_ntlb);
-/* Comparison function for EntryHi VPN fields. */
-static int r4k_vpn_cmp(const void *a, const void *b)
+/* The start bit position of VPN2 and Mask in EntryHi/PageMask registers. */
+#define VPN2_SHIFT 13
+
+/* Read full EntryHi even with CONFIG_32BIT. */
+static inline unsigned long long read_c0_entryhi_native(void)
+{
+ return cpu_has_64bits ? read_c0_entryhi_64() : read_c0_entryhi();
+}
+
+/* Write full EntryHi even with CONFIG_32BIT. */
+static inline void write_c0_entryhi_native(unsigned long long v)
{
- long v = *(unsigned long *)a - *(unsigned long *)b;
- int s = sizeof(long) > sizeof(int) ? sizeof(long) * 8 - 1: 0;
- return s ? (v != 0) | v >> s : v;
+ if (cpu_has_64bits)
+ write_c0_entryhi_64(v);
+ else
+ write_c0_entryhi(v);
}
+/* TLB entry state for uniquification. */
+struct tlbent {
+ unsigned long long wired:1;
+ unsigned long long global:1;
+ unsigned long long asid:10;
+ unsigned long long vpn:51;
+ unsigned long long pagesz:5;
+ unsigned long long index:14;
+};
+
/*
- * Initialise all TLB entries with unique values that do not clash with
- * what we have been handed over and what we'll be using ourselves.
+ * Comparison function for TLB entry sorting. Place wired entries first,
+ * then global entries, then order by the increasing VPN/ASID and the
+ * decreasing page size. This lets us avoid clashes with wired entries
+ * easily and get entries for larger pages out of the way first.
+ *
+ * We could group bits so as to reduce the number of comparisons, but this
+ * is seldom executed and not performance-critical, so prefer legibility.
*/
-static void __ref r4k_tlb_uniquify(void)
+static int r4k_entry_cmp(const void *a, const void *b)
{
- int tlbsize = current_cpu_data.tlbsize;
- bool use_slab = slab_is_available();
- int start = num_wired_entries();
- phys_addr_t tlb_vpn_size;
- unsigned long *tlb_vpns;
- unsigned long vpn_mask;
- int cnt, ent, idx, i;
-
- vpn_mask = GENMASK(cpu_vmbits - 1, 13);
- vpn_mask |= IS_ENABLED(CONFIG_64BIT) ? 3ULL << 62 : 1 << 31;
+ struct tlbent ea = *(struct tlbent *)a, eb = *(struct tlbent *)b;
+
+ if (ea.wired > eb.wired)
+ return -1;
+ else if (ea.wired < eb.wired)
+ return 1;
+ else if (ea.global > eb.global)
+ return -1;
+ else if (ea.global < eb.global)
+ return 1;
+ else if (ea.vpn < eb.vpn)
+ return -1;
+ else if (ea.vpn > eb.vpn)
+ return 1;
+ else if (ea.asid < eb.asid)
+ return -1;
+ else if (ea.asid > eb.asid)
+ return 1;
+ else if (ea.pagesz > eb.pagesz)
+ return -1;
+ else if (ea.pagesz < eb.pagesz)
+ return 1;
+ else
+ return 0;
+}
- tlb_vpn_size = tlbsize * sizeof(*tlb_vpns);
- tlb_vpns = (use_slab ?
- kmalloc(tlb_vpn_size, GFP_ATOMIC) :
- memblock_alloc_raw(tlb_vpn_size, sizeof(*tlb_vpns)));
- if (WARN_ON(!tlb_vpns))
- return; /* Pray local_flush_tlb_all() is good enough. */
+/*
+ * Fetch all the TLB entries. Mask individual VPN values retrieved with
+ * the corresponding page mask and ignoring any 1KiB extension as we'll
+ * be using 4KiB pages for uniquification.
+ */
+static void __ref r4k_tlb_uniquify_read(struct tlbent *tlb_vpns, int tlbsize)
+{
+ int start = num_wired_entries();
+ unsigned long long vpn_mask;
+ bool global;
+ int i;
- htw_stop();
+ vpn_mask = GENMASK(current_cpu_data.vmbits - 1, VPN2_SHIFT);
+ vpn_mask |= cpu_has_64bits ? 3ULL << 62 : 1 << 31;
- for (i = start, cnt = 0; i < tlbsize; i++, cnt++) {
- unsigned long vpn;
+ for (i = 0; i < tlbsize; i++) {
+ unsigned long long entryhi, vpn, mask, asid;
+ unsigned int pagesz;
write_c0_index(i);
mtc0_tlbr_hazard();
tlb_read();
tlb_read_hazard();
- vpn = read_c0_entryhi();
- vpn &= vpn_mask & PAGE_MASK;
- tlb_vpns[cnt] = vpn;
- /* Prevent any large pages from overlapping regular ones. */
- write_c0_pagemask(read_c0_pagemask() & PM_DEFAULT_MASK);
- mtc0_tlbw_hazard();
- tlb_write_indexed();
- tlbw_use_hazard();
+ global = !!(read_c0_entrylo0() & ENTRYLO_G);
+ entryhi = read_c0_entryhi_native();
+ mask = read_c0_pagemask();
+
+ asid = entryhi & cpu_asid_mask(¤t_cpu_data);
+ vpn = (entryhi & vpn_mask & ~mask) >> VPN2_SHIFT;
+ pagesz = ilog2((mask >> VPN2_SHIFT) + 1);
+
+ tlb_vpns[i].global = global;
+ tlb_vpns[i].asid = global ? 0 : asid;
+ tlb_vpns[i].vpn = vpn;
+ tlb_vpns[i].pagesz = pagesz;
+ tlb_vpns[i].wired = i < start;
+ tlb_vpns[i].index = i;
}
+}
- sort(tlb_vpns, cnt, sizeof(tlb_vpns[0]), r4k_vpn_cmp, NULL);
+/*
+ * Write unique values to all but the wired TLB entries each, using
+ * the 4KiB page size. This size might not be supported with R6, but
+ * EHINV is mandatory for R6, so we won't ever be called in that case.
+ *
+ * A sorted table is supplied with any wired entries at the beginning,
+ * followed by any global entries, and then finally regular entries.
+ * We start at the VPN and ASID values of zero and only assign user
+ * addresses, therefore guaranteeing no clash with addresses produced
+ * by UNIQUE_ENTRYHI. We avoid any VPN values used by wired or global
+ * entries, by increasing the VPN value beyond the span of such entry.
+ *
+ * When a VPN/ASID clash is found with a regular entry we increment the
+ * ASID instead until no VPN/ASID clash has been found or the ASID space
+ * has been exhausted, in which case we increase the VPN value beyond
+ * the span of the largest clashing entry.
+ *
+ * We do not need to be concerned about FTLB or MMID configurations as
+ * those are required to implement the EHINV feature.
+ */
+static void __ref r4k_tlb_uniquify_write(struct tlbent *tlb_vpns, int tlbsize)
+{
+ unsigned long long asid, vpn, vpn_size, pagesz;
+ int widx, gidx, idx, sidx, lidx, i;
- write_c0_pagemask(PM_DEFAULT_MASK);
+ vpn_size = 1ULL << (current_cpu_data.vmbits - VPN2_SHIFT);
+ pagesz = ilog2((PM_4K >> VPN2_SHIFT) + 1);
+
+ write_c0_pagemask(PM_4K);
write_c0_entrylo0(0);
write_c0_entrylo1(0);
- idx = 0;
- ent = tlbsize;
- for (i = start; i < tlbsize; i++)
- while (1) {
- unsigned long entryhi, vpn;
+ asid = 0;
+ vpn = 0;
+ widx = 0;
+ gidx = 0;
+ for (sidx = 0; sidx < tlbsize && tlb_vpns[sidx].wired; sidx++)
+ ;
+ for (lidx = sidx; lidx < tlbsize && tlb_vpns[lidx].global; lidx++)
+ ;
+ idx = gidx = sidx + 1;
+ for (i = sidx; i < tlbsize; i++) {
+ unsigned long long entryhi, vpn_pagesz = 0;
- entryhi = UNIQUE_ENTRYHI(ent);
- vpn = entryhi & vpn_mask & PAGE_MASK;
+ while (1) {
+ if (WARN_ON(vpn >= vpn_size)) {
+ dump_tlb_all();
+ /* Pray local_flush_tlb_all() will cope. */
+ return;
+ }
- if (idx >= cnt || vpn < tlb_vpns[idx]) {
- write_c0_entryhi(entryhi);
- write_c0_index(i);
- mtc0_tlbw_hazard();
- tlb_write_indexed();
- ent++;
- break;
- } else if (vpn == tlb_vpns[idx]) {
- ent++;
- } else {
+ /* VPN must be below the next wired entry. */
+ if (widx < sidx && vpn >= tlb_vpns[widx].vpn) {
+ vpn = max(vpn,
+ (tlb_vpns[widx].vpn +
+ (1ULL << tlb_vpns[widx].pagesz)));
+ asid = 0;
+ widx++;
+ continue;
+ }
+ /* VPN must be below the next global entry. */
+ if (gidx < lidx && vpn >= tlb_vpns[gidx].vpn) {
+ vpn = max(vpn,
+ (tlb_vpns[gidx].vpn +
+ (1ULL << tlb_vpns[gidx].pagesz)));
+ asid = 0;
+ gidx++;
+ continue;
+ }
+ /* Try to find a free ASID so as to conserve VPNs. */
+ if (idx < tlbsize && vpn == tlb_vpns[idx].vpn &&
+ asid == tlb_vpns[idx].asid) {
+ unsigned long long idx_pagesz;
+
+ idx_pagesz = tlb_vpns[idx].pagesz;
+ vpn_pagesz = max(vpn_pagesz, idx_pagesz);
+ do
+ idx++;
+ while (idx < tlbsize &&
+ vpn == tlb_vpns[idx].vpn &&
+ asid == tlb_vpns[idx].asid);
+ asid++;
+ if (asid > cpu_asid_mask(¤t_cpu_data)) {
+ vpn += vpn_pagesz;
+ asid = 0;
+ vpn_pagesz = 0;
+ }
+ continue;
+ }
+ /* VPN mustn't be above the next regular entry. */
+ if (idx < tlbsize && vpn > tlb_vpns[idx].vpn) {
+ vpn = max(vpn,
+ (tlb_vpns[idx].vpn +
+ (1ULL << tlb_vpns[idx].pagesz)));
+ asid = 0;
idx++;
+ continue;
}
+ break;
}
+ entryhi = (vpn << VPN2_SHIFT) | asid;
+ write_c0_entryhi_native(entryhi);
+ write_c0_index(tlb_vpns[i].index);
+ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+
+ tlb_vpns[i].asid = asid;
+ tlb_vpns[i].vpn = vpn;
+ tlb_vpns[i].pagesz = pagesz;
+
+ asid++;
+ if (asid > cpu_asid_mask(¤t_cpu_data)) {
+ vpn += 1ULL << pagesz;
+ asid = 0;
+ }
+ }
+}
+
+/*
+ * Initialise all TLB entries with unique values that do not clash with
+ * what we have been handed over and what we'll be using ourselves.
+ */
+static void __ref r4k_tlb_uniquify(void)
+{
+ int tlbsize = current_cpu_data.tlbsize;
+ bool use_slab = slab_is_available();
+ phys_addr_t tlb_vpn_size;
+ struct tlbent *tlb_vpns;
+
+ tlb_vpn_size = tlbsize * sizeof(*tlb_vpns);
+ tlb_vpns = (use_slab ?
+ kmalloc(tlb_vpn_size, GFP_ATOMIC) :
+ memblock_alloc_raw(tlb_vpn_size, sizeof(*tlb_vpns)));
+ if (WARN_ON(!tlb_vpns))
+ return; /* Pray local_flush_tlb_all() is good enough. */
+
+ htw_stop();
+
+ r4k_tlb_uniquify_read(tlb_vpns, tlbsize);
+
+ sort(tlb_vpns, tlbsize, sizeof(*tlb_vpns), r4k_entry_cmp, NULL);
+
+ r4k_tlb_uniquify_write(tlb_vpns, tlbsize);
+
+ write_c0_pagemask(PM_DEFAULT_MASK);
+
tlbw_use_hazard();
htw_start();
flush_micro_tlb();
@@ -640,7 +814,8 @@ static void r4k_tlb_configure(void)
temp_tlb_entry = current_cpu_data.tlbsize - 1;
/* From this point on the ARC firmware is dead. */
- r4k_tlb_uniquify();
+ if (!cpu_has_tlbinv)
+ r4k_tlb_uniquify();
local_flush_tlb_all();
/* Did I tell you that ARC SUCKS? */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index d9e03c6d1d5c..66ddea295c26 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -645,6 +645,9 @@
#define MSR_AMD64_DC_CFG 0xc0011022
#define MSR_AMD64_TW_CFG 0xc0011023
+#define MSR_AMD64_FP_CFG 0xc0011028
+#define MSR_AMD64_FP_CFG_ZEN1_DENORM_FIX_BIT 9
+
#define MSR_AMD64_DE_CFG 0xc0011029
#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT 1
#define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE BIT_ULL(MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT)
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index a92750f3079a..ec965de4abec 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -949,6 +949,9 @@ static void init_amd_zen1(struct cpuinfo_x86 *c)
msr_clear_bit(MSR_K7_HWCR, MSR_K7_HWCR_IRPERF_EN_BIT);
clear_cpu_cap(c, X86_FEATURE_IRPERF);
}
+
+ pr_notice_once("AMD Zen1 FPDSS bug detected, enabling mitigation.\n");
+ msr_set_bit(MSR_AMD64_FP_CFG, MSR_AMD64_FP_CFG_ZEN1_DENORM_FIX_BIT);
}
static const struct x86_cpu_id amd_zenbleed_microcode[] = {
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 8df3fa60a44f..b56b0d3c443b 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -584,10 +584,10 @@ int x509_process_extension(void *context, size_t hdrlen,
* 0x04 is where keyCertSign lands in this bit string
* 0x80 is where digitalSignature lands in this bit string
*/
- if (v[0] != ASN1_BTS)
- return -EBADMSG;
if (vlen < 4)
return -EBADMSG;
+ if (v[0] != ASN1_BTS)
+ return -EBADMSG;
if (v[2] >= 8)
return -EBADMSG;
if (v[3] & 0x80)
@@ -620,10 +620,10 @@ int x509_process_extension(void *context, size_t hdrlen,
* (Expect 0xFF if the CA is TRUE)
* vlen should match the entire extension size
*/
- if (v[0] != (ASN1_CONS_BIT | ASN1_SEQ))
- return -EBADMSG;
if (vlen < 2)
return -EBADMSG;
+ if (v[0] != (ASN1_CONS_BIT | ASN1_SEQ))
+ return -EBADMSG;
if (v[1] != vlen - 2)
return -EBADMSG;
/* Empty SEQUENCE means CA:FALSE (default value omitted per DER) */
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 0959320fe51c..b510919e49c0 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -370,13 +370,13 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
if (!mci->layers)
goto error;
+ mci->dev.release = mci_release;
+ device_initialize(&mci->dev);
+
mci->pvt_info = kzalloc(sz_pvt, GFP_KERNEL);
if (!mci->pvt_info)
goto error;
- mci->dev.release = mci_release;
- device_initialize(&mci->dev);
-
/* setup index and various internal pointers */
mci->mc_idx = mc_num;
mci->tot_dimms = tot_dimms;
diff --git a/drivers/firmware/thead,th1520-aon.c b/drivers/firmware/thead,th1520-aon.c
index 38f812ac9920..b87d4e8235b1 100644
--- a/drivers/firmware/thead,th1520-aon.c
+++ b/drivers/firmware/thead,th1520-aon.c
@@ -170,10 +170,9 @@ int th1520_aon_power_update(struct th1520_aon_chan *aon_chan, u16 rsrc,
hdr->func = TH1520_AON_PM_FUNC_SET_RESOURCE_POWER_MODE;
hdr->size = TH1520_AON_RPC_MSG_NUM;
- RPC_SET_BE16(&msg.resource, 0, rsrc);
- RPC_SET_BE16(&msg.resource, 2,
- (power_on ? TH1520_AON_PM_PW_MODE_ON :
- TH1520_AON_PM_PW_MODE_OFF));
+ msg.resource = cpu_to_be16(rsrc);
+ msg.mode = cpu_to_be16(power_on ? TH1520_AON_PM_PW_MODE_ON :
+ TH1520_AON_PM_PW_MODE_OFF);
ret = th1520_aon_call_rpc(aon_chan, &msg);
if (ret)
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 83299fd50ef0..504f6228bf35 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -2549,9 +2549,9 @@ static u32 psr2_pipe_srcsz_early_tpt_calc(struct intel_crtc_state *crtc_state,
static void clip_area_update(struct drm_rect *overlap_damage_area,
struct drm_rect *damage_area,
- struct drm_rect *pipe_src)
+ struct drm_rect *display_area)
{
- if (!drm_rect_intersect(damage_area, pipe_src))
+ if (!drm_rect_intersect(damage_area, display_area))
return;
if (overlap_damage_area->y1 == -1) {
@@ -2602,6 +2602,7 @@ static bool intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_st
static void
intel_psr2_sel_fetch_et_alignment(struct intel_atomic_state *state,
struct intel_crtc *crtc,
+ struct drm_rect *display_area,
bool *cursor_in_su_area)
{
struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
@@ -2629,7 +2630,7 @@ intel_psr2_sel_fetch_et_alignment(struct intel_atomic_state *state,
continue;
clip_area_update(&crtc_state->psr2_su_area, &new_plane_state->uapi.dst,
- &crtc_state->pipe_src);
+ display_area);
*cursor_in_su_area = true;
}
}
@@ -2725,6 +2726,12 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
struct intel_plane_state *new_plane_state, *old_plane_state;
struct intel_plane *plane;
+ struct drm_rect display_area = {
+ .x1 = 0,
+ .y1 = 0,
+ .x2 = crtc_state->hw.adjusted_mode.crtc_hdisplay,
+ .y2 = crtc_state->hw.adjusted_mode.crtc_vdisplay,
+ };
bool full_update = false, su_area_changed;
int i, ret;
@@ -2738,7 +2745,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
crtc_state->psr2_su_area.x1 = 0;
crtc_state->psr2_su_area.y1 = -1;
- crtc_state->psr2_su_area.x2 = drm_rect_width(&crtc_state->pipe_src);
+ crtc_state->psr2_su_area.x2 = drm_rect_width(&display_area);
crtc_state->psr2_su_area.y2 = -1;
/*
@@ -2776,14 +2783,14 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
damaged_area.y1 = old_plane_state->uapi.dst.y1;
damaged_area.y2 = old_plane_state->uapi.dst.y2;
clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
- &crtc_state->pipe_src);
+ &display_area);
}
if (new_plane_state->uapi.visible) {
damaged_area.y1 = new_plane_state->uapi.dst.y1;
damaged_area.y2 = new_plane_state->uapi.dst.y2;
clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
- &crtc_state->pipe_src);
+ &display_area);
}
continue;
} else if (new_plane_state->uapi.alpha != old_plane_state->uapi.alpha) {
@@ -2791,7 +2798,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
damaged_area.y1 = new_plane_state->uapi.dst.y1;
damaged_area.y2 = new_plane_state->uapi.dst.y2;
clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
- &crtc_state->pipe_src);
+ &display_area);
continue;
}
@@ -2807,7 +2814,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
damaged_area.x1 += new_plane_state->uapi.dst.x1 - src.x1;
damaged_area.x2 += new_plane_state->uapi.dst.x1 - src.x1;
- clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src);
+ clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &display_area);
}
/*
@@ -2842,7 +2849,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
* cursor is added into affected planes even when
* cursor is not updated by itself.
*/
- intel_psr2_sel_fetch_et_alignment(state, crtc, &cursor_in_su_area);
+ intel_psr2_sel_fetch_et_alignment(state, crtc, &display_area,
+ &cursor_in_su_area);
su_area_changed = intel_psr2_sel_fetch_pipe_alignment(crtc_state);
@@ -2918,8 +2926,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
skip_sel_fetch_set_loop:
if (full_update)
- clip_area_update(&crtc_state->psr2_su_area, &crtc_state->pipe_src,
- &crtc_state->pipe_src);
+ clip_area_update(&crtc_state->psr2_su_area, &display_area,
+ &display_area);
psr2_man_trk_ctl_calc(crtc_state, full_update);
crtc_state->pipe_srcsz_early_tpt =
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
index 8d4bb95f8424..cad81592c848 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
@@ -145,10 +145,12 @@ static void heartbeat(struct work_struct *wrk)
/* Just in case everything has gone horribly wrong, give it a kick */
intel_engine_flush_submission(engine);
- rq = engine->heartbeat.systole;
- if (rq && i915_request_completed(rq)) {
- i915_request_put(rq);
- engine->heartbeat.systole = NULL;
+ rq = xchg(&engine->heartbeat.systole, NULL);
+ if (rq) {
+ if (i915_request_completed(rq))
+ i915_request_put(rq);
+ else
+ engine->heartbeat.systole = rq;
}
if (!intel_engine_pm_get_if_awake(engine))
@@ -229,8 +231,11 @@ static void heartbeat(struct work_struct *wrk)
unlock:
mutex_unlock(&ce->timeline->mutex);
out:
- if (!engine->i915->params.enable_hangcheck || !next_heartbeat(engine))
- i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
+ if (!engine->i915->params.enable_hangcheck || !next_heartbeat(engine)) {
+ rq = xchg(&engine->heartbeat.systole, NULL);
+ if (rq)
+ i915_request_put(rq);
+ }
intel_engine_pm_put(engine);
}
@@ -244,8 +249,13 @@ void intel_engine_unpark_heartbeat(struct intel_engine_cs *engine)
void intel_engine_park_heartbeat(struct intel_engine_cs *engine)
{
- if (cancel_delayed_work(&engine->heartbeat.work))
- i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
+ if (cancel_delayed_work(&engine->heartbeat.work)) {
+ struct i915_request *rq;
+
+ rq = xchg(&engine->heartbeat.systole, NULL);
+ if (rq)
+ i915_request_put(rq);
+ }
}
void intel_gt_unpark_heartbeats(struct intel_gt *gt)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 452d120a210b..a208fefd3c3b 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -401,7 +401,7 @@ static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx)
static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma_addr_t phy_addr)
{
struct imx_i2c_dma *dma;
- struct dma_slave_config dma_sconfig;
+ struct dma_slave_config dma_sconfig = {};
struct device *dev = i2c_imx->adapter.dev.parent;
int ret;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 13336a2fd49c..0e9544a98e67 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -25,8 +25,10 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/lockdep.h>
#include <linux/miscdevice.h>
#include <linux/overflow.h>
+#include <linux/spinlock.h>
#include <linux/input/mt.h>
#include "../input-compat.h"
@@ -57,6 +59,7 @@ struct uinput_device {
struct input_dev *dev;
struct mutex mutex;
enum uinput_state state;
+ spinlock_t state_lock;
wait_queue_head_t waitq;
unsigned char ready;
unsigned char head;
@@ -75,6 +78,8 @@ static int uinput_dev_event(struct input_dev *dev,
struct uinput_device *udev = input_get_drvdata(dev);
struct timespec64 ts;
+ lockdep_assert_held(&dev->event_lock);
+
ktime_get_ts64(&ts);
udev->buff[udev->head] = (struct input_event) {
@@ -146,27 +151,26 @@ static void uinput_request_release_slot(struct uinput_device *udev,
static int uinput_request_send(struct uinput_device *udev,
struct uinput_request *request)
{
- int retval;
+ unsigned long flags;
+ int retval = 0;
- retval = mutex_lock_interruptible(&udev->mutex);
- if (retval)
- return retval;
+ spin_lock(&udev->state_lock);
if (udev->state != UIST_CREATED) {
retval = -ENODEV;
goto out;
}
- init_completion(&request->done);
-
/*
* Tell our userspace application about this new request
* by queueing an input event.
*/
+ spin_lock_irqsave(&udev->dev->event_lock, flags);
uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
+ spin_unlock_irqrestore(&udev->dev->event_lock, flags);
out:
- mutex_unlock(&udev->mutex);
+ spin_unlock(&udev->state_lock);
return retval;
}
@@ -175,6 +179,13 @@ static int uinput_request_submit(struct uinput_device *udev,
{
int retval;
+ /*
+ * Initialize completion before allocating the request slot.
+ * Once the slot is allocated, uinput_flush_requests() may
+ * complete it at any time, so it must be initialized first.
+ */
+ init_completion(&request->done);
+
retval = uinput_request_reserve_slot(udev, request);
if (retval)
return retval;
@@ -289,7 +300,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
struct input_dev *dev = udev->dev;
enum uinput_state old_state = udev->state;
+ /*
+ * Update state under state_lock so that concurrent
+ * uinput_request_send() sees the state change before we
+ * flush pending requests and tear down the device.
+ */
+ spin_lock(&udev->state_lock);
udev->state = UIST_NEW_DEVICE;
+ spin_unlock(&udev->state_lock);
if (dev) {
name = dev->name;
@@ -366,7 +384,9 @@ static int uinput_create_device(struct uinput_device *udev)
if (error)
goto fail2;
+ spin_lock(&udev->state_lock);
udev->state = UIST_CREATED;
+ spin_unlock(&udev->state_lock);
return 0;
@@ -384,6 +404,7 @@ static int uinput_open(struct inode *inode, struct file *file)
return -ENOMEM;
mutex_init(&newdev->mutex);
+ spin_lock_init(&newdev->state_lock);
spin_lock_init(&newdev->requests_lock);
init_waitqueue_head(&newdev->requests_waitq);
init_waitqueue_head(&newdev->waitq);
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index ff49d0770506..3c9df27f9fa7 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -369,11 +369,14 @@ struct vub300_mmc_host {
static void vub300_delete(struct kref *kref)
{ /* kref callback - softirq */
struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
+ struct mmc_host *mmc = vub300->mmc;
+
usb_free_urb(vub300->command_out_urb);
vub300->command_out_urb = NULL;
usb_free_urb(vub300->command_res_urb);
vub300->command_res_urb = NULL;
usb_put_dev(vub300->udev);
+ mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
@@ -2112,7 +2115,7 @@ static int vub300_probe(struct usb_interface *interface,
goto error1;
}
/* this also allocates memory for our VUB300 mmc host device */
- mmc = devm_mmc_alloc_host(&udev->dev, sizeof(*vub300));
+ mmc = mmc_alloc_host(sizeof(*vub300), &udev->dev);
if (!mmc) {
retval = -ENOMEM;
dev_err(&udev->dev, "not enough memory for the mmc_host\n");
@@ -2269,7 +2272,7 @@ static int vub300_probe(struct usb_interface *interface,
dev_err(&vub300->udev->dev,
"Could not find two sets of bulk-in/out endpoint pairs\n");
retval = -EINVAL;
- goto error4;
+ goto err_free_host;
}
retval =
usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
@@ -2278,14 +2281,14 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->hc_info,
sizeof(vub300->hc_info), 1000);
if (retval < 0)
- goto error4;
+ goto err_free_host;
retval =
usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
SET_ROM_WAIT_STATES,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
firmware_rom_wait_states, 0x0000, NULL, 0, 1000);
if (retval < 0)
- goto error4;
+ goto err_free_host;
dev_info(&vub300->udev->dev,
"operating_mode = %s %s %d MHz %s %d byte USB packets\n",
(mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
@@ -2300,7 +2303,7 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->system_port_status,
sizeof(vub300->system_port_status), 1000);
if (retval < 0) {
- goto error4;
+ goto err_free_host;
} else if (sizeof(vub300->system_port_status) == retval) {
vub300->card_present =
(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
@@ -2308,7 +2311,7 @@ static int vub300_probe(struct usb_interface *interface,
(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
} else {
retval = -EINVAL;
- goto error4;
+ goto err_free_host;
}
usb_set_intfdata(interface, vub300);
INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
@@ -2338,6 +2341,8 @@ static int vub300_probe(struct usb_interface *interface,
return 0;
error6:
timer_delete_sync(&vub300->inactivity_timer);
+err_free_host:
+ mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
@@ -2365,8 +2370,8 @@ static void vub300_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
/* prevent more I/O from starting */
vub300->interface = NULL;
- kref_put(&vub300->kref, vub300_delete);
mmc_remove_host(mmc);
+ kref_put(&vub300->kref, vub300_delete);
pr_info("USB vub300 remote SDIO host controller[%d]"
" now disconnected", ifnum);
return;
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
index 3f6204de9e6b..a5d61a9a225a 100644
--- a/drivers/net/ethernet/altera/altera_tse_main.c
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -572,6 +572,7 @@ static netdev_tx_t tse_start_xmit(struct sk_buff *skb, struct net_device *dev)
DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, dma_addr)) {
netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+ dev_kfree_skb_any(skb);
ret = NETDEV_TX_OK;
goto out;
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index cb702eac86c8..3c8ceff0e669 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -284,26 +284,21 @@ int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
return err;
}
-/* API for virtchnl "transaction" support ("xn" for short).
- *
- * We are reusing the completion lock to serialize the accesses to the
- * transaction state for simplicity, but it could be its own separate synchro
- * as well. For now, this API is only used from within a workqueue context;
- * raw_spin_lock() is enough.
- */
+/* API for virtchnl "transaction" support ("xn" for short). */
+
/**
* idpf_vc_xn_lock - Request exclusive access to vc transaction
* @xn: struct idpf_vc_xn* to access
*/
#define idpf_vc_xn_lock(xn) \
- raw_spin_lock(&(xn)->completed.wait.lock)
+ spin_lock(&(xn)->lock)
/**
* idpf_vc_xn_unlock - Release exclusive access to vc transaction
* @xn: struct idpf_vc_xn* to access
*/
#define idpf_vc_xn_unlock(xn) \
- raw_spin_unlock(&(xn)->completed.wait.lock)
+ spin_unlock(&(xn)->lock)
/**
* idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and
@@ -335,6 +330,7 @@ static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
xn->state = IDPF_VC_XN_IDLE;
xn->idx = i;
idpf_vc_xn_release_bufs(xn);
+ spin_lock_init(&xn->lock);
init_completion(&xn->completed);
}
@@ -403,7 +399,9 @@ static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr,
struct idpf_vc_xn *xn)
{
idpf_vc_xn_release_bufs(xn);
+ spin_lock_bh(&vcxn_mngr->xn_bm_lock);
set_bit(xn->idx, vcxn_mngr->free_xn_bm);
+ spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
}
/**
@@ -614,6 +612,10 @@ idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,
err = -ENXIO;
goto out_unlock;
case IDPF_VC_XN_ASYNC:
+ /* Set reply_sz from the actual payload so that async_handler
+ * can evaluate the response.
+ */
+ xn->reply_sz = ctlq_msg->data_len;
err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);
idpf_vc_xn_unlock(xn);
return err;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index eac3d15daa42..0a50a08eb9af 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -42,8 +42,8 @@ typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
* struct idpf_vc_xn - Data structure representing virtchnl transactions
* @completed: virtchnl event loop uses that to signal when a reply is
* available, uses kernel completion API
- * @state: virtchnl event loop stores the data below, protected by the
- * completion's lock.
+ * @lock: protects the transaction state fields below
+ * @state: virtchnl event loop stores the data below, protected by @lock
* @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be
* truncated on its way to the receiver thread according to
* reply_buf.iov_len.
@@ -58,6 +58,7 @@ typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
*/
struct idpf_vc_xn {
struct completion completed;
+ spinlock_t lock;
enum idpf_vc_xn_state state;
size_t reply_sz;
struct kvec reply;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index dbea37269d2c..33c6d61ef518 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2203,9 +2203,8 @@ void igb_down(struct igb_adapter *adapter)
for (i = 0; i < adapter->num_q_vectors; i++) {
if (adapter->q_vector[i]) {
- napi_synchronize(&adapter->q_vector[i]->napi);
- igb_set_queue_napi(adapter, i, NULL);
napi_disable(&adapter->q_vector[i]->napi);
+ igb_set_queue_napi(adapter, i, NULL);
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index acba430a94da..5903a4af9173 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -2238,6 +2238,7 @@ static const struct pci_device_id mlx5_core_pci_table[] = {
{ PCI_VDEVICE(MELLANOX, 0x1023) }, /* ConnectX-8 */
{ PCI_VDEVICE(MELLANOX, 0x1025) }, /* ConnectX-9 */
{ PCI_VDEVICE(MELLANOX, 0x1027) }, /* ConnectX-10 */
+ { PCI_VDEVICE(MELLANOX, 0x2101) }, /* ConnectX-10 NVLink-C2C */
{ PCI_VDEVICE(MELLANOX, 0xa2d2) }, /* BlueField integrated ConnectX-5 network controller */
{ PCI_VDEVICE(MELLANOX, 0xa2d3), MLX5_PCI_DEV_IS_VF}, /* BlueField integrated ConnectX-5 network controller VF */
{ PCI_VDEVICE(MELLANOX, 0xa2d6) }, /* BlueField-2 integrated ConnectX-6 Dx network controller */
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
index 502670718104..646f3d65274e 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
@@ -91,6 +91,8 @@ static int lan966x_fdma_rx_alloc_page_pool(struct lan966x_rx *rx)
pp_params.dma_dir = DMA_BIDIRECTIONAL;
rx->page_pool = page_pool_create(&pp_params);
+ if (unlikely(IS_ERR(rx->page_pool)))
+ return PTR_ERR(rx->page_pool);
for (int i = 0; i < lan966x->num_phys_ports; ++i) {
struct lan966x_port *port;
@@ -117,8 +119,10 @@ static int lan966x_fdma_rx_alloc(struct lan966x_rx *rx)
return PTR_ERR(rx->page_pool);
err = fdma_alloc_coherent(lan966x->dev, fdma);
- if (err)
+ if (err) {
+ page_pool_destroy(rx->page_pool);
return err;
+ }
fdma_dcbs_init(fdma, FDMA_DCB_INFO_DATAL(fdma->db_size),
FDMA_DCB_STATUS_INTR);
@@ -809,9 +813,15 @@ static int lan966x_qsys_sw_status(struct lan966x *lan966x)
static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
{
+ struct page *(*old_pages)[FDMA_RX_DCB_MAX_DBS];
struct page_pool *page_pool;
struct fdma fdma_rx_old;
- int err;
+ int err, i, j;
+
+ old_pages = kmemdup(lan966x->rx.page, sizeof(lan966x->rx.page),
+ GFP_KERNEL);
+ if (!old_pages)
+ return -ENOMEM;
/* Store these for later to free them */
memcpy(&fdma_rx_old, &lan966x->rx.fdma, sizeof(struct fdma));
@@ -822,7 +832,6 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
lan966x_fdma_stop_netdev(lan966x);
lan966x_fdma_rx_disable(&lan966x->rx);
- lan966x_fdma_rx_free_pages(&lan966x->rx);
lan966x->rx.page_order = round_up(new_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
lan966x->rx.max_mtu = new_mtu;
err = lan966x_fdma_rx_alloc(&lan966x->rx);
@@ -830,6 +839,11 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
goto restore;
lan966x_fdma_rx_start(&lan966x->rx);
+ for (i = 0; i < fdma_rx_old.n_dcbs; ++i)
+ for (j = 0; j < fdma_rx_old.n_dbs; ++j)
+ page_pool_put_full_page(page_pool,
+ old_pages[i][j], false);
+
fdma_free_coherent(lan966x->dev, &fdma_rx_old);
page_pool_destroy(page_pool);
@@ -837,12 +851,17 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
lan966x_fdma_wakeup_netdev(lan966x);
napi_enable(&lan966x->napi);
- return err;
+ kfree(old_pages);
+ return 0;
restore:
lan966x->rx.page_pool = page_pool;
memcpy(&lan966x->rx.fdma, &fdma_rx_old, sizeof(struct fdma));
lan966x_fdma_rx_start(&lan966x->rx);
+ lan966x_fdma_wakeup_netdev(lan966x);
+ napi_enable(&lan966x->napi);
+
+ kfree(old_pages);
return err;
}
@@ -956,6 +975,7 @@ int lan966x_fdma_init(struct lan966x *lan966x)
err = lan966x_fdma_tx_alloc(&lan966x->tx);
if (err) {
fdma_free_coherent(lan966x->dev, &lan966x->rx.fdma);
+ page_pool_destroy(lan966x->rx.page_pool);
return err;
}
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
index 37efb1ea9fcd..847a5f928e41 100644
--- a/drivers/net/ethernet/qualcomm/qca_uart.c
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -100,7 +100,7 @@ qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
if (!qca->rx_skb) {
netdev_dbg(netdev, "recv: out of RX resources\n");
n_stats->rx_errors++;
- return i;
+ return i + 1;
}
}
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index fb55efd52240..1c01e3c640ce 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -20,7 +20,7 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
unsigned int nopaged_len = skb_headlen(skb);
struct stmmac_priv *priv = tx_q->priv_data;
unsigned int entry = tx_q->cur_tx;
- unsigned int bmax, des2;
+ unsigned int bmax, buf_len, des2;
unsigned int i = 1, len;
struct dma_desc *desc;
@@ -31,17 +31,18 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
else
bmax = BUF_SIZE_2KiB;
- len = nopaged_len - bmax;
+ buf_len = min_t(unsigned int, nopaged_len, bmax);
+ len = nopaged_len - buf_len;
des2 = dma_map_single(priv->device, skb->data,
- bmax, DMA_TO_DEVICE);
+ buf_len, DMA_TO_DEVICE);
desc->des2 = cpu_to_le32(des2);
if (dma_mapping_error(priv->device, des2))
return -1;
tx_q->tx_skbuff_dma[entry].buf = des2;
- tx_q->tx_skbuff_dma[entry].len = bmax;
+ tx_q->tx_skbuff_dma[entry].len = buf_len;
/* do not close the descriptor and do not set own bit */
- stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
+ stmmac_prepare_tx_desc(priv, desc, 1, buf_len, csum, STMMAC_CHAIN_MODE,
0, false, skb->len);
while (len != 0) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
index c739bf7463b3..13d0d6b68238 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
@@ -483,7 +483,7 @@ static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size,
if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr
& boundary)) {
*alignbits = dma_align_sizetobits(size);
- dma_free_coherent(di->dmadev, size, va, *descpa);
+ dma_free_coherent(di->dmadev, *alloced, va, *descpa);
va = dma_alloc_consistent(di, size, *alignbits,
alloced, descpa);
}
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
index a6d50149e0c3..1275bd8232d2 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -828,7 +828,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
if (retval)
goto exit_free_device;
- rt2x00dev->anchor = devm_kmalloc(&usb_dev->dev,
+ rt2x00dev->anchor = devm_kmalloc(&usb_intf->dev,
sizeof(struct usb_anchor),
GFP_KERNEL);
if (!rt2x00dev->anchor) {
diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
index 49c399a57175..3aacfc79fa72 100644
--- a/drivers/nfc/pn533/uart.c
+++ b/drivers/nfc/pn533/uart.c
@@ -211,6 +211,13 @@ static size_t pn532_receive_buf(struct serdev_device *serdev,
timer_delete(&dev->cmd_timeout);
for (i = 0; i < count; i++) {
+ if (!dev->recv_skb) {
+ dev->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN,
+ GFP_KERNEL);
+ if (!dev->recv_skb)
+ return i;
+ }
+
if (unlikely(!skb_tailroom(dev->recv_skb)))
skb_trim(dev->recv_skb, 0);
@@ -219,9 +226,7 @@ static size_t pn532_receive_buf(struct serdev_device *serdev,
continue;
pn533_recv_frame(dev->priv, dev->recv_skb, 0);
- dev->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN, GFP_KERNEL);
- if (!dev->recv_skb)
- return 0;
+ dev->recv_skb = NULL;
}
return i;
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
index 77ecf9f26480..c8de8688daed 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
@@ -1460,6 +1460,8 @@ static int isst_if_get_turbo_freq_info(void __user *argp)
SST_MUL_FACTOR_FREQ)
}
+ memset(turbo_freq.bucket_core_counts, 0, sizeof(turbo_freq.bucket_core_counts));
+
if (feature_rev >= 2) {
bool has_tf_info_8 = false;
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
index 1237d9570886..4c7e64db478c 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
@@ -537,6 +537,7 @@ static void set_cdie_id(int domain_id, struct tpmi_uncore_cluster_info *cluster_
#define UNCORE_VERSION_MASK GENMASK_ULL(7, 0)
#define UNCORE_LOCAL_FABRIC_CLUSTER_ID_MASK GENMASK_ULL(15, 8)
#define UNCORE_CLUSTER_OFF_MASK GENMASK_ULL(7, 0)
+#define UNCORE_AUTONOMOUS_UFS_DISABLED BIT(32)
#define UNCORE_MAX_CLUSTER_PER_DOMAIN 8
static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
@@ -598,6 +599,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
for (i = 0; i < num_resources; ++i) {
struct tpmi_uncore_power_domain_info *pd_info;
+ bool auto_ufs_enabled;
struct resource *res;
u64 cluster_offset;
u8 cluster_mask;
@@ -647,6 +649,8 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
continue;
}
+ auto_ufs_enabled = !(header & UNCORE_AUTONOMOUS_UFS_DISABLED);
+
/* Find out number of clusters in this resource */
pd_info->cluster_count = hweight8(cluster_mask);
@@ -689,7 +693,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
cluster_info->uncore_root = tpmi_uncore;
- if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION)
+ if ((TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >=
+ UNCORE_ELC_SUPPORTED_VERSION) &&
+ auto_ufs_enabled)
cluster_info->elc_supported = true;
ret = uncore_freq_add_entry(&cluster_info->uncore_data, 0);
diff --git a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
index 8fc79f9723f0..3f5b9499d30a 100644
--- a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
@@ -352,9 +352,6 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
break;
- case IMX8MP_HDMIBLK_PD_HDCP:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
- break;
case IMX8MP_HDMIBLK_PD_HRV:
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
@@ -408,9 +405,6 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
break;
- case IMX8MP_HDMIBLK_PD_HDCP:
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
- break;
case IMX8MP_HDMIBLK_PD_HRV:
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
@@ -439,7 +433,7 @@ static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,
regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0);
regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0);
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
- BIT(0) | BIT(1) | BIT(10));
+ BIT(0) | BIT(1) | BIT(10) | BIT(11));
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0));
/*
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 31c809eeac40..47f9a8046109 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -43,7 +43,8 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci)
return;
if (UCSI_CCI_CONNECTOR(cci)) {
- if (UCSI_CCI_CONNECTOR(cci) <= ucsi->cap.num_connectors)
+ if (!ucsi->cap.num_connectors ||
+ UCSI_CCI_CONNECTOR(cci) <= ucsi->cap.num_connectors)
ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci));
else
dev_err(ucsi->dev, "bogus connector number in CCI: %lu\n",
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 08b710929947..863b45092a19 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -476,7 +476,7 @@ static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans,
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
if (key.objectid != bytenr ||
key.type != BTRFS_EXTENT_DATA_REF_KEY)
- goto fail;
+ return -ENOENT;
ref = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_extent_data_ref);
@@ -487,12 +487,11 @@ static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans,
btrfs_release_path(path);
goto again;
}
- ret = 0;
- break;
+ return 0;
}
path->slots[0]++;
}
-fail:
+
return ret;
}
@@ -2470,7 +2469,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
int i;
int action;
int level;
- int ret = 0;
+ int ret;
if (btrfs_is_testing(fs_info))
return 0;
@@ -2522,7 +2521,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
else
ret = btrfs_free_extent(trans, &ref);
if (ret)
- goto fail;
+ return ret;
} else {
/* We don't know the owning_root, leave as 0. */
ref.bytenr = btrfs_node_blockptr(buf, i);
@@ -2535,12 +2534,10 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
else
ret = btrfs_free_extent(trans, &ref);
if (ret)
- goto fail;
+ return ret;
}
}
return 0;
-fail:
- return ret;
}
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -3473,12 +3470,12 @@ int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
return 0;
if (btrfs_header_generation(buf) != trans->transid)
- goto out;
+ return 0;
if (root_id != BTRFS_TREE_LOG_OBJECTID) {
ret = check_ref_cleanup(trans, buf->start);
if (!ret)
- goto out;
+ return 0;
}
bg = btrfs_lookup_block_group(fs_info, buf->start);
@@ -3486,7 +3483,7 @@ int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
if (btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
pin_down_extent(trans, bg, buf->start, buf->len, 1);
btrfs_put_block_group(bg);
- goto out;
+ return 0;
}
/*
@@ -3510,7 +3507,7 @@ int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|| btrfs_is_zoned(fs_info)) {
pin_down_extent(trans, bg, buf->start, buf->len, 1);
btrfs_put_block_group(bg);
- goto out;
+ return 0;
}
WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags));
@@ -3520,7 +3517,6 @@ int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
btrfs_put_block_group(bg);
trace_btrfs_reserved_extent_free(fs_info, buf->start, buf->len);
-out:
return 0;
}
diff --git a/include/linux/firmware/thead/thead,th1520-aon.h b/include/linux/firmware/thead/thead,th1520-aon.h
index dae132b66873..d81f5f6f5b90 100644
--- a/include/linux/firmware/thead/thead,th1520-aon.h
+++ b/include/linux/firmware/thead/thead,th1520-aon.h
@@ -97,80 +97,6 @@ struct th1520_aon_rpc_ack_common {
#define RPC_GET_SVC_FLAG_ACK_TYPE(MESG) (((MESG)->svc & 0x40) >> 6)
#define RPC_SET_SVC_FLAG_ACK_TYPE(MESG, ACK) ((MESG)->svc |= (ACK) << 6)
-#define RPC_SET_BE64(MESG, OFFSET, SET_DATA) \
- do { \
- u8 *data = (u8 *)(MESG); \
- u64 _offset = (OFFSET); \
- u64 _set_data = (SET_DATA); \
- data[_offset + 7] = _set_data & 0xFF; \
- data[_offset + 6] = (_set_data & 0xFF00) >> 8; \
- data[_offset + 5] = (_set_data & 0xFF0000) >> 16; \
- data[_offset + 4] = (_set_data & 0xFF000000) >> 24; \
- data[_offset + 3] = (_set_data & 0xFF00000000) >> 32; \
- data[_offset + 2] = (_set_data & 0xFF0000000000) >> 40; \
- data[_offset + 1] = (_set_data & 0xFF000000000000) >> 48; \
- data[_offset + 0] = (_set_data & 0xFF00000000000000) >> 56; \
- } while (0)
-
-#define RPC_SET_BE32(MESG, OFFSET, SET_DATA) \
- do { \
- u8 *data = (u8 *)(MESG); \
- u64 _offset = (OFFSET); \
- u64 _set_data = (SET_DATA); \
- data[_offset + 3] = (_set_data) & 0xFF; \
- data[_offset + 2] = (_set_data & 0xFF00) >> 8; \
- data[_offset + 1] = (_set_data & 0xFF0000) >> 16; \
- data[_offset + 0] = (_set_data & 0xFF000000) >> 24; \
- } while (0)
-
-#define RPC_SET_BE16(MESG, OFFSET, SET_DATA) \
- do { \
- u8 *data = (u8 *)(MESG); \
- u64 _offset = (OFFSET); \
- u64 _set_data = (SET_DATA); \
- data[_offset + 1] = (_set_data) & 0xFF; \
- data[_offset + 0] = (_set_data & 0xFF00) >> 8; \
- } while (0)
-
-#define RPC_SET_U8(MESG, OFFSET, SET_DATA) \
- do { \
- u8 *data = (u8 *)(MESG); \
- data[OFFSET] = (SET_DATA) & 0xFF; \
- } while (0)
-
-#define RPC_GET_BE64(MESG, OFFSET, PTR) \
- do { \
- u8 *data = (u8 *)(MESG); \
- u64 _offset = (OFFSET); \
- *(u32 *)(PTR) = \
- (data[_offset + 7] | data[_offset + 6] << 8 | \
- data[_offset + 5] << 16 | data[_offset + 4] << 24 | \
- data[_offset + 3] << 32 | data[_offset + 2] << 40 | \
- data[_offset + 1] << 48 | data[_offset + 0] << 56); \
- } while (0)
-
-#define RPC_GET_BE32(MESG, OFFSET, PTR) \
- do { \
- u8 *data = (u8 *)(MESG); \
- u64 _offset = (OFFSET); \
- *(u32 *)(PTR) = \
- (data[_offset + 3] | data[_offset + 2] << 8 | \
- data[_offset + 1] << 16 | data[_offset + 0] << 24); \
- } while (0)
-
-#define RPC_GET_BE16(MESG, OFFSET, PTR) \
- do { \
- u8 *data = (u8 *)(MESG); \
- u64 _offset = (OFFSET); \
- *(u16 *)(PTR) = (data[_offset + 1] | data[_offset + 0] << 8); \
- } while (0)
-
-#define RPC_GET_U8(MESG, OFFSET, PTR) \
- do { \
- u8 *data = (u8 *)(MESG); \
- *(u8 *)(PTR) = (data[OFFSET]); \
- } while (0)
-
/*
* Defines for SC PM Power Mode
*/
diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h
index 9fdaba911de6..3a66d4abb6d6 100644
--- a/include/net/netfilter/nf_conntrack_timeout.h
+++ b/include/net/netfilter/nf_conntrack_timeout.h
@@ -14,6 +14,7 @@
struct nf_ct_timeout {
__u16 l3num;
const struct nf_conntrack_l4proto *l4proto;
+ struct rcu_head rcu;
char data[];
};
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 869f97c9bf73..578b8038b211 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -185,6 +185,7 @@
EM(rxrpc_skb_put_input, "PUT input ") \
EM(rxrpc_skb_put_jumbo_subpacket, "PUT jumbo-sub") \
EM(rxrpc_skb_put_oob, "PUT oob ") \
+ EM(rxrpc_skb_put_old_response, "PUT old-resp ") \
EM(rxrpc_skb_put_purge, "PUT purge ") \
EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \
EM(rxrpc_skb_put_response, "PUT response ") \
@@ -347,7 +348,7 @@
EM(rxrpc_call_see_release, "SEE release ") \
EM(rxrpc_call_see_userid_exists, "SEE u-exists") \
EM(rxrpc_call_see_waiting_call, "SEE q-conn ") \
- E_(rxrpc_call_see_zap, "SEE zap ")
+ E_(rxrpc_call_see_still_live, "SEE !still-l")
#define rxrpc_txqueue_traces \
EM(rxrpc_txqueue_await_reply, "AWR") \
@@ -520,6 +521,7 @@
#define rxrpc_req_ack_traces \
EM(rxrpc_reqack_ack_lost, "ACK-LOST ") \
EM(rxrpc_reqack_app_stall, "APP-STALL ") \
+ EM(rxrpc_reqack_jumbo_win, "JUMBO-WIN ") \
EM(rxrpc_reqack_more_rtt, "MORE-RTT ") \
EM(rxrpc_reqack_no_srv_last, "NO-SRVLAST") \
EM(rxrpc_reqack_old_rtt, "OLD-RTT ") \
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 9111ef6ccfe6..751b8cba52fc 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1855,8 +1855,20 @@ static void unplug_oldest_pwq(struct workqueue_struct *wq)
raw_spin_lock_irq(&pwq->pool->lock);
if (pwq->plugged) {
pwq->plugged = false;
- if (pwq_activate_first_inactive(pwq, true))
+ if (pwq_activate_first_inactive(pwq, true)) {
+ /*
+ * While plugged, queueing skips activation which
+ * includes bumping the nr_active count and adding the
+ * pwq to nna->pending_pwqs if the count can't be
+ * obtained. We need to restore both for the pwq being
+ * unplugged. The first call activates the first
+ * inactive work item and the second, if there are more
+ * inactive, puts the pwq on pending_pwqs.
+ */
+ pwq_activate_first_inactive(pwq, false);
+
kick_pool(pwq->pool);
+ }
}
raw_spin_unlock_irq(&pwq->pool->lock);
}
diff --git a/mm/damon/stat.c b/mm/damon/stat.c
index a8d6a3049830..3a55f6e41dc4 100644
--- a/mm/damon/stat.c
+++ b/mm/damon/stat.c
@@ -237,6 +237,12 @@ static int damon_stat_start(void)
{
int err;
+ if (damon_stat_context) {
+ if (damon_is_running(damon_stat_context))
+ return -EAGAIN;
+ damon_destroy_ctx(damon_stat_context);
+ }
+
damon_stat_context = damon_stat_build_ctx();
if (!damon_stat_context)
return -ENOMEM;
@@ -253,6 +259,7 @@ static void damon_stat_stop(void)
{
damon_stop(&damon_stat_context, 1);
damon_destroy_ctx(damon_stat_context);
+ damon_stat_context = NULL;
}
static int damon_stat_enabled_store(
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 4c0c8fdf450f..a6c3e83a3dad 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -1623,7 +1623,8 @@ static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond)
repeat_call_control->data = kdamond;
repeat_call_control->repeat = true;
repeat_call_control->dealloc_on_cancel = true;
- damon_call(ctx, repeat_call_control);
+ if (damon_call(ctx, repeat_call_control))
+ kfree(repeat_call_control);
return err;
}
diff --git a/mm/filemap.c b/mm/filemap.c
index 8a7f4ce69aff..91dcfe14a67b 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3823,14 +3823,19 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,
unsigned int nr_pages = 0, folio_type;
unsigned short mmap_miss = 0, mmap_miss_saved;
+ /*
+ * Recalculate end_pgoff based on file_end before calling
+ * next_uptodate_folio() to avoid races with concurrent
+ * truncation.
+ */
+ file_end = DIV_ROUND_UP(i_size_read(mapping->host), PAGE_SIZE) - 1;
+ end_pgoff = min(end_pgoff, file_end);
+
rcu_read_lock();
folio = next_uptodate_folio(&xas, mapping, end_pgoff);
if (!folio)
goto out;
- file_end = DIV_ROUND_UP(i_size_read(mapping->host), PAGE_SIZE) - 1;
- end_pgoff = min(end_pgoff, file_end);
-
/*
* Do not allow to map with PMD across i_size to preserve
* SIGBUS semantics.
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 0be83039c3b5..aa1f74414307 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1218,6 +1218,13 @@ int online_pages(unsigned long pfn, unsigned long nr_pages,
if (node_arg.nid >= 0)
node_set_state(nid, N_MEMORY);
+ /*
+ * Check whether we are adding normal memory to the node for the first
+ * time.
+ */
+ if (!node_state(nid, N_NORMAL_MEMORY) && zone_idx(zone) <= ZONE_NORMAL)
+ node_set_state(nid, N_NORMAL_MEMORY);
+
if (need_zonelists_rebuild)
build_all_zonelists(NULL);
@@ -1919,6 +1926,8 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages,
unsigned long flags;
char *reason;
int ret;
+ unsigned long normal_pages = 0;
+ enum zone_type zt;
/*
* {on,off}lining is constrained to full memory sections (or more
@@ -2066,6 +2075,17 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages,
/* reinitialise watermarks and update pcp limits */
init_per_zone_wmark_min();
+ /*
+ * Check whether this operation removes the last normal memory from
+ * the node. We do this before clearing N_MEMORY to avoid the possible
+ * transient "!N_MEMORY && N_NORMAL_MEMORY" state.
+ */
+ if (zone_idx(zone) <= ZONE_NORMAL) {
+ for (zt = 0; zt <= ZONE_NORMAL; zt++)
+ normal_pages += pgdat->node_zones[zt].present_pages;
+ if (!normal_pages)
+ node_clear_state(node, N_NORMAL_MEMORY);
+ }
/*
* Make sure to mark the node as memory-less before rebuilding the zone
* list. Otherwise this node would still appear in the fallback lists.
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index b992ba12aa24..d4f4e97a27f1 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -2165,6 +2165,7 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,
struct batadv_bla_claim *claim)
{
const u8 *primary_addr = primary_if->net_dev->dev_addr;
+ struct batadv_bla_backbone_gw *backbone_gw;
u16 backbone_crc;
bool is_own;
void *hdr;
@@ -2180,32 +2181,35 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,
genl_dump_check_consistent(cb, hdr);
- is_own = batadv_compare_eth(claim->backbone_gw->orig,
- primary_addr);
+ backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
+
+ is_own = batadv_compare_eth(backbone_gw->orig, primary_addr);
- spin_lock_bh(&claim->backbone_gw->crc_lock);
- backbone_crc = claim->backbone_gw->crc;
- spin_unlock_bh(&claim->backbone_gw->crc_lock);
+ spin_lock_bh(&backbone_gw->crc_lock);
+ backbone_crc = backbone_gw->crc;
+ spin_unlock_bh(&backbone_gw->crc_lock);
if (is_own)
if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
genlmsg_cancel(msg, hdr);
- goto out;
+ goto put_backbone_gw;
}
if (nla_put(msg, BATADV_ATTR_BLA_ADDRESS, ETH_ALEN, claim->addr) ||
nla_put_u16(msg, BATADV_ATTR_BLA_VID, claim->vid) ||
nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,
- claim->backbone_gw->orig) ||
+ backbone_gw->orig) ||
nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
backbone_crc)) {
genlmsg_cancel(msg, hdr);
- goto out;
+ goto put_backbone_gw;
}
genlmsg_end(msg, hdr);
ret = 0;
+put_backbone_gw:
+ batadv_backbone_gw_put(backbone_gw);
out:
return ret;
}
@@ -2483,6 +2487,7 @@ int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)
bool batadv_bla_check_claim(struct batadv_priv *bat_priv,
u8 *addr, unsigned short vid)
{
+ struct batadv_bla_backbone_gw *backbone_gw;
struct batadv_bla_claim search_claim;
struct batadv_bla_claim *claim = NULL;
struct batadv_hard_iface *primary_if = NULL;
@@ -2505,9 +2510,13 @@ bool batadv_bla_check_claim(struct batadv_priv *bat_priv,
* return false.
*/
if (claim) {
- if (!batadv_compare_eth(claim->backbone_gw->orig,
+ backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
+
+ if (!batadv_compare_eth(backbone_gw->orig,
primary_if->net_dev->dev_addr))
ret = false;
+
+ batadv_backbone_gw_put(backbone_gw);
batadv_claim_put(claim);
}
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 6e95e883c2bf..05cddcf994f6 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -798,8 +798,8 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
{
u16 num_vlan = 0;
u16 num_entries = 0;
- u16 change_offset;
- u16 tvlv_len;
+ u16 tvlv_len = 0;
+ unsigned int change_offset;
struct batadv_tvlv_tt_vlan_data *tt_vlan;
struct batadv_orig_node_vlan *vlan;
u8 *tt_change_ptr;
@@ -816,6 +816,11 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
if (*tt_len < 0)
*tt_len = batadv_tt_len(num_entries);
+ if (change_offset > U16_MAX || *tt_len > U16_MAX - change_offset) {
+ *tt_len = 0;
+ goto out;
+ }
+
tvlv_len = *tt_len;
tvlv_len += change_offset;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 60d89899fdb9..a4695882d1c4 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1042,10 +1042,7 @@ static int skb_pp_frag_ref(struct sk_buff *skb)
static void skb_kfree_head(void *head, unsigned int end_offset)
{
- if (end_offset == SKB_SMALL_HEAD_HEADROOM)
- kmem_cache_free(net_hotdata.skb_small_head_cache, head);
- else
- kfree(head);
+ kfree(head);
}
static void skb_free_head(struct sk_buff *skb)
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index f28cfd88eaf5..c2eac844bcdb 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -50,6 +50,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
{
struct xfrm_offload *xo = xfrm_offload(skb);
struct iphdr *iph = ip_hdr(skb);
+ struct net_device *dev = skb->dev;
iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
@@ -73,8 +74,10 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
}
NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
- dev_net(skb->dev), NULL, skb, skb->dev, NULL,
+ dev_net(dev), NULL, skb, dev, NULL,
xfrm4_rcv_encap_finish);
+ if (async)
+ dev_put(dev);
return 0;
}
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 3e1b9991131a..d6a0f7df9080 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -48,7 +48,8 @@ static size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
}
struct seg6_lwt {
- struct dst_cache cache;
+ struct dst_cache cache_input;
+ struct dst_cache cache_output;
struct seg6_iptunnel_encap tuninfo[];
};
@@ -488,7 +489,7 @@ static int seg6_input_core(struct net *net, struct sock *sk,
slwt = seg6_lwt_lwtunnel(lwtst);
local_bh_disable();
- dst = dst_cache_get(&slwt->cache);
+ dst = dst_cache_get(&slwt->cache_input);
local_bh_enable();
err = seg6_do_srh(skb, dst);
@@ -504,7 +505,7 @@ static int seg6_input_core(struct net *net, struct sock *sk,
/* cache only if we don't create a dst reference loop */
if (!dst->error && lwtst != dst->lwtstate) {
local_bh_disable();
- dst_cache_set_ip6(&slwt->cache, dst,
+ dst_cache_set_ip6(&slwt->cache_input, dst,
&ipv6_hdr(skb)->saddr);
local_bh_enable();
}
@@ -564,7 +565,7 @@ static int seg6_output_core(struct net *net, struct sock *sk,
slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
local_bh_disable();
- dst = dst_cache_get(&slwt->cache);
+ dst = dst_cache_get(&slwt->cache_output);
local_bh_enable();
err = seg6_do_srh(skb, dst);
@@ -591,7 +592,7 @@ static int seg6_output_core(struct net *net, struct sock *sk,
/* cache only if we don't create a dst reference loop */
if (orig_dst->lwtstate != dst->lwtstate) {
local_bh_disable();
- dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
+ dst_cache_set_ip6(&slwt->cache_output, dst, &fl6.saddr);
local_bh_enable();
}
@@ -701,11 +702,13 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
slwt = seg6_lwt_lwtunnel(newts);
- err = dst_cache_init(&slwt->cache, GFP_ATOMIC);
- if (err) {
- kfree(newts);
- return err;
- }
+ err = dst_cache_init(&slwt->cache_input, GFP_ATOMIC);
+ if (err)
+ goto err_free_newts;
+
+ err = dst_cache_init(&slwt->cache_output, GFP_ATOMIC);
+ if (err)
+ goto err_destroy_input;
memcpy(&slwt->tuninfo, tuninfo, tuninfo_len);
@@ -720,11 +723,20 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
*ts = newts;
return 0;
+
+err_destroy_input:
+ dst_cache_destroy(&slwt->cache_input);
+err_free_newts:
+ kfree(newts);
+ return err;
}
static void seg6_destroy_state(struct lwtunnel_state *lwt)
{
- dst_cache_destroy(&seg6_lwt_lwtunnel(lwt)->cache);
+ struct seg6_lwt *slwt = seg6_lwt_lwtunnel(lwt);
+
+ dst_cache_destroy(&slwt->cache_input);
+ dst_cache_destroy(&slwt->cache_output);
}
static int seg6_fill_encap_info(struct sk_buff *skb,
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 9005fc156a20..699a001ac166 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -43,6 +43,7 @@ static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
int xfrm6_transport_finish(struct sk_buff *skb, int async)
{
struct xfrm_offload *xo = xfrm_offload(skb);
+ struct net_device *dev = skb->dev;
int nhlen = -skb_network_offset(skb);
skb_network_header(skb)[IP6CB(skb)->nhoff] =
@@ -68,8 +69,10 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
}
NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
- dev_net(skb->dev), NULL, skb, skb->dev, NULL,
+ dev_net(dev), NULL, skb, dev, NULL,
xfrm6_transport_finish2);
+ if (async)
+ dev_put(dev);
return 0;
}
diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c
index 52d15df12f58..4494cf4c3828 100644
--- a/net/mptcp/pm_kernel.c
+++ b/net/mptcp/pm_kernel.c
@@ -710,7 +710,7 @@ static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry)
static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
struct mptcp_pm_addr_entry *entry,
- bool needs_id, bool replace)
+ bool replace)
{
struct mptcp_pm_addr_entry *cur, *del_entry = NULL;
int ret = -EINVAL;
@@ -769,7 +769,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
}
}
- if (!entry->addr.id && needs_id) {
+ if (!entry->addr.id) {
find_next:
entry->addr.id = find_next_zero_bit(pernet->id_bitmap,
MPTCP_PM_MAX_ADDR_ID + 1,
@@ -780,7 +780,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
}
}
- if (!entry->addr.id && needs_id)
+ if (!entry->addr.id)
goto out;
__set_bit(entry->addr.id, pernet->id_bitmap);
@@ -909,7 +909,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk,
return -ENOMEM;
entry->addr.port = 0;
- ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true, false);
+ ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, false);
if (ret < 0)
kfree(entry);
@@ -963,18 +963,6 @@ static int mptcp_nl_add_subflow_or_signal_addr(struct net *net,
return 0;
}
-static bool mptcp_pm_has_addr_attr_id(const struct nlattr *attr,
- struct genl_info *info)
-{
- struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
-
- if (!nla_parse_nested_deprecated(tb, MPTCP_PM_ADDR_ATTR_MAX, attr,
- mptcp_pm_address_nl_policy, info->extack) &&
- tb[MPTCP_PM_ADDR_ATTR_ID])
- return true;
- return false;
-}
-
/* Add an MPTCP endpoint */
int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
{
@@ -1023,9 +1011,7 @@ int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
goto out_free;
}
}
- ret = mptcp_pm_nl_append_new_local_addr(pernet, entry,
- !mptcp_pm_has_addr_attr_id(attr, info),
- true);
+ ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true);
if (ret < 0) {
GENL_SET_ERR_MSG_FMT(info, "too many addresses or duplicate one: %d", ret);
goto out_free;
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 7b92da6e49d6..09e1a93b7daa 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -4271,6 +4271,8 @@ int __init mptcp_proto_v6_init(void)
{
int err;
+ mptcp_subflow_v6_init();
+
mptcp_v6_prot = mptcp_prot;
strscpy(mptcp_v6_prot.name, "MPTCPv6", sizeof(mptcp_v6_prot.name));
mptcp_v6_prot.slab = NULL;
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 27b1698c5aa2..5a03c8824ab6 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -830,6 +830,7 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
void __init mptcp_proto_init(void);
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
int __init mptcp_proto_v6_init(void);
+void __init mptcp_subflow_v6_init(void);
#endif
struct sock *mptcp_sk_clone_init(const struct sock *sk,
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 838203e2740e..90927f6cad26 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -2145,7 +2145,15 @@ void __init mptcp_subflow_init(void)
tcp_prot_override.psock_update_sk_prot = NULL;
#endif
+ mptcp_diag_subflow_init(&subflow_ulp_ops);
+
+ if (tcp_register_ulp(&subflow_ulp_ops) != 0)
+ panic("MPTCP: failed to register subflows to ULP\n");
+}
+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+void __init mptcp_subflow_v6_init(void)
+{
/* In struct mptcp_subflow_request_sock, we assume the TCP request sock
* structures for v4 and v6 have the same size. It should not changed in
* the future but better to make sure to be warned if it is no longer
@@ -2184,10 +2192,5 @@ void __init mptcp_subflow_init(void)
/* Disable sockmap processing for subflows */
tcpv6_prot_override.psock_update_sk_prot = NULL;
#endif
-#endif
-
- mptcp_diag_subflow_init(&subflow_ulp_ops);
-
- if (tcp_register_ulp(&subflow_ulp_ops) != 0)
- panic("MPTCP: failed to register subflows to ULP\n");
}
+#endif
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index db1bf69f8775..4f52ca4c48d5 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -1021,7 +1021,7 @@ static void nft_ct_timeout_obj_destroy(const struct nft_ctx *ctx,
nf_queue_nf_hook_drop(ctx->net);
nf_ct_untimeout(ctx->net, timeout);
nf_ct_netns_put(ctx->net, ctx->family);
- kfree(priv->timeout);
+ kfree_rcu(priv->timeout, rcu);
}
static int nft_ct_timeout_obj_dump(struct sk_buff *skb,
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 7d3e82e4c2fc..868a8586dc17 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -73,11 +73,14 @@ struct rfkill_int_event {
struct rfkill_event_ext ev;
};
+/* Max rfkill events that can be "in-flight" for one data source */
+#define MAX_RFKILL_EVENT 1000
struct rfkill_data {
struct list_head list;
struct list_head events;
struct mutex mtx;
wait_queue_head_t read_wait;
+ u32 event_count;
bool input_handler;
u8 max_size;
};
@@ -255,10 +258,12 @@ static void rfkill_global_led_trigger_unregister(void)
}
#endif /* CONFIG_RFKILL_LEDS */
-static void rfkill_fill_event(struct rfkill_event_ext *ev,
- struct rfkill *rfkill,
- enum rfkill_operation op)
+static int rfkill_fill_event(struct rfkill_int_event *int_ev,
+ struct rfkill *rfkill,
+ struct rfkill_data *data,
+ enum rfkill_operation op)
{
+ struct rfkill_event_ext *ev = &int_ev->ev;
unsigned long flags;
ev->idx = rfkill->idx;
@@ -271,6 +276,15 @@ static void rfkill_fill_event(struct rfkill_event_ext *ev,
RFKILL_BLOCK_SW_PREV));
ev->hard_block_reasons = rfkill->hard_block_reasons;
spin_unlock_irqrestore(&rfkill->lock, flags);
+
+ scoped_guard(mutex, &data->mtx) {
+ if (data->event_count++ > MAX_RFKILL_EVENT) {
+ data->event_count--;
+ return -ENOSPC;
+ }
+ list_add_tail(&int_ev->list, &data->events);
+ }
+ return 0;
}
static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
@@ -282,10 +296,10 @@ static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
continue;
- rfkill_fill_event(&ev->ev, rfkill, op);
- mutex_lock(&data->mtx);
- list_add_tail(&ev->list, &data->events);
- mutex_unlock(&data->mtx);
+ if (rfkill_fill_event(ev, rfkill, data, op)) {
+ kfree(ev);
+ continue;
+ }
wake_up_interruptible(&data->read_wait);
}
}
@@ -1186,10 +1200,8 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
if (!ev)
goto free;
rfkill_sync(rfkill);
- rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD);
- mutex_lock(&data->mtx);
- list_add_tail(&ev->list, &data->events);
- mutex_unlock(&data->mtx);
+ if (rfkill_fill_event(ev, rfkill, data, RFKILL_OP_ADD))
+ kfree(ev);
}
list_add(&data->list, &rfkill_fds);
mutex_unlock(&rfkill_global_mutex);
@@ -1259,6 +1271,7 @@ static ssize_t rfkill_fop_read(struct file *file, char __user *buf,
ret = -EFAULT;
list_del(&ev->list);
+ data->event_count--;
kfree(ev);
out:
mutex_unlock(&data->mtx);
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index d369e3752538..885a28e3afc5 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -654,9 +654,6 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
goto success;
case RXRPC_SECURITY_KEY:
- ret = -EINVAL;
- if (rx->key)
- goto error;
ret = -EISCONN;
if (rx->sk.sk_state != RXRPC_UNBOUND)
goto error;
@@ -664,9 +661,6 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
goto error;
case RXRPC_SECURITY_KEYRING:
- ret = -EINVAL;
- if (rx->key)
- goto error;
ret = -EISCONN;
if (rx->sk.sk_state != RXRPC_UNBOUND)
goto error;
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 36d6ca0d1089..96ecb83c9071 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -117,7 +117,7 @@ struct rxrpc_net {
atomic_t stat_tx_jumbo[10];
atomic_t stat_rx_jumbo[10];
- atomic_t stat_why_req_ack[8];
+ atomic_t stat_why_req_ack[9];
atomic_t stat_io_loop;
};
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
index 918f41d97a2f..f035f486c139 100644
--- a/net/rxrpc/call_object.c
+++ b/net/rxrpc/call_object.c
@@ -654,11 +654,9 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace why)
if (dead) {
ASSERTCMP(__rxrpc_call_state(call), ==, RXRPC_CALL_COMPLETE);
- if (!list_empty(&call->link)) {
- spin_lock(&rxnet->call_lock);
- list_del_init(&call->link);
- spin_unlock(&rxnet->call_lock);
- }
+ spin_lock(&rxnet->call_lock);
+ list_del_rcu(&call->link);
+ spin_unlock(&rxnet->call_lock);
rxrpc_cleanup_call(call);
}
@@ -694,6 +692,7 @@ static void rxrpc_destroy_call(struct work_struct *work)
rxrpc_put_bundle(call->bundle, rxrpc_bundle_put_call);
rxrpc_put_peer(call->peer, rxrpc_peer_put_call);
rxrpc_put_local(call->local, rxrpc_local_put_call);
+ key_put(call->key);
call_rcu(&call->rcu, rxrpc_rcu_free_call);
}
@@ -730,24 +729,20 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
_enter("");
if (!list_empty(&rxnet->calls)) {
- spin_lock(&rxnet->call_lock);
+ int shown = 0;
- while (!list_empty(&rxnet->calls)) {
- call = list_entry(rxnet->calls.next,
- struct rxrpc_call, link);
- _debug("Zapping call %p", call);
+ spin_lock(&rxnet->call_lock);
- rxrpc_see_call(call, rxrpc_call_see_zap);
- list_del_init(&call->link);
+ list_for_each_entry(call, &rxnet->calls, link) {
+ rxrpc_see_call(call, rxrpc_call_see_still_live);
pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n",
call, refcount_read(&call->ref),
rxrpc_call_states[__rxrpc_call_state(call)],
call->flags, call->events);
- spin_unlock(&rxnet->call_lock);
- cond_resched();
- spin_lock(&rxnet->call_lock);
+ if (++shown >= 10)
+ break;
}
spin_unlock(&rxnet->call_lock);
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
index 98ad9b51ca2c..9a41ec708aeb 100644
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -247,6 +247,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+ bool secured = false;
int ret;
if (conn->state == RXRPC_CONN_ABORTED)
@@ -262,6 +263,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret;
case RXRPC_PACKET_TYPE_RESPONSE:
+ spin_lock_irq(&conn->state_lock);
+ if (conn->state != RXRPC_CONN_SERVICE_CHALLENGING) {
+ spin_unlock_irq(&conn->state_lock);
+ return 0;
+ }
+ spin_unlock_irq(&conn->state_lock);
+
ret = conn->security->verify_response(conn, skb);
if (ret < 0)
return ret;
@@ -272,11 +280,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret;
spin_lock_irq(&conn->state_lock);
- if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING)
+ if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
conn->state = RXRPC_CONN_SERVICE;
+ secured = true;
+ }
spin_unlock_irq(&conn->state_lock);
- if (conn->state == RXRPC_CONN_SERVICE) {
+ if (secured) {
/* Offload call state flipping to the I/O thread. As
* we've already received the packet, put it on the
* front of the queue.
@@ -557,11 +567,11 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)
spin_lock_irq(&local->lock);
old = conn->tx_response;
if (old) {
- struct rxrpc_skb_priv *osp = rxrpc_skb(skb);
+ struct rxrpc_skb_priv *osp = rxrpc_skb(old);
/* Always go with the response to the most recent challenge. */
if (after(sp->resp.challenge_serial, osp->resp.challenge_serial))
- conn->tx_response = old;
+ conn->tx_response = skb;
else
old = skb;
} else {
@@ -569,4 +579,5 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)
}
spin_unlock_irq(&local->lock);
rxrpc_poke_conn(conn, rxrpc_conn_get_poke_response);
+ rxrpc_free_skb(old, rxrpc_skb_put_old_response);
}
diff --git a/net/rxrpc/input_rack.c b/net/rxrpc/input_rack.c
index 13c371261e0a..9eb109ffba56 100644
--- a/net/rxrpc/input_rack.c
+++ b/net/rxrpc/input_rack.c
@@ -413,6 +413,6 @@ void rxrpc_rack_timer_expired(struct rxrpc_call *call, ktime_t overran_by)
break;
//case RXRPC_CALL_RACKTIMER_ZEROWIN:
default:
- pr_warn("Unexpected rack timer %u", call->rack_timer_mode);
+ pr_warn("Unexpected rack timer %u", mode);
}
}
diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c
index e939ecf417c4..697956931925 100644
--- a/net/rxrpc/io_thread.c
+++ b/net/rxrpc/io_thread.c
@@ -419,7 +419,8 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
if (sp->hdr.callNumber > chan->call_id) {
if (rxrpc_to_client(sp)) {
- rxrpc_put_call(call, rxrpc_call_put_input);
+ if (call)
+ rxrpc_put_call(call, rxrpc_call_put_input);
return rxrpc_protocol_error(skb,
rxrpc_eproto_unexpected_implicit_end);
}
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index 9fdc1f031c9d..e0c29ebe6b6d 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -13,6 +13,7 @@
#include <crypto/skcipher.h>
#include <linux/module.h>
#include <linux/net.h>
+#include <linux/overflow.h>
#include <linux/skbuff.h>
#include <linux/key-type.h>
#include <linux/ctype.h>
@@ -72,7 +73,7 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
return -EKEYREJECTED;
plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
- prep->quotalen = datalen + plen;
+ prep->quotalen += datalen + plen;
plen -= sizeof(*token);
token = kzalloc(sizeof(*token), GFP_KERNEL);
@@ -171,7 +172,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
size_t plen;
const __be32 *ticket, *key;
s64 tmp;
- u32 tktlen, keylen;
+ size_t raw_keylen, raw_tktlen, keylen, tktlen;
_enter(",{%x,%x,%x,%x},%x",
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -181,32 +182,36 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
goto reject;
key = xdr + (6 * 2 + 1);
- keylen = ntohl(key[-1]);
- _debug("keylen: %x", keylen);
- keylen = round_up(keylen, 4);
+ raw_keylen = ntohl(key[-1]);
+ _debug("keylen: %zx", raw_keylen);
+ if (raw_keylen > AFSTOKEN_GK_KEY_MAX)
+ goto reject;
+ keylen = round_up(raw_keylen, 4);
if ((6 * 2 + 2) * 4 + keylen > toklen)
goto reject;
ticket = xdr + (6 * 2 + 1 + (keylen / 4) + 1);
- tktlen = ntohl(ticket[-1]);
- _debug("tktlen: %x", tktlen);
- tktlen = round_up(tktlen, 4);
+ raw_tktlen = ntohl(ticket[-1]);
+ _debug("tktlen: %zx", raw_tktlen);
+ if (raw_tktlen > AFSTOKEN_GK_TOKEN_MAX)
+ goto reject;
+ tktlen = round_up(raw_tktlen, 4);
if ((6 * 2 + 2) * 4 + keylen + tktlen != toklen) {
- kleave(" = -EKEYREJECTED [%x!=%x, %x,%x]",
+ kleave(" = -EKEYREJECTED [%zx!=%x, %zx,%zx]",
(6 * 2 + 2) * 4 + keylen + tktlen, toklen,
keylen, tktlen);
goto reject;
}
plen = sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen;
- prep->quotalen = datalen + plen;
+ prep->quotalen += datalen + plen;
plen -= sizeof(*token);
token = kzalloc(sizeof(*token), GFP_KERNEL);
if (!token)
goto nomem;
- token->rxgk = kzalloc(sizeof(*token->rxgk) + keylen, GFP_KERNEL);
+ token->rxgk = kzalloc(struct_size_t(struct rxgk_key, _key, raw_keylen), GFP_KERNEL);
if (!token->rxgk)
goto nomem_token;
@@ -221,9 +226,9 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
token->rxgk->enctype = tmp = xdr_dec64(xdr + 5 * 2);
if (tmp < 0 || tmp > UINT_MAX)
goto reject_token;
- token->rxgk->key.len = ntohl(key[-1]);
+ token->rxgk->key.len = raw_keylen;
token->rxgk->key.data = token->rxgk->_key;
- token->rxgk->ticket.len = ntohl(ticket[-1]);
+ token->rxgk->ticket.len = raw_tktlen;
if (token->rxgk->endtime != 0) {
expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
@@ -236,8 +241,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
memcpy(token->rxgk->key.data, key, token->rxgk->key.len);
/* Pad the ticket so that we can use it directly in XDR */
- token->rxgk->ticket.data = kzalloc(round_up(token->rxgk->ticket.len, 4),
- GFP_KERNEL);
+ token->rxgk->ticket.data = kzalloc(tktlen, GFP_KERNEL);
if (!token->rxgk->ticket.data)
goto nomem_yrxgk;
memcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len);
@@ -274,6 +278,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
nomem:
return -ENOMEM;
reject_token:
+ kfree(token->rxgk);
kfree(token);
reject:
return -EKEYREJECTED;
@@ -460,6 +465,7 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
memcpy(&kver, prep->data, sizeof(kver));
prep->data += sizeof(kver);
prep->datalen -= sizeof(kver);
+ prep->quotalen = 0;
_debug("KEY I/F VERSION: %u", kver);
@@ -497,7 +503,7 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
goto error;
plen = sizeof(*token->kad) + v1->ticket_length;
- prep->quotalen = plen + sizeof(*token);
+ prep->quotalen += plen + sizeof(*token);
ret = -ENOMEM;
token = kzalloc(sizeof(*token), GFP_KERNEL);
@@ -616,7 +622,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
_enter("");
- if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->securities)
+ if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->key)
return -EINVAL;
description = memdup_sockptr_nul(optval, optlen);
diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c
index d70db367e358..870e59bf06af 100644
--- a/net/rxrpc/output.c
+++ b/net/rxrpc/output.c
@@ -479,6 +479,8 @@ static size_t rxrpc_prepare_data_subpacket(struct rxrpc_call *call,
why = rxrpc_reqack_old_rtt;
else if (!last && !after(READ_ONCE(call->send_top), txb->seq))
why = rxrpc_reqack_app_stall;
+ else if (call->tx_winsize <= (2 * req->n) || call->cong_cwnd <= (2 * req->n))
+ why = rxrpc_reqack_jumbo_win;
else
goto dont_set_request_ack;
diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c
index 59292f7f9205..e9a27fa7b25d 100644
--- a/net/rxrpc/proc.c
+++ b/net/rxrpc/proc.c
@@ -10,6 +10,10 @@
#include <net/af_rxrpc.h>
#include "ar-internal.h"
+#define RXRPC_PROC_ADDRBUF_SIZE \
+ (sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") + \
+ sizeof(":12345"))
+
static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
[RXRPC_CONN_UNUSED] = "Unused ",
[RXRPC_CONN_CLIENT_UNSECURED] = "ClUnsec ",
@@ -53,7 +57,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
enum rxrpc_call_state state;
rxrpc_seq_t tx_bottom;
- char lbuff[50], rbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
long timeout = 0;
if (v == &rxnet->calls) {
@@ -69,11 +73,11 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
local = call->local;
if (local)
- sprintf(lbuff, "%pISpc", &local->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &local->srx.transport);
else
strcpy(lbuff, "no_local");
- sprintf(rbuff, "%pISpc", &call->dest_srx.transport);
+ scnprintf(rbuff, sizeof(rbuff), "%pISpc", &call->dest_srx.transport);
state = rxrpc_call_state(call);
if (state != RXRPC_CALL_SERVER_PREALLOC)
@@ -142,7 +146,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
struct rxrpc_connection *conn;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
const char *state;
- char lbuff[50], rbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == &rxnet->conn_proc_list) {
seq_puts(seq,
@@ -161,8 +165,8 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
goto print;
}
- sprintf(lbuff, "%pISpc", &conn->local->srx.transport);
- sprintf(rbuff, "%pISpc", &conn->peer->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &conn->local->srx.transport);
+ scnprintf(rbuff, sizeof(rbuff), "%pISpc", &conn->peer->srx.transport);
print:
state = rxrpc_is_conn_aborted(conn) ?
rxrpc_call_completions[conn->completion] :
@@ -228,7 +232,7 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_bundle *bundle;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
- char lbuff[50], rbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == &rxnet->bundle_proc_list) {
seq_puts(seq,
@@ -242,8 +246,8 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
bundle = list_entry(v, struct rxrpc_bundle, proc_link);
- sprintf(lbuff, "%pISpc", &bundle->local->srx.transport);
- sprintf(rbuff, "%pISpc", &bundle->peer->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &bundle->local->srx.transport);
+ scnprintf(rbuff, sizeof(rbuff), "%pISpc", &bundle->peer->srx.transport);
seq_printf(seq,
"UDP %-47.47s %-47.47s %4x %3u %3d"
" %c%c%c %08x | %08x %08x %08x %08x %08x\n",
@@ -279,7 +283,7 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_peer *peer;
time64_t now;
- char lbuff[50], rbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -290,9 +294,9 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
peer = list_entry(v, struct rxrpc_peer, hash_link);
- sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &peer->local->srx.transport);
- sprintf(rbuff, "%pISpc", &peer->srx.transport);
+ scnprintf(rbuff, sizeof(rbuff), "%pISpc", &peer->srx.transport);
now = ktime_get_seconds();
seq_printf(seq,
@@ -401,7 +405,7 @@ const struct seq_operations rxrpc_peer_seq_ops = {
static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_local *local;
- char lbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -412,7 +416,7 @@ static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
local = hlist_entry(v, struct rxrpc_local, link);
- sprintf(lbuff, "%pISpc", &local->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &local->srx.transport);
seq_printf(seq,
"UDP %-47.47s %3u %3u %3u\n",
@@ -518,11 +522,12 @@ int rxrpc_stats_show(struct seq_file *seq, void *v)
atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_IDLE]),
atomic_read(&rxnet->stat_rx_acks[0]));
seq_printf(seq,
- "Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u\n",
+ "Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u jwin=%u\n",
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_ack_lost]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_more_rtt]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_old_rtt]),
- atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]));
+ atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]),
+ atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_jumbo_win]));
seq_printf(seq,
"Why-Req-A: nolast=%u retx=%u slows=%u smtxw=%u\n",
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_no_srv_last]),
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index 43cbf9efd89f..c39f5066d8e8 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -1085,6 +1085,9 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
_enter("");
+ if ((end - p) * sizeof(__be32) < 24)
+ return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
+ rxgk_abort_resp_short_auth);
if (memcmp(p, conn->rxgk.nonce, 20) != 0)
return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
rxgk_abort_resp_bad_nonce);
@@ -1098,7 +1101,7 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
p += xdr_round_up(app_len) / sizeof(__be32);
if (end - p < 4)
return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
- rxgk_abort_resp_short_applen);
+ rxgk_abort_resp_short_auth);
level = ntohl(*p++);
epoch = ntohl(*p++);
@@ -1164,7 +1167,8 @@ static int rxgk_verify_authenticator(struct rxrpc_connection *conn,
}
p = auth;
- ret = rxgk_do_verify_authenticator(conn, krb5, skb, p, p + auth_len);
+ ret = rxgk_do_verify_authenticator(conn, krb5, skb, p,
+ p + auth_len / sizeof(*p));
error:
kfree(auth);
return ret;
@@ -1208,7 +1212,8 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
token_offset = offset;
token_len = ntohl(rhdr.token_len);
- if (xdr_round_up(token_len) + sizeof(__be32) > len)
+ if (token_len > len ||
+ xdr_round_up(token_len) + sizeof(__be32) > len)
goto short_packet;
trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, token_len);
@@ -1223,7 +1228,7 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
auth_offset = offset;
auth_len = ntohl(xauth_len);
- if (auth_len < len)
+ if (auth_len > len)
goto short_packet;
if (auth_len & 3)
goto inconsistent;
@@ -1268,16 +1273,18 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
if (ret < 0) {
rxrpc_abort_conn(conn, skb, RXGK_SEALEDINCON, ret,
rxgk_abort_resp_auth_dec);
- goto out;
+ goto out_gk;
}
ret = rxgk_verify_authenticator(conn, krb5, skb, auth_offset, auth_len);
if (ret < 0)
- goto out;
+ goto out_gk;
conn->key = key;
key = NULL;
ret = 0;
+out_gk:
+ rxgk_put(gk);
out:
key_put(key);
_leave(" = %d", ret);
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index a756855a0a62..4a3c63094149 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -197,6 +197,7 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
struct rxrpc_crypt iv;
__be32 *tmpbuf;
size_t tmpsize = 4 * sizeof(__be32);
+ int ret;
_enter("");
@@ -225,13 +226,13 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
skcipher_request_set_sync_tfm(req, ci);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x);
- crypto_skcipher_encrypt(req);
+ ret = crypto_skcipher_encrypt(req);
skcipher_request_free(req);
memcpy(&conn->rxkad.csum_iv, tmpbuf + 2, sizeof(conn->rxkad.csum_iv));
kfree(tmpbuf);
- _leave(" = 0");
- return 0;
+ _leave(" = %d", ret);
+ return ret;
}
/*
@@ -264,6 +265,7 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
struct scatterlist sg;
size_t pad;
u16 check;
+ int ret;
_enter("");
@@ -286,11 +288,11 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
- crypto_skcipher_encrypt(req);
+ ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
- _leave(" = 0");
- return 0;
+ _leave(" = %d", ret);
+ return ret;
}
/*
@@ -345,7 +347,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
union {
__be32 buf[2];
} crypto __aligned(8);
- u32 x, y;
+ u32 x, y = 0;
int ret;
_enter("{%d{%x}},{#%u},%u,",
@@ -376,8 +378,10 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
- crypto_skcipher_encrypt(req);
+ ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
+ if (ret < 0)
+ goto out;
y = ntohl(crypto.buf[1]);
y = (y >> 16) & 0xffff;
@@ -413,6 +417,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
memset(p + txb->pkt_len, 0, gap);
}
+out:
skcipher_request_free(req);
_leave(" = %d [set %x]", ret, y);
return ret;
@@ -453,8 +458,10 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
- crypto_skcipher_decrypt(req);
+ ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
+ if (ret < 0)
+ return ret;
/* Extract the decrypted packet length */
if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
@@ -531,10 +538,14 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, sp->len, iv.x);
- crypto_skcipher_decrypt(req);
+ ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
if (sg != _sg)
kfree(sg);
+ if (ret < 0) {
+ WARN_ON_ONCE(ret != -ENOMEM);
+ return ret;
+ }
/* Extract the decrypted packet length */
if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
@@ -602,8 +613,10 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
- crypto_skcipher_encrypt(req);
+ ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
+ if (ret < 0)
+ goto out;
y = ntohl(crypto.buf[1]);
cksum = (y >> 16) & 0xffff;
@@ -958,6 +971,7 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
struct in_addr addr;
unsigned int life;
time64_t issue, now;
+ int ret;
bool little_endian;
u8 *p, *q, *name, *end;
@@ -977,8 +991,11 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
sg_init_one(&sg[0], ticket, ticket_len);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x);
- crypto_skcipher_decrypt(req);
+ ret = crypto_skcipher_decrypt(req);
skcipher_request_free(req);
+ if (ret < 0)
+ return rxrpc_abort_conn(conn, skb, RXKADBADTICKET, -EPROTO,
+ rxkad_abort_resp_tkt_short);
p = ticket;
end = p + ticket_len;
@@ -1073,21 +1090,23 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
/*
* decrypt the response packet
*/
-static void rxkad_decrypt_response(struct rxrpc_connection *conn,
- struct rxkad_response *resp,
- const struct rxrpc_crypt *session_key)
+static int rxkad_decrypt_response(struct rxrpc_connection *conn,
+ struct rxkad_response *resp,
+ const struct rxrpc_crypt *session_key)
{
struct skcipher_request *req = rxkad_ci_req;
struct scatterlist sg[1];
struct rxrpc_crypt iv;
+ int ret;
_enter(",,%08x%08x",
ntohl(session_key->n[0]), ntohl(session_key->n[1]));
mutex_lock(&rxkad_ci_mutex);
- if (crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
- sizeof(*session_key)) < 0)
- BUG();
+ ret = crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
+ sizeof(*session_key));
+ if (ret < 0)
+ goto unlock;
memcpy(&iv, session_key, sizeof(iv));
@@ -1096,12 +1115,14 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn,
skcipher_request_set_sync_tfm(req, rxkad_ci);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
- crypto_skcipher_decrypt(req);
+ ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
+unlock:
mutex_unlock(&rxkad_ci_mutex);
_leave("");
+ return ret;
}
/*
@@ -1194,7 +1215,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
/* use the session key from inside the ticket to decrypt the
* response */
- rxkad_decrypt_response(conn, response, &session_key);
+ ret = rxkad_decrypt_response(conn, response, &session_key);
+ if (ret < 0)
+ goto temporary_error_free_ticket;
if (ntohl(response->encrypted.epoch) != conn->proto.epoch ||
ntohl(response->encrypted.cid) != conn->proto.cid ||
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index ebbb78b842de..39a6b21d6b8f 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -637,7 +637,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
memset(&cp, 0, sizeof(cp));
cp.local = rx->local;
cp.peer = peer;
- cp.key = rx->key;
+ cp.key = key;
cp.security_level = rx->min_sec_level;
cp.exclusive = rx->exclusive | p->exclusive;
cp.upgrade = p->upgrade;
diff --git a/net/rxrpc/server_key.c b/net/rxrpc/server_key.c
index 36b05fd842a7..27491f1e1273 100644
--- a/net/rxrpc/server_key.c
+++ b/net/rxrpc/server_key.c
@@ -125,6 +125,9 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
_enter("");
+ if (rx->securities)
+ return -EINVAL;
+
if (optlen <= 0 || optlen > PAGE_SIZE - 1)
return -EINVAL;
diff --git a/net/tipc/group.c b/net/tipc/group.c
index 3e137d8c9d2f..215f2a7d8458 100644
--- a/net/tipc/group.c
+++ b/net/tipc/group.c
@@ -746,6 +746,7 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
u32 port = msg_origport(hdr);
struct tipc_member *m, *pm;
u16 remitted, in_flight;
+ u16 acked;
if (!grp)
return;
@@ -798,7 +799,10 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
case GRP_ACK_MSG:
if (!m)
return;
- m->bc_acked = msg_grp_bc_acked(hdr);
+ acked = msg_grp_bc_acked(hdr);
+ if (less_eq(acked, m->bc_acked))
+ return;
+ m->bc_acked = acked;
if (--grp->bc_ackers)
return;
list_del_init(&m->small_win);
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index eecf1146c34f..16aaf41a8cc0 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -584,6 +584,16 @@ static int tls_do_encryption(struct sock *sk,
if (rc == -EBUSY) {
rc = tls_encrypt_async_wait(ctx);
rc = rc ?: -EINPROGRESS;
+ /*
+ * The async callback tls_encrypt_done() has already
+ * decremented encrypt_pending and restored the sge on
+ * both success and error. Skip the synchronous cleanup
+ * below on error, just remove the record and return.
+ */
+ if (rc != -EINPROGRESS) {
+ list_del(&rec->list);
+ return rc;
+ }
}
if (!rc || rc != -EINPROGRESS) {
atomic_dec(&ctx->encrypt_pending);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 79943fb34806..6b251c76f6be 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1979,6 +1979,8 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
{
scm->fp = scm_fp_dup(UNIXCB(skb).fp);
+
+ unix_peek_fpl(scm->fp);
}
static void unix_destruct_scm(struct sk_buff *skb)
diff --git a/net/unix/af_unix.h b/net/unix/af_unix.h
index 59db179df9bb..6b96c1007aec 100644
--- a/net/unix/af_unix.h
+++ b/net/unix/af_unix.h
@@ -30,6 +30,7 @@ void unix_del_edges(struct scm_fp_list *fpl);
void unix_update_edges(struct unix_sock *receiver);
int unix_prepare_fpl(struct scm_fp_list *fpl);
void unix_destroy_fpl(struct scm_fp_list *fpl);
+void unix_peek_fpl(struct scm_fp_list *fpl);
void unix_gc(void);
void wait_for_unix_gc(struct scm_fp_list *fpl);
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 65396a4e1b07..529b21d043d9 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -121,8 +121,13 @@ static struct unix_vertex *unix_edge_successor(struct unix_edge *edge)
return edge->successor->vertex;
}
-static bool unix_graph_maybe_cyclic;
-static bool unix_graph_grouped;
+enum {
+ UNIX_GRAPH_NOT_CYCLIC,
+ UNIX_GRAPH_MAYBE_CYCLIC,
+ UNIX_GRAPH_CYCLIC,
+};
+
+static unsigned char unix_graph_state;
static void unix_update_graph(struct unix_vertex *vertex)
{
@@ -132,8 +137,7 @@ static void unix_update_graph(struct unix_vertex *vertex)
if (!vertex)
return;
- unix_graph_maybe_cyclic = true;
- unix_graph_grouped = false;
+ unix_graph_state = UNIX_GRAPH_MAYBE_CYCLIC;
}
static LIST_HEAD(unix_unvisited_vertices);
@@ -315,6 +319,25 @@ void unix_destroy_fpl(struct scm_fp_list *fpl)
unix_free_vertices(fpl);
}
+static bool gc_in_progress;
+static seqcount_t unix_peek_seq = SEQCNT_ZERO(unix_peek_seq);
+
+void unix_peek_fpl(struct scm_fp_list *fpl)
+{
+ static DEFINE_SPINLOCK(unix_peek_lock);
+
+ if (!fpl || !fpl->count_unix)
+ return;
+
+ if (!READ_ONCE(gc_in_progress))
+ return;
+
+ /* Invalidate the final refcnt check in unix_vertex_dead(). */
+ spin_lock(&unix_peek_lock);
+ raw_write_seqcount_barrier(&unix_peek_seq);
+ spin_unlock(&unix_peek_lock);
+}
+
static bool unix_vertex_dead(struct unix_vertex *vertex)
{
struct unix_edge *edge;
@@ -348,6 +371,36 @@ static bool unix_vertex_dead(struct unix_vertex *vertex)
return true;
}
+static LIST_HEAD(unix_visited_vertices);
+static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2;
+
+static bool unix_scc_dead(struct list_head *scc, bool fast)
+{
+ struct unix_vertex *vertex;
+ bool scc_dead = true;
+ unsigned int seq;
+
+ seq = read_seqcount_begin(&unix_peek_seq);
+
+ list_for_each_entry_reverse(vertex, scc, scc_entry) {
+ /* Don't restart DFS from this vertex. */
+ list_move_tail(&vertex->entry, &unix_visited_vertices);
+
+ /* Mark vertex as off-stack for __unix_walk_scc(). */
+ if (!fast)
+ vertex->index = unix_vertex_grouped_index;
+
+ if (scc_dead)
+ scc_dead = unix_vertex_dead(vertex);
+ }
+
+ /* If MSG_PEEK intervened, defer this SCC to the next round. */
+ if (read_seqcount_retry(&unix_peek_seq, seq))
+ return false;
+
+ return scc_dead;
+}
+
static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist)
{
struct unix_vertex *vertex;
@@ -401,12 +454,11 @@ static bool unix_scc_cyclic(struct list_head *scc)
return false;
}
-static LIST_HEAD(unix_visited_vertices);
-static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2;
-
-static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_index,
- struct sk_buff_head *hitlist)
+static unsigned long __unix_walk_scc(struct unix_vertex *vertex,
+ unsigned long *last_index,
+ struct sk_buff_head *hitlist)
{
+ unsigned long cyclic_sccs = 0;
LIST_HEAD(vertex_stack);
struct unix_edge *edge;
LIST_HEAD(edge_stack);
@@ -469,9 +521,7 @@ static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_inde
}
if (vertex->index == vertex->scc_index) {
- struct unix_vertex *v;
struct list_head scc;
- bool scc_dead = true;
/* SCC finalised.
*
@@ -480,25 +530,14 @@ static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_inde
*/
__list_cut_position(&scc, &vertex_stack, &vertex->scc_entry);
- list_for_each_entry_reverse(v, &scc, scc_entry) {
- /* Don't restart DFS from this vertex in unix_walk_scc(). */
- list_move_tail(&v->entry, &unix_visited_vertices);
-
- /* Mark vertex as off-stack. */
- v->index = unix_vertex_grouped_index;
-
- if (scc_dead)
- scc_dead = unix_vertex_dead(v);
- }
-
- if (scc_dead) {
+ if (unix_scc_dead(&scc, false)) {
unix_collect_skb(&scc, hitlist);
} else {
if (unix_vertex_max_scc_index < vertex->scc_index)
unix_vertex_max_scc_index = vertex->scc_index;
- if (!unix_graph_maybe_cyclic)
- unix_graph_maybe_cyclic = unix_scc_cyclic(&scc);
+ if (unix_scc_cyclic(&scc))
+ cyclic_sccs++;
}
list_del(&scc);
@@ -507,13 +546,17 @@ static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_inde
/* Need backtracking ? */
if (!list_empty(&edge_stack))
goto prev_vertex;
+
+ return cyclic_sccs;
}
+static unsigned long unix_graph_cyclic_sccs;
+
static void unix_walk_scc(struct sk_buff_head *hitlist)
{
unsigned long last_index = UNIX_VERTEX_INDEX_START;
+ unsigned long cyclic_sccs = 0;
- unix_graph_maybe_cyclic = false;
unix_vertex_max_scc_index = UNIX_VERTEX_INDEX_START;
/* Visit every vertex exactly once.
@@ -523,46 +566,40 @@ static void unix_walk_scc(struct sk_buff_head *hitlist)
struct unix_vertex *vertex;
vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry);
- __unix_walk_scc(vertex, &last_index, hitlist);
+ cyclic_sccs += __unix_walk_scc(vertex, &last_index, hitlist);
}
list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices);
swap(unix_vertex_unvisited_index, unix_vertex_grouped_index);
- unix_graph_grouped = true;
+ unix_graph_cyclic_sccs = cyclic_sccs;
+ unix_graph_state = cyclic_sccs ? UNIX_GRAPH_CYCLIC : UNIX_GRAPH_NOT_CYCLIC;
}
static void unix_walk_scc_fast(struct sk_buff_head *hitlist)
{
- unix_graph_maybe_cyclic = false;
+ unsigned long cyclic_sccs = unix_graph_cyclic_sccs;
while (!list_empty(&unix_unvisited_vertices)) {
struct unix_vertex *vertex;
struct list_head scc;
- bool scc_dead = true;
vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry);
list_add(&scc, &vertex->scc_entry);
- list_for_each_entry_reverse(vertex, &scc, scc_entry) {
- list_move_tail(&vertex->entry, &unix_visited_vertices);
-
- if (scc_dead)
- scc_dead = unix_vertex_dead(vertex);
- }
-
- if (scc_dead)
+ if (unix_scc_dead(&scc, true)) {
+ cyclic_sccs--;
unix_collect_skb(&scc, hitlist);
- else if (!unix_graph_maybe_cyclic)
- unix_graph_maybe_cyclic = unix_scc_cyclic(&scc);
+ }
list_del(&scc);
}
list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices);
-}
-static bool gc_in_progress;
+ unix_graph_cyclic_sccs = cyclic_sccs;
+ unix_graph_state = cyclic_sccs ? UNIX_GRAPH_CYCLIC : UNIX_GRAPH_NOT_CYCLIC;
+}
static void __unix_gc(struct work_struct *work)
{
@@ -571,14 +608,14 @@ static void __unix_gc(struct work_struct *work)
spin_lock(&unix_gc_lock);
- if (!unix_graph_maybe_cyclic) {
+ if (unix_graph_state == UNIX_GRAPH_NOT_CYCLIC) {
spin_unlock(&unix_gc_lock);
goto skip_gc;
}
__skb_queue_head_init(&hitlist);
- if (unix_graph_grouped)
+ if (unix_graph_state == UNIX_GRAPH_CYCLIC)
unix_walk_scc_fast(&hitlist);
else
unix_walk_scc(&hitlist);
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index c9ddef869aa5..3d80c5210e04 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -503,7 +503,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
/* An encap_type of -1 indicates async resumption. */
if (encap_type == -1) {
async = 1;
- dev_put(skb->dev);
seq = XFRM_SKB_CB(skb)->seq.input.low;
goto resume;
}
@@ -656,8 +655,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
dev_hold(skb->dev);
nexthdr = x->type->input(x, skb);
- if (nexthdr == -EINPROGRESS)
+ if (nexthdr == -EINPROGRESS) {
+ if (async)
+ dev_put(skb->dev);
return 0;
+ }
dev_put(skb->dev);
}
@@ -692,9 +694,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
err = xfrm_inner_mode_input(x, skb);
- if (err == -EINPROGRESS)
+ if (err == -EINPROGRESS) {
+ if (async)
+ dev_put(skb->dev);
return 0;
- else if (err) {
+ } else if (err) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
goto drop;
}
@@ -731,6 +735,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
sp->olen = 0;
if (skb_valid_dst(skb))
skb_dst_drop(skb);
+ if (async)
+ dev_put(skb->dev);
gro_cells_receive(&gro_cells, skb);
return 0;
} else {
@@ -750,6 +756,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
sp->olen = 0;
if (skb_valid_dst(skb))
skb_dst_drop(skb);
+ if (async)
+ dev_put(skb->dev);
gro_cells_receive(&gro_cells, skb);
return err;
}
@@ -760,6 +768,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
drop_unlock:
spin_unlock(&x->lock);
drop:
+ if (async)
+ dev_put(skb->dev);
xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
kfree_skb(skb);
return 0;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 4dd8341225bc..306e4f65ce26 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -3951,6 +3951,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
return err;
}
upe->hard = !!hard;
+ /* clear the padding bytes */
+ memset_after(upe, 0, hard);
nlmsg_end(skb, nlh);
return 0;
@@ -4108,6 +4110,7 @@ static int build_report(struct sk_buff *skb, u8 proto,
return -EMSGSIZE;
ur = nlmsg_data(nlh);
+ memset(ur, 0, sizeof(*ur));
ur->proto = proto;
memcpy(&ur->sel, sel, sizeof(ur->sel));
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 133dfa16308a..010c398f6a70 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -56,7 +56,7 @@ static bool allow_missing_ns_imports;
static bool error_occurred;
-static bool extra_warn;
+static bool extra_warn __attribute__((unused));
bool target_is_big_endian;
bool host_is_big_endian;
diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c
index 3a943adf9087..5073165d1f3c 100644
--- a/sound/hda/codecs/realtek/alc662.c
+++ b/sound/hda/codecs/realtek/alc662.c
@@ -313,7 +313,6 @@ enum {
ALC897_FIXUP_HEADSET_MIC_PIN2,
ALC897_FIXUP_UNIS_H3C_X500S,
ALC897_FIXUP_HEADSET_MIC_PIN3,
- ALC897_FIXUP_H610M_HP_PIN,
};
static const struct hda_fixup alc662_fixups[] = {
@@ -767,13 +766,6 @@ static const struct hda_fixup alc662_fixups[] = {
{ }
},
},
- [ALC897_FIXUP_H610M_HP_PIN] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, 0x0321403f }, /* HP out */
- { }
- },
- },
};
static const struct hda_quirk alc662_fixup_tbl[] = {
@@ -823,7 +815,6 @@ static const struct hda_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
- SND_PCI_QUIRK(0x1458, 0xa194, "H610M H V2 DDR4", ALC897_FIXUP_H610M_HP_PIN),
SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
prev parent reply other threads:[~2026-04-18 8:52 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-18 8:51 Linux 6.18.23 Greg Kroah-Hartman
2026-04-18 8:51 ` Greg Kroah-Hartman [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2026041828-perm-siesta-5f30@gregkh \
--to=gregkh@linuxfoundation.org \
--cc=akpm@linux-foundation.org \
--cc=jslaby@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=lwn@lwn.net \
--cc=stable@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.