* Re: Linux 5.10.253
2026-04-18 8:50 Linux 5.10.253 Greg Kroah-Hartman
@ 2026-04-18 8:50 ` Greg Kroah-Hartman
0 siblings, 0 replies; 2+ messages in thread
From: Greg Kroah-Hartman @ 2026-04-18 8:50 UTC (permalink / raw)
To: linux-kernel, akpm, torvalds, stable; +Cc: lwn, jslaby, Greg Kroah-Hartman
diff --git a/Documentation/hwmon/adm1177.rst b/Documentation/hwmon/adm1177.rst
index 471be1e98d6f..fc0c3390c302 100644
--- a/Documentation/hwmon/adm1177.rst
+++ b/Documentation/hwmon/adm1177.rst
@@ -26,10 +26,10 @@ devices explicitly. Please see :doc:`/i2c/instantiating-devices` for details.
Sysfs entries
-------------
-The following attributes are supported. Current maxim attribute
+The following attributes are supported. Current maximum attribute
is read-write, all other attributes are read-only.
-in0_input Measured voltage in microvolts.
+in0_input Measured voltage in millivolts.
-curr1_input Measured current in microamperes.
-curr1_max_alarm Overcurrent alarm in microamperes.
+curr1_input Measured current in milliamperes.
+curr1_max Overcurrent shutdown threshold in milliamperes.
diff --git a/Makefile b/Makefile
index bceb0c9760a7..3efb1fbf5028 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 5
PATCHLEVEL = 10
-SUBLEVEL = 252
+SUBLEVEL = 253
EXTRAVERSION =
NAME = Dare mighty things
diff --git a/arch/arm/include/asm/string.h b/arch/arm/include/asm/string.h
index b5ad23acb303..369781ec5511 100644
--- a/arch/arm/include/asm/string.h
+++ b/arch/arm/include/asm/string.h
@@ -33,13 +33,17 @@ static inline void *memset32(uint32_t *p, uint32_t v, __kernel_size_t n)
}
#define __HAVE_ARCH_MEMSET64
-extern void *__memset64(uint64_t *, uint32_t low, __kernel_size_t, uint32_t hi);
+extern void *__memset64(uint64_t *, uint32_t first, __kernel_size_t, uint32_t second);
static inline void *memset64(uint64_t *p, uint64_t v, __kernel_size_t n)
{
- if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
- return __memset64(p, v, n * 8, v >> 32);
- else
- return __memset64(p, v >> 32, n * 8, v);
+ union {
+ uint64_t val;
+ struct {
+ uint32_t first, second;
+ };
+ } word = { .val = v };
+
+ return __memset64(p, word.first, n * 8, word.second);
}
#endif
diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c
index b7ea609386d5..d86a36120738 100644
--- a/arch/arm/mach-omap2/cm_common.c
+++ b/arch/arm/mach-omap2/cm_common.c
@@ -333,8 +333,10 @@ int __init omap2_cm_base_init(void)
data = (struct omap_prcm_init_data *)match->data;
ret = of_address_to_resource(np, 0, &res);
- if (ret)
+ if (ret) {
+ of_node_put(np);
return ret;
+ }
if (data->index == TI_CLKM_CM)
mem = &cm_base;
@@ -380,8 +382,10 @@ int __init omap_cm_init(void)
continue;
ret = omap2_clk_provider_init(np, data->index, NULL, data->mem);
- if (ret)
+ if (ret) {
+ of_node_put(np);
return ret;
+ }
}
return 0;
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index 73338cf80d76..a1288d438071 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -774,8 +774,10 @@ int __init omap2_control_base_init(void)
data = (struct control_init_data *)match->data;
mem = of_iomap(np, 0);
- if (!mem)
+ if (!mem) {
+ of_node_put(np);
return -ENOMEM;
+ }
if (data->index == TI_CLKM_CTRL) {
omap2_ctrl_base = mem;
@@ -796,7 +798,7 @@ int __init omap2_control_base_init(void)
*/
int __init omap_control_init(void)
{
- struct device_node *np, *scm_conf;
+ struct device_node *np, *scm_conf, *clocks_node;
const struct of_device_id *match;
const struct omap_prcm_init_data *data;
int ret;
@@ -815,22 +817,27 @@ int __init omap_control_init(void)
if (scm_conf) {
syscon = syscon_node_to_regmap(scm_conf);
- if (IS_ERR(syscon))
- return PTR_ERR(syscon);
+ if (IS_ERR(syscon)) {
+ ret = PTR_ERR(syscon);
+ goto err_put_scm_conf;
+ }
- if (of_get_child_by_name(scm_conf, "clocks")) {
+ clocks_node = of_get_child_by_name(scm_conf, "clocks");
+ if (clocks_node) {
+ of_node_put(clocks_node);
ret = omap2_clk_provider_init(scm_conf,
data->index,
syscon, NULL);
if (ret)
- return ret;
+ goto err_put_scm_conf;
}
+ of_node_put(scm_conf);
} else {
/* No scm_conf found, direct access */
ret = omap2_clk_provider_init(np, data->index, NULL,
data->mem);
if (ret)
- return ret;
+ goto of_node_put;
}
}
@@ -841,6 +848,14 @@ int __init omap_control_init(void)
}
return 0;
+
+err_put_scm_conf:
+ if (scm_conf)
+ of_node_put(scm_conf);
+of_node_put:
+ of_node_put(np);
+ return ret;
+
}
/**
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 65b2d82efa27..fb2d48cfe756 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -752,8 +752,10 @@ int __init omap2_prm_base_init(void)
data = (struct omap_prcm_init_data *)match->data;
ret = of_address_to_resource(np, 0, &res);
- if (ret)
+ if (ret) {
+ of_node_put(np);
return ret;
+ }
data->mem = ioremap(res.start, resource_size(&res));
@@ -799,8 +801,10 @@ int __init omap_prcm_init(void)
data = match->data;
ret = omap2_clk_provider_init(np, data->index, NULL, data->mem);
- if (ret)
+ if (ret) {
+ of_node_put(np);
return ret;
+ }
}
omap_cm_init();
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 adc0a096ab4c..f6ca412b8da8 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi
@@ -81,6 +81,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/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 9a65fb528110..2c5b9ba13f26 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -65,11 +65,11 @@ extern bool arm64_use_ng_mappings;
#define _PAGE_DEFAULT (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
-#define PAGE_KERNEL __pgprot(PROT_NORMAL)
-#define PAGE_KERNEL_RO __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
-#define PAGE_KERNEL_ROX __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
-#define PAGE_KERNEL_EXEC __pgprot(PROT_NORMAL & ~PTE_PXN)
-#define PAGE_KERNEL_EXEC_CONT __pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_CONT)
+#define PAGE_KERNEL __pgprot(PROT_NORMAL | PTE_DIRTY)
+#define PAGE_KERNEL_RO __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY | PTE_DIRTY)
+#define PAGE_KERNEL_ROX __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY | PTE_DIRTY)
+#define PAGE_KERNEL_EXEC __pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_DIRTY)
+#define PAGE_KERNEL_EXEC_CONT __pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_CONT | PTE_DIRTY)
#define PAGE_S2_MEMATTR(attr) \
({ \
diff --git a/arch/mips/lib/multi3.c b/arch/mips/lib/multi3.c
index 4c2483f410c2..92b3778bb56f 100644
--- a/arch/mips/lib/multi3.c
+++ b/arch/mips/lib/multi3.c
@@ -4,12 +4,12 @@
#include "libgcc.h"
/*
- * GCC 7 & older can suboptimally generate __multi3 calls for mips64r6, so for
+ * GCC 9 & older can suboptimally generate __multi3 calls for mips64r6, so for
* that specific case only we implement that intrinsic here.
*
* See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82981
*/
-#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 8)
+#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 10)
/* multiply 64-bit values, low 64-bits returned */
static inline long long notrace dmulu(long long a, long long b)
@@ -51,4 +51,4 @@ ti_type notrace __multi3(ti_type a, ti_type b)
}
EXPORT_SYMBOL(__multi3);
-#endif /* 64BIT && CPU_MIPSR6 && GCC7 */
+#endif /* 64BIT && CPU_MIPSR6 && GCC9 */
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index ade591927cbf..1788bf0d82e0 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -109,7 +109,7 @@ extern void __update_cache(pte_t pte);
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
/* This is the size of the initially mapped kernel memory */
-#if defined(CONFIG_64BIT)
+#if defined(CONFIG_64BIT) || defined(CONFIG_KALLSYMS)
#define KERNEL_INITIAL_ORDER 26 /* 1<<26 = 64MB */
#else
#define KERNEL_INITIAL_ORDER 25 /* 1<<25 = 32MB */
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index 2f95c2429f77..27e914543c44 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -55,6 +55,7 @@ ENTRY(parisc_kernel_start)
.import __bss_start,data
.import __bss_stop,data
+ .import __end,data
load32 PA(__bss_start),%r3
load32 PA(__bss_stop),%r4
@@ -148,7 +149,11 @@ $cpu_ok:
* everything ... it will get remapped correctly later */
ldo 0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */
load32 (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */
- load32 PA(pg0),%r1
+ load32 PA(_end),%r1
+ SHRREG %r1,PAGE_SHIFT,%r1 /* %r1 is PFN count for _end symbol */
+ cmpb,<<,n %r11,%r1,1f
+ copy %r1,%r11 /* %r1 PFN count smaller than %r11 */
+1: load32 PA(pg0),%r1
$pgt_fill_loop:
STREGM %r3,ASM_PTE_ENTRY_SIZE(%r1)
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 6df110c1254e..ab9efc429615 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -279,7 +279,7 @@ extern long __get_user_bad(void);
".section .fixup,\"ax\"\n" \
"4: li %0,%3\n" \
" li %1,0\n" \
- " li %1+1,0\n" \
+ " li %L1,0\n" \
" b 3b\n" \
".previous\n" \
EX_TABLE(1b, 4b) \
diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c
index bcdc2c203ec9..e108d316a744 100644
--- a/arch/powerpc/platforms/83xx/km83xx.c
+++ b/arch/powerpc/platforms/83xx/km83xx.c
@@ -156,8 +156,8 @@ machine_device_initcall(mpc83xx_km, mpc83xx_declare_of_platform_devices);
/* list of the supported boards */
static char *board[] __initdata = {
- "Keymile,KMETER1",
- "Keymile,kmpbec8321",
+ "keymile,KMETER1",
+ "keymile,kmpbec8321",
NULL
};
diff --git a/arch/riscv/kernel/kgdb.c b/arch/riscv/kernel/kgdb.c
index 1d83b3696721..eb737c7a563b 100644
--- a/arch/riscv/kernel/kgdb.c
+++ b/arch/riscv/kernel/kgdb.c
@@ -194,7 +194,7 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
{DBG_REG_T1, GDB_SIZEOF_REG, offsetof(struct pt_regs, t1)},
{DBG_REG_T2, GDB_SIZEOF_REG, offsetof(struct pt_regs, t2)},
{DBG_REG_FP, GDB_SIZEOF_REG, offsetof(struct pt_regs, s0)},
- {DBG_REG_S1, GDB_SIZEOF_REG, offsetof(struct pt_regs, a1)},
+ {DBG_REG_S1, GDB_SIZEOF_REG, offsetof(struct pt_regs, s1)},
{DBG_REG_A0, GDB_SIZEOF_REG, offsetof(struct pt_regs, a0)},
{DBG_REG_A1, GDB_SIZEOF_REG, offsetof(struct pt_regs, a1)},
{DBG_REG_A2, GDB_SIZEOF_REG, offsetof(struct pt_regs, a2)},
@@ -263,8 +263,9 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
gdb_regs[DBG_REG_S6_OFF] = task->thread.s[6];
gdb_regs[DBG_REG_S7_OFF] = task->thread.s[7];
gdb_regs[DBG_REG_S8_OFF] = task->thread.s[8];
- gdb_regs[DBG_REG_S9_OFF] = task->thread.s[10];
- gdb_regs[DBG_REG_S10_OFF] = task->thread.s[11];
+ gdb_regs[DBG_REG_S9_OFF] = task->thread.s[9];
+ gdb_regs[DBG_REG_S10_OFF] = task->thread.s[10];
+ gdb_regs[DBG_REG_S11_OFF] = task->thread.s[11];
gdb_regs[DBG_REG_EPC_OFF] = task->thread.ra;
}
diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h
index f9eddbca79d2..489469606902 100644
--- a/arch/s390/include/asm/barrier.h
+++ b/arch/s390/include/asm/barrier.h
@@ -56,8 +56,8 @@ do { \
* @size: number of elements in array
*/
#define array_index_mask_nospec array_index_mask_nospec
-static inline unsigned long array_index_mask_nospec(unsigned long index,
- unsigned long size)
+static __always_inline unsigned long array_index_mask_nospec(unsigned long index,
+ unsigned long size)
{
unsigned long mask;
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 127a8d295ae3..106f4b21faf2 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -420,12 +420,15 @@ ENTRY(system_call)
# svc 0: system call number in %r1
llgfr %r1,%r1 # clear high word in r1
sth %r1,__PT_INT_CODE+2(%r11)
- cghi %r1,NR_syscalls
- jnl .Lsysc_nr_ok
+ lghi %r0,NR_syscalls-1
+ clgr %r1,%r0 # CC0/1 if r1 in bounds
+ slbgr %r0,%r0 # mask = -1 in bounds, 0 out of bounds
+ ngr %r1,%r0 # clamp r1
slag %r8,%r1,3
.Lsysc_nr_ok:
stg %r2,__PT_ORIG_GPR2(%r11)
stg %r7,STACK_FRAME_OVERHEAD(%r15)
+ xgr %r1,%r1 # scrub r1, unclamped user value for svc 1-255
lg %r9,0(%r8,%r10) # get system call add.
TSTMSK __TI_flags(%r12),_TIF_TRACE
jnz .Lsysc_tracesys
diff --git a/arch/s390/lib/xor.c b/arch/s390/lib/xor.c
index 29d9470dbceb..7a5bb4eef9da 100644
--- a/arch/s390/lib/xor.c
+++ b/arch/s390/lib/xor.c
@@ -28,8 +28,8 @@ static void xor_xc_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
" j 3f\n"
"2: xc 0(1,%1),0(%2)\n"
"3:\n"
- : : "d" (bytes), "a" (p1), "a" (p2)
- : "0", "1", "cc", "memory");
+ : "+d" (bytes), "+a" (p1), "+a" (p2)
+ : : "0", "1", "cc", "memory");
}
static void xor_xc_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c
index 143747c45206..48ddbc547bd9 100644
--- a/arch/sh/drivers/platform_early.c
+++ b/arch/sh/drivers/platform_early.c
@@ -26,10 +26,6 @@ static int platform_match(struct device *dev, struct device_driver *drv)
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
- /* When driver_override is set, only bind to the matching driver */
- if (pdev->driver_override)
- return !strcmp(pdev->driver_override, drv->name);
-
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 7c675832712d..e25ad8157921 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -151,7 +151,7 @@ extern int __init efi_reuse_config(u64 tables, int nr_tables);
extern void efi_delete_dummy_variable(void);
extern void efi_switch_mm(struct mm_struct *mm);
extern void efi_recover_from_page_fault(unsigned long phys_addr);
-extern void efi_free_boot_services(void);
+extern void efi_unmap_boot_services(void);
/* kexec external ABI */
struct efi_setup_data {
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index a479530e59ab..390db709b432 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -529,6 +529,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/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 3a3878817c20..77886d2d34ad 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1901,6 +1901,7 @@ early_initcall(validate_x2apic);
static inline void try_to_enable_x2apic(int remap_mode) { }
static inline void __x2apic_enable(void) { }
+static inline void __x2apic_disable(void) { }
#endif /* !CONFIG_X86_X2APIC */
void __init enable_IR_x2apic(void)
@@ -2664,6 +2665,11 @@ static void lapic_resume(void)
if (x2apic_mode) {
__x2apic_enable();
} else {
+ if (x2apic_enabled()) {
+ pr_warn_once("x2apic: re-enabled by firmware during resume. Disabling\n");
+ __x2apic_disable();
+ }
+
/*
* Make sure the APICBASE points to the right address
*
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index bf07b2c5418a..39602a7ed1fc 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -1102,6 +1102,9 @@ static void init_amd_zn(struct cpuinfo_x86 *c)
if (c->x86 == 0x19 && !cpu_has(c, X86_FEATURE_BTC_NO))
set_cpu_cap(c, X86_FEATURE_BTC_NO);
}
+
+ 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 bool cpu_has_zenbleed_microcode(void)
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index 63dbf67d107b..a5c5eb3fea22 100644
--- a/arch/x86/kvm/svm/avic.c
+++ b/arch/x86/kvm/svm/avic.c
@@ -203,7 +203,7 @@ void avic_init_vmcb(struct vcpu_svm *svm)
vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK;
vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK;
vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT;
- if (kvm_apicv_activated(svm->vcpu.kvm))
+ if (kvm_vcpu_apicv_active(&svm->vcpu))
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
else
vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 0ca511389227..97783bf50a3f 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1230,7 +1230,7 @@ static void init_vmcb(struct vcpu_svm *svm)
svm_check_invpcid(svm);
- if (kvm_vcpu_apicv_active(&svm->vcpu))
+ if (avic && irqchip_in_kernel(svm->vcpu.kvm))
avic_init_vmcb(svm);
/*
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 98a5924d98b7..e06182127e1c 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -433,6 +433,9 @@ static int is_errata93(struct pt_regs *regs, unsigned long address)
|| boot_cpu_data.x86 != 0xf)
return 0;
+ if (user_mode(regs))
+ return 0;
+
if (address != regs->ip)
return 0;
@@ -697,9 +700,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
if (is_prefetch(regs, error_code, address))
return;
- if (is_errata93(regs, address))
- return;
-
/*
* Buggy firmware could access regions which might page fault, try to
* recover from such faults.
@@ -925,40 +925,6 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
}
-static noinline void
-mm_fault_error(struct pt_regs *regs, unsigned long error_code,
- unsigned long address, vm_fault_t fault)
-{
- if (fatal_signal_pending(current) && !(error_code & X86_PF_USER)) {
- no_context(regs, error_code, address, 0, 0);
- return;
- }
-
- if (fault & VM_FAULT_OOM) {
- /* Kernel mode? Handle exceptions or die: */
- if (!(error_code & X86_PF_USER)) {
- no_context(regs, error_code, address,
- SIGSEGV, SEGV_MAPERR);
- return;
- }
-
- /*
- * We ran out of memory, call the OOM killer, and return the
- * userspace (which will retry the fault, or kill us if we got
- * oom-killed):
- */
- pagefault_out_of_memory();
- } else {
- if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
- VM_FAULT_HWPOISON_LARGE))
- do_sigbus(regs, error_code, address, fault);
- else if (fault & VM_FAULT_SIGSEGV)
- bad_area_nosemaphore(regs, error_code, address);
- else
- BUG();
- }
-}
-
static int spurious_kernel_fault_check(unsigned long error_code, pte_t *pte)
{
if ((error_code & X86_PF_WRITE) && !pte_write(*pte))
@@ -1184,7 +1150,7 @@ NOKPROBE_SYMBOL(do_kern_addr_fault);
/* Handle faults in the user portion of the address space */
static inline
void do_user_addr_fault(struct pt_regs *regs,
- unsigned long hw_error_code,
+ unsigned long error_code,
unsigned long address)
{
struct vm_area_struct *vma;
@@ -1196,6 +1162,21 @@ void do_user_addr_fault(struct pt_regs *regs,
tsk = current;
mm = tsk->mm;
+ if (unlikely((error_code & (X86_PF_USER | X86_PF_INSTR)) == X86_PF_INSTR)) {
+ /*
+ * Whoops, this is kernel mode code trying to execute from
+ * user memory. Unless this is AMD erratum #93, which
+ * corrupts RIP such that it looks like a user address,
+ * this is unrecoverable. Don't even try to look up the
+ * VMA.
+ */
+ if (is_errata93(regs, address))
+ return;
+
+ bad_area_nosemaphore(regs, error_code, address);
+ return;
+ }
+
/* kprobes don't want to hook the spurious faults: */
if (unlikely(kprobe_page_fault(regs, X86_TRAP_PF)))
return;
@@ -1204,8 +1185,8 @@ void do_user_addr_fault(struct pt_regs *regs,
* Reserved bits are never expected to be set on
* entries in the user portion of the page tables.
*/
- if (unlikely(hw_error_code & X86_PF_RSVD))
- pgtable_bad(regs, hw_error_code, address);
+ if (unlikely(error_code & X86_PF_RSVD))
+ pgtable_bad(regs, error_code, address);
/*
* If SMAP is on, check for invalid kernel (supervisor) access to user
@@ -1215,10 +1196,10 @@ void do_user_addr_fault(struct pt_regs *regs,
* enforcement appears to be consistent with the USER bit.
*/
if (unlikely(cpu_feature_enabled(X86_FEATURE_SMAP) &&
- !(hw_error_code & X86_PF_USER) &&
+ !(error_code & X86_PF_USER) &&
!(regs->flags & X86_EFLAGS_AC)))
{
- bad_area_nosemaphore(regs, hw_error_code, address);
+ bad_area_nosemaphore(regs, error_code, address);
return;
}
@@ -1227,7 +1208,7 @@ void do_user_addr_fault(struct pt_regs *regs,
* in a region with pagefaults disabled then we must not take the fault
*/
if (unlikely(faulthandler_disabled() || !mm)) {
- bad_area_nosemaphore(regs, hw_error_code, address);
+ bad_area_nosemaphore(regs, error_code, address);
return;
}
@@ -1248,9 +1229,9 @@ void do_user_addr_fault(struct pt_regs *regs,
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
- if (hw_error_code & X86_PF_WRITE)
+ if (error_code & X86_PF_WRITE)
flags |= FAULT_FLAG_WRITE;
- if (hw_error_code & X86_PF_INSTR)
+ if (error_code & X86_PF_INSTR)
flags |= FAULT_FLAG_INSTRUCTION;
#ifdef CONFIG_X86_64
@@ -1266,7 +1247,7 @@ void do_user_addr_fault(struct pt_regs *regs,
* to consider the PF_PK bit.
*/
if (is_vsyscall_vaddr(address)) {
- if (emulate_vsyscall(hw_error_code, regs, address))
+ if (emulate_vsyscall(error_code, regs, address))
return;
}
#endif
@@ -1289,7 +1270,7 @@ void do_user_addr_fault(struct pt_regs *regs,
* Fault from code in kernel from
* which we do not expect faults.
*/
- bad_area_nosemaphore(regs, hw_error_code, address);
+ bad_area_nosemaphore(regs, error_code, address);
return;
}
retry:
@@ -1305,17 +1286,17 @@ void do_user_addr_fault(struct pt_regs *regs,
vma = find_vma(mm, address);
if (unlikely(!vma)) {
- bad_area(regs, hw_error_code, address);
+ bad_area(regs, error_code, address);
return;
}
if (likely(vma->vm_start <= address))
goto good_area;
if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
- bad_area(regs, hw_error_code, address);
+ bad_area(regs, error_code, address);
return;
}
if (unlikely(expand_stack(vma, address))) {
- bad_area(regs, hw_error_code, address);
+ bad_area(regs, error_code, address);
return;
}
@@ -1324,8 +1305,8 @@ void do_user_addr_fault(struct pt_regs *regs,
* we can handle it..
*/
good_area:
- if (unlikely(access_error(hw_error_code, vma))) {
- bad_area_access_error(regs, hw_error_code, address, vma);
+ if (unlikely(access_error(error_code, vma))) {
+ bad_area_access_error(regs, error_code, address, vma);
return;
}
@@ -1347,7 +1328,7 @@ void do_user_addr_fault(struct pt_regs *regs,
/* Quick path to respond to signals */
if (fault_signal_pending(fault, regs)) {
if (!user_mode(regs))
- no_context(regs, hw_error_code, address, SIGBUS,
+ no_context(regs, error_code, address, SIGBUS,
BUS_ADRERR);
return;
}
@@ -1364,9 +1345,36 @@ void do_user_addr_fault(struct pt_regs *regs,
}
mmap_read_unlock(mm);
- if (unlikely(fault & VM_FAULT_ERROR)) {
- mm_fault_error(regs, hw_error_code, address, fault);
+ if (likely(!(fault & VM_FAULT_ERROR)))
return;
+
+ if (fatal_signal_pending(current) && !(error_code & X86_PF_USER)) {
+ no_context(regs, error_code, address, 0, 0);
+ return;
+ }
+
+ if (fault & VM_FAULT_OOM) {
+ /* Kernel mode? Handle exceptions or die: */
+ if (!(error_code & X86_PF_USER)) {
+ no_context(regs, error_code, address,
+ SIGSEGV, SEGV_MAPERR);
+ return;
+ }
+
+ /*
+ * We ran out of memory, call the OOM killer, and return the
+ * userspace (which will retry the fault, or kill us if we got
+ * oom-killed):
+ */
+ pagefault_out_of_memory();
+ } else {
+ if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
+ VM_FAULT_HWPOISON_LARGE))
+ do_sigbus(regs, error_code, address, fault);
+ else if (fault & VM_FAULT_SIGSEGV)
+ bad_area_nosemaphore(regs, error_code, address);
+ else
+ BUG();
}
check_v8086_mode(regs, address, tsk);
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 41229bcbe0d9..6c8a585e15e7 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -831,7 +831,7 @@ static void __init __efi_enter_virtual_mode(void)
}
efi_check_for_embedded_firmwares();
- efi_free_boot_services();
+ efi_unmap_boot_services();
if (!efi_is_mixed())
efi_native_runtime_setup();
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index c1eec019dcee..99b282d6c130 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -333,7 +333,7 @@ void __init efi_reserve_boot_services(void)
/*
* Because the following memblock_reserve() is paired
- * with memblock_free_late() for this region in
+ * with free_reserved_area() for this region in
* efi_free_boot_services(), we must be extremely
* careful not to reserve, and subsequently free,
* critical regions of memory (like the kernel image) or
@@ -396,17 +396,33 @@ static void __init efi_unmap_pages(efi_memory_desc_t *md)
pr_err("Failed to unmap VA mapping for 0x%llx\n", va);
}
-void __init efi_free_boot_services(void)
+struct efi_freeable_range {
+ u64 start;
+ u64 end;
+};
+
+static struct efi_freeable_range *ranges_to_free;
+
+void __init efi_unmap_boot_services(void)
{
struct efi_memory_map_data data = { 0 };
efi_memory_desc_t *md;
int num_entries = 0;
+ int idx = 0;
+ size_t sz;
void *new, *new_md;
/* Keep all regions for /sys/kernel/debug/efi */
if (efi_enabled(EFI_DBG))
return;
+ sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
+ ranges_to_free = kzalloc(sz, GFP_KERNEL);
+ if (!ranges_to_free) {
+ pr_err("Failed to allocate storage for freeable EFI regions\n");
+ return;
+ }
+
for_each_efi_memory_desc(md) {
unsigned long long start = md->phys_addr;
unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -451,7 +467,15 @@ void __init efi_free_boot_services(void)
size -= rm_size;
}
- memblock_free_late(start, size);
+ /*
+ * With CONFIG_DEFERRED_STRUCT_PAGE_INIT parts of the memory
+ * map are still not initialized and we can't reliably free
+ * memory here.
+ * Queue the ranges to free at a later point.
+ */
+ ranges_to_free[idx].start = start;
+ ranges_to_free[idx].end = start + size;
+ idx++;
}
if (!num_entries)
@@ -492,6 +516,31 @@ void __init efi_free_boot_services(void)
}
}
+static int __init efi_free_boot_services(void)
+{
+ struct efi_freeable_range *range = ranges_to_free;
+ unsigned long freed = 0;
+
+ if (!ranges_to_free)
+ return 0;
+
+ while (range->start) {
+ void *start = phys_to_virt(range->start);
+ void *end = phys_to_virt(range->end);
+
+ free_reserved_area(start, end, -1, NULL);
+ freed += (end - start);
+ range++;
+ }
+ kfree(ranges_to_free);
+
+ if (freed)
+ pr_info("Freeing EFI boot services memory: %ldK\n", freed / SZ_1K);
+
+ return 0;
+}
+arch_initcall(efi_free_boot_services);
+
/*
* A number of config table entries get remapped to virtual addresses
* after entering EFI virtual mode. However, the kexec kernel requires
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 3d622904f4c3..5e0fe58f8bdd 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -515,8 +515,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
sgl->cur = 0;
- if (sg)
+ if (sg) {
+ sg_unmark_end(sg + MAX_SGL_ENTS - 1);
sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
+ }
list_add_tail(&sgl->list, &ctx->tsgl_list);
}
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index da97fd0c6b51..12384b3cdd6e 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -20,13 +20,14 @@ ACPI_MODULE_NAME("evxfregn")
/*******************************************************************************
*
- * FUNCTION: acpi_install_address_space_handler
+ * FUNCTION: acpi_install_address_space_handler_internal
*
* PARAMETERS: device - Handle for the device
* space_id - The address space ID
* handler - Address of the handler
* setup - Address of the setup function
* context - Value passed to the handler on each access
+ * Run_reg - Run _REG methods for this address space?
*
* RETURN: Status
*
@@ -37,13 +38,16 @@ ACPI_MODULE_NAME("evxfregn")
* are executed here, and these methods can only be safely executed after
* the default handlers have been installed and the hardware has been
* initialized (via acpi_enable_subsystem.)
+ * To avoid this problem pass FALSE for Run_Reg and later on call
+ * acpi_execute_reg_methods() to execute _REG.
*
******************************************************************************/
-acpi_status
-acpi_install_address_space_handler(acpi_handle device,
- acpi_adr_space_type space_id,
- acpi_adr_space_handler handler,
- acpi_adr_space_setup setup, void *context)
+static acpi_status
+acpi_install_address_space_handler_internal(acpi_handle device,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup,
+ void *context, u8 run_reg)
{
struct acpi_namespace_node *node;
acpi_status status;
@@ -80,14 +84,40 @@ acpi_install_address_space_handler(acpi_handle device,
/* Run all _REG methods for this address space */
- acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT);
+ if (run_reg) {
+ acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT);
+ }
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(status);
}
+acpi_status
+acpi_install_address_space_handler(acpi_handle device,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup, void *context)
+{
+ return acpi_install_address_space_handler_internal(device, space_id,
+ handler, setup,
+ context, TRUE);
+}
+
ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)
+acpi_status
+acpi_install_address_space_handler_no_reg(acpi_handle device,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup,
+ void *context)
+{
+ return acpi_install_address_space_handler_internal(device, space_id,
+ handler, setup,
+ context, FALSE);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler_no_reg)
/*******************************************************************************
*
@@ -226,3 +256,51 @@ acpi_remove_address_space_handler(acpi_handle device,
}
ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_execute_reg_methods
+ *
+ * PARAMETERS: device - Handle for the device
+ * space_id - The address space ID
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute _REG for all op_regions of a given space_id.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_execute_reg_methods);
+
+ /* Parameter validation */
+
+ if (!device) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_validate_handle(device);
+ if (node) {
+
+ /* Run all _REG methods for this address space */
+
+ acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT);
+ } else {
+ status = AE_BAD_PARAMETER;
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_execute_reg_methods)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index b20206316fbe..10f7e3ef5879 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -96,6 +96,7 @@ enum {
EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */
EC_FLAGS_EVENT_HANDLER_INSTALLED, /* Event handler installed */
EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */
+ EC_FLAGS_EC_REG_CALLED, /* OpReg ACPI _REG method called */
EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
EC_FLAGS_STARTED, /* Driver is started */
EC_FLAGS_STOPPED, /* Driver is stopped */
@@ -1497,6 +1498,7 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
* ec_install_handlers - Install service callbacks and register query methods.
* @ec: Target EC.
* @device: ACPI device object corresponding to @ec.
+ * @call_reg: If _REG should be called to notify OpRegion availability
*
* Install a handler for the EC address space type unless it has been installed
* already. If @device is not NULL, also look for EC query methods in the
@@ -1509,7 +1511,8 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
* -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred,
* or 0 (success) otherwise.
*/
-static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
+static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
+ bool call_reg)
{
acpi_status status;
@@ -1517,15 +1520,21 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
acpi_ec_enter_noirq(ec);
- status = acpi_install_address_space_handler(ec->handle,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler,
- NULL, ec);
+ status = acpi_install_address_space_handler_no_reg(ec->handle,
+ ACPI_ADR_SPACE_EC,
+ &acpi_ec_space_handler,
+ NULL, ec);
if (ACPI_FAILURE(status)) {
acpi_ec_stop(ec, false);
return -ENODEV;
}
set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
+ ec->address_space_handler_holder = ec->handle;
+ }
+
+ if (call_reg && !test_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags)) {
+ acpi_execute_reg_methods(ec->handle, ACPI_ADR_SPACE_EC);
+ set_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags);
}
if (!device)
@@ -1577,7 +1586,8 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
static void ec_remove_handlers(struct acpi_ec *ec)
{
if (test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
- if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
+ if (ACPI_FAILURE(acpi_remove_address_space_handler(
+ ec->address_space_handler_holder,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err("failed to remove space handler\n");
clear_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
@@ -1613,11 +1623,11 @@ static void ec_remove_handlers(struct acpi_ec *ec)
}
}
-static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device)
+static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool call_reg)
{
int ret;
- ret = ec_install_handlers(ec, device);
+ ret = ec_install_handlers(ec, device, call_reg);
if (ret)
return ret;
@@ -1679,7 +1689,7 @@ static int acpi_ec_add(struct acpi_device *device)
}
}
- ret = acpi_ec_setup(ec, device);
+ ret = acpi_ec_setup(ec, device, true);
if (ret)
goto err;
@@ -1799,7 +1809,7 @@ void __init acpi_ec_dsdt_probe(void)
* At this point, the GPE is not fully initialized, so do not to
* handle the events.
*/
- ret = acpi_ec_setup(ec, NULL);
+ ret = acpi_ec_setup(ec, NULL, true);
if (ret) {
acpi_ec_free(ec);
return;
@@ -1963,7 +1973,7 @@ void __init acpi_ec_ecdt_probe(void)
* At this point, the namespace is not initialized, so do not find
* the namespace objects, or handle the events.
*/
- ret = acpi_ec_setup(ec, NULL);
+ ret = acpi_ec_setup(ec, NULL, false);
if (ret) {
acpi_ec_free(ec);
goto out;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f6c929787c9e..4edf591f8a3a 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -169,6 +169,7 @@ static inline void acpi_early_processor_osc(void) {}
-------------------------------------------------------------------------- */
struct acpi_ec {
acpi_handle handle;
+ acpi_handle address_space_handler_holder;
int gpe;
int irq;
unsigned long command_addr;
diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c
index d93409f2b2a0..691326449022 100644
--- a/drivers/acpi/osi.c
+++ b/drivers/acpi/osi.c
@@ -413,6 +413,19 @@ static const struct dmi_system_id acpi_osi_dmi_table[] __initconst = {
},
},
+ /*
+ * The screen backlight turns off during udev device creation
+ * when returning true for _OSI("Windows 2009")
+ */
+ {
+ .callback = dmi_disable_osi_win7,
+ .ident = "Acer Aspire One D255",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AOD255"),
+ },
+ },
+
/*
* The wireless hotkey does not work on those machines when
* returning true for _OSI("Windows 2012")
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 0418febc5cf2..6ed849172167 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1755,7 +1755,7 @@ acpi_status __init acpi_os_initialize(void)
* Use acpi_os_map_generic_address to pre-map the reset
* register if it's in system memory.
*/
- void *rv;
+ void __iomem *rv;
rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register);
pr_debug(PREFIX "%s: map reset_reg %s\n", __func__,
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index e79c004ca0b2..df03b6ed16fb 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -372,6 +372,14 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "80E1"),
},
},
+ {
+ .callback = init_nvs_save_s3,
+ .ident = "Lenovo G70-35",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "80Q5"),
+ },
+ },
/*
* ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using
* the Low Power S0 Idle firmware interface (see
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 107c28ec23b8..9be577e7c357 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4461,8 +4461,6 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
WARN_ON_ONCE(sg == NULL);
- VPRINTK("unmapping %u sg elements\n", qc->n_elem);
-
if (qc->n_elem)
dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir);
@@ -4494,7 +4492,6 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
if (n_elem < 1)
return -1;
- VPRINTK("%d sg elements mapped\n", n_elem);
qc->orig_n_elem = qc->n_elem;
qc->n_elem = n_elem;
qc->flags |= ATA_QCFLAG_DMAMAP;
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
index d5c97dba2dd4..6a7334fb9a03 100644
--- a/drivers/ata/libata-sata.c
+++ b/drivers/ata/libata-sata.c
@@ -1258,8 +1258,6 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
{
int rc = 0;
- ata_scsi_dump_cdb(ap, cmd);
-
if (likely(ata_dev_enabled(ap->link.device)))
rc = __ata_scsi_queuecmd(cmd, ap->link.device);
else {
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 655be7e96dfc..ae89d6fd32c0 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1296,8 +1296,6 @@ static void scsi_6_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
u64 lba = 0;
u32 len;
- VPRINTK("six-byte command\n");
-
lba |= ((u64)(cdb[1] & 0x1f)) << 16;
lba |= ((u64)cdb[2]) << 8;
lba |= ((u64)cdb[3]);
@@ -1323,8 +1321,6 @@ static void scsi_10_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
u64 lba = 0;
u32 len = 0;
- VPRINTK("ten-byte command\n");
-
lba |= ((u64)cdb[2]) << 24;
lba |= ((u64)cdb[3]) << 16;
lba |= ((u64)cdb[4]) << 8;
@@ -1352,8 +1348,6 @@ static void scsi_16_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
u64 lba = 0;
u32 len = 0;
- VPRINTK("sixteen-byte command\n");
-
lba |= ((u64)cdb[2]) << 56;
lba |= ((u64)cdb[3]) << 48;
lba |= ((u64)cdb[4]) << 40;
@@ -1674,6 +1668,42 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
ata_qc_done(qc);
}
+static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ int ret;
+
+ if (!ap->ops->qc_defer)
+ goto issue;
+
+ /* Check if the command needs to be deferred. */
+ ret = ap->ops->qc_defer(qc);
+ switch (ret) {
+ case 0:
+ break;
+ case ATA_DEFER_LINK:
+ ret = SCSI_MLQUEUE_DEVICE_BUSY;
+ break;
+ case ATA_DEFER_PORT:
+ ret = SCSI_MLQUEUE_HOST_BUSY;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ ret = SCSI_MLQUEUE_HOST_BUSY;
+ break;
+ }
+
+ if (ret) {
+ /* Force a requeue of the command to defer its execution. */
+ ata_qc_free(qc);
+ return ret;
+ }
+
+issue:
+ ata_qc_issue(qc);
+
+ return 0;
+}
+
/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @dev: ATA device to which the command is addressed
@@ -1697,72 +1727,50 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
* spin_lock_irqsave(host lock)
*
* RETURNS:
- * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
- * needs to be deferred.
+ * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY or SCSI_MLQUEUE_HOST_BUSY if the
+ * command needs to be deferred.
*/
static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
ata_xlat_func_t xlat_func)
{
struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
- int rc;
- VPRINTK("ENTER\n");
+ lockdep_assert_held(ap->lock);
+ /*
+ * ata_scsi_qc_new() calls scsi_done(cmd) in case of failure. So we
+ * have nothing further to do when allocating a qc fails.
+ */
qc = ata_scsi_qc_new(dev, cmd);
if (!qc)
- goto err_mem;
+ return 0;
/* data is present; dma-map it */
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
cmd->sc_data_direction == DMA_TO_DEVICE) {
if (unlikely(scsi_bufflen(cmd) < 1)) {
ata_dev_warn(dev, "WARNING: zero len r/w req\n");
- goto err_did;
+ cmd->result = (DID_ERROR << 16);
+ goto done;
}
ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));
-
qc->dma_dir = cmd->sc_data_direction;
}
qc->complete_fn = ata_scsi_qc_complete;
if (xlat_func(qc))
- goto early_finish;
-
- if (ap->ops->qc_defer) {
- if ((rc = ap->ops->qc_defer(qc)))
- goto defer;
- }
+ goto done;
- /* select device, send command to hardware */
- ata_qc_issue(qc);
-
- VPRINTK("EXIT\n");
- return 0;
+ return ata_scsi_qc_issue(ap, qc);
-early_finish:
+done:
ata_qc_free(qc);
cmd->scsi_done(cmd);
DPRINTK("EXIT - early finish (good or error)\n");
return 0;
-
-err_did:
- ata_qc_free(qc);
- cmd->result = (DID_ERROR << 16);
- cmd->scsi_done(cmd);
-err_mem:
- DPRINTK("EXIT - internal\n");
- return 0;
-
-defer:
- ata_qc_free(qc);
- DPRINTK("EXIT - defer\n");
- if (rc == ATA_DEFER_LINK)
- return SCSI_MLQUEUE_DEVICE_BUSY;
- else
- return SCSI_MLQUEUE_HOST_BUSY;
}
struct ata_scsi_args {
@@ -1897,8 +1905,6 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
2
};
- VPRINTK("ENTER\n");
-
/* set scsi removable (RMB) bit per ata bit, or if the
* AHCI port says it's external (Hotplug-capable, eSATA).
*/
@@ -2309,8 +2315,6 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
u8 dpofua, bp = 0xff;
u16 fp;
- VPRINTK("ENTER\n");
-
six_byte = (scsicmd[0] == MODE_SENSE);
ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */
/*
@@ -2428,8 +2432,6 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
log2_per_phys = ata_id_log2_per_physical_sector(dev->id);
lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys);
- VPRINTK("ENTER\n");
-
if (args->cmd->cmnd[0] == READ_CAPACITY) {
if (last_lba >= 0xffffffffULL)
last_lba = 0xffffffff;
@@ -2496,7 +2498,6 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
*/
static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf)
{
- VPRINTK("ENTER\n");
rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */
return 0;
@@ -2596,8 +2597,6 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
struct scsi_cmnd *cmd = qc->scsicmd;
unsigned int err_mask = qc->err_mask;
- VPRINTK("ENTER, err_mask 0x%X\n", err_mask);
-
/* handle completion from new EH */
if (unlikely(qc->ap->ops->error_handler &&
(err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) {
@@ -3732,8 +3731,6 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
u8 buffer[64];
const u8 *p = buffer;
- VPRINTK("ENTER\n");
-
six_byte = (cdb[0] == MODE_SELECT);
if (six_byte) {
if (scmd->cmd_len < 5) {
@@ -4032,26 +4029,6 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
return NULL;
}
-/**
- * ata_scsi_dump_cdb - dump SCSI command contents to dmesg
- * @ap: ATA port to which the command was being sent
- * @cmd: SCSI command to dump
- *
- * Prints the contents of a SCSI command via printk().
- */
-
-void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd)
-{
-#ifdef ATA_VERBOSE_DEBUG
- struct scsi_device *scsidev = cmd->device;
-
- VPRINTK("CDB (%u:%d,%d,%lld) %9ph\n",
- ap->print_id,
- scsidev->channel, scsidev->id, scsidev->lun,
- cmd->cmnd);
-#endif
-}
-
int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
@@ -4139,8 +4116,6 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
spin_lock_irqsave(ap->lock, irq_flags);
- ata_scsi_dump_cdb(ap, cmd);
-
dev = ata_scsi_find_dev(ap, scsidev);
if (likely(dev))
rc = __ata_scsi_queuecmd(cmd, dev);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index b71ea4a680b0..88bce10775af 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -888,8 +888,6 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
if (unlikely(!bytes))
goto atapi_check;
- VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
-
if (unlikely(__atapi_pio_bytes(qc, bytes)))
goto err_out;
ata_sff_sync(ap); /* flush */
@@ -2614,7 +2612,6 @@ static void ata_bmdma_fill_sg(struct ata_queued_cmd *qc)
prd[pi].addr = cpu_to_le32(addr);
prd[pi].flags_len = cpu_to_le32(len & 0xffff);
- VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
pi++;
sg_len -= len;
@@ -2674,7 +2671,6 @@ static void ata_bmdma_fill_sg_dumb(struct ata_queued_cmd *qc)
prd[++pi].addr = cpu_to_le32(addr + 0x8000);
}
prd[pi].flags_len = cpu_to_le32(blen);
- VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
pi++;
sg_len -= len;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index bf71bd9e66cd..d71fffe48495 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -150,7 +150,6 @@ extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, u64 lun);
void ata_scsi_sdev_config(struct scsi_device *sdev);
int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev);
-void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd);
int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev);
/* libata-eh.c */
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index d15d033be2c9..ec14c3089e32 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1776,6 +1776,7 @@ void pm_runtime_reinit(struct device *dev)
void pm_runtime_remove(struct device *dev)
{
__pm_runtime_disable(dev, false);
+ flush_work(&dev->power.work);
pm_runtime_reinit(dev);
}
diff --git a/drivers/base/property.c b/drivers/base/property.c
index e9fdef1f4517..c26ce7fd6832 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -21,7 +21,7 @@
struct fwnode_handle *dev_fwnode(const struct device *dev)
{
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
- &dev->of_node->fwnode : dev->fwnode;
+ of_fwnode_handle(dev->of_node) : dev->fwnode;
}
EXPORT_SYMBOL_GPL(dev_fwnode);
@@ -48,12 +48,14 @@ bool fwnode_property_present(const struct fwnode_handle *fwnode,
{
bool ret;
+ if (IS_ERR_OR_NULL(fwnode))
+ return false;
+
ret = fwnode_call_bool_op(fwnode, property_present, propname);
- if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
- !IS_ERR_OR_NULL(fwnode->secondary))
- ret = fwnode_call_bool_op(fwnode->secondary, property_present,
- propname);
- return ret;
+ if (ret)
+ return ret;
+
+ return fwnode_call_bool_op(fwnode->secondary, property_present, propname);
}
EXPORT_SYMBOL_GPL(fwnode_property_present);
@@ -233,15 +235,16 @@ static int fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
{
int ret;
+ if (IS_ERR_OR_NULL(fwnode))
+ return -EINVAL;
+
ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
elem_size, val, nval);
- if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
- !IS_ERR_OR_NULL(fwnode->secondary))
- ret = fwnode_call_int_op(
- fwnode->secondary, property_read_int_array, propname,
- elem_size, val, nval);
+ if (ret != -EINVAL)
+ return ret;
- return ret;
+ return fwnode_call_int_op(fwnode->secondary, property_read_int_array, propname,
+ elem_size, val, nval);
}
/**
@@ -372,14 +375,16 @@ int fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
{
int ret;
+ if (IS_ERR_OR_NULL(fwnode))
+ return -EINVAL;
+
ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
val, nval);
- if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
- !IS_ERR_OR_NULL(fwnode->secondary))
- ret = fwnode_call_int_op(fwnode->secondary,
- property_read_string_array, propname,
- val, nval);
- return ret;
+ if (ret != -EINVAL)
+ return ret;
+
+ return fwnode_call_int_op(fwnode->secondary, property_read_string_array, propname,
+ val, nval);
}
EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
@@ -479,7 +484,20 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
unsigned int nargs, unsigned int index,
struct fwnode_reference_args *args)
{
- return fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop,
+ int ret;
+
+ if (IS_ERR_OR_NULL(fwnode))
+ return -ENOENT;
+
+ ret = fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop,
+ nargs, index, args);
+ if (ret == 0)
+ return ret;
+
+ if (IS_ERR_OR_NULL(fwnode->secondary))
+ return ret;
+
+ return fwnode_call_int_op(fwnode->secondary, get_reference_args, prop, nargs_prop,
nargs, index, args);
}
EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
@@ -614,6 +632,31 @@ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode)
}
EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
+/**
+ * fwnode_get_next_parent_dev - Find device of closest ancestor fwnode
+ * @fwnode: firmware node
+ *
+ * Given a firmware node (@fwnode), this function finds its closest ancestor
+ * firmware node that has a corresponding struct device and returns that struct
+ * device.
+ *
+ * The caller of this function is expected to call put_device() on the returned
+ * device when they are done.
+ */
+struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
+{
+ struct device *dev = NULL;
+
+ fwnode_handle_get(fwnode);
+ do {
+ fwnode = fwnode_get_next_parent(fwnode);
+ if (fwnode)
+ dev = get_dev_from_fwnode(fwnode);
+ } while (fwnode && !dev);
+ fwnode_handle_put(fwnode);
+ return dev;
+}
+
/**
* fwnode_count_parents - Return the number of parents a node has
* @fwnode: The node the parents of which are to be counted
@@ -649,17 +692,45 @@ EXPORT_SYMBOL_GPL(fwnode_count_parents);
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
unsigned int depth)
{
- unsigned int i;
-
fwnode_handle_get(fwnode);
- for (i = 0; i < depth && fwnode; i++)
+ do {
+ if (depth-- == 0)
+ break;
fwnode = fwnode_get_next_parent(fwnode);
+ } while (fwnode);
return fwnode;
}
EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
+/**
+ * fwnode_is_ancestor_of - Test if @test_ancestor is ancestor of @test_child
+ * @test_ancestor: Firmware which is tested for being an ancestor
+ * @test_child: Firmware which is tested for being the child
+ *
+ * A node is considered an ancestor of itself too.
+ *
+ * Returns true if @test_ancestor is an ancestor of @test_child.
+ * Otherwise, returns false.
+ */
+bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor,
+ struct fwnode_handle *test_child)
+{
+ if (IS_ERR_OR_NULL(test_ancestor))
+ return false;
+
+ fwnode_handle_get(test_child);
+ do {
+ if (test_child == test_ancestor) {
+ fwnode_handle_put(test_child);
+ return true;
+ }
+ test_child = fwnode_get_next_parent(test_child);
+ } while (test_child);
+ return false;
+}
+
/**
* fwnode_get_next_child_node - Return the next child node handle for a node
* @fwnode: Firmware node to find the next child node for.
@@ -669,7 +740,18 @@ struct fwnode_handle *
fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
struct fwnode_handle *child)
{
- return fwnode_call_ptr_op(fwnode, get_next_child_node, child);
+ struct fwnode_handle *next;
+
+ if (IS_ERR_OR_NULL(fwnode))
+ return NULL;
+
+ /* Try to find a child in primary fwnode */
+ next = fwnode_call_ptr_op(fwnode, get_next_child_node, child);
+ if (next)
+ return next;
+
+ /* When no more children in primary, continue with secondary */
+ return fwnode_call_ptr_op(fwnode->secondary, get_next_child_node, child);
}
EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
@@ -685,7 +767,7 @@ fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode,
{
struct fwnode_handle *next_child = child;
- if (!fwnode)
+ if (IS_ERR_OR_NULL(fwnode))
return NULL;
do {
@@ -707,24 +789,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node);
struct fwnode_handle *device_get_next_child_node(struct device *dev,
struct fwnode_handle *child)
{
- struct acpi_device *adev = ACPI_COMPANION(dev);
- struct fwnode_handle *fwnode = NULL, *next;
-
- if (dev->of_node)
- fwnode = &dev->of_node->fwnode;
- else if (adev)
- fwnode = acpi_fwnode_handle(adev);
-
- /* Try to find a child in primary fwnode */
- next = fwnode_get_next_child_node(fwnode, child);
- if (next)
- return next;
-
- /* When no more children in primary, continue with secondary */
- if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary))
- next = fwnode_get_next_child_node(fwnode->secondary, child);
-
- return next;
+ return fwnode_get_next_child_node(dev_fwnode(dev), child);
}
EXPORT_SYMBOL_GPL(device_get_next_child_node);
@@ -785,9 +850,18 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put);
/**
* fwnode_device_is_available - check if a device is available for use
* @fwnode: Pointer to the fwnode of the device.
+ *
+ * For fwnode node types that don't implement the .device_is_available()
+ * operation, this function returns true.
*/
bool fwnode_device_is_available(const struct fwnode_handle *fwnode)
{
+ if (IS_ERR_OR_NULL(fwnode))
+ return false;
+
+ if (!fwnode_has_op(fwnode, device_is_available))
+ return true;
+
return fwnode_call_bool_op(fwnode, device_is_available);
}
EXPORT_SYMBOL_GPL(fwnode_device_is_available);
@@ -810,28 +884,31 @@ EXPORT_SYMBOL_GPL(device_get_child_node_count);
bool device_dma_supported(struct device *dev)
{
+ const struct fwnode_handle *fwnode = dev_fwnode(dev);
+
/* For DT, this is always supported.
* For ACPI, this depends on CCA, which
* is determined by the acpi_dma_supported().
*/
- if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ if (is_of_node(fwnode))
return true;
- return acpi_dma_supported(ACPI_COMPANION(dev));
+ return acpi_dma_supported(to_acpi_device_node(fwnode));
}
EXPORT_SYMBOL_GPL(device_dma_supported);
enum dev_dma_attr device_get_dma_attr(struct device *dev)
{
+ const struct fwnode_handle *fwnode = dev_fwnode(dev);
enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED;
- if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
- if (of_dma_is_coherent(dev->of_node))
+ if (is_of_node(fwnode)) {
+ if (of_dma_is_coherent(to_of_node(fwnode)))
attr = DEV_DMA_COHERENT;
else
attr = DEV_DMA_NON_COHERENT;
} else
- attr = acpi_get_dma_attr(ACPI_COMPANION(dev));
+ attr = acpi_get_dma_attr(to_acpi_device_node(fwnode));
return attr;
}
@@ -949,14 +1026,13 @@ EXPORT_SYMBOL(device_get_mac_address);
* Returns Linux IRQ number on success. Other values are determined
* accordingly to acpi_/of_ irq_get() operation.
*/
-int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index)
+int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index)
{
- struct device_node *of_node = to_of_node(fwnode);
struct resource res;
int ret;
- if (IS_ENABLED(CONFIG_OF) && of_node)
- return of_irq_get(of_node, index);
+ if (is_of_node(fwnode))
+ return of_irq_get(to_of_node(fwnode), index);
ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res);
if (ret)
@@ -978,7 +1054,32 @@ struct fwnode_handle *
fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_handle *prev)
{
- return fwnode_call_ptr_op(fwnode, graph_get_next_endpoint, prev);
+ struct fwnode_handle *ep, *port_parent = NULL;
+ const struct fwnode_handle *parent;
+
+ /*
+ * If this function is in a loop and the previous iteration returned
+ * an endpoint from fwnode->secondary, then we need to use the secondary
+ * as parent rather than @fwnode.
+ */
+ if (prev) {
+ port_parent = fwnode_graph_get_port_parent(prev);
+ parent = port_parent;
+ } else {
+ parent = fwnode;
+ }
+ if (IS_ERR_OR_NULL(parent))
+ return NULL;
+
+ ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
+ if (ep)
+ goto out_put_port_parent;
+
+ ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
+
+out_put_port_parent:
+ fwnode_handle_put(port_parent);
+ return ep;
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index e86d069894c0..3ad37e5615ea 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1587,6 +1587,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
unsigned int val_num)
{
void *orig_work_buf;
+ unsigned int selector_reg;
unsigned int win_offset;
unsigned int win_page;
bool page_chg;
@@ -1605,10 +1606,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
return -EINVAL;
}
- /* It is possible to have selector register inside data window.
- In that case, selector register is located on every page and
- it needs no page switching, when accessed alone. */
+ /*
+ * Calculate the address of the selector register in the corresponding
+ * data window if it is located on every page.
+ */
+ page_chg = in_range(range->selector_reg, range->window_start, range->window_len);
+ if (page_chg)
+ selector_reg = range->range_min + win_page * range->window_len +
+ range->selector_reg - range->window_start;
+
+ /*
+ * It is possible to have selector register inside data window.
+ * In that case, selector register is located on every page and it
+ * needs no page switching, when accessed alone.
+ *
+ * Nevertheless we should synchronize the cache values for it.
+ * This can't be properly achieved if the selector register is
+ * the first and the only one to be read inside the data window.
+ * That's why we update it in that case as well.
+ *
+ * However, we specifically avoid updating it for the default page,
+ * when it's overlapped with the real data window, to prevent from
+ * infinite looping.
+ */
if (val_num > 1 ||
+ (page_chg && selector_reg != range->selector_reg) ||
range->window_start + win_offset != range->selector_reg) {
/* Use separate work_buf during page switching */
orig_work_buf = map->work_buf;
@@ -1617,7 +1639,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
ret = _regmap_update_bits(map, range->selector_reg,
range->selector_mask,
win_page << range->selector_shift,
- &page_chg, false);
+ NULL, false);
map->work_buf = orig_work_buf;
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index 7227fc7ab8ed..8d75e9b91e0b 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -483,38 +483,20 @@ void drbd_al_begin_io(struct drbd_device *device, struct drbd_interval *i)
int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i)
{
- struct lru_cache *al = device->act_log;
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
unsigned first = i->sector >> (AL_EXTENT_SHIFT-9);
unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9);
- unsigned nr_al_extents;
- unsigned available_update_slots;
unsigned enr;
- D_ASSERT(device, first <= last);
-
- nr_al_extents = 1 + last - first; /* worst case: all touched extends are cold. */
- available_update_slots = min(al->nr_elements - al->used,
- al->max_pending_changes - al->pending_changes);
-
- /* We want all necessary updates for a given request within the same transaction
- * We could first check how many updates are *actually* needed,
- * and use that instead of the worst-case nr_al_extents */
- if (available_update_slots < nr_al_extents) {
- /* Too many activity log extents are currently "hot".
- *
- * If we have accumulated pending changes already,
- * we made progress.
- *
- * If we cannot get even a single pending change through,
- * stop the fast path until we made some progress,
- * or requests to "cold" extents could be starved. */
- if (!al->pending_changes)
- __set_bit(__LC_STARVING, &device->act_log->flags);
- return -ENOBUFS;
+ if (i->partially_in_al_next_enr) {
+ D_ASSERT(device, first < i->partially_in_al_next_enr);
+ D_ASSERT(device, last >= i->partially_in_al_next_enr);
+ first = i->partially_in_al_next_enr;
}
+ D_ASSERT(device, first <= last);
+
/* Is resync active in this area? */
for (enr = first; enr <= last; enr++) {
struct lc_element *tmp;
@@ -529,14 +511,21 @@ int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *
}
}
- /* Checkout the refcounts.
- * Given that we checked for available elements and update slots above,
- * this has to be successful. */
+ /* Try to checkout the refcounts. */
for (enr = first; enr <= last; enr++) {
struct lc_element *al_ext;
al_ext = lc_get_cumulative(device->act_log, enr);
- if (!al_ext)
- drbd_info(device, "LOGIC BUG for enr=%u\n", enr);
+
+ if (!al_ext) {
+ /* Did not work. We may have exhausted the possible
+ * changes per transaction. Or raced with someone
+ * "locking" it against changes.
+ * Remember where to continue from.
+ */
+ if (enr > first)
+ i->partially_in_al_next_enr = enr;
+ return -ENOBUFS;
+ }
}
return 0;
}
@@ -556,7 +545,11 @@ void drbd_al_complete_io(struct drbd_device *device, struct drbd_interval *i)
for (enr = first; enr <= last; enr++) {
extent = lc_find(device->act_log, enr);
- if (!extent) {
+ /* Yes, this masks a bug elsewhere. However, during normal
+ * operation this is harmless, so no need to crash the kernel
+ * by the BUG_ON(refcount == 0) in lc_put().
+ */
+ if (!extent || extent->refcnt == 0) {
drbd_err(device, "al_complete_io() called on inactive extent %u\n", enr);
continue;
}
diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h
index b8c2dee5edc8..7e277b80dea1 100644
--- a/drivers/block/drbd/drbd_interval.h
+++ b/drivers/block/drbd/drbd_interval.h
@@ -8,12 +8,15 @@
struct drbd_interval {
struct rb_node rb;
sector_t sector; /* start sector of the interval */
- unsigned int size; /* size in bytes */
sector_t end; /* highest interval end in subtree */
+ unsigned int size; /* size in bytes */
unsigned int local:1 /* local or remote request? */;
unsigned int waiting:1; /* someone is waiting for completion */
unsigned int completed:1; /* this has been completed already;
* ignore for conflict detection */
+
+ /* to resume a partially successful drbd_al_begin_io_nonblock(); */
+ unsigned int partially_in_al_next_enr;
};
static inline void drbd_clear_interval(struct drbd_interval *i)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 3010044f0810..a27a6ab6c2b6 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -1780,8 +1780,11 @@ static void btusb_work(struct work_struct *work)
if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_CVSD) {
if (hdev->voice_setting & 0x0020) {
static const int alts[3] = { 2, 4, 5 };
+ unsigned int sco_idx;
- new_alts = alts[data->sco_num - 1];
+ sco_idx = min_t(unsigned int, data->sco_num - 1,
+ ARRAY_SIZE(alts) - 1);
+ new_alts = alts[sco_idx];
} else {
new_alts = data->sco_num;
}
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 7495ca34c9e7..ee107360e3bc 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -541,6 +541,8 @@ static int download_firmware(struct ll_device *lldev)
if (err || !fw->data || !fw->size) {
bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s",
err, bts_scr_name);
+ if (!err)
+ release_firmware(fw);
return -EINVAL;
}
ptr = (void *)fw->data;
diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c
index 670bb6b0765f..4e2fc9ba2b21 100644
--- a/drivers/clk/tegra/clk-tegra124-emc.c
+++ b/drivers/clk/tegra/clk-tegra124-emc.c
@@ -190,8 +190,8 @@ static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra)
tegra->emc_node = NULL;
tegra->emc = platform_get_drvdata(pdev);
+ put_device(&pdev->dev);
if (!tegra->emc) {
- put_device(&pdev->dev);
pr_err("%s: cannot find EMC driver\n", __func__);
return NULL;
}
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index aa39ff31ec9f..3225c7b747b0 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -311,6 +311,17 @@ static void cs_start(struct cpufreq_policy *policy)
dbs_info->requested_freq = policy->cur;
}
+static void cs_limits(struct cpufreq_policy *policy)
+{
+ struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
+
+ /*
+ * The limits have changed, so may have the current frequency. Reset
+ * requested_freq to avoid any unintended outcomes due to the mismatch.
+ */
+ dbs_info->requested_freq = policy->cur;
+}
+
static struct dbs_governor cs_governor = {
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
.kobj_type = { .default_attrs = cs_attributes },
@@ -320,6 +331,7 @@ static struct dbs_governor cs_governor = {
.init = cs_init,
.exit = cs_exit,
.start = cs_start,
+ .limits = cs_limits,
};
#define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index d8b1a0d4cd21..158488bbb7e7 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -430,7 +430,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
ret = gov->init(dbs_data);
if (ret)
- goto free_policy_dbs_info;
+ goto free_dbs_data;
/*
* The sampling interval should not be less than the transition latency
@@ -457,13 +457,15 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
/* Failure, so roll back. */
pr_err("initialization failed (dbs_data kobject init error %d)\n", ret);
- kobject_put(&dbs_data->attr_set.kobj);
-
policy->governor_data = NULL;
if (!have_governor_per_policy())
gov->gdbs_data = NULL;
- gov->exit(dbs_data);
+
+ kobject_put(&dbs_data->attr_set.kobj);
+ goto free_policy_dbs_info;
+
+free_dbs_data:
kfree(dbs_data);
free_policy_dbs_info:
@@ -555,6 +557,7 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);
void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
{
+ struct dbs_governor *gov = dbs_governor_of(policy);
struct policy_dbs_info *policy_dbs;
/* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
@@ -566,6 +569,8 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
mutex_lock(&policy_dbs->update_mutex);
cpufreq_policy_apply_limits(policy);
gov_update_sample_delay(policy_dbs, 0);
+ if (gov->limits)
+ gov->limits(policy);
mutex_unlock(&policy_dbs->update_mutex);
out:
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index bab8e6140377..3d21e77ec1ee 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -139,6 +139,7 @@ struct dbs_governor {
int (*init)(struct dbs_data *dbs_data);
void (*exit)(struct dbs_data *dbs_data);
void (*start)(struct cpufreq_policy *policy);
+ void (*limits)(struct cpufreq_policy *policy);
};
static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 87a57cee40fc..1c1fa6ac9244 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -319,16 +319,6 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
bool *stop_tick)
{
- /*
- * If there is only a single idle state (or none), there is nothing
- * meaningful for the governor to choose. Skip the governor and
- * always use state 0 with the tick running.
- */
- if (drv->state_count <= 1) {
- *stop_tick = false;
- return 0;
- }
-
return cpuidle_curr_governor->select(drv, dev, stop_tick);
}
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 0ef92109ce22..64d5ba13f4ba 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -52,9 +52,10 @@ static int atmel_sha204a_rng_read_nonblocking(struct hwrng *rng, void *data,
rng->priv = 0;
} else {
work_data = kmalloc(sizeof(*work_data), GFP_ATOMIC);
- if (!work_data)
+ if (!work_data) {
+ atomic_dec(&i2c_priv->tfm_count);
return -ENOMEM;
-
+ }
work_data->ctx = i2c_priv;
work_data->client = i2c_priv->client;
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 12e9ba5b114d..ff7fda42b5ca 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -174,8 +174,10 @@
#define XILINX_DMA_MAX_TRANS_LEN_MAX 23
#define XILINX_DMA_V2_MAX_TRANS_LEN_MAX 26
#define XILINX_DMA_CR_COALESCE_MAX GENMASK(23, 16)
+#define XILINX_DMA_CR_DELAY_MAX GENMASK(31, 24)
#define XILINX_DMA_CR_CYCLIC_BD_EN_MASK BIT(4)
#define XILINX_DMA_CR_COALESCE_SHIFT 16
+#define XILINX_DMA_CR_DELAY_SHIFT 24
#define XILINX_DMA_BD_SOP BIT(27)
#define XILINX_DMA_BD_EOP BIT(26)
#define XILINX_DMA_COALESCE_MAX 255
@@ -411,6 +413,7 @@ struct xilinx_dma_tx_descriptor {
* @stop_transfer: Differentiate b/w DMA IP's quiesce
* @tdest: TDEST value for mcdma
* @has_vflip: S2MM vertical flip
+ * @irq_delay: Interrupt delay timeout
*/
struct xilinx_dma_chan {
struct xilinx_dma_device *xdev;
@@ -449,6 +452,7 @@ struct xilinx_dma_chan {
int (*stop_transfer)(struct xilinx_dma_chan *chan);
u16 tdest;
bool has_vflip;
+ u8 irq_delay;
};
/**
@@ -964,16 +968,16 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
struct xilinx_cdma_tx_segment,
node);
cdma_hw = &cdma_seg->hw;
- residue += (cdma_hw->control - cdma_hw->status) &
- chan->xdev->max_buffer_len;
+ residue += (cdma_hw->control & chan->xdev->max_buffer_len) -
+ (cdma_hw->status & chan->xdev->max_buffer_len);
} else if (chan->xdev->dma_config->dmatype ==
XDMA_TYPE_AXIDMA) {
axidma_seg = list_entry(entry,
struct xilinx_axidma_tx_segment,
node);
axidma_hw = &axidma_seg->hw;
- residue += (axidma_hw->control - axidma_hw->status) &
- chan->xdev->max_buffer_len;
+ residue += (axidma_hw->control & chan->xdev->max_buffer_len) -
+ (axidma_hw->status & chan->xdev->max_buffer_len);
} else {
aximcdma_seg =
list_entry(entry,
@@ -981,8 +985,8 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
node);
aximcdma_hw = &aximcdma_seg->hw;
residue +=
- (aximcdma_hw->control - aximcdma_hw->status) &
- chan->xdev->max_buffer_len;
+ (aximcdma_hw->control & chan->xdev->max_buffer_len) -
+ (aximcdma_hw->status & chan->xdev->max_buffer_len);
}
}
@@ -1186,14 +1190,6 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
dma_cookie_init(dchan);
- if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
- /* For AXI DMA resetting once channel will reset the
- * other channel as well so enable the interrupts here.
- */
- dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
- XILINX_DMA_DMAXR_ALL_IRQ_MASK);
- }
-
if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
XILINX_CDMA_CR_SGMODE);
@@ -1514,8 +1510,29 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
if (chan->err)
return;
- if (list_empty(&chan->pending_list))
+ if (list_empty(&chan->pending_list)) {
+ if (chan->cyclic) {
+ struct xilinx_dma_tx_descriptor *desc;
+ struct list_head *entry;
+
+ desc = list_last_entry(&chan->done_list,
+ struct xilinx_dma_tx_descriptor, node);
+ list_for_each(entry, &desc->segments) {
+ struct xilinx_axidma_tx_segment *axidma_seg;
+ struct xilinx_axidma_desc_hw *axidma_hw;
+ axidma_seg = list_entry(entry,
+ struct xilinx_axidma_tx_segment,
+ node);
+ axidma_hw = &axidma_seg->hw;
+ axidma_hw->status = 0;
+ }
+
+ list_splice_tail_init(&chan->done_list, &chan->active_list);
+ chan->desc_pendingcount = 0;
+ chan->idle = false;
+ }
return;
+ }
if (!chan->idle)
return;
@@ -1539,6 +1556,10 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
if (chan->has_sg)
xilinx_write(chan, XILINX_DMA_REG_CURDESC,
head_desc->async_tx.phys);
+ reg &= ~XILINX_DMA_CR_DELAY_MAX;
+ reg |= chan->irq_delay << XILINX_DMA_CR_DELAY_SHIFT;
+ reg |= XILINX_DMA_DMAXR_ALL_IRQ_MASK;
+ dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
xilinx_dma_start(chan);
@@ -1855,15 +1876,8 @@ static irqreturn_t xilinx_dma_irq_handler(int irq, void *data)
}
}
- if (status & XILINX_DMA_DMASR_DLY_CNT_IRQ) {
- /*
- * Device takes too long to do the transfer when user requires
- * responsiveness.
- */
- dev_dbg(chan->dev, "Inter-packet latency too long\n");
- }
-
- if (status & XILINX_DMA_DMASR_FRM_CNT_IRQ) {
+ if (status & (XILINX_DMA_DMASR_FRM_CNT_IRQ |
+ XILINX_DMA_DMASR_DLY_CNT_IRQ)) {
spin_lock(&chan->lock);
xilinx_dma_complete_descriptor(chan);
chan->idle = true;
@@ -2780,6 +2794,8 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
/* Retrieve the channel properties from the device tree */
has_dre = of_property_read_bool(node, "xlnx,include-dre");
+ of_property_read_u8(node, "xlnx,irq-delay", &chan->irq_delay);
+
chan->genlock = of_property_read_bool(node, "xlnx,genlock-mode");
err = of_property_read_u32(node, "xlnx,datawidth", &value);
@@ -2845,7 +2861,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
return -EINVAL;
}
- xdev->common.directions |= chan->direction;
+ xdev->common.directions |= BIT(chan->direction);
/* Request the interrupt */
chan->irq = irq_of_parse_and_map(node, chan->tdest);
diff --git a/drivers/firmware/efi/mokvar-table.c b/drivers/firmware/efi/mokvar-table.c
index 3ac37f8cfd68..69ac876ca809 100644
--- a/drivers/firmware/efi/mokvar-table.c
+++ b/drivers/firmware/efi/mokvar-table.c
@@ -85,7 +85,7 @@ static struct kobject *mokvar_kobj;
* as an alternative to ordinary EFI variables, due to platform-dependent
* limitations. The memory occupied by this table is marked as reserved.
*
- * This routine must be called before efi_free_boot_services() in order
+ * This routine must be called before efi_unmap_boot_services() in order
* to guarantee that it can mark the table as reserved.
*
* Implicit inputs:
@@ -99,13 +99,13 @@ static struct kobject *mokvar_kobj;
*/
void __init efi_mokvar_table_init(void)
{
+ struct efi_mokvar_table_entry __aligned(1) *mokvar_entry, *next_entry;
efi_memory_desc_t md;
void *va = NULL;
unsigned long cur_offset = 0;
unsigned long offset_limit;
unsigned long map_size_needed = 0;
unsigned long size;
- struct efi_mokvar_table_entry *mokvar_entry;
int err;
if (!efi_enabled(EFI_MEMMAP))
@@ -142,7 +142,7 @@ void __init efi_mokvar_table_init(void)
return;
}
mokvar_entry = va;
-
+next:
/* Check for last sentinel entry */
if (mokvar_entry->name[0] == '\0') {
if (mokvar_entry->data_size != 0)
@@ -156,7 +156,19 @@ void __init efi_mokvar_table_init(void)
mokvar_entry->name[sizeof(mokvar_entry->name) - 1] = '\0';
/* Advance to the next entry */
- cur_offset += sizeof(*mokvar_entry) + mokvar_entry->data_size;
+ size = sizeof(*mokvar_entry) + mokvar_entry->data_size;
+ cur_offset += size;
+
+ /*
+ * Don't bother remapping if the current entry header and the
+ * next one end on the same page.
+ */
+ next_entry = (void *)((unsigned long)mokvar_entry + size);
+ if (((((unsigned long)(mokvar_entry + 1) - 1) ^
+ ((unsigned long)(next_entry + 1) - 1)) & PAGE_MASK) == 0) {
+ mokvar_entry = next_entry;
+ goto next;
+ }
}
if (va)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index 53efc07cf424..ad89377404dd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -932,7 +932,10 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
*ef = dma_fence_get(&info->eviction_fence->base);
}
- vm->process_info = *process_info;
+ if (cmpxchg(&vm->process_info, NULL, *process_info) != NULL) {
+ ret = -EINVAL;
+ goto already_acquired;
+ }
/* Validate page directory and attach eviction fence */
ret = amdgpu_bo_reserve(vm->root.base.bo, true);
@@ -969,6 +972,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
amdgpu_bo_unreserve(vm->root.base.bo);
reserve_pd_fail:
vm->process_info = NULL;
+already_acquired:
if (info) {
/* Two fence references: one in info and one in *ef */
dma_fence_put(&info->eviction_fence->base);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index da8e0cd0fa26..f2ce7fe3039e 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -167,7 +167,7 @@ struct dc_stream_state *dc_create_stream_for_sink(
if (sink == NULL)
return NULL;
- stream = kzalloc(sizeof(struct dc_stream_state), GFP_KERNEL);
+ stream = kzalloc(sizeof(struct dc_stream_state), GFP_ATOMIC);
if (stream == NULL)
goto alloc_fail;
diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c
index cd93c44f2662..cf092cdcbf8f 100644
--- a/drivers/gpu/drm/ast/ast_dp501.c
+++ b/drivers/gpu/drm/ast/ast_dp501.c
@@ -484,7 +484,7 @@ static void ast_init_analog(struct drm_device *dev)
/* Finally, clear bits [17:16] of SCU2c */
data = ast_read32(ast, 0x1202c);
data &= 0xfffcffff;
- ast_write32(ast, 0, data);
+ ast_write32(ast, 0x1202c, data);
/* Disable DVO */
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x00);
diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c
index aaf8d625ce1a..11883609bb09 100644
--- a/drivers/gpu/drm/drm_ioc32.c
+++ b/drivers/gpu/drm/drm_ioc32.c
@@ -28,6 +28,7 @@
* IN THE SOFTWARE.
*/
#include <linux/compat.h>
+#include <linux/nospec.h>
#include <linux/ratelimit.h>
#include <linux/export.h>
@@ -992,6 +993,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (nr >= ARRAY_SIZE(drm_compat_ioctls))
return drm_ioctl(filp, cmd, arg);
+ nr = array_index_nospec(nr, ARRAY_SIZE(drm_compat_ioctls));
fn = drm_compat_ioctls[nr].fn;
if (!fn)
return drm_ioctl(filp, cmd, arg);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 6ae9056e7a18..72b72b81468a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -201,6 +201,7 @@ struct exynos_drm_private {
struct device *g2d_dev;
struct device *dma_dev;
+ struct device *vidi_dev;
void *mapping;
/* for atomic commit */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index d87ab8ecb023..062dd41252a5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -185,15 +185,17 @@ static ssize_t vidi_store_connection(struct device *dev,
const char *buf, size_t len)
{
struct vidi_context *ctx = dev_get_drvdata(dev);
- int ret;
+ int ret, new_connected;
- ret = kstrtoint(buf, 0, &ctx->connected);
+ ret = kstrtoint(buf, 0, &new_connected);
if (ret)
return ret;
- if (ctx->connected > 1)
+ if (new_connected > 1)
return -EINVAL;
+ mutex_lock(&ctx->lock);
+
/* use fake edid data for test. */
if (!ctx->raw_edid)
ctx->raw_edid = (struct edid *)fake_edid_info;
@@ -201,14 +203,21 @@ static ssize_t vidi_store_connection(struct device *dev,
/* if raw_edid isn't same as fake data then it can't be tested. */
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
DRM_DEV_DEBUG_KMS(dev, "edid data is not fake data.\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto fail;
}
+ ctx->connected = new_connected;
+ mutex_unlock(&ctx->lock);
+
DRM_DEV_DEBUG_KMS(dev, "requested connection.\n");
drm_helper_hpd_irq_event(ctx->drm_dev);
return len;
+fail:
+ mutex_unlock(&ctx->lock);
+ return ret;
}
static DEVICE_ATTR(connection, 0644, vidi_show_connection,
@@ -223,9 +232,14 @@ ATTRIBUTE_GROUPS(vidi);
int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
struct drm_file *file_priv)
{
- struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev);
+ struct exynos_drm_private *priv = drm_dev->dev_private;
+ struct device *dev = priv ? priv->vidi_dev : NULL;
+ struct vidi_context *ctx = dev ? dev_get_drvdata(dev) : NULL;
struct drm_exynos_vidi_connection *vidi = data;
+ if (!ctx)
+ return -ENODEV;
+
if (!vidi) {
DRM_DEV_DEBUG_KMS(ctx->dev,
"user data for vidi is null.\n");
@@ -238,40 +252,57 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
return -EINVAL;
}
+ mutex_lock(&ctx->lock);
if (ctx->connected == vidi->connection) {
+ mutex_unlock(&ctx->lock);
DRM_DEV_DEBUG_KMS(ctx->dev,
"same connection request.\n");
return -EINVAL;
}
+ mutex_unlock(&ctx->lock);
if (vidi->connection) {
struct edid *raw_edid;
+ struct edid edid_buf;
+ void *edid_userptr = u64_to_user_ptr(vidi->edid);
+
+ if (copy_from_user(&edid_buf, edid_userptr, sizeof(struct edid)))
+ return -EFAULT;
- raw_edid = (struct edid *)(unsigned long)vidi->edid;
- if (!drm_edid_is_valid(raw_edid)) {
+ if (!drm_edid_is_valid(&edid_buf)) {
DRM_DEV_DEBUG_KMS(ctx->dev,
"edid data is invalid.\n");
return -EINVAL;
}
- ctx->raw_edid = drm_edid_duplicate(raw_edid);
- if (!ctx->raw_edid) {
+
+ raw_edid = drm_edid_duplicate(&edid_buf);
+
+ if (!raw_edid) {
DRM_DEV_DEBUG_KMS(ctx->dev,
"failed to allocate raw_edid.\n");
return -ENOMEM;
}
+ mutex_lock(&ctx->lock);
+ ctx->raw_edid = raw_edid;
+ mutex_unlock(&ctx->lock);
} else {
/*
* with connection = 0, free raw_edid
* only if raw edid data isn't same as fake data.
*/
+ mutex_lock(&ctx->lock);
if (ctx->raw_edid && ctx->raw_edid !=
(struct edid *)fake_edid_info) {
kfree(ctx->raw_edid);
ctx->raw_edid = NULL;
}
+ mutex_unlock(&ctx->lock);
}
+ mutex_lock(&ctx->lock);
ctx->connected = vidi->connection;
+ mutex_unlock(&ctx->lock);
+
drm_helper_hpd_irq_event(ctx->drm_dev);
return 0;
@@ -286,7 +317,7 @@ static enum drm_connector_status vidi_detect(struct drm_connector *connector,
* connection request would come from user side
* to do hotplug through specific ioctl.
*/
- return ctx->connected ? connector_status_connected :
+ return READ_ONCE(ctx->connected) ? connector_status_connected :
connector_status_disconnected;
}
@@ -308,22 +339,24 @@ static int vidi_get_modes(struct drm_connector *connector)
struct vidi_context *ctx = ctx_from_connector(connector);
struct edid *edid;
int edid_len;
- int count;
+ int count = 0;
/*
* the edid data comes from user side and it would be set
* to ctx->raw_edid through specific ioctl.
*/
+
+ mutex_lock(&ctx->lock);
if (!ctx->raw_edid) {
DRM_DEV_DEBUG_KMS(ctx->dev, "raw_edid is null.\n");
- return 0;
+ goto fail;
}
edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
if (!edid) {
DRM_DEV_DEBUG_KMS(ctx->dev, "failed to allocate edid\n");
- return 0;
+ goto fail;
}
drm_connector_update_edid_property(connector, edid);
@@ -332,6 +365,8 @@ static int vidi_get_modes(struct drm_connector *connector)
kfree(edid);
+fail:
+ mutex_unlock(&ctx->lock);
return count;
}
@@ -385,6 +420,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
{
struct vidi_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
+ struct exynos_drm_private *priv = drm_dev->dev_private;
struct drm_encoder *encoder = &ctx->encoder;
struct exynos_drm_plane *exynos_plane;
struct exynos_drm_plane_config plane_config = { 0 };
@@ -392,6 +428,8 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
int ret;
ctx->drm_dev = drm_dev;
+ if (priv)
+ priv->vidi_dev = dev;
plane_config.pixel_formats = formats;
plane_config.num_pixel_formats = ARRAY_SIZE(formats);
@@ -437,8 +475,12 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
static void vidi_unbind(struct device *dev, struct device *master, void *data)
{
struct vidi_context *ctx = dev_get_drvdata(dev);
+ struct drm_device *drm_dev = data;
+ struct exynos_drm_private *priv = drm_dev->dev_private;
del_timer_sync(&ctx->timer);
+ if (priv)
+ priv->vidi_dev = NULL;
}
static const struct component_ops vidi_component_ops = {
@@ -470,11 +512,15 @@ static int vidi_remove(struct platform_device *pdev)
{
struct vidi_context *ctx = platform_get_drvdata(pdev);
+ mutex_lock(&ctx->lock);
+
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
kfree(ctx->raw_edid);
ctx->raw_edid = NULL;
}
+ mutex_unlock(&ctx->lock);
+
component_del(&pdev->dev, &vidi_component_ops);
return 0;
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index e6b8d6dfb598..831e99c56ecb 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -420,8 +420,10 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
val = intel_de_read_fw(dev_priv, GMBUS3);
do {
- if (extra_byte_added && len == 1)
+ if (extra_byte_added && len == 1) {
+ len--;
break;
+ }
*buf++ = val & 0xff;
val >>= 8;
diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
index 379496186c7f..69df19ef25af 100644
--- a/drivers/gpu/drm/msm/msm_gpummu.c
+++ b/drivers/gpu/drm/msm/msm_gpummu.c
@@ -72,7 +72,7 @@ static void msm_gpummu_destroy(struct msm_mmu *mmu)
{
struct msm_gpummu *gpummu = to_msm_gpummu(mmu);
- dma_free_attrs(mmu->dev, TABLE_SIZE, gpummu->table, gpummu->pt_base,
+ dma_free_attrs(mmu->dev, TABLE_SIZE + 32, gpummu->table, gpummu->pt_base,
DMA_ATTR_FORCE_CONTIGUOUS);
kfree(gpummu);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index aa8e4a732b7c..51fb5a6c582d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -1176,6 +1176,9 @@ nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg)
u8 size = msg->size;
int ret;
+ if (pm_runtime_suspended(nv_connector->base.dev->dev))
+ return -EBUSY;
+
nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
if (!nv_encoder || !(aux = nv_encoder->aux))
return -ENODEV;
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 88ec2550ef67..ea859af2988c 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -2962,9 +2962,11 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
if (rdev->family == CHIP_HAINAN) {
if ((rdev->pdev->revision == 0x81) ||
(rdev->pdev->revision == 0xC3) ||
+ (rdev->pdev->device == 0x6660) ||
(rdev->pdev->device == 0x6664) ||
(rdev->pdev->device == 0x6665) ||
- (rdev->pdev->device == 0x6667)) {
+ (rdev->pdev->device == 0x6667) ||
+ (rdev->pdev->device == 0x666F)) {
max_sclk = 75000;
}
if ((rdev->pdev->revision == 0xC3) ||
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 7bb26655cb3c..74d27b564d56 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -1539,11 +1539,9 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
return -EPROBE_DEFER;
dsi->slave = platform_get_drvdata(gangster);
-
- if (!dsi->slave) {
- put_device(&gangster->dev);
+ put_device(&gangster->dev);
+ if (!dsi->slave)
return -EPROBE_DEFER;
- }
dsi->slave->master = dsi;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 361f96d09374..9bec26fda14c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -4247,10 +4247,10 @@ int vmw_execbuf_process(struct drm_file *file_priv,
fput(sync_file->file);
put_unused_fd(out_fence_fd);
} else {
+ struct seqno_waiter_rm_context *ctx;
/* Link the fence with the FD created earlier */
fd_install(out_fence_fd, sync_file->file);
- struct seqno_waiter_rm_context *ctx =
- kmalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
ctx->dev_priv = dev_priv;
vmw_seqno_waiter_add(dev_priv);
if (dma_fence_add_callback(&fence->base, &ctx->base,
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 2f82946fb36a..9d425f81d622 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1116,14 +1116,21 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*/
if (*rsize == rsize_orig &&
rdesc[offs] == 0x09 && rdesc[offs + 1] == 0x76) {
- *rsize = rsize_orig + 1;
- rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL);
- if (!rdesc)
- return NULL;
+ __u8 *new_rdesc;
+
+ new_rdesc = devm_kzalloc(&hdev->dev, rsize_orig + 1,
+ GFP_KERNEL);
+ if (!new_rdesc)
+ return rdesc;
hid_info(hdev, "Fixing up %s keyb report descriptor\n",
drvdata->quirks & QUIRK_T100CHI ?
"T100CHI" : "T90CHI");
+
+ memcpy(new_rdesc, rdesc, rsize_orig);
+ *rsize = rsize_orig + 1;
+ rdesc = new_rdesc;
+
memmove(rdesc + offs + 4, rdesc + offs + 2, 12);
rdesc[offs] = 0x19;
rdesc[offs + 1] = 0x00;
diff --git a/drivers/hid/hid-cmedia.c b/drivers/hid/hid-cmedia.c
index 3296c5050264..4f400cf142c6 100644
--- a/drivers/hid/hid-cmedia.c
+++ b/drivers/hid/hid-cmedia.c
@@ -57,7 +57,7 @@ static int cmhid_raw_event(struct hid_device *hid, struct hid_report *report,
{
struct cmhid *cm = hid_get_drvdata(hid);
- if (len != CM6533_JD_RAWEV_LEN)
+ if (len != CM6533_JD_RAWEV_LEN || !(hid->claimed & HID_CLAIMED_INPUT))
goto out;
if (memcmp(data+CM6533_JD_SFX_OFFSET, ji_sfx, sizeof(ji_sfx)))
goto out;
diff --git a/drivers/hid/hid-creative-sb0540.c b/drivers/hid/hid-creative-sb0540.c
index b4c8e7a5d3e0..dfd6add353d1 100644
--- a/drivers/hid/hid-creative-sb0540.c
+++ b/drivers/hid/hid-creative-sb0540.c
@@ -153,7 +153,7 @@ static int creative_sb0540_raw_event(struct hid_device *hid,
u64 code, main_code;
int key;
- if (len != 6)
+ if (len != 6 || !(hid->claimed & HID_CLAIMED_INPUT))
return 0;
/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index 589f13ff0b60..9fb98c8e1ffb 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -319,6 +319,8 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
usleep_range(90, 100);
retries++;
} else {
+ usleep_range(980, 1000);
+ mcp_cancel_last_cmd(mcp);
return ret;
}
} else {
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 227cf3f6ca22..948bd59ab5d2 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -442,12 +442,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
dev_warn(&hdev->dev, "failed to fetch feature %d\n",
report->id);
} else {
+ /* The report ID in the request and the response should match */
+ if (report->id != buf[0]) {
+ hid_err(hdev, "Returned feature report did not match the request\n");
+ goto free;
+ }
+
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
size, 0);
if (ret)
dev_warn(&hdev->dev, "failed to report feature\n");
}
+free:
kfree(buf);
}
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index 0d003caee113..dda1131eab77 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -114,7 +114,7 @@ static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,
unsigned key;
unsigned short index;
- if (report->id == data[0]) {
+ if (report->id == data[0] && (hdev->claimed & HID_CLAIMED_INPUT)) {
/* break keys */
for (index = 0; index < 4; index++) {
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 2a7cd5be8744..12d70983ed40 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1251,10 +1251,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
switch (data[0]) {
case 0x04:
+ if (len < 32) {
+ dev_warn(wacom->pen_input->dev.parent,
+ "Report 0x04 too short: %zu bytes\n", len);
+ break;
+ }
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
fallthrough;
case 0x03:
+ if (i == 1 && len < 22) {
+ dev_warn(wacom->pen_input->dev.parent,
+ "Report 0x03 too short: %zu bytes\n", len);
+ break;
+ }
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
wacom_intuos_bt_process_data(wacom, data + i);
diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c
index 6e8bb661894b..1ddc95646f19 100644
--- a/drivers/hwmon/adm1177.c
+++ b/drivers/hwmon/adm1177.c
@@ -10,6 +10,8 @@
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
@@ -35,7 +37,7 @@ struct adm1177_state {
struct i2c_client *client;
struct regulator *reg;
u32 r_sense_uohm;
- u32 alert_threshold_ua;
+ u64 alert_threshold_ua;
bool vrange_high;
};
@@ -50,7 +52,7 @@ static int adm1177_write_cmd(struct adm1177_state *st, u8 cmd)
}
static int adm1177_write_alert_thr(struct adm1177_state *st,
- u32 alert_threshold_ua)
+ u64 alert_threshold_ua)
{
u64 val;
int ret;
@@ -93,8 +95,8 @@ static int adm1177_read(struct device *dev, enum hwmon_sensor_types type,
*val = div_u64((105840000ull * dummy),
4096 * st->r_sense_uohm);
return 0;
- case hwmon_curr_max_alarm:
- *val = st->alert_threshold_ua;
+ case hwmon_curr_max:
+ *val = div_u64(st->alert_threshold_ua, 1000);
return 0;
default:
return -EOPNOTSUPP;
@@ -128,9 +130,10 @@ static int adm1177_write(struct device *dev, enum hwmon_sensor_types type,
switch (type) {
case hwmon_curr:
switch (attr) {
- case hwmon_curr_max_alarm:
- adm1177_write_alert_thr(st, val);
- return 0;
+ case hwmon_curr_max:
+ val = clamp_val(val, 0,
+ div_u64(105840000ULL, st->r_sense_uohm));
+ return adm1177_write_alert_thr(st, (u64)val * 1000);
default:
return -EOPNOTSUPP;
}
@@ -158,7 +161,7 @@ static umode_t adm1177_is_visible(const void *data,
if (st->r_sense_uohm)
return 0444;
return 0;
- case hwmon_curr_max_alarm:
+ case hwmon_curr_max:
if (st->r_sense_uohm)
return 0644;
return 0;
@@ -172,7 +175,7 @@ static umode_t adm1177_is_visible(const void *data,
static const struct hwmon_channel_info *adm1177_info[] = {
HWMON_CHANNEL_INFO(curr,
- HWMON_C_INPUT | HWMON_C_MAX_ALARM),
+ HWMON_C_INPUT | HWMON_C_MAX),
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT),
NULL
@@ -201,7 +204,8 @@ static int adm1177_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct adm1177_state *st;
- u32 alert_threshold_ua;
+ u64 alert_threshold_ua;
+ u32 prop;
int ret;
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
@@ -229,22 +233,26 @@ static int adm1177_probe(struct i2c_client *client)
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&st->r_sense_uohm))
st->r_sense_uohm = 0;
- if (device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
- &alert_threshold_ua)) {
- if (st->r_sense_uohm)
- /*
- * set maximum default value from datasheet based on
- * shunt-resistor
- */
- alert_threshold_ua = div_u64(105840000000,
- st->r_sense_uohm);
- else
- alert_threshold_ua = 0;
+ if (!device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
+ &prop)) {
+ alert_threshold_ua = prop;
+ } else if (st->r_sense_uohm) {
+ /*
+ * set maximum default value from datasheet based on
+ * shunt-resistor
+ */
+ alert_threshold_ua = div_u64(105840000000ULL,
+ st->r_sense_uohm);
+ } else {
+ alert_threshold_ua = 0;
}
st->vrange_high = device_property_read_bool(dev,
"adi,vrange-high-enable");
- if (alert_threshold_ua && st->r_sense_uohm)
- adm1177_write_alert_thr(st, alert_threshold_ua);
+ if (alert_threshold_ua && st->r_sense_uohm) {
+ ret = adm1177_write_alert_thr(st, alert_threshold_ua);
+ if (ret)
+ return ret;
+ }
ret = adm1177_write_cmd(st, ADM1177_CMD_V_CONT |
ADM1177_CMD_I_CONT |
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index 5787db933fad..b292ef48b80b 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -151,27 +151,27 @@ static struct max16065_data *max16065_update_device(struct device *dev)
int i;
for (i = 0; i < data->num_adc; i++)
- data->adc[i]
- = max16065_read_adc(client, MAX16065_ADC(i));
+ WRITE_ONCE(data->adc[i],
+ max16065_read_adc(client, MAX16065_ADC(i)));
if (data->have_current) {
- data->adc[MAX16065_NUM_ADC]
- = max16065_read_adc(client, MAX16065_CSP_ADC);
- data->curr_sense
- = i2c_smbus_read_byte_data(client,
- MAX16065_CURR_SENSE);
+ WRITE_ONCE(data->adc[MAX16065_NUM_ADC],
+ max16065_read_adc(client, MAX16065_CSP_ADC));
+ WRITE_ONCE(data->curr_sense,
+ i2c_smbus_read_byte_data(client, MAX16065_CURR_SENSE));
}
for (i = 0; i < 2; i++)
- data->fault[i]
- = i2c_smbus_read_byte_data(client, MAX16065_FAULT(i));
+ WRITE_ONCE(data->fault[i],
+ i2c_smbus_read_byte_data(client, MAX16065_FAULT(i)));
/*
* MAX16067 and MAX16068 have separate undervoltage and
* overvoltage alarm bits. Squash them together.
*/
if (data->chip == max16067 || data->chip == max16068)
- data->fault[0] |= data->fault[1];
+ WRITE_ONCE(data->fault[0],
+ data->fault[0] | data->fault[1]);
data->last_updated = jiffies;
data->valid = 1;
@@ -185,7 +185,7 @@ static ssize_t max16065_alarm_show(struct device *dev,
{
struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
struct max16065_data *data = max16065_update_device(dev);
- int val = data->fault[attr2->nr];
+ int val = READ_ONCE(data->fault[attr2->nr]);
if (val < 0)
return val;
@@ -203,7 +203,7 @@ static ssize_t max16065_input_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct max16065_data *data = max16065_update_device(dev);
- int adc = data->adc[attr->index];
+ int adc = READ_ONCE(data->adc[attr->index]);
if (unlikely(adc < 0))
return adc;
@@ -216,7 +216,7 @@ static ssize_t max16065_current_show(struct device *dev,
struct device_attribute *da, char *buf)
{
struct max16065_data *data = max16065_update_device(dev);
- int curr_sense = data->curr_sense;
+ int curr_sense = READ_ONCE(data->curr_sense);
if (unlikely(curr_sense < 0))
return curr_sense;
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 1a6c8ebc32e1..8d4b17087081 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -422,6 +422,12 @@ static ssize_t occ_show_freq_2(struct device *dev,
return sysfs_emit(buf, "%u\n", val);
}
+static u64 occ_get_powr_avg(u64 accum, u32 samples)
+{
+ return (samples == 0) ? 0 :
+ mul_u64_u32_div(accum, 1000000UL, samples);
+}
+
static ssize_t occ_show_power_1(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -443,9 +449,8 @@ static ssize_t occ_show_power_1(struct device *dev,
val = get_unaligned_be16(&power->sensor_id);
break;
case 1:
- val = get_unaligned_be32(&power->accumulator) /
- get_unaligned_be32(&power->update_tag);
- val *= 1000000ULL;
+ val = occ_get_powr_avg(get_unaligned_be32(&power->accumulator),
+ get_unaligned_be32(&power->update_tag));
break;
case 2:
val = (u64)get_unaligned_be32(&power->update_tag) *
@@ -461,12 +466,6 @@ static ssize_t occ_show_power_1(struct device *dev,
return sysfs_emit(buf, "%llu\n", val);
}
-static u64 occ_get_powr_avg(u64 accum, u32 samples)
-{
- return (samples == 0) ? 0 :
- mul_u64_u32_div(accum, 1000000UL, samples);
-}
-
static ssize_t occ_show_power_2(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -727,7 +726,7 @@ static ssize_t occ_show_extended(struct device *dev,
switch (sattr->nr) {
case 0:
if (extn->flags & EXTN_FLAG_SENSOR_ID) {
- rc = sysfs_emit(buf, "%u",
+ rc = sysfs_emit(buf, "%u\n",
get_unaligned_be32(&extn->sensor_id));
} else {
rc = sysfs_emit(buf, "%02x%02x%02x%02x\n",
diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c
index 3f1b826dac8a..5f04950796e8 100644
--- a/drivers/hwmon/pmbus/isl68137.c
+++ b/drivers/hwmon/pmbus/isl68137.c
@@ -80,8 +80,11 @@ static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client,
{
int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
- return sprintf(buf, "%d\n",
- (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0);
+ if (val < 0)
+ return val;
+
+ return sysfs_emit(buf, "%d\n",
+ (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS);
}
static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c
index 212433eb6cc3..7794e5cf550f 100644
--- a/drivers/hwmon/pmbus/pxe1610.c
+++ b/drivers/hwmon/pmbus/pxe1610.c
@@ -104,7 +104,10 @@ static int pxe1610_probe(struct i2c_client *client)
* By default this device doesn't boot to page 0, so set page 0
* to access all pmbus registers.
*/
- i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to set page 0\n");
/* Read Manufacturer id */
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
index 10332693edf0..70bf03af3777 100644
--- a/drivers/i2c/busses/i2c-fsi.c
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -728,6 +728,7 @@ static int fsi_i2c_probe(struct device *dev)
rc = i2c_add_adapter(&port->adapter);
if (rc < 0) {
dev_err(dev, "Failed to register adapter: %d\n", rc);
+ of_node_put(np);
kfree(port);
continue;
}
diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c
index 2216577b1005..fa99c37b1c9d 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -548,7 +548,7 @@ static int bme680_wait_for_eoc(struct bme680_data *data)
* + heater duration
*/
int wait_eoc_us = ((data->oversampling_temp + data->oversampling_press +
- data->oversampling_humid) * 1936) + (477 * 4) +
+ data->oversampling_humid) * 1963) + (477 * 4) +
(477 * 5) + 1000 + (data->heater_dur * 1000);
usleep_range(wait_eoc_us, wait_eoc_us + 100);
diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c
index 56d8bd2dd92f..0f0bf4c534d8 100644
--- a/drivers/iio/dac/ad5770r.c
+++ b/drivers/iio/dac/ad5770r.c
@@ -323,7 +323,7 @@ static int ad5770r_read_raw(struct iio_dev *indio_dev,
chan->address,
st->transf_buf, 2);
if (ret)
- return 0;
+ return ret;
buf16 = st->transf_buf[0] + (st->transf_buf[1] << 8);
*val = buf16 >> 2;
diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c
index 79527fbc250a..608ab7a0cdcc 100644
--- a/drivers/iio/dac/ds4424.c
+++ b/drivers/iio/dac/ds4424.c
@@ -141,7 +141,7 @@ static int ds4424_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (val < S8_MIN || val > S8_MAX)
+ if (val <= S8_MIN || val > S8_MAX)
return -EINVAL;
if (val > 0) {
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index 7803173c5063..03090ad26803 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -320,7 +320,9 @@ static int mpu3050_read_raw(struct iio_dev *indio_dev,
}
case IIO_CHAN_INFO_RAW:
/* Resume device */
- pm_runtime_get_sync(mpu3050->dev);
+ ret = pm_runtime_resume_and_get(mpu3050->dev);
+ if (ret)
+ return ret;
mutex_lock(&mpu3050->lock);
ret = mpu3050_set_8khz_samplerate(mpu3050);
@@ -651,14 +653,20 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p)
static int mpu3050_buffer_preenable(struct iio_dev *indio_dev)
{
struct mpu3050 *mpu3050 = iio_priv(indio_dev);
+ int ret;
- pm_runtime_get_sync(mpu3050->dev);
+ ret = pm_runtime_resume_and_get(mpu3050->dev);
+ if (ret)
+ return ret;
/* Unless we have OUR trigger active, run at full speed */
- if (!mpu3050->hw_irq_trigger)
- return mpu3050_set_8khz_samplerate(mpu3050);
+ if (!mpu3050->hw_irq_trigger) {
+ ret = mpu3050_set_8khz_samplerate(mpu3050);
+ if (ret)
+ pm_runtime_put_autosuspend(mpu3050->dev);
+ }
- return 0;
+ return ret;
}
static int mpu3050_buffer_postdisable(struct iio_dev *indio_dev)
@@ -1129,11 +1137,16 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq)
ret = iio_trigger_register(mpu3050->trig);
if (ret)
- return ret;
+ goto err_iio_trigger;
indio_dev->trig = iio_trigger_get(mpu3050->trig);
return 0;
+
+err_iio_trigger:
+ free_irq(mpu3050->irq, mpu3050->trig);
+
+ return ret;
}
int mpu3050_common_probe(struct device *dev,
@@ -1221,12 +1234,6 @@ int mpu3050_common_probe(struct device *dev,
goto err_power_down;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(dev, "device register failed\n");
- goto err_cleanup_buffer;
- }
-
dev_set_drvdata(dev, indio_dev);
/* Check if we have an assigned IRQ to use as trigger */
@@ -1249,9 +1256,20 @@ int mpu3050_common_probe(struct device *dev,
pm_runtime_use_autosuspend(dev);
pm_runtime_put(dev);
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(dev, "device register failed\n");
+ goto err_iio_device_register;
+ }
+
return 0;
-err_cleanup_buffer:
+err_iio_device_register:
+ pm_runtime_get_sync(dev);
+ pm_runtime_put_noidle(dev);
+ pm_runtime_disable(dev);
+ if (irq)
+ free_irq(mpu3050->irq, mpu3050->trig);
iio_triggered_buffer_cleanup(indio_dev);
err_power_down:
mpu3050_power_down(mpu3050);
@@ -1265,13 +1283,13 @@ int mpu3050_common_remove(struct device *dev)
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct mpu3050 *mpu3050 = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
pm_runtime_get_sync(dev);
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
- iio_triggered_buffer_cleanup(indio_dev);
if (mpu3050->irq)
- free_irq(mpu3050->irq, mpu3050);
- iio_device_unregister(indio_dev);
+ free_irq(mpu3050->irq, mpu3050->trig);
+ iio_triggered_buffer_cleanup(indio_dev);
mpu3050_power_down(mpu3050);
return 0;
diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c
index ef5bcbc4b45b..ff2c003c17ca 100644
--- a/drivers/iio/gyro/mpu3050-i2c.c
+++ b/drivers/iio/gyro/mpu3050-i2c.c
@@ -19,8 +19,7 @@ static int mpu3050_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id)
struct mpu3050 *mpu3050 = i2c_mux_priv(mux);
/* Just power up the device, that is all that is needed */
- pm_runtime_get_sync(mpu3050->dev);
- return 0;
+ return pm_runtime_resume_and_get(mpu3050->dev);
}
static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 134f3aa59145..b05ab6c04d97 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -322,6 +322,8 @@ static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev,
return -EINVAL;
conf.odr = inv_icm42600_accel_odr_conv[idx / 2];
+ if (conf.odr == st->conf.accel.odr)
+ return 0;
pm_runtime_get_sync(dev);
mutex_lock(&st->lock);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
index 32d7f8364230..f29c3e8531e6 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -377,6 +377,7 @@ static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_timestamp *ts = iio_priv(indio_dev);
struct device *dev = regmap_get_device(st->map);
unsigned int sensor;
unsigned int *watermark;
@@ -398,6 +399,8 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
mutex_lock(&st->lock);
+ inv_icm42600_timestamp_apply_odr(ts, 0, 0, 0);
+
ret = inv_icm42600_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
if (ret)
goto out_unlock;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index d20209302711..550e083c93ed 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -334,6 +334,8 @@ static int inv_icm42600_gyro_write_odr(struct iio_dev *indio_dev,
return -EINVAL;
conf.odr = inv_icm42600_gyro_odr_conv[idx / 2];
+ if (conf.odr == st->conf.gyro.odr)
+ return 0;
pm_runtime_get_sync(dev);
mutex_lock(&st->lock);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 29ee52c3036b..579c6a2d4d37 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -201,6 +201,10 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
const struct st_lsm6dsx_reg *batch_reg;
u8 data;
+ /* Only internal sensors have a FIFO ODR configuration register. */
+ if (sensor->id >= ARRAY_SIZE(hw->settings->batch))
+ return 0;
+
batch_reg = &hw->settings->batch[sensor->id];
if (batch_reg->addr) {
int val;
diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
index abbf2e662e7d..e0a72ff2ebf8 100644
--- a/drivers/iio/light/bh1780.c
+++ b/drivers/iio/light/bh1780.c
@@ -109,10 +109,10 @@ static int bh1780_read_raw(struct iio_dev *indio_dev,
case IIO_LIGHT:
pm_runtime_get_sync(&bh1780->client->dev);
value = bh1780_read_word(bh1780, BH1780_REG_DLOW);
- if (value < 0)
- return value;
pm_runtime_mark_last_busy(&bh1780->client->dev);
pm_runtime_put_autosuspend(&bh1780->client->dev);
+ if (value < 0)
+ return value;
*val = value;
return IIO_VAL_INT;
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index ce21c0fcd1c0..76b1d6efe223 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -105,17 +105,23 @@ static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct vcnl4035_data *data = iio_priv(indio_dev);
/* Ensure naturally aligned timestamp */
- u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)] __aligned(8) = { };
+ struct {
+ u16 als_data;
+ aligned_s64 timestamp;
+ } buffer = { };
+ unsigned int val;
int ret;
- ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
+ ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, &val);
if (ret < 0) {
dev_err(&data->client->dev,
"Trigger consumer can't read from sensor.\n");
goto fail_read;
}
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- iio_get_time_ns(indio_dev));
+
+ buffer.als_data = val;
+ iio_push_to_buffers_with_timestamp(indio_dev, &buffer,
+ iio_get_time_ns(indio_dev));
fail_read:
iio_trigger_notify_done(indio_dev->trig);
@@ -380,7 +386,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
- .endianness = IIO_LE,
+ .endianness = IIO_CPU,
},
},
{
@@ -394,7 +400,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
- .endianness = IIO_LE,
+ .endianness = IIO_CPU,
},
},
};
diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c
index 7c8c18ab8764..3e67a1366eac 100644
--- a/drivers/iio/potentiometer/mcp4131.c
+++ b/drivers/iio/potentiometer/mcp4131.c
@@ -222,7 +222,7 @@ static int mcp4131_write_raw(struct iio_dev *indio_dev,
mutex_lock(&data->lock);
- data->buf[0] = address << MCP4131_WIPER_SHIFT;
+ data->buf[0] = address;
data->buf[0] |= MCP4131_WRITE | (val >> 8);
data->buf[1] = val & 0xFF; /* 8 bits here */
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index d479408a2cf7..58ce6c7eec4e 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -341,14 +341,29 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
if (rdma_rw_io_needs_mr(qp->device, port_num, dir, sg_cnt)) {
ret = rdma_rw_init_mr_wrs(ctx, qp, port_num, sg, sg_cnt,
sg_offset, remote_addr, rkey, dir);
- } else if (sg_cnt > 1) {
+ /*
+ * If MR init succeeded or failed for a reason other
+ * than pool exhaustion, that result is final.
+ *
+ * Pool exhaustion (-EAGAIN) from the max_sgl_rd
+ * optimization is recoverable: fall back to
+ * direct SGE posting. iWARP and force_mr require
+ * MRs unconditionally, so -EAGAIN is terminal.
+ */
+ if (ret != -EAGAIN ||
+ rdma_protocol_iwarp(qp->device, port_num) ||
+ unlikely(rdma_rw_force_mr))
+ goto out;
+ }
+
+ if (sg_cnt > 1)
ret = rdma_rw_init_map_wrs(ctx, qp, sg, sg_cnt, sg_offset,
remote_addr, rkey, dir);
- } else {
+ else
ret = rdma_rw_init_single_wr(ctx, qp, sg, sg_offset,
remote_addr, rkey, dir);
- }
+out:
if (ret < 0)
goto out_unmap_sg;
return ret;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index c4d9cdc4ee97..c48e3be67540 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -436,6 +436,8 @@ static int mthca_create_srq(struct ib_srq *ibsrq,
if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof(__u32))) {
mthca_free_srq(to_mdev(ibsrq->device), srq);
+ mthca_unmap_user_db(to_mdev(ibsrq->device), &context->uar,
+ context->db_tab, ucmd.db_index);
return -EFAULT;
}
@@ -444,6 +446,7 @@ static int mthca_create_srq(struct ib_srq *ibsrq,
static int mthca_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
{
+ mthca_free_srq(to_mdev(srq->device), to_msrq(srq));
if (udata) {
struct mthca_ucontext *context =
rdma_udata_to_drv_context(
@@ -454,8 +457,6 @@ static int mthca_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
mthca_unmap_user_db(to_mdev(srq->device), &context->uar,
context->db_tab, to_msrq(srq)->db_index);
}
-
- mthca_free_srq(to_mdev(srq->device), to_msrq(srq));
return 0;
}
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 31f7d09c71dc..7fdc8e988b6d 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -269,6 +269,8 @@ static const struct xpad_device {
{ 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
{ 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
{ 0x1532, 0x0a29, "Razer Wolverine V2", 0, XTYPE_XBOXONE },
+ { 0x1532, 0x0a57, "Razer Wolverine V3 Pro (Wired)", 0, XTYPE_XBOX360 },
+ { 0x1532, 0x0a59, "Razer Wolverine V3 Pro (2.4 GHz Dongle)", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 },
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index faed4590a8a9..449dbf90d247 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"
@@ -56,6 +58,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;
@@ -74,6 +77,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) {
@@ -145,27 +150,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;
}
@@ -174,6 +178,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;
@@ -288,7 +299,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;
@@ -365,7 +383,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;
@@ -383,6 +403,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/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index 6b23e679606e..828b7a8c381b 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -534,6 +534,8 @@ static void rmi_f54_work(struct work_struct *work)
int error;
int i;
+ mutex_lock(&f54->data_mutex);
+
report_size = rmi_f54_get_report_size(f54);
if (report_size == 0) {
dev_err(&fn->dev, "Bad report size, report type=%d\n",
@@ -542,8 +544,6 @@ static void rmi_f54_work(struct work_struct *work)
goto error; /* retry won't help */
}
- mutex_lock(&f54->data_mutex);
-
/*
* Need to check if command has completed.
* If not try again later.
diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
index 9195234e42e6..329e9b0fe954 100644
--- a/drivers/input/serio/i8042-acpipnpio.h
+++ b/drivers/input/serio/i8042-acpipnpio.h
@@ -1187,6 +1187,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ },
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "WUJIE Series-X5SP4NAG"),
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 68153e6329b5..9b6aa97be7b5 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -1243,7 +1243,6 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)
if (fault & DMA_FSTS_ITE) {
head = readl(iommu->reg + DMAR_IQH_REG);
head = ((head >> shift) - 1 + QI_LENGTH) % QI_LENGTH;
- head |= 1;
tail = readl(iommu->reg + DMAR_IQT_REG);
tail = ((tail >> shift) - 1 + QI_LENGTH) % QI_LENGTH;
@@ -1252,7 +1251,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)
do {
if (qi->desc_status[head] == QI_IN_USE)
qi->desc_status[head] = QI_ABORT;
- head = (head - 2 + QI_LENGTH) % QI_LENGTH;
+ head = (head - 1 + QI_LENGTH) % QI_LENGTH;
} while (head != tail);
if (qi->desc_status[wait_index] == QI_ABORT)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 1934d1cc219b..6b86a29990e3 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -3382,6 +3382,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
int lpi_base;
int nr_lpis;
int nr_ites;
+ int id_bits;
int sz;
if (!its_alloc_device_table(its, dev_id))
@@ -3394,7 +3395,10 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
/*
* Even if the device wants a single LPI, the ITT must be
* sized as a power of two (and you need at least one bit...).
+ * Also honor the ITS's own EID limit.
*/
+ id_bits = FIELD_GET(GITS_TYPER_IDBITS, its->typer) + 1;
+ nvecs = min_t(unsigned int, nvecs, BIT(id_bits));
nr_ites = max(2, nvecs);
sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index 71651086bc4d..3be74b87b809 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -178,7 +178,9 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
mutex_unlock(&dmxdev->mutex);
return -ENOMEM;
}
- dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
+ dmxdev->dvr_buffer.data = mem;
+ dmxdev->dvr_buffer.size = DVR_BUFFER_SIZE;
+ dvb_ringbuffer_reset(&dmxdev->dvr_buffer);
if (dmxdev->may_do_mmap)
dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
file->f_flags & O_NONBLOCK);
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index c594b1bdfcaa..c8cbe901bcf0 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -228,6 +228,9 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
unsigned char htype = p->ule_sndu_type & 0x00FF;
+ if (htype >= ARRAY_SIZE(ule_mandatory_ext_handlers))
+ return -1;
+
/* Discriminate mandatory and optional extension headers. */
if (hlen == 0) {
/* Mandatory extension header */
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 08b3ac8ff108..18b48a398429 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -2198,9 +2198,11 @@ static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_ms
struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
u8 n_overflow = 1;
u16 i = 1000;
+ u16 serpar_num;
+
if (msg[0].len < 3)
return -EOPNOTSUPP;
- u16 serpar_num = msg[0].buf[0];
+ serpar_num = msg[0].buf[0];
while (n_overflow == 1 && i) {
n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
@@ -2219,10 +2221,12 @@ static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg
struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
u8 n_overflow = 1, n_empty = 1;
u16 i = 1000;
+ u16 serpar_num;
+ u16 read_word;
+
if (msg[0].len < 1 || msg[1].len < 2)
return -EOPNOTSUPP;
- u16 serpar_num = msg[0].buf[0];
- u16 read_word;
+ serpar_num = msg[0].buf[0];
while (n_overflow == 1 && i) {
n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c
index c0782fd96c59..e940fd3b5747 100644
--- a/drivers/media/mc/mc-request.c
+++ b/drivers/media/mc/mc-request.c
@@ -190,6 +190,8 @@ static long media_request_ioctl_reinit(struct media_request *req)
struct media_device *mdev = req->mdev;
unsigned long flags;
+ mutex_lock(&mdev->req_queue_mutex);
+
spin_lock_irqsave(&req->lock, flags);
if (req->state != MEDIA_REQUEST_STATE_IDLE &&
req->state != MEDIA_REQUEST_STATE_COMPLETE) {
@@ -197,6 +199,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
"request: %s not in idle or complete state, cannot reinit\n",
req->debug_str);
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return -EBUSY;
}
if (req->access_count) {
@@ -204,6 +207,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
"request: %s is being accessed, cannot reinit\n",
req->debug_str);
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return -EBUSY;
}
req->state = MEDIA_REQUEST_STATE_CLEANING;
@@ -214,6 +218,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
spin_lock_irqsave(&req->lock, flags);
req->state = MEDIA_REQUEST_STATE_IDLE;
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return 0;
}
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 6d6d30dbbe68..d470321ac577 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -2963,13 +2963,14 @@ static long __video_do_ioctl(struct file *file,
vfh = file->private_data;
/*
- * We need to serialize streamon/off with queueing new requests.
+ * We need to serialize streamon/off/reqbufs with queueing new requests.
* These ioctls may trigger the cancellation of a streaming
* operation, and that should not be mixed with queueing a new
* request at the same time.
*/
if (v4l2_device_supports_requests(vfd->v4l2_dev) &&
- (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF)) {
+ (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF ||
+ cmd == VIDIOC_REQBUFS)) {
req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex;
if (mutex_lock_interruptible(req_queue_lock))
diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c
index 3da6112fbe39..67371389cc33 100644
--- a/drivers/mmc/host/mmci_qcom_dml.c
+++ b/drivers/mmc/host/mmci_qcom_dml.c
@@ -109,6 +109,7 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name)
&dma_spec))
return -ENODEV;
+ of_node_put(dma_spec.np);
if (dma_spec.args_count)
return dma_spec.args[0];
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 3a171221f97c..d7bc5654a0f8 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -59,6 +59,9 @@
#define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF
#define GLI_9750_MISC_TX1_DLY_VALUE 0x5
+#define SDHCI_GLI_9750_GM_BURST_SIZE 0x510
+#define SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT GENMASK(17, 16)
+
#define SDHCI_GLI_9750_TUNING_CONTROL 0x540
#define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4)
#define GLI_9750_TUNING_CONTROL_EN_ON 0x1
@@ -152,10 +155,16 @@ static void gli_set_9750(struct sdhci_host *host)
u32 misc_value;
u32 parameter_value;
u32 control_value;
+ u32 burst_value;
u16 ctrl2;
gl9750_wt_on(host);
+ /* clear R_OSRC_Lmt to avoid DMA write corruption */
+ burst_value = sdhci_readl(host, SDHCI_GLI_9750_GM_BURST_SIZE);
+ burst_value &= ~SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT;
+ sdhci_writel(host, burst_value, SDHCI_GLI_9750_GM_BURST_SIZE);
+
driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9091930f5859..bb4856407c0c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -4444,8 +4444,15 @@ int sdhci_setup_host(struct sdhci_host *host)
* their platform code before calling sdhci_add_host(), and we
* won't assume 8-bit width for hosts without that CAP.
*/
- if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
+ if (host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA) {
+ host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
+ if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400)
+ host->caps1 &= ~SDHCI_SUPPORT_HS400;
+ mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
+ mmc->caps &= ~(MMC_CAP_DDR | MMC_CAP_UHS);
+ } else {
mmc->caps |= MMC_CAP_4_BIT_DATA;
+ }
if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23)
mmc->caps &= ~MMC_CAP_CMD23;
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 05ffd5bf5a6f..90c31803066d 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2371,8 +2371,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/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index cb3509051047..e4739d843f7b 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -245,6 +245,9 @@ struct brcmnand_controller {
u32 edu_ext_addr;
u32 edu_cmd;
u32 edu_config;
+ int sas; /* spare area size, per flash cache */
+ int sector_size_1k;
+ u8 *oob;
/* flash_dma reg */
const u16 *flash_dma_offsets;
@@ -252,7 +255,7 @@ struct brcmnand_controller {
dma_addr_t dma_pa;
int (*dma_trans)(struct brcmnand_host *host, u64 addr, u32 *buf,
- u32 len, u8 dma_cmd);
+ u8 *oob, u32 len, u8 dma_cmd);
/* in-memory cache of the FLASH_CACHE, used only for some commands */
u8 flash_cache[FC_BYTES];
@@ -1527,6 +1530,23 @@ static irqreturn_t brcmnand_edu_irq(int irq, void *data)
edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr);
edu_readl(ctrl, EDU_EXT_ADDR);
+ if (ctrl->oob) {
+ if (ctrl->edu_cmd == EDU_CMD_READ) {
+ ctrl->oob += read_oob_from_regs(ctrl,
+ ctrl->edu_count + 1,
+ ctrl->oob, ctrl->sas,
+ ctrl->sector_size_1k);
+ } else {
+ brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
+ ctrl->edu_ext_addr);
+ brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+ ctrl->oob += write_oob_to_regs(ctrl,
+ ctrl->edu_count,
+ ctrl->oob, ctrl->sas,
+ ctrl->sector_size_1k);
+ }
+ }
+
mb(); /* flush previous writes */
edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd);
edu_readl(ctrl, EDU_CMD);
@@ -1908,9 +1928,10 @@ static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
* Kick EDU engine
*/
static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
- u32 len, u8 cmd)
+ u8 *oob, u32 len, u8 cmd)
{
struct brcmnand_controller *ctrl = host->ctrl;
+ struct brcmnand_cfg *cfg = &host->hwcfg;
unsigned long timeo = msecs_to_jiffies(200);
int ret = 0;
int dir = (cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
@@ -1918,6 +1939,9 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
unsigned int trans = len >> FC_SHIFT;
dma_addr_t pa;
+ dev_dbg(ctrl->dev, "EDU %s %p:%p\n", ((edu_cmd == EDU_CMD_READ) ?
+ "read" : "write"), buf, oob);
+
pa = dma_map_single(ctrl->dev, buf, len, dir);
if (dma_mapping_error(ctrl->dev, pa)) {
dev_err(ctrl->dev, "unable to map buffer for EDU DMA\n");
@@ -1929,6 +1953,8 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
ctrl->edu_ext_addr = addr;
ctrl->edu_cmd = edu_cmd;
ctrl->edu_count = trans;
+ ctrl->sas = cfg->spare_area_size;
+ ctrl->oob = oob;
edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr);
edu_readl(ctrl, EDU_DRAM_ADDR);
@@ -1937,6 +1963,16 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
edu_writel(ctrl, EDU_LENGTH, FC_BYTES);
edu_readl(ctrl, EDU_LENGTH);
+ if (ctrl->oob && (ctrl->edu_cmd == EDU_CMD_WRITE)) {
+ brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
+ ctrl->edu_ext_addr);
+ brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+ ctrl->oob += write_oob_to_regs(ctrl,
+ 1,
+ ctrl->oob, ctrl->sas,
+ ctrl->sector_size_1k);
+ }
+
/* Start edu engine */
mb(); /* flush previous writes */
edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd);
@@ -1951,6 +1987,14 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
dma_unmap_single(ctrl->dev, pa, len, dir);
+ /* read last subpage oob */
+ if (ctrl->oob && (ctrl->edu_cmd == EDU_CMD_READ)) {
+ ctrl->oob += read_oob_from_regs(ctrl,
+ 1,
+ ctrl->oob, ctrl->sas,
+ ctrl->sector_size_1k);
+ }
+
/* for program page check NAND status */
if (((brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
INTFC_FLASH_STATUS) & NAND_STATUS_FAIL) &&
@@ -2060,7 +2104,7 @@ static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
}
static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
- u32 len, u8 dma_cmd)
+ u8 *oob, u32 len, u8 dma_cmd)
{
struct brcmnand_controller *ctrl = host->ctrl;
dma_addr_t buf_pa;
@@ -2205,8 +2249,9 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
try_dmaread:
brcmnand_clear_ecc_addr(ctrl);
- if (ctrl->dma_trans && !oob && flash_dma_buf_ok(buf)) {
- err = ctrl->dma_trans(host, addr, buf,
+ if (ctrl->dma_trans && (has_edu(ctrl) || !oob) &&
+ flash_dma_buf_ok(buf)) {
+ err = ctrl->dma_trans(host, addr, buf, oob,
trans * FC_BYTES,
CMD_PAGE_READ);
@@ -2354,10 +2399,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < ctrl->max_oob; i += 4)
oob_reg_write(ctrl, i, 0xffffffff);
- if (use_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
- if (ctrl->dma_trans(host, addr, (u32 *)buf, mtd->writesize,
+ if (mtd->oops_panic_write) {
+ /* switch to interrupt polling and PIO mode */
+ disable_ctrl_irqs(ctrl);
+ } else if (use_dma(ctrl) && (has_edu(ctrl) || !oob) && flash_dma_buf_ok(buf)) {
+ if (ctrl->dma_trans(host, addr, (u32 *)buf, oob, mtd->writesize,
CMD_PROGRAM_PAGE))
-
ret = -EIO;
goto out;
diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
index 544cf5fe946a..bd86b96ad64f 100644
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
@@ -2840,7 +2840,7 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
sizeof(*cdns_ctrl->cdma_desc),
&cdns_ctrl->dma_cdma_desc,
GFP_KERNEL);
- if (!cdns_ctrl->dma_cdma_desc)
+ if (!cdns_ctrl->cdma_desc)
return -ENOMEM;
cdns_ctrl->buf_size = SZ_16K;
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 308fcbe394a5..b40dc3ac8615 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4383,11 +4383,16 @@ static void nand_shutdown(struct mtd_info *mtd)
static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret;
if (!chip->ops.lock_area)
return -ENOTSUPP;
- return chip->ops.lock_area(chip, ofs, len);
+ nand_get_device(chip);
+ ret = chip->ops.lock_area(chip, ofs, len);
+ nand_release_device(chip);
+
+ return ret;
}
/**
@@ -4399,11 +4404,16 @@ static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret;
if (!chip->ops.unlock_area)
return -ENOTSUPP;
- return chip->ops.unlock_area(chip, ofs, len);
+ nand_get_device(chip);
+ ret = chip->ops.unlock_area(chip, ofs, len);
+ nand_release_device(chip);
+
+ return ret;
}
/* Set default functions */
diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c
index 3351be651473..c06ba7a2a34b 100644
--- a/drivers/mtd/parsers/redboot.c
+++ b/drivers/mtd/parsers/redboot.c
@@ -17,15 +17,15 @@
#include <linux/module.h>
struct fis_image_desc {
- unsigned char name[16]; // Null terminated name
- uint32_t flash_base; // Address within FLASH of image
- uint32_t mem_base; // Address in memory where it executes
- uint32_t size; // Length of image
- uint32_t entry_point; // Execution entry point
- uint32_t data_length; // Length of actual data
- unsigned char _pad[256-(16+7*sizeof(uint32_t))];
- uint32_t desc_cksum; // Checksum over image descriptor
- uint32_t file_cksum; // Checksum over image data
+ unsigned char name[16]; // Null terminated name
+ u32 flash_base; // Address within FLASH of image
+ u32 mem_base; // Address in memory where it executes
+ u32 size; // Length of image
+ u32 entry_point; // Execution entry point
+ u32 data_length; // Length of actual data
+ unsigned char _pad[256 - (16 + 7 * sizeof(u32))];
+ u32 desc_cksum; // Checksum over image descriptor
+ u32 file_cksum; // Checksum over image data
};
struct fis_list {
@@ -91,12 +91,12 @@ static int parse_redboot_partitions(struct mtd_info *master,
parse_redboot_of(master);
- if ( directory < 0 ) {
+ if (directory < 0) {
offset = master->size + directory * master->erasesize;
while (mtd_block_isbad(master, offset)) {
if (!offset) {
- nogood:
- printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
+nogood:
+ pr_notice("Failed to find a non-bad block to check for RedBoot partition table\n");
return -EIO;
}
offset -= master->erasesize;
@@ -114,8 +114,8 @@ static int parse_redboot_partitions(struct mtd_info *master,
if (!buf)
return -ENOMEM;
- printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
- master->name, offset);
+ pr_notice("Searching for RedBoot partition table in %s at offset 0x%lx\n",
+ master->name, offset);
ret = mtd_read(master, offset, master->erasesize, &retlen,
(void *)buf);
@@ -151,14 +151,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
&& swab32(buf[i].size) < master->erasesize)) {
int j;
/* Update numslots based on actual FIS directory size */
- numslots = swab32(buf[i].size) / sizeof (struct fis_image_desc);
+ numslots = swab32(buf[i].size) / sizeof(struct fis_image_desc);
for (j = 0; j < numslots; ++j) {
-
/* A single 0xff denotes a deleted entry.
* Two of them in a row is the end of the table.
*/
if (buf[j].name[0] == 0xff) {
- if (buf[j].name[1] == 0xff) {
+ if (buf[j].name[1] == 0xff) {
break;
} else {
continue;
@@ -185,8 +184,8 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
if (i == numslots) {
/* Didn't find it */
- printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
- master->name);
+ pr_notice("No RedBoot partition table detected in %s\n",
+ master->name);
ret = 0;
goto out;
}
@@ -205,7 +204,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
break;
new_fl = kmalloc(sizeof(struct fis_list), GFP_KERNEL);
- namelen += strlen(buf[i].name)+1;
+ namelen += strlen(buf[i].name) + 1;
if (!new_fl) {
ret = -ENOMEM;
goto out;
@@ -214,13 +213,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
if (data && data->origin)
buf[i].flash_base -= data->origin;
else
- buf[i].flash_base &= master->size-1;
+ buf[i].flash_base &= master->size - 1;
/* I'm sure the JFFS2 code has done me permanent damage.
* I now think the following is _normal_
*/
prev = &fl;
- while(*prev && (*prev)->img->flash_base < new_fl->img->flash_base)
+ while (*prev && (*prev)->img->flash_base < new_fl->img->flash_base)
prev = &(*prev)->next;
new_fl->next = *prev;
*prev = new_fl;
@@ -240,7 +239,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
}
#endif
- parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
+ parts = kzalloc(sizeof(*parts) * nrparts + nulllen + namelen, GFP_KERNEL);
if (!parts) {
ret = -ENOMEM;
@@ -249,41 +248,40 @@ static int parse_redboot_partitions(struct mtd_info *master,
nullname = (char *)&parts[nrparts];
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
- if (nulllen > 0) {
+ if (nulllen > 0)
strcpy(nullname, nullstring);
- }
#endif
names = nullname + nulllen;
- i=0;
+ i = 0;
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if (fl->img->flash_base) {
- parts[0].name = nullname;
- parts[0].size = fl->img->flash_base;
- parts[0].offset = 0;
+ parts[0].name = nullname;
+ parts[0].size = fl->img->flash_base;
+ parts[0].offset = 0;
i++;
}
#endif
- for ( ; i<nrparts; i++) {
+ for ( ; i < nrparts; i++) {
parts[i].size = fl->img->size;
parts[i].offset = fl->img->flash_base;
parts[i].name = names;
strcpy(names, fl->img->name);
#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
- if (!memcmp(names, "RedBoot", 8) ||
- !memcmp(names, "RedBoot config", 15) ||
- !memcmp(names, "FIS directory", 14)) {
+ if (!strcmp(names, "RedBoot") ||
+ !strcmp(names, "RedBoot config") ||
+ !strcmp(names, "FIS directory")) {
parts[i].mask_flags = MTD_WRITEABLE;
}
#endif
- names += strlen(names)+1;
+ names += strlen(names) + 1;
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
- if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
+ if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
i++;
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
+ parts[i].offset = parts[i - 1].size + parts[i - 1].offset;
parts[i].size = fl->next->img->flash_base - parts[i].offset;
parts[i].name = nullname;
}
@@ -297,6 +295,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
out:
while (fl) {
struct fis_list *old = fl;
+
fl = fl->next;
kfree(old);
}
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index 00a80f0adece..7cea482f2d5f 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -114,6 +114,8 @@ static const struct attribute_group com20020_state_group = {
.attrs = com20020_state_attrs,
};
+static struct com20020_pci_card_info card_info_2p5mbit;
+
static void com20020pci_remove(struct pci_dev *pdev);
static int com20020pci_probe(struct pci_dev *pdev,
@@ -139,7 +141,7 @@ static int com20020pci_probe(struct pci_dev *pdev,
ci = (struct com20020_pci_card_info *)id->driver_data;
if (!ci)
- return -EINVAL;
+ ci = &card_info_2p5mbit;
priv->ci = ci;
mm = &ci->misc_map;
@@ -346,6 +348,18 @@ static struct com20020_pci_card_info card_info_5mbit = {
.flags = ARC_IS_5MBIT,
};
+static struct com20020_pci_card_info card_info_2p5mbit = {
+ .name = "ARC-PCI",
+ .devcount = 1,
+ .chan_map_tbl = {
+ {
+ .bar = 2,
+ .offset = 0x00,
+ .size = 0x08,
+ },
+ },
+};
+
static struct com20020_pci_card_info card_info_sohard = {
.name = "SOHARD SH ARC-PCI",
.devcount = 1,
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
index 8b6cf2bf9025..bb31f986ae59 100644
--- a/drivers/net/bonding/bond_debugfs.c
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -34,11 +34,17 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
for (; hash_index != RLB_NULL_INDEX;
hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
- seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
- &client_info->ip_src,
- &client_info->ip_dst,
- &client_info->mac_dst,
- client_info->slave->dev->name);
+ if (client_info->slave)
+ seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
+ &client_info->ip_src,
+ &client_info->ip_dst,
+ &client_info->mac_dst,
+ client_info->slave->dev->name);
+ else
+ seq_printf(m, "%-15pI4 %-15pI4 %-17pM (none)\n",
+ &client_info->ip_src,
+ &client_info->ip_dst,
+ &client_info->mac_dst);
}
spin_unlock_bh(&bond->mode_lock);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 87e23796680b..812e1792c232 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2592,8 +2592,14 @@ static void bond_miimon_commit(struct bonding *bond)
continue;
+ case BOND_LINK_FAIL:
+ case BOND_LINK_BACK:
+ slave_dbg(bond->dev, slave->dev, "link_new_state %d on slave\n",
+ slave->link_new_state);
+ continue;
+
default:
- slave_err(bond->dev, slave->dev, "invalid new link %d on slave\n",
+ slave_err(bond->dev, slave->dev, "invalid link_new_state %d on slave\n",
slave->link_new_state);
bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 1b6a696182f7..02aea5a4b8ca 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -312,6 +312,7 @@ static void ser_release(struct work_struct *work)
dev_close(ser->dev);
unregister_netdevice(ser->dev);
debugfs_deinit(ser);
+ tty_kref_put(tty->link);
tty_kref_put(tty);
}
rtnl_unlock();
@@ -346,6 +347,7 @@ static int ldisc_open(struct tty_struct *tty)
ser = netdev_priv(dev);
ser->tty = tty_kref_get(tty);
+ tty_kref_get(tty->link);
ser->dev = dev;
debugfs_init(ser, tty);
tty->receive_room = N_TTY_BUF_SIZE;
@@ -354,6 +356,7 @@ static int ldisc_open(struct tty_struct *tty)
rtnl_lock();
result = register_netdevice(dev);
if (result) {
+ tty_kref_put(tty->link);
tty_kref_put(tty);
rtnl_unlock();
free_netdev(dev);
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index a7d594a5ad36..f651a8ba7d53 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -751,7 +751,9 @@ static int hi3110_open(struct net_device *net)
return ret;
mutex_lock(&priv->hi3110_lock);
- hi3110_power_enable(priv->transceiver, 1);
+ ret = hi3110_power_enable(priv->transceiver, 1);
+ if (ret)
+ goto out_close_candev;
priv->force_quit = 0;
priv->tx_skb = NULL;
@@ -798,6 +800,7 @@ static int hi3110_open(struct net_device *net)
hi3110_hw_sleep(spi);
out_close:
hi3110_power_enable(priv->transceiver, 0);
+ out_close_candev:
close_candev(net);
mutex_unlock(&priv->hi3110_lock);
return ret;
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 88d065718e99..b06b15debafa 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1207,6 +1207,7 @@ static int mcp251x_open(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
+ bool release_irq = false;
unsigned long flags = 0;
int ret;
@@ -1252,12 +1253,24 @@ static int mcp251x_open(struct net_device *net)
return 0;
out_free_irq:
- free_irq(spi->irq, priv);
+ /* The IRQ handler might be running, and if so it will be waiting
+ * for the lock. But free_irq() must wait for the handler to finish
+ * so calling it here would deadlock.
+ *
+ * Setting priv->force_quit will let the handler exit right away
+ * without any access to the hardware. This make it safe to call
+ * free_irq() after the lock is released.
+ */
+ priv->force_quit = 1;
+ release_irq = true;
+
mcp251x_hw_sleep(spi);
out_close:
mcp251x_power_enable(priv->transceiver, 0);
close_candev(net);
mutex_unlock(&priv->mcp_lock);
+ if (release_irq)
+ free_irq(spi->irq, priv);
return ret;
}
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index f8baf8283a65..65aa1100e894 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -438,6 +438,11 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
start = CPC_HEADER_SIZE;
while (msg_count) {
+ if (start + CPC_MSG_HEADER_LEN > urb->actual_length) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
+
msg = (struct ems_cpc_msg *)&ibuf[start];
switch (msg->type) {
@@ -467,7 +472,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
start += CPC_MSG_HEADER_LEN + msg->length;
msg_count--;
- if (start > urb->transfer_buffer_length) {
+ if (start > urb->actual_length) {
netdev_err(netdev, "format error\n");
break;
}
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 58a7ac1d7c7f..ce5676845f28 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -413,9 +413,8 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
}
}
-static int gs_usb_set_bittiming(struct net_device *netdev)
+static int gs_usb_set_bittiming(struct gs_can *dev)
{
- struct gs_can *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.bittiming;
struct usb_interface *intf = dev->iface;
int rc;
@@ -445,7 +444,7 @@ static int gs_usb_set_bittiming(struct net_device *netdev)
kfree(dbt);
if (rc < 0)
- dev_err(netdev->dev.parent, "Couldn't set bittimings (err=%d)",
+ dev_err(dev->netdev->dev.parent, "Couldn't set bittimings (err=%d)",
rc);
return (rc > 0) ? 0 : rc;
@@ -675,6 +674,13 @@ static int gs_can_open(struct net_device *netdev)
if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)
flags |= GS_CAN_MODE_TRIPLE_SAMPLE;
+ rc = gs_usb_set_bittiming(dev);
+ if (rc) {
+ netdev_err(netdev, "failed to set bittiming: %pe\n", ERR_PTR(rc));
+ kfree(dm);
+ return rc;
+ }
+
/* finally start device */
dev->can.state = CAN_STATE_ERROR_ACTIVE;
dm->mode = cpu_to_le32(GS_CAN_MODE_START);
@@ -888,7 +894,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev->can.state = CAN_STATE_STOPPED;
dev->can.clock.freq = le32_to_cpu(bt_const->fclk_can);
dev->can.bittiming_const = &dev->bt_const;
- dev->can.do_set_bittiming = gs_usb_set_bittiming;
dev->can.ctrlmode_supported = 0;
diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c
index dc5290b36598..c8b2b814bafe 100644
--- a/drivers/net/can/usb/ucan.c
+++ b/drivers/net/can/usb/ucan.c
@@ -745,7 +745,7 @@ static void ucan_read_bulk_callback(struct urb *urb)
len = le16_to_cpu(m->len);
/* check sanity (length of content) */
- if (urb->actual_length - pos < len) {
+ if ((len == 0) || (urb->actual_length - pos < len)) {
netdev_warn(up->netdev,
"invalid message (short; no data; l:%d)\n",
urb->actual_length);
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index d0f94a5fae5a..7c64317e0f19 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -871,13 +871,17 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
ret = bcm_sf2_sw_rst(priv);
if (ret) {
pr_err("%s: failed to software reset switch\n", __func__);
+ if (!priv->wol_ports_mask)
+ clk_disable_unprepare(priv->clk);
return ret;
}
ret = bcm_sf2_cfp_resume(ds);
- if (ret)
+ if (ret) {
+ if (!priv->wol_ports_mask)
+ clk_disable_unprepare(priv->clk);
return ret;
-
+ }
if (priv->hw_params.num_gphy == 1)
bcm_sf2_gphy_enable_set(ds, true);
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
index b779f3adbc56..1903e00d159e 100644
--- a/drivers/net/ethernet/altera/altera_tse_main.c
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -591,6 +591,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/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 3de7674a8467..00f2df29ed61 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1181,7 +1181,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- unsigned long flags;
DBGPR("-->xgbe_powerdown\n");
@@ -1192,8 +1191,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
return -EINVAL;
}
- spin_lock_irqsave(&pdata->lock, flags);
-
if (caller == XGMAC_DRIVER_CONTEXT)
netif_device_detach(netdev);
@@ -1209,8 +1206,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
pdata->power_down = 1;
- spin_unlock_irqrestore(&pdata->lock, flags);
-
DBGPR("<--xgbe_powerdown\n");
return 0;
@@ -1220,7 +1215,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- unsigned long flags;
DBGPR("-->xgbe_powerup\n");
@@ -1231,8 +1225,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
return -EINVAL;
}
- spin_lock_irqsave(&pdata->lock, flags);
-
pdata->power_down = 0;
xgbe_napi_enable(pdata, 0);
@@ -1247,8 +1239,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
xgbe_start_timers(pdata);
- spin_unlock_irqrestore(&pdata->lock, flags);
-
DBGPR("<--xgbe_powerup\n");
return 0;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index a218dc6f2edd..dfd1add6dbaa 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -185,7 +185,6 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev)
pdata->netdev = netdev;
pdata->dev = dev;
- spin_lock_init(&pdata->lock);
spin_lock_init(&pdata->xpcs_lock);
mutex_init(&pdata->rss_mutex);
spin_lock_init(&pdata->tstamp_lock);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 61f22462197a..7a755c1fd5ef 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -1050,9 +1050,6 @@ struct xgbe_prv_data {
unsigned int pp3;
unsigned int pp4;
- /* Overall device lock */
- spinlock_t lock;
-
/* XPCS indirect addressing lock */
spinlock_t xpcs_lock;
unsigned int xpcs_window_def_reg;
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 61d076e09571..be87b018e0e6 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -935,6 +935,17 @@ int arc_emac_probe(struct net_device *ndev, int interface)
/* Set poll rate so that it polls every 1 ms */
arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
+ /*
+ * Put the device into a known quiescent state before requesting
+ * the IRQ. Clear only EMAC interrupt status bits here; leave the
+ * MDIO completion bit alone and avoid writing TXPL_MASK, which is
+ * used to force TX polling rather than acknowledge interrupts.
+ */
+ arc_reg_set(priv, R_ENABLE, 0);
+ arc_reg_set(priv, R_STATUS, RXINT_MASK | TXINT_MASK | ERR_MASK |
+ TXCH_MASK | MSER_MASK | RXCR_MASK |
+ RXFR_MASK | RXFL_MASK);
+
ndev->irq = irq;
dev_info(dev, "IRQ is %d\n", ndev->irq);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 35c12938cb34..ac402631576c 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -102,7 +102,7 @@ static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
& RBUF_STATUS_WOL)) {
retries++;
- if (retries > 5) {
+ if (retries > 50) {
netdev_crit(dev, "polling wol mode timeout\n");
return -ETIMEDOUT;
}
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index e8be9e5a244f..954a51fe0cd7 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -12232,7 +12232,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
advertising);
- if (netif_running(dev) && tp->link_up) {
+ if (netif_running(dev) && netif_carrier_ok(dev)) {
cmd->base.speed = tp->link_config.active_speed;
cmd->base.duplex = tp->link_config.active_duplex;
ethtool_convert_legacy_u32_to_link_mode(
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index c407e8d0eb61..8751d6ea9a5e 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2786,7 +2786,7 @@ static void gem_get_ethtool_stats(struct net_device *dev,
spin_lock_irq(&bp->stats_lock);
gem_update_stats(bp);
memcpy(data, &bp->ethtool_stats, sizeof(u64)
- * (GEM_STATS_LEN + QUEUE_STATS_LEN * MACB_MAX_QUEUES));
+ * (GEM_STATS_LEN + QUEUE_STATS_LEN * bp->num_queues));
spin_unlock_irq(&bp->stats_lock);
}
@@ -3381,6 +3381,9 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
struct macb *bp = netdev_priv(netdev);
int ret;
+ if (!(netdev->hw_features & NETIF_F_NTUPLE))
+ return -EOPNOTSUPP;
+
switch (cmd->cmd) {
case ETHTOOL_SRXCLSRLINS:
if ((cmd->fs.location >= bp->max_tuples)
@@ -4731,6 +4734,8 @@ static int __maybe_unused macb_suspend(struct device *dev)
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
queue_writel(queue, ISR, -1);
}
+ spin_unlock_irqrestore(&bp->lock, flags);
+
/* Change interrupt handler and
* Enable WoL IRQ on queue 0
*/
@@ -4742,11 +4747,12 @@ static int __maybe_unused macb_suspend(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
+ spin_lock_irqsave(&bp->lock, flags);
queue_writel(bp->queues, IER, GEM_BIT(WOL));
gem_writel(bp, WOL, MACB_BIT(MAG));
+ spin_unlock_irqrestore(&bp->lock, flags);
} else {
err = devm_request_irq(dev, bp->queues[0].irq, macb_wol_interrupt,
IRQF_SHARED, netdev->name, bp->queues);
@@ -4754,13 +4760,13 @@ static int __maybe_unused macb_suspend(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
+ spin_lock_irqsave(&bp->lock, flags);
queue_writel(bp->queues, IER, MACB_BIT(WOL));
macb_writel(bp, WOL, MACB_BIT(MAG));
+ spin_unlock_irqrestore(&bp->lock, flags);
}
- spin_unlock_irqrestore(&bp->lock, flags);
enable_irq_wake(bp->queues[0].irq);
}
@@ -4822,6 +4828,8 @@ static int __maybe_unused macb_resume(struct device *dev)
queue_readl(bp->queues, ISR);
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
queue_writel(bp->queues, ISR, -1);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
/* Replace interrupt handler on queue 0 */
devm_free_irq(dev, bp->queues[0].irq, bp->queues);
err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt,
@@ -4830,10 +4838,8 @@ static int __maybe_unused macb_resume(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
- spin_unlock_irqrestore(&bp->lock, flags);
disable_irq_wake(bp->queues[0].irq);
diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
index 3593b310c325..e6c17e0af1cc 100644
--- a/drivers/net/ethernet/cadence/macb_pci.c
+++ b/drivers/net/ethernet/cadence/macb_pci.c
@@ -97,10 +97,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
err_plat_dev_register:
- clk_unregister(plat_data.hclk);
+ clk_unregister_fixed_rate(plat_data.hclk);
err_hclk_register:
- clk_unregister(plat_data.pclk);
+ clk_unregister_fixed_rate(plat_data.pclk);
err_pclk_register:
return err;
@@ -110,10 +110,12 @@ static void macb_remove(struct pci_dev *pdev)
{
struct platform_device *plat_dev = pci_get_drvdata(pdev);
struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
+ struct clk *pclk = plat_data->pclk;
+ struct clk *hclk = plat_data->hclk;
- clk_unregister(plat_data->pclk);
- clk_unregister(plat_data->hclk);
platform_device_unregister(plat_dev);
+ clk_unregister_fixed_rate(pclk);
+ clk_unregister_fixed_rate(hclk);
}
static const struct pci_device_id dev_id_table[] = {
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index 09d64a29f56e..d0063495a4a7 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -395,8 +395,10 @@ void gem_ptp_remove(struct net_device *ndev)
{
struct macb *bp = netdev_priv(ndev);
- if (bp->ptp_clock)
+ if (bp->ptp_clock) {
ptp_clock_unregister(bp->ptp_clock);
+ bp->ptp_clock = NULL;
+ }
gem_ptp_clear_timer(bp);
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index bc9a7f2d2350..32653d9abb34 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -931,19 +931,19 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *),
GFP_KERNEL);
if (!priv->tx_skbs)
- return -ENOMEM;
+ goto err_free_rx_skbs;
/* Allocate descriptors */
priv->rxdes = dma_alloc_coherent(priv->dev,
MAX_RX_QUEUE_ENTRIES * sizeof(struct ftgmac100_rxdes),
&priv->rxdes_dma, GFP_KERNEL);
if (!priv->rxdes)
- return -ENOMEM;
+ goto err_free_tx_skbs;
priv->txdes = dma_alloc_coherent(priv->dev,
MAX_TX_QUEUE_ENTRIES * sizeof(struct ftgmac100_txdes),
&priv->txdes_dma, GFP_KERNEL);
if (!priv->txdes)
- return -ENOMEM;
+ goto err_free_rxdes;
/* Allocate scratch packet buffer */
priv->rx_scratch = dma_alloc_coherent(priv->dev,
@@ -951,9 +951,29 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
&priv->rx_scratch_dma,
GFP_KERNEL);
if (!priv->rx_scratch)
- return -ENOMEM;
+ goto err_free_txdes;
return 0;
+
+err_free_txdes:
+ dma_free_coherent(priv->dev,
+ MAX_TX_QUEUE_ENTRIES *
+ sizeof(struct ftgmac100_txdes),
+ priv->txdes, priv->txdes_dma);
+ priv->txdes = NULL;
+err_free_rxdes:
+ dma_free_coherent(priv->dev,
+ MAX_RX_QUEUE_ENTRIES *
+ sizeof(struct ftgmac100_rxdes),
+ priv->rxdes, priv->rxdes_dma);
+ priv->rxdes = NULL;
+err_free_tx_skbs:
+ kfree(priv->tx_skbs);
+ priv->tx_skbs = NULL;
+err_free_rx_skbs:
+ kfree(priv->rx_skbs);
+ priv->rx_skbs = NULL;
+ return -ENOMEM;
}
static void ftgmac100_init_rings(struct ftgmac100 *priv)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index cf98a00296ed..c934cae9f0d4 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -549,6 +549,8 @@ static void enetc_get_ringparam(struct net_device *ndev,
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ ring->rx_max_pending = priv->rx_bd_count;
+ ring->tx_max_pending = priv->tx_bd_count;
ring->rx_pending = priv->rx_bd_count;
ring->tx_pending = priv->tx_bd_count;
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 0b7502902913..d7e7c619a98e 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -2951,8 +2951,6 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
dma_error:
dev_err(&pdev->dev, "TX DMA map failed\n");
buffer_info->dma = 0;
- if (count)
- count--;
while (count--) {
if (i == 0)
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index b700663a634d..902ada6a3b06 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5633,8 +5633,6 @@ static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
dma_error:
dev_err(&pdev->dev, "Tx DMA map failed\n");
buffer_info->dma = 0;
- if (count)
- count--;
while (count--) {
if (i == 0)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 3ddb712b732d..014734ea71ff 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -3655,10 +3655,10 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
cfilter.n_proto = ETH_P_IP;
if (mask.dst_ip[0] & tcf.dst_ip[0])
memcpy(&cfilter.ip.v4.dst_ip, tcf.dst_ip,
- ARRAY_SIZE(tcf.dst_ip));
- else if (mask.src_ip[0] & tcf.dst_ip[0])
+ sizeof(cfilter.ip.v4.dst_ip));
+ else if (mask.src_ip[0] & tcf.src_ip[0])
memcpy(&cfilter.ip.v4.src_ip, tcf.src_ip,
- ARRAY_SIZE(tcf.dst_ip));
+ sizeof(cfilter.ip.v4.src_ip));
break;
case VIRTCHNL_TCP_V6_FLOW:
cfilter.n_proto = ETH_P_IPV6;
@@ -3713,7 +3713,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
/* for ipv6, mask is set for all sixteen bytes (4 words) */
if (cfilter.n_proto == ETH_P_IPV6 && mask.dst_ip[3])
if (memcmp(&cfilter.ip.v6.dst_ip6, &cf->ip.v6.dst_ip6,
- sizeof(cfilter.ip.v6.src_ip6)))
+ sizeof(cfilter.ip.v6.dst_ip6)))
continue;
if (mask.vlan_id)
if (cfilter.vlan_id != cf->vlan_id)
@@ -3799,10 +3799,10 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
cfilter->n_proto = ETH_P_IP;
if (mask.dst_ip[0] & tcf.dst_ip[0])
memcpy(&cfilter->ip.v4.dst_ip, tcf.dst_ip,
- ARRAY_SIZE(tcf.dst_ip));
- else if (mask.src_ip[0] & tcf.dst_ip[0])
+ sizeof(cfilter->ip.v4.dst_ip));
+ else if (mask.src_ip[0] & tcf.src_ip[0])
memcpy(&cfilter->ip.v4.src_ip, tcf.src_ip,
- ARRAY_SIZE(tcf.dst_ip));
+ sizeof(cfilter->ip.v4.src_ip));
break;
case VIRTCHNL_TCP_V6_FLOW:
cfilter->n_proto = ETH_P_IPV6;
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 7593e8b7469c..e59de43704b5 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -1522,11 +1522,8 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb,
/* The minimum packet size with TCTL.PSP set is 17 so pad the skb
* in order to meet this minimum size requirement.
*/
- if (skb->len < 17) {
- if (skb_padto(skb, 17))
- return NETDEV_TX_OK;
- skb->len = 17;
- }
+ if (skb_put_padto(skb, 17))
+ return NETDEV_TX_OK;
return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb));
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
index 060561f63311..62ac22d82e1a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -60,9 +60,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
if (err)
return err;
- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
- if (err)
- return err;
+ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
index 13dd34c571b9..ce533e7d679a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
@@ -28,7 +28,6 @@ static void mlx5e_reset_txqsq_cc_pc(struct mlx5e_txqsq *sq)
"SQ 0x%x: cc (0x%x) != pc (0x%x)\n",
sq->sqn, sq->cc, sq->pc);
sq->cc = 0;
- sq->dma_fifo_cc = 0;
sq->pc = 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index 02558ac2ace6..eb414452dbd0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -770,48 +770,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
return 0;
}
-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
- u32 *running_ver, u32 *pending_ver)
+void mlx5_fw_version_query(struct mlx5_core_dev *dev,
+ u32 *running_ver, u32 *pending_ver)
{
u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
bool pending_version_exists;
int component_index;
int err;
+ *running_ver = 0;
+ *pending_ver = 0;
+
if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
!MLX5_CAP_MCAM_REG(dev, mcqs)) {
mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
- return -EOPNOTSUPP;
+ return;
}
component_index = mlx5_get_boot_img_component_index(dev);
- if (component_index < 0)
- return component_index;
+ if (component_index < 0) {
+ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
+ component_index);
+ return;
+ }
+ *running_ver = U32_MAX; /* indicate failure */
err = mlx5_reg_mcqi_version_query(dev, component_index,
MCQI_FW_RUNNING_VERSION,
reg_mcqi_version);
- if (err)
- return err;
-
- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
-
+ if (!err)
+ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
+ version);
+ else
+ mlx5_core_warn(dev, "failed to query running version, err %d\n",
+ err);
+
+ *pending_ver = U32_MAX; /* indicate failure */
err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
- if (err)
- return err;
+ if (err) {
+ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
+ err);
+ return;
+ }
if (!pending_version_exists) {
*pending_ver = 0;
- return 0;
+ return;
}
err = mlx5_reg_mcqi_version_query(dev, component_index,
MCQI_FW_STORED_VERSION,
reg_mcqi_version);
- if (err)
- return err;
-
- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
-
- return 0;
+ if (!err)
+ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
+ version);
+ else
+ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
+ err);
+
+ return;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index b285f1515e4e..d3279536c902 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -209,8 +209,8 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev);
int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
struct netlink_ext_ack *extack);
-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
- u32 *running_ver, u32 *stored_ver);
+void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
+ u32 *stored_ver);
void mlx5e_init(void);
void mlx5e_cleanup(void);
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
index 0b7301db20ed..466b919b4be8 100644
--- a/drivers/net/ethernet/qualcomm/qca_uart.c
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -115,7 +115,7 @@ qca_tty_receive(struct serdev_device *serdev, const unsigned char *data,
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 d2cdc02d9f94..f2e5c4021a67 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(void *p, struct sk_buff *skb, int csum)
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(void *p, struct sk_buff *skb, int csum)
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/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 07510e068742..2dc3e5be1d71 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -305,7 +305,7 @@ static void am65_cpsw_nuss_ndo_slave_set_rx_mode(struct net_device *ndev)
cpsw_ale_set_allmulti(common->ale,
ndev->flags & IFF_ALLMULTI, port->port_id);
- port_mask = ALE_PORT_HOST;
+ port_mask = BIT(port->port_id) | ALE_PORT_HOST;
/* Clear all mcast from ALE */
cpsw_ale_flush_multicast(common->ale, port_mask, -1);
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index bec6a68a973c..eb4262017d23 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -420,14 +420,13 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
ale->port_mask_bits);
if ((mask & port_mask) == 0)
return; /* ports dont intersect, not interested */
- mask &= ~port_mask;
+ mask &= (~port_mask | ALE_PORT_HOST);
- /* free if only remaining port is host port */
- if (mask)
+ if (mask == 0x0 || mask == ALE_PORT_HOST)
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+ else
cpsw_ale_set_port_mask(ale_entry, mask,
ale->port_mask_bits);
- else
- cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
}
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 071822028ea5..516f40e7560a 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -103,7 +103,7 @@
#define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
#define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
+#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
#define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
@@ -129,7 +129,7 @@
#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
+#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
#define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
#define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
#define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8654e05ddc41..665952e64e9b 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1412,7 +1412,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
return err;
phy_resume(phydev);
- phy_led_triggers_register(phydev);
return err;
@@ -1669,8 +1668,6 @@ void phy_detach(struct phy_device *phydev)
}
phydev->phylink = NULL;
- phy_led_triggers_unregister(phydev);
-
if (phydev->mdio.dev.driver)
module_put(phydev->mdio.dev.driver->owner);
@@ -2900,10 +2897,14 @@ static int phy_probe(struct device *dev)
/* Set the state to READY by default */
phydev->state = PHY_READY;
+ /* Register the PHY LED triggers */
+ phy_led_triggers_register(phydev);
+
+ return 0;
+
out:
/* Re-assert the reset signal on error */
- if (err)
- phy_device_reset(phydev, 1);
+ phy_device_reset(phydev, 1);
return err;
}
@@ -2914,6 +2915,8 @@ static int phy_remove(struct device *dev)
cancel_delayed_work_sync(&phydev->state_queue);
+ phy_led_triggers_unregister(phydev);
+
phydev->state = PHY_DOWN;
sfp_bus_del_upstream(phydev->sfp_bus);
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index ab9431ea295a..7d38ce2e7701 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -1400,14 +1400,14 @@ static int aqc111_suspend(struct usb_interface *intf, pm_message_t message)
aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
SFR_MEDIUM_STATUS_MODE, 2, ®16);
- aqc111_write_cmd(dev, AQ_WOL_CFG, 0, 0,
- WOL_CFG_SIZE, &wol_cfg);
- aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
- &aqc111_data->phy_cfg);
+ aqc111_write_cmd_nopm(dev, AQ_WOL_CFG, 0, 0,
+ WOL_CFG_SIZE, &wol_cfg);
+ aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
+ &aqc111_data->phy_cfg);
} else {
aqc111_data->phy_cfg |= AQ_LOW_POWER;
- aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
- &aqc111_data->phy_cfg);
+ aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
+ &aqc111_data->phy_cfg);
/* Disable RX path */
aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index a552bb1665b8..c5a09edff629 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -132,11 +132,18 @@ kalmia_bind(struct usbnet *dev, struct usb_interface *intf)
{
int status;
u8 ethernet_addr[ETH_ALEN];
+ static const u8 ep_addr[] = {
+ 1 | USB_DIR_IN,
+ 2 | USB_DIR_OUT,
+ 0};
/* Don't bind to AT command interface */
if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
return -EINVAL;
+ if (!usb_check_bulk_endpoints(intf, ep_addr))
+ return -ENODEV;
+
dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK);
dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK);
dev->status = NULL;
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 3ebf876dd60f..51da806bbad1 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -883,6 +883,13 @@ static int kaweth_probe(
const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
int result = 0;
int rv = -EIO;
+ static const u8 bulk_ep_addr[] = {
+ 1 | USB_DIR_IN,
+ 2 | USB_DIR_OUT,
+ 0};
+ static const u8 int_ep_addr[] = {
+ 3 | USB_DIR_IN,
+ 0};
dev_dbg(dev,
"Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x\n",
@@ -896,6 +903,12 @@ static int kaweth_probe(
(int)udev->descriptor.bLength,
(int)udev->descriptor.bDescriptorType);
+ if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
+ !usb_check_int_endpoints(intf, int_ep_addr)) {
+ dev_err(dev, "couldn't find required endpoints\n");
+ return -ENODEV;
+ }
+
netdev = alloc_etherdev(sizeof(*kaweth));
if (!netdev)
return -ENOMEM;
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 10c61ac0198a..f0643d9d8ff9 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2463,6 +2463,10 @@ static void lan78xx_init_ltm(struct lan78xx_net *dev)
u32 buf;
u32 regs[6] = { 0 };
+ /* LAN7850 is USB 2.0 and does not support LTM */
+ if (dev->chipid == ID_REV_CHIP_ID_7850_)
+ return;
+
ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (buf & USB_CFG1_LTM_ENABLE_) {
u8 temp[2];
@@ -3279,6 +3283,7 @@ static void lan78xx_rx_csum_offload(struct lan78xx_net *dev,
*/
if (!(dev->net->features & NETIF_F_RXCSUM) ||
unlikely(rx_cmd_a & RX_CMD_A_ICSM_) ||
+ unlikely(rx_cmd_a & RX_CMD_A_CSE_MASK_) ||
((rx_cmd_a & RX_CMD_A_FVTG_) &&
!(dev->net->features & NETIF_F_HW_VLAN_CTAG_RX))) {
skb->ip_summed = CHECKSUM_NONE;
@@ -3346,7 +3351,8 @@ static int lan78xx_rx(struct lan78xx_net *dev, struct sk_buff *skb)
size = (rx_cmd_a & RX_CMD_A_LEN_MASK_);
align_count = (4 - ((size + RXW_PADDING) % 4)) % 4;
- if (unlikely(rx_cmd_a & RX_CMD_A_RED_)) {
+ if (unlikely(rx_cmd_a & RX_CMD_A_RED_) &&
+ (rx_cmd_a & RX_CMD_A_RX_HARD_ERRS_MASK_)) {
netif_dbg(dev, rx_err, dev->net,
"Error rx_cmd_a=0x%08x", rx_cmd_a);
} else {
diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h
index 968e5e5faee0..17a934acff3d 100644
--- a/drivers/net/usb/lan78xx.h
+++ b/drivers/net/usb/lan78xx.h
@@ -74,6 +74,9 @@
#define RX_CMD_A_ICSM_ (0x00004000)
#define RX_CMD_A_LEN_MASK_ (0x00003FFF)
+#define RX_CMD_A_RX_HARD_ERRS_MASK_ \
+ (RX_CMD_A_RX_ERRS_MASK_ & ~RX_CMD_A_CSE_MASK_)
+
/* Rx Command B */
#define RX_CMD_B_CSUM_SHIFT_ (16)
#define RX_CMD_B_CSUM_MASK_ (0xFFFF0000)
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index ba18ada7b60f..4a16960faaf6 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -841,8 +841,19 @@ static void unlink_all_urbs(pegasus_t *pegasus)
static int alloc_urbs(pegasus_t *pegasus)
{
+ static const u8 bulk_ep_addr[] = {
+ 1 | USB_DIR_IN,
+ 2 | USB_DIR_OUT,
+ 0};
+ static const u8 int_ep_addr[] = {
+ 3 | USB_DIR_IN,
+ 0};
int res = -ENOMEM;
+ if (!usb_check_bulk_endpoints(pegasus->intf, bulk_ep_addr) ||
+ !usb_check_int_endpoints(pegasus->intf, int_ep_addr))
+ return -ENODEV;
+
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) {
return res;
@@ -1197,6 +1208,7 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus = netdev_priv(net);
pegasus->dev_index = dev_index;
+ pegasus->intf = intf;
res = alloc_urbs(pegasus);
if (res < 0) {
@@ -1208,7 +1220,6 @@ static int pegasus_probe(struct usb_interface *intf,
INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier);
- pegasus->intf = intf;
pegasus->usb = dev;
pegasus->net = net;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 5698683779ee..fe7b28a595f1 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1740,6 +1740,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Don't wait up for transmitted skbs to be freed. */
if (!use_napi) {
skb_orphan(skb);
+ skb_dst_drop(skb);
nf_reset_ct(skb);
}
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 7973d4070ee3..5e5dfa9579d3 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2098,12 +2098,14 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
ns_olen = request->len - skb_network_offset(request) -
sizeof(struct ipv6hdr) - sizeof(*ns);
for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
- if (!ns->opt[i + 1]) {
+ if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) {
kfree_skb(reply);
return NULL;
}
if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
- daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+ if ((ns->opt[i + 1] << 3) >=
+ sizeof(struct nd_opt_hdr) + ETH_ALEN)
+ daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
break;
}
}
@@ -2258,6 +2260,11 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
{
struct ipv6hdr *pip6;
+ /* check if nd_tbl is not initiliazed due to
+ * ipv6.disable=1 set during boot
+ */
+ if (!ipv6_stub->nd_tbl)
+ return false;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
return false;
pip6 = ipv6_hdr(skb);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
index b7df576bb84d..2c0ea993d71f 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/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c
index 1c56cc2742b0..459b30a1050d 100644
--- a/drivers/net/wireless/marvell/libertas/main.c
+++ b/drivers/net/wireless/marvell/libertas/main.c
@@ -882,8 +882,8 @@ static void lbs_free_adapter(struct lbs_private *priv)
{
lbs_free_cmd_buffer(priv);
kfifo_free(&priv->event_fifo);
- del_timer(&priv->command_timer);
- del_timer(&priv->tx_lockup_timer);
+ timer_delete_sync(&priv->command_timer);
+ timer_delete_sync(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer);
}
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
index 5f363653ed9d..464072535541 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.c
+++ b/drivers/net/wireless/microchip/wilc1000/hif.c
@@ -157,7 +157,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
u32 index = 0;
u32 i, scan_timeout;
u8 *buffer;
- u8 valuesize = 0;
+ u32 valuesize = 0;
u8 *search_ssid_vals = NULL;
struct host_if_drv *hif_drv = vif->hif_drv;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
index 8b3c90231110..0f76e34af4d7 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -830,7 +830,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/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 109c51e49792..30430b4a4188 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1813,6 +1813,8 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
wl->wow_enabled);
WARN_ON(!wl->wow_enabled);
+ mutex_lock(&wl->mutex);
+
ret = pm_runtime_force_resume(wl->dev);
if (ret < 0) {
wl1271_error("ELP wakeup failure!");
@@ -1829,8 +1831,6 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
run_irq_work = true;
spin_unlock_irqrestore(&wl->wl_lock, flags);
- mutex_lock(&wl->mutex);
-
/* test the recovery flag before calling any SDIO functions */
pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
&wl->flags);
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index e86cc3425e99..ac1411db8e5a 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -213,7 +213,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (skb_headroom(skb) < (total_len - skb->len) &&
pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) {
wl1271_free_tx_id(wl, id);
- return -EAGAIN;
+ return -ENOMEM;
}
desc = skb_push(skb, total_len - skb->len);
diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
index 78320d7bd2a1..237b344a30bb 100644
--- a/drivers/nfc/nxp-nci/i2c.c
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -47,8 +47,8 @@ static int nxp_nci_i2c_set_mode(void *phy_id,
{
struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
- gpiod_set_value(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
- gpiod_set_value(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
+ gpiod_set_value_cansleep(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
+ gpiod_set_value_cansleep(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
usleep_range(10000, 15000);
if (mode == NXP_NCI_MODE_COLD)
diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
index e92535ebb528..28cd41d38906 100644
--- a/drivers/nfc/pn533/uart.c
+++ b/drivers/nfc/pn533/uart.c
@@ -211,14 +211,22 @@ static int pn532_receive_buf(struct serdev_device *serdev,
del_timer(&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);
+
skb_put_u8(dev->recv_skb, *data++);
if (!pn532_uart_rx_is_frame(dev->recv_skb))
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/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c
index 77ada0a5c739..3ba6b387406c 100644
--- a/drivers/nfc/pn533/usb.c
+++ b/drivers/nfc/pn533/usb.c
@@ -633,6 +633,7 @@ static void pn533_usb_disconnect(struct usb_interface *interface)
usb_free_urb(phy->out_urb);
usb_free_urb(phy->ack_urb);
kfree(phy->ack_buffer);
+ usb_put_dev(phy->udev);
nfc_info(&interface->dev, "NXP PN533 NFC device disconnected\n");
}
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 9ec59960f216..1aacc40ad09f 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -502,14 +502,15 @@ EXPORT_SYMBOL_GPL(nd_synchronize);
static void nd_async_device_register(void *d, async_cookie_t cookie)
{
struct device *dev = d;
+ struct device *parent = dev->parent;
if (device_add(dev) != 0) {
dev_err(dev, "%s: failed\n", __func__);
put_device(dev);
}
put_device(dev);
- if (dev->parent)
- put_device(dev->parent);
+ if (parent)
+ put_device(parent);
}
static void nd_async_device_unregister(void *d, async_cookie_t cookie)
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index db905c30fbc6..3deca0d9a26b 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -3265,6 +3265,7 @@ nvme_fc_delete_ctrl(struct nvme_ctrl *nctrl)
* waiting for io to terminate
*/
nvme_fc_delete_association(ctrl);
+ cancel_work_sync(&ctrl->ioerr_work);
}
static void
@@ -3322,7 +3323,6 @@ nvme_fc_reset_ctrl_work(struct work_struct *work)
/* will block will waiting for io to terminate */
nvme_fc_delete_association(ctrl);
- cancel_work_sync(&ctrl->ioerr_work);
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING))
dev_err(ctrl->ctrl.device,
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 7a6827306e74..03df42e613f0 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -324,7 +324,7 @@ static void nvme_dbbuf_set(struct nvme_dev *dev)
/* Free memory and continue on */
nvme_dbbuf_dma_free(dev);
- for (i = 1; i <= dev->online_queues; i++)
+ for (i = 1; i < dev->online_queues; i++)
nvme_dbbuf_free(&dev->queues[i]);
}
}
@@ -1097,7 +1097,8 @@ static int nvme_poll(struct blk_mq_hw_ctx *hctx)
struct nvme_queue *nvmeq = hctx->driver_data;
bool found;
- if (!nvme_cqe_pending(nvmeq))
+ if (!test_bit(NVMEQ_POLLED, &nvmeq->flags) ||
+ !nvme_cqe_pending(nvmeq))
return 0;
spin_lock(&nvmeq->cq_poll_lock);
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index 5d8e57e5fdb1..6db9dcdbb3c3 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -300,7 +300,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
{
struct bio_vec *iov = cmd->iov;
struct scatterlist *sg;
- u32 length, offset, sg_offset;
+ u32 length, offset, sg_offset, iov_len;
unsigned int sg_remaining;
int nr_pages;
@@ -317,8 +317,6 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
sg_remaining = cmd->req.sg_cnt - cmd->sg_idx;
while (length) {
- u32 iov_len = min_t(u32, length, sg->length - sg_offset);
-
if (!sg_remaining) {
nvmet_tcp_fatal_error(cmd->queue);
return;
@@ -328,6 +326,8 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
return;
}
+ iov_len = min_t(u32, length, sg->length - sg_offset);
+
iov->bv_page = sg_page(sg);
iov->bv_len = iov_len;
iov->bv_offset = sg->offset + sg_offset;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index de500afdcf97..fe15e59e7c56 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -1601,14 +1601,6 @@ static int pci_dma_configure(struct device *dev)
ret = acpi_dma_configure(dev, acpi_get_dma_attr(adev));
}
- /*
- * Attempt to enable ACS regardless of capability because some Root
- * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have
- * the standard ACS capability but still support ACS via those
- * quirks.
- */
- pci_enable_acs(to_pci_dev(dev));
-
pci_put_host_bridge_device(bridge);
return ret;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 82bde2a92cf6..c25bb6bbc6d9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -894,7 +894,7 @@ static void pci_std_enable_acs(struct pci_dev *dev)
* pci_enable_acs - enable ACS if hardware support it
* @dev: the PCI device
*/
-void pci_enable_acs(struct pci_dev *dev)
+static void pci_enable_acs(struct pci_dev *dev)
{
if (!pci_acs_enable)
goto disable_acs_redir;
@@ -3548,6 +3548,14 @@ bool pci_acs_path_enabled(struct pci_dev *start,
void pci_acs_init(struct pci_dev *dev)
{
dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+
+ /*
+ * Attempt to enable ACS regardless of capability because some Root
+ * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have
+ * the standard ACS capability but still support ACS via those
+ * quirks.
+ */
+ pci_enable_acs(dev);
}
/**
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 5079800f56ce..c2fd92a9ee1a 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -547,7 +547,6 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
}
void pci_acs_init(struct pci_dev *dev);
-void pci_enable_acs(struct pci_dev *dev);
#ifdef CONFIG_PCI_QUIRKS
int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
int pci_dev_specific_enable_acs(struct pci_dev *dev);
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index ea01a121b8fc..5166a115879e 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -9,6 +9,7 @@
* Copyright (C) 2014 Cogent Embedded, Inc.
*/
+#include <linux/cleanup.h>
#include <linux/extcon-provider.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -98,7 +99,6 @@ struct rcar_gen3_phy {
struct rcar_gen3_chan *ch;
u32 int_enable_bits;
bool initialized;
- bool otg_initialized;
bool powered;
};
@@ -109,9 +109,8 @@ struct rcar_gen3_chan {
struct rcar_gen3_phy rphys[NUM_OF_PHYS];
struct regulator *vbus;
struct work_struct work;
- struct mutex lock; /* protects rphys[...].powered */
+ spinlock_t lock; /* protects access to hardware and driver data structure. */
enum usb_dr_mode dr_mode;
- int irq;
bool extcon_host;
bool is_otg_channel;
bool uses_otg_pins;
@@ -288,16 +287,16 @@ static bool rcar_gen3_is_any_rphy_initialized(struct rcar_gen3_chan *ch)
return false;
}
-static bool rcar_gen3_needs_init_otg(struct rcar_gen3_chan *ch)
+static bool rcar_gen3_is_any_otg_rphy_initialized(struct rcar_gen3_chan *ch)
{
- int i;
+ enum rcar_gen3_phy_index i;
- for (i = 0; i < NUM_OF_PHYS; i++) {
- if (ch->rphys[i].otg_initialized)
- return false;
+ for (i = PHY_INDEX_BOTH_HC; i <= PHY_INDEX_EHCI; i++) {
+ if (ch->rphys[i].initialized)
+ return true;
}
- return true;
+ return false;
}
static bool rcar_gen3_are_all_rphys_power_off(struct rcar_gen3_chan *ch)
@@ -319,7 +318,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
bool is_b_device;
enum phy_mode cur_mode, new_mode;
- if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch))
+ guard(spinlock_irqsave)(&ch->lock);
+
+ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch))
return -EIO;
if (sysfs_streq(buf, "host"))
@@ -357,7 +358,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
{
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
- if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch))
+ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch))
return -EIO;
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
@@ -370,6 +371,9 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
void __iomem *usb2_base = ch->base;
u32 val;
+ if (!ch->is_otg_channel || rcar_gen3_is_any_otg_rphy_initialized(ch))
+ return;
+
/* Should not use functions of read-modify-write a register */
val = readl(usb2_base + USB2_LINECTRL1);
val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN |
@@ -394,16 +398,29 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
{
struct rcar_gen3_chan *ch = _ch;
void __iomem *usb2_base = ch->base;
- u32 status = readl(usb2_base + USB2_OBINTSTA);
+ struct device *dev = ch->dev;
irqreturn_t ret = IRQ_NONE;
+ u32 status;
+
+ pm_runtime_get_noresume(dev);
+
+ if (pm_runtime_suspended(dev))
+ goto rpm_put;
+
+ spin_lock(&ch->lock);
+ status = readl(usb2_base + USB2_OBINTSTA);
if (status & USB2_OBINT_BITS) {
- dev_vdbg(ch->dev, "%s: %08x\n", __func__, status);
+ dev_vdbg(dev, "%s: %08x\n", __func__, status);
writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
rcar_gen3_device_recognition(ch);
ret = IRQ_HANDLED;
}
+ spin_unlock(&ch->lock);
+
+rpm_put:
+ pm_runtime_put_noidle(dev);
return ret;
}
@@ -413,17 +430,8 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
struct rcar_gen3_chan *channel = rphy->ch;
void __iomem *usb2_base = channel->base;
u32 val;
- int ret;
- if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) {
- INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
- ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq,
- IRQF_SHARED, dev_name(channel->dev), channel);
- if (ret < 0) {
- dev_err(channel->dev, "No irq handler (%d)\n", channel->irq);
- return ret;
- }
- }
+ guard(spinlock_irqsave)(&channel->lock);
/* Initialize USB2 part */
val = readl(usb2_base + USB2_INT_ENABLE);
@@ -435,12 +443,9 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
}
- /* Initialize otg part */
- if (channel->is_otg_channel) {
- if (rcar_gen3_needs_init_otg(channel))
- rcar_gen3_init_otg(channel);
- rphy->otg_initialized = true;
- }
+ /* Initialize otg part (only if we initialize a PHY with IRQs). */
+ if (rphy->int_enable_bits)
+ rcar_gen3_init_otg(channel);
rphy->initialized = true;
@@ -454,10 +459,9 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
void __iomem *usb2_base = channel->base;
u32 val;
- rphy->initialized = false;
+ guard(spinlock_irqsave)(&channel->lock);
- if (channel->is_otg_channel)
- rphy->otg_initialized = false;
+ rphy->initialized = false;
val = readl(usb2_base + USB2_INT_ENABLE);
val &= ~rphy->int_enable_bits;
@@ -465,9 +469,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
val &= ~USB2_INT_ENABLE_UCOM_INTEN;
writel(val, usb2_base + USB2_INT_ENABLE);
- if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel))
- free_irq(channel->irq, channel);
-
return 0;
}
@@ -476,19 +477,21 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
struct rcar_gen3_phy *rphy = phy_get_drvdata(p);
struct rcar_gen3_chan *channel = rphy->ch;
void __iomem *usb2_base = channel->base;
+ unsigned long flags;
u32 val;
int ret = 0;
- mutex_lock(&channel->lock);
- if (!rcar_gen3_are_all_rphys_power_off(channel))
- goto out;
-
if (channel->vbus) {
ret = regulator_enable(channel->vbus);
if (ret)
- goto out;
+ return ret;
}
+ spin_lock_irqsave(&channel->lock, flags);
+
+ if (!rcar_gen3_are_all_rphys_power_off(channel))
+ goto out;
+
val = readl(usb2_base + USB2_USBCTR);
val |= USB2_USBCTR_PLL_RST;
writel(val, usb2_base + USB2_USBCTR);
@@ -498,7 +501,8 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
out:
/* The powered flag should be set for any other phys anyway */
rphy->powered = true;
- mutex_unlock(&channel->lock);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
return 0;
}
@@ -507,20 +511,23 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
{
struct rcar_gen3_phy *rphy = phy_get_drvdata(p);
struct rcar_gen3_chan *channel = rphy->ch;
+ unsigned long flags;
int ret = 0;
- mutex_lock(&channel->lock);
+ spin_lock_irqsave(&channel->lock, flags);
rphy->powered = false;
- if (!rcar_gen3_are_all_rphys_power_off(channel))
- goto out;
+ if (rcar_gen3_are_all_rphys_power_off(channel)) {
+ u32 val = readl(channel->base + USB2_USBCTR);
+
+ val |= USB2_USBCTR_PLL_RST;
+ writel(val, channel->base + USB2_USBCTR);
+ }
+ spin_unlock_irqrestore(&channel->lock, flags);
if (channel->vbus)
ret = regulator_disable(channel->vbus);
-out:
- mutex_unlock(&channel->lock);
-
return ret;
}
@@ -616,7 +623,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
struct phy_provider *provider;
struct resource *res;
const struct phy_ops *phy_usb2_ops;
- int ret = 0, i;
+ int ret = 0, i, irq;
if (!dev->of_node) {
dev_err(dev, "This driver needs device tree\n");
@@ -632,8 +639,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (IS_ERR(channel->base))
return PTR_ERR(channel->base);
- /* get irq number here and request_irq for OTG in phy_init */
- channel->irq = platform_get_irq_optional(pdev, 0);
channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node);
if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
channel->is_otg_channel = true;
@@ -662,7 +667,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
goto error;
}
- mutex_init(&channel->lock);
+ spin_lock_init(&channel->lock);
+
for (i = 0; i < NUM_OF_PHYS; i++) {
channel->rphys[i].phy = devm_phy_create(dev, NULL,
phy_usb2_ops);
@@ -688,6 +694,20 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, channel);
channel->dev = dev;
+ irq = platform_get_irq_optional(pdev, 0);
+ if (irq < 0 && irq != -ENXIO) {
+ ret = irq;
+ goto error;
+ } else if (irq > 0) {
+ INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
+ ret = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
+ IRQF_SHARED, dev_name(dev), channel);
+ if (ret < 0) {
+ dev_err(dev, "Failed to request irq (%d)\n", irq);
+ goto error;
+ }
+ }
+
provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate);
if (IS_ERR(provider)) {
dev_err(dev, "Failed to register PHY provider\n");
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 5536b8f4bfd1..3c0aec368ea9 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -799,6 +799,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
dev_err(dev,
"%s: Reading \"reg\" from \"%s\" failed: %d\n",
__func__, subnode->name, ret);
+ of_node_put(serdes);
return ret;
}
of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes);
@@ -811,6 +812,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
wiz->lane_phy_type[i] = phy_type;
}
+ of_node_put(serdes);
return 0;
}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 730581d13064..804547558318 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -1111,9 +1111,12 @@ int mtk_pctrl_init(struct platform_device *pdev,
goto chip_error;
}
- ret = mtk_eint_init(pctl, pdev);
- if (ret)
- goto chip_error;
+ /* Only initialize EINT if we have EINT pins */
+ if (data->eint_hw.ap_num > 0) {
+ ret = mtk_eint_init(pctl, pdev);
+ if (ret)
+ goto chip_error;
+ }
return 0;
diff --git a/drivers/platform/olpc/olpc-xo175-ec.c b/drivers/platform/olpc/olpc-xo175-ec.c
index 0d46706afd2d..d8a9a215a14c 100644
--- a/drivers/platform/olpc/olpc-xo175-ec.c
+++ b/drivers/platform/olpc/olpc-xo175-ec.c
@@ -482,7 +482,7 @@ static int olpc_xo175_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *resp,
dev_dbg(dev, "CMD %x, %zd bytes expected\n", cmd, resp_len);
if (inlen > 5) {
- dev_err(dev, "command len %zd too big!\n", resp_len);
+ dev_err(dev, "command len %zd too big!\n", inlen);
return -EOVERFLOW;
}
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index 9bc2652b15e7..12d695adf3f7 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -93,6 +93,13 @@ static const struct dmi_system_id button_array_table[] = {
DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Tablet Gen 2"),
},
},
+ {
+ .ident = "Lenovo ThinkPad X1 Fold 16 Gen 1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Fold 16 Gen 1"),
+ },
+ },
{
.ident = "Microsoft Surface Go 3",
.matches = {
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index d18b6ddba982..1dbf19fe8559 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -9412,14 +9412,16 @@ static int tpacpi_battery_get(int what, int battery, int *ret)
{
switch (what) {
case THRESHOLD_START:
- if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, ret, battery))
+ if (!battery_info.batteries[battery].start_support ||
+ ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, ret, battery)))
return -ENODEV;
/* The value is in the low 8 bits of the response */
*ret = *ret & 0xFF;
return 0;
case THRESHOLD_STOP:
- if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_STOP, ret, battery))
+ if (!battery_info.batteries[battery].stop_support ||
+ ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_STOP, ret, battery)))
return -ENODEV;
/* Value is in lower 8 bits */
*ret = *ret & 0xFF;
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index eff29dc7e2c6..13ba93e7ed8f 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -402,6 +402,16 @@ static const struct ts_dmi_data gdix1002_00_upside_down_data = {
.properties = gdix1001_upside_down_props,
};
+static const struct property_entry gdix1001_y_inverted_props[] = {
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ { }
+};
+
+static const struct ts_dmi_data gdix1001_y_inverted_data = {
+ .acpi_name = "GDIX1001",
+ .properties = gdix1001_y_inverted_props,
+};
+
static const struct property_entry gp_electronic_t701_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
@@ -1552,6 +1562,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_SKU, "PN20170413488"),
},
},
+ {
+ /* SUPI S10 */
+ .driver_data = (void *)&gdix1001_y_inverted_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SUPI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "S10"),
+ },
+ },
{
/* Techbite Arc 11.6 */
.driver_data = (void *)&techbite_arc_11_6_data,
diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
index b3d206ebb289..6f2f097b677d 100644
--- a/drivers/regulator/pca9450-regulator.c
+++ b/drivers/regulator/pca9450-regulator.c
@@ -704,11 +704,6 @@ static int pca9450_i2c_probe(struct i2c_client *i2c,
unsigned int device_id, i;
int ret;
- if (!i2c->irq) {
- dev_err(&i2c->dev, "No IRQ configured?\n");
- return -EINVAL;
- }
-
pca9450 = devm_kzalloc(&i2c->dev, sizeof(struct pca9450), GFP_KERNEL);
if (!pca9450)
return -ENOMEM;
@@ -775,23 +770,25 @@ static int pca9450_i2c_probe(struct i2c_client *i2c,
}
}
- ret = devm_request_threaded_irq(pca9450->dev, pca9450->irq, NULL,
- pca9450_irq_handler,
- (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
- "pca9450-irq", pca9450);
- if (ret != 0) {
- dev_err(pca9450->dev, "Failed to request IRQ: %d\n",
- pca9450->irq);
- return ret;
- }
- /* Unmask all interrupt except PWRON/WDOG/RSVD */
- ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK,
- IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS |
- IRQ_THERM_105 | IRQ_THERM_125,
- IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD);
- if (ret) {
- dev_err(&i2c->dev, "Unmask irq error\n");
- return ret;
+ if (pca9450->irq) {
+ ret = devm_request_threaded_irq(pca9450->dev, pca9450->irq, NULL,
+ pca9450_irq_handler,
+ (IRQF_TRIGGER_LOW | IRQF_ONESHOT),
+ "pca9450-irq", pca9450);
+ if (ret != 0) {
+ dev_err(pca9450->dev, "Failed to request IRQ: %d\n",
+ pca9450->irq);
+ return ret;
+ }
+ /* Unmask all interrupt except PWRON/WDOG/RSVD */
+ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK,
+ IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS |
+ IRQ_THERM_105 | IRQ_THERM_125,
+ IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD);
+ if (ret) {
+ dev_err(&i2c->dev, "Unmask irq error\n");
+ return ret;
+ }
}
/* Clear PRESET_EN bit in BUCK123_DVS to use DVS registers */
diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
index c348ea35e47c..be3a2fa12394 100644
--- a/drivers/remoteproc/qcom_sysmon.c
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -196,7 +196,7 @@ static struct qmi_elem_info ssctl_shutdown_resp_ei[] = {
};
struct ssctl_subsys_event_req {
- u8 subsys_name_len;
+ u32 subsys_name_len;
char subsys_name[SSCTL_SUBSYS_NAME_LENGTH];
u32 event;
u8 evt_driven_valid;
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c
index ffab935ddd95..d8046e589742 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -1680,11 +1680,13 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
memset(ci, 0, sizeof(*ci));
- /* get first info from zcrypt device driver about this apqn */
- rc = zcrypt_device_status_ext(cardnr, domain, &devstat);
- if (rc)
- return rc;
- ci->hwtype = devstat.hwtype;
+ /* if specific domain given, fetch status and hw info for this apqn */
+ if (domain != AUTOSEL_DOM) {
+ rc = zcrypt_device_status_ext(cardnr, domain, &devstat);
+ if (rc)
+ return rc;
+ ci->hwtype = devstat.hwtype;
+ }
/* prep page for rule array and var array use */
pg = (u8 *) __get_free_page(GFP_KERNEL);
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
index f5195bca1d85..20e17dc61530 100644
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -84,8 +84,7 @@ static ssize_t cca_serialnr_show(struct device *dev,
memset(&ci, 0, sizeof(ci));
- if (ap_domain_index >= 0)
- cca_get_info(ac->id, ap_domain_index, &ci, zc->online);
+ cca_get_info(ac->id, AUTOSEL_DOM, &ci, zc->online);
return scnprintf(buf, PAGE_SIZE, "%s\n", ci.serial);
}
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index b793e342ab7c..0a3da58d9522 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -4238,7 +4238,8 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
switch (mad_status) {
case IBMVFC_MAD_SUCCESS:
ibmvfc_dbg(vhost, "Discover Targets succeeded\n");
- vhost->num_targets = be32_to_cpu(rsp->num_written);
+ vhost->num_targets = min_t(u32, be32_to_cpu(rsp->num_written),
+ max_targets);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);
break;
case IBMVFC_MAD_FAILED:
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 5f2009327a59..0f144fbf2a6c 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -10558,6 +10558,8 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
iounmap(phba->sli4_hba.conf_regs_memmap_p);
if (phba->sli4_hba.dpp_regs_memmap_p)
iounmap(phba->sli4_hba.dpp_regs_memmap_p);
+ if (phba->sli4_hba.dpp_regs_memmap_wc_p)
+ iounmap(phba->sli4_hba.dpp_regs_memmap_wc_p);
break;
case LPFC_SLI_INTF_IF_TYPE_1:
default:
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 49931577da38..0b3242b058b9 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -14966,6 +14966,32 @@ lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset)
return NULL;
}
+static __maybe_unused void __iomem *
+lpfc_dpp_wc_map(struct lpfc_hba *phba, uint8_t dpp_barset)
+{
+
+ /* DPP region is supposed to cover 64-bit BAR2 */
+ if (dpp_barset != WQ_PCI_BAR_4_AND_5) {
+ lpfc_log_msg(phba, KERN_WARNING, LOG_INIT,
+ "3273 dpp_barset x%x != WQ_PCI_BAR_4_AND_5\n",
+ dpp_barset);
+ return NULL;
+ }
+
+ if (!phba->sli4_hba.dpp_regs_memmap_wc_p) {
+ void __iomem *dpp_map;
+
+ dpp_map = ioremap_wc(phba->pci_bar2_map,
+ pci_resource_len(phba->pcidev,
+ PCI_64BIT_BAR4));
+
+ if (dpp_map)
+ phba->sli4_hba.dpp_regs_memmap_wc_p = dpp_map;
+ }
+
+ return phba->sli4_hba.dpp_regs_memmap_wc_p;
+}
+
/**
* lpfc_modify_hba_eq_delay - Modify Delay Multiplier on EQs
* @phba: HBA structure that EQs are on.
@@ -15876,9 +15902,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
uint8_t dpp_barset;
uint32_t dpp_offset;
uint8_t wq_create_version;
-#ifdef CONFIG_X86
- unsigned long pg_addr;
-#endif
/* sanity check on queue memory */
if (!wq || !cq)
@@ -16070,14 +16093,15 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
#ifdef CONFIG_X86
/* Enable combined writes for DPP aperture */
- pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK;
- rc = set_memory_wc(pg_addr, 1);
- if (rc) {
+ bar_memmap_p = lpfc_dpp_wc_map(phba, dpp_barset);
+ if (!bar_memmap_p) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3272 Cannot setup Combined "
"Write on WQ[%d] - disable DPP\n",
wq->queue_id);
phba->cfg_enable_dpp = 0;
+ } else {
+ wq->dpp_regaddr = bar_memmap_p + dpp_offset;
}
#else
phba->cfg_enable_dpp = 0;
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 100cb1a94811..80c168b2a2dd 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -772,6 +772,9 @@ struct lpfc_sli4_hba {
void __iomem *dpp_regs_memmap_p; /* Kernel memory mapped address for
* dpp registers
*/
+ void __iomem *dpp_regs_memmap_wc_p;/* Kernel memory mapped address for
+ * dpp registers with write combining
+ */
union {
struct {
/* IF Type 0, BAR 0 PCI cfg space reg mem map */
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 8d570632982f..e69d1c0ea450 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -310,6 +310,7 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
rcu_read_lock();
__clear_bit(SCMD_STATE_INFLIGHT, &cmd->state);
if (unlikely(scsi_host_in_recovery(shost))) {
+ unsigned int busy;
/*
* Ensure the clear of SCMD_STATE_INFLIGHT is visible to
* other CPUs before counting busy requests. Otherwise,
@@ -318,7 +319,7 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
*/
smp_mb();
- unsigned int busy = scsi_host_busy(shost);
+ busy = scsi_host_busy(shost);
spin_lock_irqsave(shost->host_lock, flags);
if (shost->host_failed || shost->host_eh_scheduled)
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 1eb58f8765e2..8766ec93652c 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1703,7 +1703,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
break;
default:
- if (channel < shost->max_channel) {
+ if (channel <= shost->max_channel) {
res = scsi_scan_host_selected(shost, channel, id, lun,
SCSI_SCAN_MANUAL);
} else {
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 6a1428d453f3..38eac74f7f75 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -184,7 +184,7 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
unsigned char *type_ptr = ses_dev->page1_types;
unsigned char *desc_ptr = ses_dev->page2 + 8;
- if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len) < 0)
+ if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len))
return NULL;
for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) {
@@ -497,9 +497,8 @@ struct efd {
};
static int ses_enclosure_find_by_addr(struct enclosure_device *edev,
- void *data)
+ struct efd *efd)
{
- struct efd *efd = data;
int i;
struct ses_component *scomp;
@@ -652,7 +651,7 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
if (efd.addr) {
efd.dev = &sdev->sdev_gendev;
- enclosure_for_each_device(ses_enclosure_find_by_addr, &efd);
+ ses_enclosure_find_by_addr(edev, &efd);
}
}
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 917ba169d418..d91e022a0154 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1832,8 +1832,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
cmd_request->payload_sz = payload_sz;
/* Invokes the vsc to start an IO */
- ret = storvsc_do_io(dev, cmd_request, get_cpu());
- put_cpu();
+ migrate_disable();
+ ret = storvsc_do_io(dev, cmd_request, smp_processor_id());
+ migrate_enable();
if (ret == -EAGAIN) {
if (payload_sz > sizeof(cmd_request->mpb))
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c5f41023c71b..c7bf0e6bc303 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3880,14 +3880,6 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
spin_unlock_irqrestore(hba->host->host_lock, flags);
mutex_unlock(&hba->uic_cmd_mutex);
- /*
- * If the h8 exit fails during the runtime resume process, it becomes
- * stuck and cannot be recovered through the error handler. To fix
- * this, use link recovery instead of the error handler.
- */
- if (ret && hba->pm_op_in_progress)
- ret = ufshcd_link_recovery(hba);
-
return ret;
}
@@ -8727,7 +8719,15 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
} else {
dev_err(hba->dev, "%s: hibern8 exit failed %d\n",
__func__, ret);
- goto vendor_suspend;
+ /*
+ * If the h8 exit fails during the runtime resume
+ * process, it becomes stuck and cannot be recovered
+ * through the error handler. To fix this, use link
+ * recovery instead of the error handler.
+ */
+ ret = ufshcd_link_recovery(hba);
+ if (ret)
+ goto vendor_suspend;
}
} else if (ufshcd_is_link_off(hba)) {
/*
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
index 1e0041ec8132..0e50f9e0ada8 100644
--- a/drivers/soc/bcm/bcm2835-power.c
+++ b/drivers/soc/bcm/bcm2835-power.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/mfd/bcm2835-pm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -150,40 +151,34 @@ struct bcm2835_power {
static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
{
- u64 start;
+ u32 val;
if (!reg)
return 0;
- start = ktime_get_ns();
-
/* Enable the module's async AXI bridges. */
ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
- while (ASB_READ(reg) & ASB_ACK) {
- cpu_relax();
- if (ktime_get_ns() - start >= 1000)
- return -ETIMEDOUT;
- }
+
+ if (readl_poll_timeout_atomic(power->asb + reg, val,
+ !(val & ASB_ACK), 0, 5))
+ return -ETIMEDOUT;
return 0;
}
static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
{
- u64 start;
+ u32 val;
if (!reg)
return 0;
- start = ktime_get_ns();
-
/* Enable the module's async AXI bridges. */
ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
- while (!(ASB_READ(reg) & ASB_ACK)) {
- cpu_relax();
- if (ktime_get_ns() - start >= 1000)
- return -ETIMEDOUT;
- }
+
+ if (readl_poll_timeout_atomic(power->asb + reg, val,
+ !!(val & ASB_ACK), 0, 5))
+ return -ETIMEDOUT;
return 0;
}
@@ -566,11 +561,11 @@ static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
switch (id) {
case BCM2835_RESET_V3D:
- return !PM_READ(PM_GRAFX & PM_V3DRSTN);
+ return !(PM_READ(PM_GRAFX) & PM_V3DRSTN);
case BCM2835_RESET_H264:
- return !PM_READ(PM_IMAGE & PM_H264RSTN);
+ return !(PM_READ(PM_IMAGE) & PM_H264RSTN);
case BCM2835_RESET_ISP:
- return !PM_READ(PM_IMAGE & PM_ISPRSTN);
+ return !(PM_READ(PM_IMAGE) & PM_ISPRSTN);
default:
return -EINVAL;
}
diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 7abc9b6a04ab..0309ed2df0d7 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1827,6 +1827,8 @@ EXPORT_SYMBOL(qman_create_fq);
void qman_destroy_fq(struct qman_fq *fq)
{
+ int leaked;
+
/*
* We don't need to lock the FQ as it is a pre-condition that the FQ be
* quiesced. Instead, run some checks.
@@ -1834,11 +1836,29 @@ void qman_destroy_fq(struct qman_fq *fq)
switch (fq->state) {
case qman_fq_state_parked:
case qman_fq_state_oos:
- if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID))
- qman_release_fqid(fq->fqid);
+ /*
+ * There's a race condition here on releasing the fqid,
+ * setting the fq_table to NULL, and freeing the fqid.
+ * To prevent it, this order should be respected:
+ */
+ if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID)) {
+ leaked = qman_shutdown_fq(fq->fqid);
+ if (leaked)
+ pr_debug("FQID %d leaked\n", fq->fqid);
+ }
DPAA_ASSERT(fq_table[fq->idx]);
fq_table[fq->idx] = NULL;
+
+ if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID) && !leaked) {
+ /*
+ * fq_table[fq->idx] should be set to null before
+ * freeing fq->fqid otherwise it could by allocated by
+ * qman_alloc_fqid() while still being !NULL
+ */
+ smp_wmb();
+ gen_pool_free(qm_fqalloc, fq->fqid | DPAA_GENALLOC_OFF, 1);
+ }
return;
default:
break;
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 319cd96bd201..540815ae49e7 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -914,7 +914,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
enable_irq(irq);
}
- ret = devm_spi_register_controller(&pdev->dev, controller);
+ ret = spi_register_controller(controller);
if (ret < 0) {
dev_err_probe(&pdev->dev, ret, "spi_register_controller error\n");
goto free_dma;
@@ -943,6 +943,7 @@ static int fsl_lpspi_remove(struct platform_device *pdev)
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
+ spi_unregister_controller(controller);
fsl_lpspi_dma_exit(controller);
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index fd098e62a308..67222f170fa9 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -1000,6 +1000,14 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = -EIO;
goto out;
}
+ if (IS_ENABLED(CONFIG_LOCKDEP)) {
+ /*
+ * dev->spinlock is for private use by the attached low-level
+ * driver. Reinitialize it to stop lock-dependency tracking
+ * between attachments to different low-level drivers.
+ */
+ spin_lock_init(&dev->spinlock);
+ }
dev->driver = driv;
dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr
: dev->driver->driver_name;
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 5906f32aa01f..3482fd74edb4 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -176,6 +176,18 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
? current_range_type : voltage_range_type;
}
+ /*
+ * Check if hardware is present before attempting any I/O operations.
+ * Reading 0xff from status register typically indicates no hardware
+ * on the bus (floating bus reads as all 1s).
+ */
+ if (inb(dev->iobase + DT2815_STATUS) == 0xff) {
+ dev_err(dev->class_dev,
+ "No hardware detected at I/O base 0x%lx\n",
+ dev->iobase);
+ return -ENODEV;
+ }
+
/* Init the 2815 */
outb(0x00, dev->iobase + DT2815_STATUS);
for (i = 0; i < 100; i++) {
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index 0d3d4cafce2e..ee5faea858e6 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -316,6 +316,18 @@ static int me4000_xilinx_download(struct comedi_device *dev,
unsigned int val;
unsigned int i;
+ /* Get data stream length from header. */
+ if (size >= 4) {
+ file_length = (((unsigned int)data[0] & 0xff) << 24) +
+ (((unsigned int)data[1] & 0xff) << 16) +
+ (((unsigned int)data[2] & 0xff) << 8) +
+ ((unsigned int)data[3] & 0xff);
+ }
+ if (size < 16 || file_length > size - 16) {
+ dev_err(dev->class_dev, "Firmware length inconsistency\n");
+ return -EINVAL;
+ }
+
if (!xilinx_iobase)
return -ENODEV;
@@ -347,10 +359,6 @@ static int me4000_xilinx_download(struct comedi_device *dev,
outl(val, devpriv->plx_regbase + PLX9052_CNTRL);
/* Download Xilinx firmware */
- file_length = (((unsigned int)data[0] & 0xff) << 24) +
- (((unsigned int)data[1] & 0xff) << 16) +
- (((unsigned int)data[2] & 0xff) << 8) +
- ((unsigned int)data[3] & 0xff);
usleep_range(10, 1000);
for (i = 0; i < file_length; i++) {
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index ef18e387471b..adfd9daf738d 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -345,6 +345,25 @@ static int me2600_xilinx_download(struct comedi_device *dev,
unsigned int file_length;
unsigned int i;
+ /*
+ * Format of the firmware
+ * Build longs from the byte-wise coded header
+ * Byte 1-3: length of the array
+ * Byte 4-7: version
+ * Byte 8-11: date
+ * Byte 12-15: reserved
+ */
+ if (size >= 4) {
+ file_length = (((unsigned int)data[0] & 0xff) << 24) +
+ (((unsigned int)data[1] & 0xff) << 16) +
+ (((unsigned int)data[2] & 0xff) << 8) +
+ ((unsigned int)data[3] & 0xff);
+ }
+ if (size < 16 || file_length > size - 16) {
+ dev_err(dev->class_dev, "Firmware length inconsistency\n");
+ return -EINVAL;
+ }
+
/* disable irq's on PLX */
writel(0x00, devpriv->plx_regbase + PLX9052_INTCSR);
@@ -358,22 +377,6 @@ static int me2600_xilinx_download(struct comedi_device *dev,
writeb(0x00, dev->mmio + 0x0);
sleep(1);
- /*
- * Format of the firmware
- * Build longs from the byte-wise coded header
- * Byte 1-3: length of the array
- * Byte 4-7: version
- * Byte 8-11: date
- * Byte 12-15: reserved
- */
- if (size < 16)
- return -EINVAL;
-
- file_length = (((unsigned int)data[0] & 0xff) << 24) +
- (((unsigned int)data[1] & 0xff) << 16) +
- (((unsigned int)data[2] & 0xff) << 8) +
- ((unsigned int)data[3] & 0xff);
-
/*
* Loop for writing firmware byte by byte to xilinx
* Firmware data start at offset 16
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index dffce1aa3e69..b347878b1359 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -699,7 +699,8 @@ static int atmio16d_attach(struct comedi_device *dev,
static void atmio16d_detach(struct comedi_device *dev)
{
- reset_atmio16d(dev);
+ if (dev->private)
+ reset_atmio16d(dev);
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
index c43cca4a3828..ac6e947214cb 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
@@ -194,21 +194,25 @@ u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, u
cnt = 0;
- while (cnt < in_len) {
+ while (cnt + 2 <= in_len) {
+ u8 ie_len = in_ie[cnt + 1];
+
+ if (cnt + 2 + ie_len > in_len)
+ break;
+
if (eid == in_ie[cnt]
- && (!oui || !memcmp(&in_ie[cnt+2], oui, oui_len))) {
+ && (!oui || (ie_len >= oui_len && !memcmp(&in_ie[cnt + 2], oui, oui_len)))) {
target_ie = &in_ie[cnt];
if (ie)
- memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2);
+ memcpy(ie, &in_ie[cnt], ie_len + 2);
if (ielen)
- *ielen = in_ie[cnt+1]+2;
+ *ielen = ie_len + 2;
break;
- } else {
- cnt += in_ie[cnt+1]+2; /* goto next */
}
+ cnt += ie_len + 2; /* goto next */
}
return target_ie;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index 364e6cd76054..7cc3a0e4e089 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -967,10 +967,12 @@ static void find_network(struct adapter *adapter)
struct wlan_network *tgt_network = &pmlmepriv->cur_network;
pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
- if (pwlan)
- pwlan->fixed = false;
- else
+ if (!pwlan) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_assoc_resources : pwlan == NULL\n\n"));
+ return;
+ }
+
+ pwlan->fixed = false;
if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) &&
(adapter->stapriv.asoc_sta_count == 1))
@@ -2257,7 +2259,10 @@ int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_
while (i < in_len) {
ielength = initial_out_len;
- if (in_ie[i] == 0xDD && in_ie[i+2] == 0x00 && in_ie[i+3] == 0x50 && in_ie[i+4] == 0xF2 && in_ie[i+5] == 0x02 && i+5 < in_len) { /* WMM element ID and OUI */
+ if (i + 5 < in_len &&
+ in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 &&
+ in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 &&
+ in_ie[i + 5] == 0x02) {
for (j = i; j < i + 9; j++) {
out_ie[ielength] = in_ie[j];
ielength++;
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index 8a8cbebde98f..03421fc5e583 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -899,7 +899,7 @@ static bool nhi_wake_supported(struct pci_dev *pdev)
* If power rails are sustainable for wakeup from S4 this
* property is set by the BIOS.
*/
- if (device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
+ if (!device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
return !!val;
return true;
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index 47ae1fbe805b..04d8c6dd619f 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -148,7 +148,22 @@ void serial8250_tx_dma_flush(struct uart_8250_port *p)
*/
dma->tx_size = 0;
+ /*
+ * We can't use `dmaengine_terminate_sync` because `uart_flush_buffer` is
+ * holding the uart port spinlock.
+ */
dmaengine_terminate_async(dma->txchan);
+
+ /*
+ * The callback might or might not run. If it doesn't run, we need to ensure
+ * that `tx_running` is cleared so that we can schedule new transactions.
+ * If it does run, then the zombie callback will clear `tx_running` again
+ * and perform a no-op since `tx_size` was cleared above.
+ *
+ * In either case, we ASSUME the DMA transaction will terminate before we
+ * issue a new `serial8250_tx_dma`.
+ */
+ dma->tx_running = 0;
}
int serial8250_rx_dma(struct uart_8250_port *p)
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index fd34fbc9cdee..964328adba6a 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -57,6 +57,8 @@ struct serial_private {
};
#define PCI_DEVICE_ID_HPE_PCI_SERIAL 0x37e
+#define PCIE_VENDOR_ID_ASIX 0x125B
+#define PCIE_DEVICE_ID_AX99100 0x9100
static const struct pci_device_id pci_use_msi[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
@@ -69,6 +71,8 @@ static const struct pci_device_id pci_use_msi[] = {
0xA000, 0x1000) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL,
PCI_ANY_ID, PCI_ANY_ID) },
+ { PCI_DEVICE_SUB(PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
+ 0xA000, 0x1000) },
{ }
};
@@ -853,6 +857,7 @@ static int pci_netmos_init(struct pci_dev *dev)
case PCI_DEVICE_ID_NETMOS_9912:
case PCI_DEVICE_ID_NETMOS_9922:
case PCI_DEVICE_ID_NETMOS_9900:
+ case PCIE_DEVICE_ID_AX99100:
num_serial = pci_netmos_9900_numports(dev);
break;
@@ -2480,6 +2485,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.init = pci_netmos_init,
.setup = pci_netmos_9900_setup,
},
+ {
+ .vendor = PCIE_VENDOR_ID_ASIX,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_netmos_init,
+ .setup = pci_netmos_9900_setup,
+ },
/*
* EndRun Technologies
*/
@@ -5825,6 +5838,10 @@ static const struct pci_device_id serial_pci_tbl[] = {
0xA000, 0x3002,
0, 0, pbn_NETMOS9900_2s_115200 },
+ { PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
/*
* Best Connectivity and Rosewill PCI Multi I/O cards
*/
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index c65a190ac060..4b9c54ee00e8 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2485,6 +2485,12 @@ void serial8250_do_shutdown(struct uart_port *port)
* the IRQ chain.
*/
serial_port_in(port, UART_RX);
+ /*
+ * LCR writes on DW UART can trigger late (unmaskable) IRQs.
+ * Handle them before releasing the handler.
+ */
+ synchronize_irq(port->irq);
+
serial8250_rpm_put(up);
up->ops->release_irq(up);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 07543731bfa5..ff02753db5b4 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1218,6 +1218,12 @@ static int acm_probe(struct usb_interface *intf,
if (!data_interface || !control_interface)
return -ENODEV;
goto skip_normal_probe;
+ } else if (quirks == NO_UNION_12) {
+ data_interface = usb_ifnum_to_if(usb_dev, 2);
+ control_interface = usb_ifnum_to_if(usb_dev, 1);
+ if (!data_interface || !control_interface)
+ return -ENODEV;
+ goto skip_normal_probe;
}
/* normal probing*/
@@ -1379,6 +1385,8 @@ static int acm_probe(struct usb_interface *intf,
acm->ctrl_caps = h.usb_cdc_acm_descriptor->bmCapabilities;
if (quirks & NO_CAP_LINE)
acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
+ if (quirks & MISSING_CAP_BRK)
+ acm->ctrl_caps |= USB_CDC_CAP_BRK;
acm->ctrlsize = ctrlsize;
acm->readsize = readsize;
acm->rx_buflimit = num_rx_buf;
@@ -1747,6 +1755,9 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */
.driver_info = DISABLE_ECHO, /* Don't echo banner */
},
+ { USB_DEVICE(0x04b8, 0x0d12), /* EPSON HMD Com&Sens */
+ .driver_info = NO_UNION_12, /* union descriptor is garbage */
+ },
{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
@@ -1990,6 +2001,9 @@ static const struct usb_device_id acm_ids[] = {
.driver_info = IGNORE_DEVICE,
},
+ /* CH343 supports CAP_BRK, but doesn't advertise it */
+ { USB_DEVICE(0x1a86, 0x55d3), .driver_info = MISSING_CAP_BRK, },
+
/* control interfaces without any protocol set */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_PROTO_NONE) },
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 3aa7f0a3ad71..705ea2feeb40 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -141,3 +141,5 @@ struct acm {
#define CLEAR_HALT_CONDITIONS BIT(5)
#define SEND_ZERO_PACKET BIT(6)
#define DISABLE_ECHO BIT(7)
+#define MISSING_CAP_BRK BIT(8)
+#define NO_UNION_12 BIT(9)
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 26a59443d25f..62bf2c90decf 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -212,7 +212,8 @@ static void wdm_in_callback(struct urb *urb)
/* we may already be in overflow */
if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
memmove(desc->ubuf + desc->length, desc->inbuf, length);
- desc->length += length;
+ smp_wmb(); /* against wdm_read() */
+ WRITE_ONCE(desc->length, desc->length + length);
}
}
skip_error:
@@ -519,6 +520,7 @@ static ssize_t wdm_read
return -ERESTARTSYS;
cntr = READ_ONCE(desc->length);
+ smp_rmb(); /* against wdm_in_callback() */
if (cntr == 0) {
desc->read = 0;
retry:
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index ff706f48e0ad..fcd5c5b533e9 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -254,6 +254,9 @@ static int usbtmc_release(struct inode *inode, struct file *file)
list_del(&file_data->file_elem);
spin_unlock_irq(&file_data->data->dev_lock);
+
+ /* flush anchored URBs */
+ usbtmc_draw_down(file_data);
mutex_unlock(&file_data->data->io_mutex);
kref_put(&file_data->data->kref, usbtmc_delete);
@@ -696,7 +699,7 @@ static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
buffer[1] = data->bTag;
buffer[2] = ~data->bTag;
- retval = usb_bulk_msg(data->usb_dev,
+ retval = usb_bulk_msg_killable(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, USBTMC_HEADER_SIZE,
@@ -1316,7 +1319,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
buffer[11] = 0; /* Reserved */
/* Send bulk URB */
- retval = usb_bulk_msg(data->usb_dev,
+ retval = usb_bulk_msg_killable(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, USBTMC_HEADER_SIZE,
@@ -1388,7 +1391,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
actual = 0;
/* Send bulk URB */
- retval = usb_bulk_msg(data->usb_dev,
+ retval = usb_bulk_msg_killable(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev,
data->bulk_in),
buffer, bufsize, &actual,
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index 3c705f1bead8..ddb316dd2a82 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -288,10 +288,9 @@ struct ulpi *ulpi_register_interface(struct device *dev,
ulpi->ops = ops;
ret = ulpi_register(dev, ulpi);
- if (ret) {
- kfree(ulpi);
+ if (ret)
return ERR_PTR(ret);
- }
+
return ulpi;
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 059ea576c6c1..855d0e2eadb1 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -41,16 +41,19 @@ static void usb_api_blocking_completion(struct urb *urb)
/*
- * Starts urb and waits for completion or timeout. Note that this call
- * is NOT interruptible. Many device driver i/o requests should be
- * interruptible and therefore these drivers should implement their
- * own interruptible routines.
+ * Starts urb and waits for completion or timeout.
+ * Whether or not the wait is killable depends on the flag passed in.
+ * For example, compare usb_bulk_msg() and usb_bulk_msg_killable().
+ *
+ * For non-killable waits, we enforce a maximum limit on the timeout value.
*/
-static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length,
+ bool killable)
{
struct api_context ctx;
unsigned long expire;
int retval;
+ long rc;
init_completion(&ctx.done);
urb->context = &ctx;
@@ -59,13 +62,24 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
if (unlikely(retval))
goto out;
- expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
- if (!wait_for_completion_timeout(&ctx.done, expire)) {
+ if (!killable && (timeout <= 0 || timeout > USB_MAX_SYNCHRONOUS_TIMEOUT))
+ timeout = USB_MAX_SYNCHRONOUS_TIMEOUT;
+ expire = (timeout > 0) ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
+ if (killable)
+ rc = wait_for_completion_killable_timeout(&ctx.done, expire);
+ else
+ rc = wait_for_completion_timeout(&ctx.done, expire);
+ if (rc <= 0) {
usb_kill_urb(urb);
- retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
+ if (ctx.status != -ENOENT)
+ retval = ctx.status;
+ else if (rc == 0)
+ retval = -ETIMEDOUT;
+ else
+ retval = rc;
dev_dbg(&urb->dev->dev,
- "%s timed out on ep%d%s len=%u/%u\n",
+ "%s timed out or killed on ep%d%s len=%u/%u\n",
current->comm,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
@@ -99,7 +113,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
- retv = usb_start_wait_urb(urb, timeout, &length);
+ retv = usb_start_wait_urb(urb, timeout, &length, false);
if (retv < 0)
return retv;
else
@@ -116,8 +130,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
* @index: USB message index value
* @data: pointer to the data to send
* @size: length in bytes of the data to send
- * @timeout: time in msecs to wait for the message to complete before timing
- * out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
*
* Context: !in_interrupt ()
*
@@ -172,8 +185,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg);
* @index: USB message index value
* @driver_data: pointer to the data to send
* @size: length in bytes of the data to send
- * @timeout: time in msecs to wait for the message to complete before timing
- * out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
* @memflags: the flags for memory allocation for buffers
*
* Context: !in_interrupt ()
@@ -235,8 +247,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_send);
* @index: USB message index value
* @driver_data: pointer to the data to be filled in by the message
* @size: length in bytes of the data to be received
- * @timeout: time in msecs to wait for the message to complete before timing
- * out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
* @memflags: the flags for memory allocation for buffers
*
* Context: !in_interrupt ()
@@ -307,8 +318,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_recv);
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred
* in bytes
- * @timeout: time in msecs to wait for the message to complete before
- * timing out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
*
* Context: !in_interrupt ()
*
@@ -388,10 +398,59 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
- return usb_start_wait_urb(urb, timeout, actual_length);
+ return usb_start_wait_urb(urb, timeout, actual_length, false);
}
EXPORT_SYMBOL_GPL(usb_bulk_msg);
+/**
+ * usb_bulk_msg_killable - Builds a bulk urb, sends it off and waits for completion in a killable state
+ * @usb_dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @data: pointer to the data to send
+ * @len: length in bytes of the data to send
+ * @actual_length: pointer to a location to put the actual length transferred
+ * in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ * timing out (if <= 0, the wait is as long as possible)
+ *
+ * Context: task context, might sleep.
+ *
+ * This function is just like usb_blk_msg(), except that it waits in a
+ * killable state and there is no limit on the timeout length.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length parameter.
+ *
+ */
+int usb_bulk_msg_killable(struct usb_device *usb_dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
+{
+ struct urb *urb;
+ struct usb_host_endpoint *ep;
+
+ ep = usb_pipe_endpoint(usb_dev, pipe);
+ if (!ep || len < 0)
+ return -EINVAL;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+
+ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_INT) {
+ pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
+ usb_fill_int_urb(urb, usb_dev, pipe, data, len,
+ usb_api_blocking_completion, NULL,
+ ep->desc.bInterval);
+ } else
+ usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
+ usb_api_blocking_completion, NULL);
+
+ return usb_start_wait_urb(urb, timeout, actual_length, true);
+}
+EXPORT_SYMBOL_GPL(usb_bulk_msg_killable);
+
/*-------------------------------------------------------------------*/
static void sg_clean(struct usb_sg_request *io)
diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c
index fb1588e7c282..ad0941070849 100644
--- a/drivers/usb/core/phy.c
+++ b/drivers/usb/core/phy.c
@@ -138,16 +138,10 @@ int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
list_for_each_entry(roothub_entry, head, list) {
err = phy_set_mode(roothub_entry->phy, mode);
if (err)
- goto err_out;
+ return err;
}
return 0;
-
-err_out:
- list_for_each_entry_continue_reverse(roothub_entry, head, list)
- phy_power_off(roothub_entry->phy);
-
- return err;
}
EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 52c95e7bd64b..4d56b186fcc4 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -205,6 +205,10 @@ static const struct usb_device_id usb_quirk_list[] = {
/* HP v222w 16GB Mini USB Drive */
{ USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT },
+ /* Huawei 4G LTE module ME906S */
+ { USB_DEVICE(0x03f0, 0xa31d), .driver_info =
+ USB_QUIRK_DISCONNECT_SUSPEND },
+
/* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -390,6 +394,7 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Silicon Motion Flash Drive */
{ USB_DEVICE(0x090c, 0x1000), .driver_info = USB_QUIRK_DELAY_INIT },
+ { USB_DEVICE(0x090c, 0x2000), .driver_info = USB_QUIRK_DELAY_INIT },
/* Sound Devices USBPre2 */
{ USB_DEVICE(0x0926, 0x0202), .driver_info =
@@ -473,6 +478,8 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Razer - Razer Blade Keyboard */
{ USB_DEVICE(0x1532, 0x0116), .driver_info =
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+ /* Razer - Razer Kiyo Pro Webcam */
+ { USB_DEVICE(0x1532, 0x0e05), .driver_info = USB_QUIRK_NO_LPM },
/* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */
{ USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index c285b23c3707..e3738a1aa9f4 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -996,13 +996,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
if (status)
goto fail;
- spin_lock_init(&hidg->write_spinlock);
hidg->write_pending = 1;
hidg->req = NULL;
- spin_lock_init(&hidg->read_spinlock);
- init_waitqueue_head(&hidg->write_queue);
- init_waitqueue_head(&hidg->read_queue);
- INIT_LIST_HEAD(&hidg->completed_out_req);
/* create char device */
cdev_init(&hidg->cdev, &f_hidg_fops);
@@ -1272,6 +1267,12 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
mutex_lock(&opts->lock);
++opts->refcnt;
+ spin_lock_init(&hidg->write_spinlock);
+ spin_lock_init(&hidg->read_spinlock);
+ init_waitqueue_head(&hidg->write_queue);
+ init_waitqueue_head(&hidg->read_queue);
+ INIT_LIST_HEAD(&hidg->completed_out_req);
+
device_initialize(&hidg->dev);
hidg->dev.release = hidg_release;
hidg->dev.class = hidg_class;
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index ee95e8f5f9d4..dc820c9586a7 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -11,6 +11,7 @@
/* #define VERBOSE_DEBUG */
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -690,9 +691,11 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc;
}
+ mutex_lock(&rndis_opts->lock);
rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass;
rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol;
+ mutex_unlock(&rndis_opts->lock);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c
index 51c1cae162d9..71506f9b0163 100644
--- a/drivers/usb/gadget/function/f_subset.c
+++ b/drivers/usb/gadget/function/f_subset.c
@@ -6,6 +6,7 @@
* Copyright (C) 2008 Nokia Corporation
*/
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -451,8 +452,14 @@ static struct usb_function_instance *geth_alloc_inst(void)
static void geth_free(struct usb_function *f)
{
struct f_gether *eth;
+ struct f_gether_opts *opts;
+
+ opts = container_of(f->fi, struct f_gether_opts, func_inst);
eth = func_to_geth(f);
+ mutex_lock(&opts->lock);
+ opts->refcnt--;
+ mutex_unlock(&opts->lock);
kfree(eth);
}
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index 30c3a44abb18..cbab39a5e753 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -1032,6 +1032,13 @@ static void usbg_cmd_work(struct work_struct *work)
se_cmd = &cmd->se_cmd;
tpg = cmd->fu->tpg;
tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ struct usb_gadget *gadget = fuas_to_gadget(cmd->fu);
+
+ dev_err(&gadget->dev, "Missing nexus, ignoring command\n");
+ return;
+ }
+
dir = get_cmd_dir(cmd->cmd_buf);
if (dir < 0) {
transport_init_se_cmd(se_cmd,
@@ -1162,6 +1169,13 @@ static void bot_cmd_work(struct work_struct *work)
se_cmd = &cmd->se_cmd;
tpg = cmd->fu->tpg;
tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ struct usb_gadget *gadget = fuas_to_gadget(cmd->fu);
+
+ dev_err(&gadget->dev, "Missing nexus, ignoring command\n");
+ return;
+ }
+
dir = get_cmd_dir(cmd->cmd_buf);
if (dir < 0) {
transport_init_se_cmd(se_cmd,
diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c
index e2d7f69128a0..f8ed471ab9a8 100644
--- a/drivers/usb/gadget/function/f_uac1_legacy.c
+++ b/drivers/usb/gadget/function/f_uac1_legacy.c
@@ -360,19 +360,46 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_audio *audio = req->context;
- int status = req->status;
- u32 data = 0;
struct usb_ep *out_ep = audio->out_ep;
- switch (status) {
-
- case 0: /* normal completion? */
- if (ep == out_ep)
+ switch (req->status) {
+ case 0:
+ if (ep == out_ep) {
f_audio_out_ep_complete(ep, req);
- else if (audio->set_con) {
- memcpy(&data, req->buf, req->length);
- audio->set_con->set(audio->set_con, audio->set_cmd,
- le16_to_cpu(data));
+ } else if (audio->set_con) {
+ struct usb_audio_control *con = audio->set_con;
+ u8 type = con->type;
+ u32 data;
+ bool valid_request = false;
+
+ switch (type) {
+ case UAC_FU_MUTE: {
+ u8 value;
+
+ if (req->actual == sizeof(value)) {
+ memcpy(&value, req->buf, sizeof(value));
+ data = value;
+ valid_request = true;
+ }
+ break;
+ }
+ case UAC_FU_VOLUME: {
+ __le16 value;
+
+ if (req->actual == sizeof(value)) {
+ memcpy(&value, req->buf, sizeof(value));
+ data = le16_to_cpu(value);
+ valid_request = true;
+ }
+ break;
+ }
+ }
+
+ if (valid_request)
+ con->set(con, audio->set_cmd, data);
+ else
+ usb_ep_set_halt(ep);
+
audio->set_con = NULL;
}
break;
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 5d39aff263f0..7821e7284222 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -393,6 +393,14 @@ uvc_function_disconnect(struct uvc_device *uvc)
{
int ret;
+ mutex_lock(&uvc->lock);
+ if (uvc->func_unbound) {
+ dev_dbg(&uvc->vdev.dev, "skipping function deactivate (unbound)\n");
+ mutex_unlock(&uvc->lock);
+ return;
+ }
+ mutex_unlock(&uvc->lock);
+
if ((ret = usb_function_deactivate(&uvc->func)) < 0)
uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret);
}
@@ -411,6 +419,15 @@ static ssize_t function_name_show(struct device *dev,
static DEVICE_ATTR_RO(function_name);
+static void uvc_vdev_release(struct video_device *vdev)
+{
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+
+ /* Signal uvc_function_unbind() that the video device has been released */
+ if (uvc->vdev_release_done)
+ complete(uvc->vdev_release_done);
+}
+
static int
uvc_register_video(struct uvc_device *uvc)
{
@@ -421,7 +438,7 @@ uvc_register_video(struct uvc_device *uvc)
uvc->vdev.v4l2_dev = &uvc->v4l2_dev;
uvc->vdev.fops = &uvc_v4l2_fops;
uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops;
- uvc->vdev.release = video_device_release_empty;
+ uvc->vdev.release = uvc_vdev_release;
uvc->vdev.vfl_dir = VFL_DIR_TX;
uvc->vdev.lock = &uvc->video.mutex;
uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@@ -595,6 +612,9 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
int ret = -EINVAL;
uvcg_info(f, "%s()\n", __func__);
+ mutex_lock(&uvc->lock);
+ uvc->func_unbound = false;
+ mutex_unlock(&uvc->lock);
opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters.
@@ -887,18 +907,25 @@ static void uvc_free(struct usb_function *f)
static void uvc_function_unbind(struct usb_configuration *c,
struct usb_function *f)
{
+ DECLARE_COMPLETION_ONSTACK(vdev_release_done);
struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f);
long wait_ret = 1;
+ bool connected;
uvcg_info(f, "%s()\n", __func__);
+ mutex_lock(&uvc->lock);
+ uvc->func_unbound = true;
+ uvc->vdev_release_done = &vdev_release_done;
+ connected = uvc->func_connected;
+ mutex_unlock(&uvc->lock);
/* If we know we're connected via v4l2, then there should be a cleanup
* of the device from userspace either via UVC_EVENT_DISCONNECT or
* though the video device removal uevent. Allow some time for the
* application to close out before things get deleted.
*/
- if (uvc->func_connected) {
+ if (connected) {
uvcg_dbg(f, "waiting for clean disconnect\n");
wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
uvc->func_connected == false, msecs_to_jiffies(500));
@@ -909,8 +936,13 @@ static void uvc_function_unbind(struct usb_configuration *c,
video_unregister_device(&uvc->vdev);
v4l2_device_unregister(&uvc->v4l2_dev);
- if (uvc->func_connected) {
- /* Wait for the release to occur to ensure there are no longer any
+ mutex_lock(&uvc->lock);
+ connected = uvc->func_connected;
+ mutex_unlock(&uvc->lock);
+
+ if (connected) {
+ /*
+ * Wait for the release to occur to ensure there are no longer any
* pending operations that may cause panics when resources are cleaned
* up.
*/
@@ -920,6 +952,10 @@ static void uvc_function_unbind(struct usb_configuration *c,
uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret);
}
+ /* Wait for the video device to be released */
+ wait_for_completion(&vdev_release_done);
+ uvc->vdev_release_done = NULL;
+
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf);
@@ -937,6 +973,8 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
return ERR_PTR(-ENOMEM);
mutex_init(&uvc->video.mutex);
+ mutex_init(&uvc->lock);
+ uvc->func_unbound = true;
uvc->state = UVC_STATE_DISCONNECTED;
init_waitqueue_head(&uvc->func_connected_queue);
opts = fi_to_f_uvc_opts(fi);
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 5e5f699a434f..ca8ba978159a 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -1141,6 +1141,10 @@ void gether_disconnect(struct gether *link)
DBG(dev, "%s\n", __func__);
+ spin_lock(&dev->lock);
+ dev->port_usb = NULL;
+ spin_unlock(&dev->lock);
+
netif_stop_queue(dev->net);
netif_carrier_off(dev->net);
@@ -1178,10 +1182,6 @@ void gether_disconnect(struct gether *link)
dev->header_len = 0;
dev->unwrap = NULL;
dev->wrap = NULL;
-
- spin_lock(&dev->lock);
- dev->port_usb = NULL;
- spin_unlock(&dev->lock);
}
EXPORT_SYMBOL_GPL(gether_disconnect);
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 6c4fc4913f4f..ff67d0c4ebc4 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -118,6 +118,9 @@ struct uvc_device {
enum uvc_state state;
struct usb_function func;
struct uvc_video video;
+ struct completion *vdev_release_done;
+ struct mutex lock; /* protects func_unbound and func_connected */
+ bool func_unbound;
bool func_connected;
wait_queue_head_t func_connected_queue;
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 65abd55ce234..2a1efaf3708e 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -234,12 +234,18 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
return -EINVAL;
- if (sub->type == UVC_EVENT_SETUP && uvc->func_connected)
+ mutex_lock(&uvc->lock);
+
+ if (sub->type == UVC_EVENT_SETUP && uvc->func_connected) {
+ mutex_unlock(&uvc->lock);
return -EBUSY;
+ }
ret = v4l2_event_subscribe(fh, sub, 2, NULL);
- if (ret < 0)
+ if (ret < 0) {
+ mutex_unlock(&uvc->lock);
return ret;
+ }
if (sub->type == UVC_EVENT_SETUP) {
uvc->func_connected = true;
@@ -247,6 +253,7 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
uvc_function_connect(uvc);
}
+ mutex_unlock(&uvc->lock);
return 0;
}
@@ -255,7 +262,9 @@ static void uvc_v4l2_disable(struct uvc_device *uvc)
uvc_function_disconnect(uvc);
uvcg_video_enable(&uvc->video, 0);
uvcg_free_buffers(&uvc->video.queue);
+ mutex_lock(&uvc->lock);
uvc->func_connected = false;
+ mutex_unlock(&uvc->lock);
wake_up_interruptible(&uvc->func_connected_queue);
}
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 0852d231959a..bbcd5923ce5e 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -458,8 +458,13 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
/* Report reset and disconnect events to the driver */
if (dum->ints_enabled && (disconnect || reset)) {
- stop_activity(dum);
++dum->callback_usage;
+ /*
+ * stop_activity() can drop dum->lock, so it must
+ * not come between the dum->ints_enabled test
+ * and the ++dum->callback_usage.
+ */
+ stop_activity(dum);
spin_unlock(&dum->lock);
if (reset)
usb_gadget_udc_reset(&dum->gadget, dum->driver);
@@ -1516,6 +1521,12 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
/* rescan to continue with any other queued i/o */
if (rescan)
goto top;
+
+ /* request not fully transferred; stop iterating to
+ * preserve data ordering across queued requests.
+ */
+ if (req->req.actual < req->req.length)
+ break;
}
return sent;
}
diff --git a/drivers/usb/host/ehci-brcm.c b/drivers/usb/host/ehci-brcm.c
index 3e0ebe8cc649..b230ad4426e7 100644
--- a/drivers/usb/host/ehci-brcm.c
+++ b/drivers/usb/host/ehci-brcm.c
@@ -31,8 +31,8 @@ static inline void ehci_brcm_wait_for_sof(struct ehci_hcd *ehci, u32 delay)
int res;
/* Wait for next microframe (every 125 usecs) */
- res = readl_relaxed_poll_timeout(&ehci->regs->frame_index, val,
- val != frame_idx, 1, 130);
+ res = readl_relaxed_poll_timeout_atomic(&ehci->regs->frame_index,
+ val, val != frame_idx, 1, 130);
if (res)
ehci_err(ehci, "Error waiting for SOF\n");
udelay(delay);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7eb060197474..d3573c59fb8d 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3982,7 +3982,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
(xhci->xhc_state & XHCI_STATE_HALTED)) {
spin_unlock_irqrestore(&xhci->lock, flags);
- kfree(command);
+ xhci_free_command(xhci, command);
return -ENODEV;
}
@@ -3990,7 +3990,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
slot_id);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
- kfree(command);
+ xhci_free_command(xhci, command);
return ret;
}
xhci_ring_cmd_db(xhci);
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index fc0e22cc6fda..69c220bc2665 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -708,7 +708,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
if (signal_pending (current))
{
mutex_unlock(&mdc800->io_lock);
- return -EINTR;
+ return len == left ? -EINTR : len-left;
}
sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
@@ -731,9 +731,11 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
mutex_unlock(&mdc800->io_lock);
return len-left;
}
- wait_event_timeout(mdc800->download_wait,
+ retval = wait_event_timeout(mdc800->download_wait,
mdc800->downloaded,
msecs_to_jiffies(TO_DOWNLOAD_GET_READY));
+ if (!retval)
+ usb_kill_urb(mdc800->download_urb);
mdc800->downloaded = 0;
if (mdc800->download_urb->status != 0)
{
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index d972c0962939..8b9047f74ba0 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -733,7 +733,7 @@ static int uss720_probe(struct usb_interface *intf,
ret = get_1284_register(pp, 0, ®, GFP_KERNEL);
dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
if (ret < 0)
- return ret;
+ goto probe_abort;
ret = usb_find_last_int_in_endpoint(interface, &epd);
if (!ret) {
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 36192fbf915a..4cf10c9301b7 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -271,6 +271,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
dev->int_buffer, YUREX_BUF_SIZE, yurex_interrupt,
dev, 1);
dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ dev->bbu = -1;
if (usb_submit_urb(dev->urb, GFP_KERNEL)) {
retval = -EIO;
dev_err(&interface->dev, "Could not submitting URB\n");
@@ -279,7 +280,6 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
- dev->bbu = -1;
/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &yurex_class);
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 50e6a01cb633..8fdb7ea49401 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -804,6 +804,15 @@ static int usbhs_remove(struct platform_device *pdev)
usbhs_platform_call(priv, hardware_exit, pdev);
reset_control_assert(priv->rsts);
+
+ /*
+ * Explicitly free the IRQ to ensure the interrupt handler is
+ * disabled and synchronized before freeing resources.
+ * devm_free_irq() calls free_irq() which waits for any running
+ * ISR to complete, preventing UAF.
+ */
+ devm_free_irq(&pdev->dev, priv->irq, priv);
+
usbhs_mod_remove(priv);
usbhs_fifo_remove(priv);
usbhs_pipe_remove(priv);
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index 821b81337025..ae5aff85252f 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -108,9 +108,14 @@ static void *usb_role_switch_match(struct fwnode_handle *fwnode, const char *id,
static struct usb_role_switch *
usb_role_switch_is_parent(struct fwnode_handle *fwnode)
{
- struct fwnode_handle *parent = fwnode_get_parent(fwnode);
+ struct fwnode_handle *parent;
struct device *dev;
+ if (fwnode_property_match_string(fwnode, "compatible", "usb-b-connector") < 0)
+ return NULL;
+
+ parent = fwnode_get_parent(fwnode);
+
if (!fwnode_property_present(parent, "usb-role-switch")) {
fwnode_handle_put(parent);
return NULL;
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 618e2b16e204..74320352b5a5 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -73,6 +73,7 @@ static const struct usb_device_id edgeport_4port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BLACKBOX_IC135A) },
{ }
};
@@ -121,6 +122,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BLACKBOX_IC135A) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
@@ -546,6 +548,7 @@ static void get_product_info(struct edgeport_serial *edge_serial)
case ION_DEVICE_ID_EDGEPORT_2_DIN:
case ION_DEVICE_ID_EDGEPORT_4_DIN:
case ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU:
+ case ION_DEVICE_ID_BLACKBOX_IC135A:
product_info->IsRS232 = 1;
break;
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index 9a6f742ad3ab..c82a275e8e76 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -211,6 +211,7 @@
//
// Definitions for other product IDs
+#define ION_DEVICE_ID_BLACKBOX_IC135A 0x0801 // OEM device (rebranded Edgeport/4)
#define ION_DEVICE_ID_MT4X56USB 0x1403 // OEM device
#define ION_DEVICE_ID_E5805A 0x1A01 // OEM device (rebranded Edgeport/4)
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index f7179fe526d0..859080768abb 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2441,6 +2441,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM815 and SRM825L */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825L */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825L */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM825WN (Diag) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825WN (AT) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825WN (NMEA) */
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
@@ -2461,6 +2464,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0302, 0xff) }, /* Rolling RW101R-GL (laptop MBIM) */
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0802, 0xff), /* Rolling RW350-GL (laptop MBIM) */
.driver_info = RSVD(5) },
+ { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff) }, /* Rolling RW135R-GL (laptop MBIM) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 28537a1a0e0b..cbbca3573d65 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -24,6 +25,9 @@
#include <linux/seq_file.h>
#include <linux/miscdevice.h>
#include <linux/moduleparam.h>
+#include <linux/notifier.h>
+#include <linux/security.h>
+#include <linux/wait.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
@@ -37,6 +41,7 @@
#include <xen/page.h>
#include <xen/xen-ops.h>
#include <xen/balloon.h>
+#include <xen/xenbus.h>
#include "privcmd.h"
@@ -55,10 +60,20 @@ module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint,
MODULE_PARM_DESC(dm_op_buf_max_size,
"Maximum size of a dm_op hypercall buffer");
+static bool unrestricted;
+module_param(unrestricted, bool, 0);
+MODULE_PARM_DESC(unrestricted,
+ "Don't restrict hypercalls to target domain if running in a domU");
+
struct privcmd_data {
domid_t domid;
};
+/* DOMID_INVALID implies no restriction */
+static domid_t target_domain = DOMID_INVALID;
+static bool restrict_wait;
+static DECLARE_WAIT_QUEUE_HEAD(restrict_wait_wq);
+
static int privcmd_vma_range_is_mapped(
struct vm_area_struct *vma,
unsigned long addr,
@@ -878,13 +893,16 @@ static long privcmd_ioctl(struct file *file,
static int privcmd_open(struct inode *ino, struct file *file)
{
- struct privcmd_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+ struct privcmd_data *data;
+ if (wait_event_interruptible(restrict_wait_wq, !restrict_wait) < 0)
+ return -EINTR;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- /* DOMID_INVALID implies no restriction */
- data->domid = DOMID_INVALID;
+ data->domid = target_domain;
file->private_data = data;
return 0;
@@ -977,6 +995,52 @@ static struct miscdevice privcmd_dev = {
.fops = &xen_privcmd_fops,
};
+static int init_restrict(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ char *target;
+ unsigned int domid;
+
+ /* Default to an guaranteed unused domain-id. */
+ target_domain = DOMID_IDLE;
+
+ target = xenbus_read(XBT_NIL, "target", "", NULL);
+ if (IS_ERR(target) || kstrtouint(target, 10, &domid)) {
+ pr_err("No target domain found, blocking all hypercalls\n");
+ goto out;
+ }
+
+ target_domain = domid;
+
+ out:
+ if (!IS_ERR(target))
+ kfree(target);
+
+ restrict_wait = false;
+ wake_up_all(&restrict_wait_wq);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block xenstore_notifier = {
+ .notifier_call = init_restrict,
+};
+
+static void __init restrict_driver(void)
+{
+ if (unrestricted) {
+ if (security_locked_down(LOCKDOWN_XEN_USER_ACTIONS))
+ pr_warn("Kernel is locked down, parameter \"unrestricted\" ignored\n");
+ else
+ return;
+ }
+
+ restrict_wait = true;
+
+ register_xenstore_notifier(&xenstore_notifier);
+}
+
static int __init privcmd_init(void)
{
int err;
@@ -984,6 +1048,9 @@ static int __init privcmd_init(void)
if (!xen_domain())
return -ENODEV;
+ if (!xen_initial_domain())
+ restrict_driver();
+
err = misc_register(&privcmd_dev);
if (err != 0) {
pr_err("Could not register Xen privcmd device\n");
@@ -1002,6 +1069,9 @@ static int __init privcmd_init(void)
static void __exit privcmd_exit(void)
{
+ if (!xen_initial_domain())
+ unregister_xenstore_notifier(&xenstore_notifier);
+
misc_deregister(&privcmd_dev);
misc_deregister(&xen_privcmdbuf_dev);
}
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index ce8ffb595a46..cb2affe11b02 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -378,11 +378,8 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
acpi_psd[acpi_id].domain);
}
- status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- if (!pblk)
- return AE_OK;
- }
+ if (!pblk && !acpi_has_method(handle, "_CST"))
+ return AE_OK;
/* .. and it has a C-state */
__set_bit(acpi_id, acpi_id_cst_present);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 29f0ba4adfbc..7a2b91f6cf14 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2548,8 +2548,8 @@ static int validate_super(struct btrfs_fs_info *fs_info,
if (mirror_num >= 0 &&
btrfs_super_bytenr(sb) != btrfs_sb_offset(mirror_num)) {
- btrfs_err(fs_info, "super offset mismatch %llu != %u",
- btrfs_super_bytenr(sb), BTRFS_SUPER_INFO_OFFSET);
+ btrfs_err(fs_info, "super offset mismatch %llu != %llu",
+ btrfs_super_bytenr(sb), btrfs_sb_offset(mirror_num));
ret = -EINVAL;
}
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 4a35d51dfef8..574a00db258a 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -4524,7 +4524,8 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
ret = btrfs_update_root(trans, fs_info->tree_root,
&root->root_key, &root->root_item);
- if (ret < 0) {
+ if (unlikely(ret < 0)) {
+ btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
goto out;
}
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index fd4768c5e439..dd27fdb9521a 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -1630,7 +1630,7 @@ static int check_dev_extent_item(const struct extent_buffer *leaf,
if (unlikely(prev_key->offset + prev_len > key->offset)) {
generic_err(leaf, slot,
"dev extent overlap, prev offset %llu len %llu current offset %llu",
- prev_key->objectid, prev_len, key->offset);
+ prev_key->offset, prev_len, key->offset);
return -EUCLEAN;
}
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 2bba6e8d4374..da77493f4c17 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -7553,8 +7553,9 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans)
smp_rmb();
ret = update_dev_stat_item(trans, device);
- if (!ret)
- atomic_sub(stats_cnt, &device->dev_stats_ccnt);
+ if (ret)
+ break;
+ atomic_sub(stats_cnt, &device->dev_stats_ccnt);
}
mutex_unlock(&fs_devices->device_list_mutex);
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 1fddb9cd3e88..398a5da2cb9a 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1129,6 +1129,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
struct ceph_mds_client *mdsc = fsc->mdsc;
struct inode *inode = d_inode(dentry);
+ struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_mds_request *req;
bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
int err = -EROFS;
@@ -1173,7 +1174,19 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
* We have enough caps, so we assume that the unlink
* will succeed. Fix up the target inode and dcache.
*/
- drop_nlink(inode);
+
+ /*
+ * Protect the i_nlink update with i_ceph_lock
+ * to precent racing against ceph_fill_inode()
+ * handling our completion on a worker thread
+ * and don't decrement if i_nlink has already
+ * been updated to zero by this completion.
+ */
+ spin_lock(&ci->i_ceph_lock);
+ if (inode->i_nlink > 0)
+ drop_nlink(inode);
+ spin_unlock(&ci->i_ceph_lock);
+
d_delete(dentry);
} else if (err == -EJUKEBOX) {
try_async = false;
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 9daa256f69d4..96cbfebbb648 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -36,6 +36,7 @@
#include <linux/fips.h>
#include <crypto/arc4.h>
#include <crypto/aead.h>
+#include <crypto/algapi.h>
int __cifs_calc_signature(struct smb_rqst *rqst,
struct TCP_Server_Info *server, char *signature,
@@ -255,7 +256,7 @@ int cifs_verify_signature(struct smb_rqst *rqst,
/* cifs_dump_mem("what we think it should be: ",
what_we_think_sig_should_be, 16); */
- if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
+ if (crypto_memneq(server_response_sig, what_we_think_sig_should_be, 8))
return -EACCES;
else
return 0;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index fab543bb0eaf..a1a27a11dd95 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -26,6 +26,7 @@
#include <linux/mm.h>
#include <linux/mempool.h>
#include <linux/workqueue.h>
+#include <linux/fcntl.h>
#include "cifs_fs_sb.h"
#include "cifsacl.h"
#include <crypto/internal/hash.h>
@@ -2124,4 +2125,14 @@ static inline bool cifs_ses_exiting(struct cifs_ses *ses)
return ret;
}
+static inline int cifs_open_create_options(unsigned int oflags, int opts)
+{
+ /* O_SYNC also has bit for O_DSYNC so following check picks up either */
+ if (oflags & O_SYNC)
+ opts |= CREATE_WRITE_THROUGH;
+ if (oflags & O_DIRECT)
+ opts |= CREATE_NO_BUFFER;
+ return opts;
+}
+
#endif /* _CIFS_GLOB_H */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 29da38dfccdb..769c7759601d 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2951,7 +2951,6 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
/* find first : in payload */
payload = upayload->data;
delim = strnchr(payload, upayload->datalen, ':');
- cifs_dbg(FYI, "payload=%s\n", payload);
if (!delim) {
cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n",
upayload->datalen);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 0d7238cb45b5..73d43d8911aa 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -348,6 +348,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
goto out;
}
+ create_options |= cifs_open_create_options(oflags, create_options);
/*
* if we're not using unix extensions, see if we need to set
* ATTR_READONLY on the create call
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index a56738244f3a..0191ae0ff8c1 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -216,19 +216,13 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
*********************************************************************/
disposition = cifs_get_disposition(f_flags);
-
/* BB pass O_SYNC flag through on file attributes .. BB */
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (!buf)
return -ENOMEM;
- /* O_SYNC also has bit for O_DSYNC so following check picks up either */
- if (f_flags & O_SYNC)
- create_options |= CREATE_WRITE_THROUGH;
-
- if (f_flags & O_DIRECT)
- create_options |= CREATE_NO_BUFFER;
+ create_options |= cifs_open_create_options(f_flags, create_options);
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
@@ -750,13 +744,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
}
desired_access = cifs_convert_flags(cfile->f_flags);
-
- /* O_SYNC also has bit for O_DSYNC so following check picks up either */
- if (cfile->f_flags & O_SYNC)
- create_options |= CREATE_WRITE_THROUGH;
-
- if (cfile->f_flags & O_DIRECT)
- create_options |= CREATE_NO_BUFFER;
+ create_options |= cifs_open_create_options(cfile->f_flags,
+ create_options);
if (server->ops->get_lease_key)
server->ops->get_lease_key(inode, &cfile->fid);
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 1297acb5bf8e..5e11362ecc47 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -437,7 +437,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
static int
parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
- size_t buf_len,
+ size_t buf_len, struct cifs_ses *ses,
struct cifs_server_iface **iface_list,
size_t *iface_count)
{
@@ -447,6 +447,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
struct iface_info_ipv4 *p4;
struct iface_info_ipv6 *p6;
struct cifs_server_iface *info;
+ __be16 port;
ssize_t bytes_left;
size_t next = 0;
int nb_iface = 0;
@@ -493,6 +494,15 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
goto out;
}
+ spin_lock(&cifs_tcp_ses_lock);
+ if (ses->server->dstaddr.ss_family == AF_INET)
+ port = ((struct sockaddr_in *)&ses->server->dstaddr)->sin_port;
+ else if (ses->server->dstaddr.ss_family == AF_INET6)
+ port = ((struct sockaddr_in6 *)&ses->server->dstaddr)->sin6_port;
+ else
+ port = cpu_to_be16(CIFS_PORT);
+ spin_unlock(&cifs_tcp_ses_lock);
+
info = *iface_list;
bytes_left = buf_len;
p = buf;
@@ -519,7 +529,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
/* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
- addr4->sin_port = cpu_to_be16(CIFS_PORT);
+ addr4->sin_port = port;
cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
&addr4->sin_addr);
@@ -533,7 +543,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
/* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
addr6->sin6_flowinfo = 0;
addr6->sin6_scope_id = 0;
- addr6->sin6_port = cpu_to_be16(CIFS_PORT);
+ addr6->sin6_port = port;
cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
&addr6->sin6_addr);
@@ -600,7 +610,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
goto out;
}
- rc = parse_server_interfaces(out_buf, ret_data_len,
+ rc = parse_server_interfaces(out_buf, ret_data_len, ses,
&iface_list, &iface_count);
if (rc)
goto out;
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index adb324234b44..c02e57d8e228 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -31,6 +31,7 @@
#include <asm/processor.h>
#include <linux/mempool.h>
#include <linux/highmem.h>
+#include <crypto/algapi.h>
#include <crypto/aead.h>
#include "smb2pdu.h"
#include "cifsglob.h"
@@ -687,7 +688,8 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (rc)
return rc;
- if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) {
+ if (crypto_memneq(server_response_sig, shdr->Signature,
+ SMB2_SIGNATURE_SIZE)) {
cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx\n",
shdr->Command, shdr->MessageId);
return -EACCES;
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index b0e8711fd7fd..6d37805d3155 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3231,7 +3231,9 @@ static int ext4_split_extent_at(handle_t *handle,
ext4_ext_mark_unwritten(ex2);
err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags);
- if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM)
+ if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM)
+ goto out_err;
+ if (!err)
goto out;
/*
@@ -3247,7 +3249,8 @@ static int ext4_split_extent_at(handle_t *handle,
if (IS_ERR(path)) {
EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld",
split, PTR_ERR(path));
- return PTR_ERR(path);
+ err = PTR_ERR(path);
+ goto out_err;
}
depth = ext_depth(inode);
ex = path[depth].p_ext;
@@ -3303,6 +3306,9 @@ static int ext4_split_extent_at(handle_t *handle,
*/
ext4_ext_dirty(handle, inode, path + path->p_depth);
return err;
+out_err:
+ /* Remove all remaining potentially stale extents. */
+ ext4_es_remove_extent(inode, ee_block, ee_len);
out:
ext4_ext_show_leaf(inode, *ppath);
return err;
@@ -3705,11 +3711,15 @@ static int ext4_split_convert_extents(handle_t *handle,
/* Convert to unwritten */
if (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN) {
split_flag |= EXT4_EXT_DATA_VALID1;
- /* Convert to initialized */
- } else if (flags & EXT4_GET_BLOCKS_CONVERT) {
+ /* Split the existing unwritten extent */
+ } else if (flags & (EXT4_GET_BLOCKS_UNWRIT_EXT |
+ EXT4_GET_BLOCKS_CONVERT)) {
split_flag |= ee_block + ee_len <= eof_block ?
EXT4_EXT_MAY_ZEROOUT : 0;
- split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2);
+ split_flag |= EXT4_EXT_MARK_UNWRIT2;
+ /* Convert to initialized */
+ if (flags & EXT4_GET_BLOCKS_CONVERT)
+ split_flag |= EXT4_EXT_DATA_VALID2;
}
flags |= EXT4_GET_BLOCKS_PRE_IO;
return ext4_split_extent(handle, inode, ppath, map, split_flag, flags);
@@ -3874,7 +3884,7 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
/* get_block() before submitting IO, split the extent */
if (flags & EXT4_GET_BLOCKS_PRE_IO) {
ret = ext4_split_convert_extents(handle, inode, map, ppath,
- flags | EXT4_GET_BLOCKS_CONVERT);
+ flags);
if (ret < 0) {
err = ret;
goto out2;
diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c
index be768ef1fd16..26b7782b03f4 100644
--- a/fs/ext4/fast_commit.c
+++ b/fs/ext4/fast_commit.c
@@ -902,7 +902,7 @@ static int ext4_fc_submit_inode_data_all(journal_t *journal)
finish_wait(&ei->i_fc_wait, &wait);
}
spin_unlock(&sbi->s_fc_lock);
- ret = jbd2_submit_inode_data(ei->jinode);
+ ret = jbd2_submit_inode_data(READ_ONCE(ei->jinode));
if (ret)
return ret;
spin_lock(&sbi->s_fc_lock);
@@ -927,7 +927,7 @@ static int ext4_fc_wait_inode_data_all(journal_t *journal)
continue;
spin_unlock(&sbi->s_fc_lock);
- ret = jbd2_wait_inode_data(journal, pos->jinode);
+ ret = jbd2_wait_inode_data(journal, READ_ONCE(pos->jinode));
if (ret)
return ret;
spin_lock(&sbi->s_fc_lock);
@@ -1480,19 +1480,21 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl,
/* Immediately update the inode on disk. */
ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh);
if (ret)
- goto out;
+ goto out_brelse;
ret = sync_dirty_buffer(iloc.bh);
if (ret)
- goto out;
+ goto out_brelse;
ret = ext4_mark_inode_used(sb, ino);
if (ret)
- goto out;
+ goto out_brelse;
/* Given that we just wrote the inode on disk, this SHOULD succeed. */
inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
if (IS_ERR(inode)) {
jbd_debug(1, "Inode not found.");
- return -EFSCORRUPTED;
+ inode = NULL;
+ ret = -EFSCORRUPTED;
+ goto out_brelse;
}
/*
@@ -1508,13 +1510,14 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl,
ext4_inode_csum_set(inode, ext4_raw_inode(&iloc), EXT4_I(inode));
ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh);
sync_dirty_buffer(iloc.bh);
+out_brelse:
brelse(iloc.bh);
out:
iput(inode);
if (!ret)
blkdev_issue_flush(sb->s_bdev, GFP_KERNEL);
- return 0;
+ return ret;
}
/*
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index c91e0cef04a5..98bd01483afb 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -686,6 +686,12 @@ static int recently_deleted(struct super_block *sb, ext4_group_t group, int ino)
if (unlikely(!gdp))
return 0;
+ /* Inode was never used in this filesystem? */
+ if (ext4_has_group_desc_csum(sb) &&
+ (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+ ino >= EXT4_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gdp)))
+ return 0;
+
bh = sb_find_get_block(sb, ext4_inode_table(sb, gdp) +
(ino / inodes_per_block));
if (!bh || !buffer_uptodate(bh))
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 719d9a2bc5a7..d56a3c90dc4f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -121,6 +121,8 @@ void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw,
static inline int ext4_begin_ordered_truncate(struct inode *inode,
loff_t new_size)
{
+ struct jbd2_inode *jinode = READ_ONCE(EXT4_I(inode)->jinode);
+
trace_ext4_begin_ordered_truncate(inode, new_size);
/*
* If jinode is zero, then we never opened the file for
@@ -128,10 +130,10 @@ static inline int ext4_begin_ordered_truncate(struct inode *inode,
* jbd2_journal_begin_ordered_truncate() since there's no
* outstanding writes we need to flush.
*/
- if (!EXT4_I(inode)->jinode)
+ if (!jinode)
return 0;
return jbd2_journal_begin_ordered_truncate(EXT4_JOURNAL(inode),
- EXT4_I(inode)->jinode,
+ jinode,
new_size);
}
@@ -4231,8 +4233,13 @@ int ext4_inode_attach_jinode(struct inode *inode)
spin_unlock(&inode->i_lock);
return -ENOMEM;
}
- ei->jinode = jinode;
- jbd2_journal_init_jbd_inode(ei->jinode, inode);
+ jbd2_journal_init_jbd_inode(jinode, inode);
+ /*
+ * Publish ->jinode only after it is fully initialized so that
+ * readers never observe a partially initialized jbd2_inode.
+ */
+ smp_wmb();
+ WRITE_ONCE(ei->jinode, jinode);
jinode = NULL;
}
spin_unlock(&inode->i_lock);
@@ -5576,6 +5583,18 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size)
inode_inc_iversion(inode);
+ /*
+ * If file has inline data but new size exceeds inline capacity,
+ * convert to extent-based storage first to prevent inconsistent
+ * state (inline flag set but size exceeds inline capacity).
+ */
+ if (ext4_has_inline_data(inode) &&
+ attr->ia_size > EXT4_I(inode)->i_inline_size) {
+ error = ext4_convert_inline_data(inode);
+ if (error)
+ goto err_out;
+ }
+
if (shrink) {
if (ext4_should_order_data(inode)) {
error = ext4_begin_ordered_truncate(inode,
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index d1a616bbb5bd..4a151c26e9d0 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -1929,8 +1929,12 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
return 0;
err = ext4_mb_load_buddy(ac->ac_sb, group, e4b);
- if (err)
+ if (err) {
+ if (EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info) &&
+ !(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY))
+ return 0;
return err;
+ }
ext4_lock_group(ac->ac_sb, group);
if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)))
@@ -2890,9 +2894,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
rcu_read_unlock();
iput(sbi->s_buddy_cache);
err_freesgi:
- rcu_read_lock();
- kvfree(rcu_dereference(sbi->s_group_info));
- rcu_read_unlock();
+ kvfree(rcu_access_pointer(sbi->s_group_info));
return -ENOMEM;
}
@@ -3084,7 +3086,8 @@ int ext4_mb_release(struct super_block *sb)
struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
int count;
- if (sbi->s_group_info) {
+ group_info = rcu_access_pointer(sbi->s_group_info);
+ if (group_info) {
for (i = 0; i < ngroups; i++) {
cond_resched();
grinfo = ext4_get_group_info(sb, i);
@@ -3102,12 +3105,9 @@ int ext4_mb_release(struct super_block *sb)
num_meta_group_infos = (ngroups +
EXT4_DESC_PER_BLOCK(sb) - 1) >>
EXT4_DESC_PER_BLOCK_BITS(sb);
- rcu_read_lock();
- group_info = rcu_dereference(sbi->s_group_info);
for (i = 0; i < num_meta_group_infos; i++)
kfree(group_info[i]);
kvfree(group_info);
- rcu_read_unlock();
}
kfree(sbi->s_mb_offsets);
kfree(sbi->s_mb_maxs);
@@ -3308,8 +3308,7 @@ void ext4_exit_mballoc(void)
* Returns 0 if success or error code
*/
static noinline_for_stack int
-ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
- handle_t *handle, unsigned int reserv_clstrs)
+ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, handle_t *handle)
{
struct buffer_head *bitmap_bh = NULL;
struct ext4_group_desc *gdp;
@@ -3396,13 +3395,6 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
percpu_counter_sub(&sbi->s_freeclusters_counter, ac->ac_b_ex.fe_len);
- /*
- * Now reduce the dirty block count also. Should not go negative
- */
- if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED))
- /* release all the reserved blocks if non delalloc */
- percpu_counter_sub(&sbi->s_dirtyclusters_counter,
- reserv_clstrs);
if (sbi->s_log_groups_per_flex) {
ext4_group_t flex_group = ext4_flex_group(sbi,
@@ -5271,7 +5263,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
ext4_mb_pa_free(ac);
}
if (likely(ac->ac_status == AC_STATUS_FOUND)) {
- *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs);
+ *errp = ext4_mb_mark_diskspace_used(ac, handle);
if (*errp) {
ext4_discard_allocated_blocks(ac);
goto errout;
@@ -5303,12 +5295,9 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
kmem_cache_free(ext4_ac_cachep, ac);
if (inquota && ar->len < inquota)
dquot_free_block(ar->inode, EXT4_C2B(sbi, inquota - ar->len));
- if (!ar->len) {
- if ((ar->flags & EXT4_MB_DELALLOC_RESERVED) == 0)
- /* release all the reserved blocks if non delalloc */
- percpu_counter_sub(&sbi->s_dirtyclusters_counter,
- reserv_clstrs);
- }
+ /* release any reserved blocks */
+ if (reserv_clstrs)
+ percpu_counter_sub(&sbi->s_dirtyclusters_counter, reserv_clstrs);
trace_ext4_allocate_blocks(ar, (unsigned long long)block);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 41e49fee35e5..c698dd5816c3 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1207,18 +1207,16 @@ static void ext4_put_super(struct super_block *sb)
if (!sb_rdonly(sb))
ext4_commit_super(sb, 1);
- rcu_read_lock();
- group_desc = rcu_dereference(sbi->s_group_desc);
+ group_desc = rcu_access_pointer(sbi->s_group_desc);
for (i = 0; i < sbi->s_gdb_count; i++)
brelse(group_desc[i]);
kvfree(group_desc);
- flex_groups = rcu_dereference(sbi->s_flex_groups);
+ flex_groups = rcu_access_pointer(sbi->s_flex_groups);
if (flex_groups) {
for (i = 0; i < sbi->s_flex_groups_allocated; i++)
kvfree(flex_groups[i]);
kvfree(flex_groups);
}
- rcu_read_unlock();
percpu_counter_destroy(&sbi->s_freeclusters_counter);
percpu_counter_destroy(&sbi->s_freeinodes_counter);
percpu_counter_destroy(&sbi->s_dirs_counter);
@@ -3369,6 +3367,13 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
"extents feature\n");
return 0;
}
+ if (ext4_has_feature_bigalloc(sb) &&
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
+ ext4_msg(sb, KERN_WARNING,
+ "bad geometry: bigalloc file system with non-zero "
+ "first_data_block\n");
+ return 0;
+ }
#if !IS_ENABLED(CONFIG_QUOTA) || !IS_ENABLED(CONFIG_QFMT_V2)
if (!readonly && (ext4_has_feature_quota(sb) ||
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 86297f59b43e..219f9e1a2643 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -1364,10 +1364,13 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc,
error = wpc->ops->map_blocks(wpc, inode, file_offset);
if (error)
break;
- if (WARN_ON_ONCE(wpc->iomap.type == IOMAP_INLINE))
- continue;
if (wpc->iomap.type == IOMAP_HOLE)
continue;
+ if (WARN_ON_ONCE(wpc->iomap.type != IOMAP_UNWRITTEN &&
+ wpc->iomap.type != IOMAP_MAPPED)) {
+ error = -EIO;
+ break;
+ }
iomap_add_to_ioend(inode, file_offset, page, iop, wpc, wbc,
&submit_list);
count++;
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 8a2446d44b03..e9a9f965a004 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -303,7 +303,15 @@ int jbd2_log_do_checkpoint(journal_t *journal)
*/
BUFFER_TRACE(bh, "queue");
get_bh(bh);
- J_ASSERT_BH(bh, !buffer_jwrite(bh));
+ if (WARN_ON_ONCE(buffer_jwrite(bh))) {
+ put_bh(bh); /* drop the ref we just took */
+ spin_unlock(&journal->j_list_lock);
+ /* Clean up any previously batched buffers */
+ if (batch_count)
+ __flush_batch(journal, &batch_count);
+ jbd2_journal_abort(journal, -EFSCORRUPTED);
+ return -EFSCORRUPTED;
+ }
journal->j_chkpt_bhs[batch_count++] = bh;
transaction->t_chp_stats.cs_written++;
transaction->t_checkpoint_list = jh->b_cpnext;
@@ -361,7 +369,10 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr))
return 1;
- J_ASSERT(blocknr != 0);
+ if (WARN_ON_ONCE(blocknr == 0)) {
+ jbd2_journal_abort(journal, -EFSCORRUPTED);
+ return -EFSCORRUPTED;
+ }
/*
* We need to make sure that any blocks that were recently written out
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 7022ae52b1f2..f2916ad9db67 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -5438,9 +5438,14 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
int len = xdr->buf->len - post_err_offset;
so->so_replay.rp_status = op->status;
- so->so_replay.rp_buflen = len;
- read_bytes_from_xdr_buf(xdr->buf, post_err_offset,
+ if (len <= NFSD4_REPLAY_ISIZE) {
+ so->so_replay.rp_buflen = len;
+ read_bytes_from_xdr_buf(xdr->buf,
+ post_err_offset,
so->so_replay.rp_buf, len);
+ } else {
+ so->so_replay.rp_buflen = 0;
+ }
}
status:
*p = op->status;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 07e5b1b23c91..8178d7d01648 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -152,20 +152,18 @@ static int exports_net_open(struct net *net, struct file *file)
seq = file->private_data;
seq->private = nn->svc_export_cache;
+ get_net(net);
return 0;
}
-static int exports_proc_open(struct inode *inode, struct file *file)
+static int exports_release(struct inode *inode, struct file *file)
{
- return exports_net_open(current->nsproxy->net_ns, file);
-}
+ struct seq_file *seq = file->private_data;
+ struct cache_detail *cd = seq->private;
-static const struct proc_ops exports_proc_ops = {
- .proc_open = exports_proc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = seq_release,
-};
+ put_net(cd->net);
+ return seq_release(inode, file);
+}
static int exports_nfsd_open(struct inode *inode, struct file *file)
{
@@ -176,7 +174,7 @@ static const struct file_operations exports_nfsd_operations = {
.open = exports_nfsd_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = exports_release,
};
static int export_features_show(struct seq_file *m, void *v)
@@ -1423,6 +1421,19 @@ static struct file_system_type nfsd_fs_type = {
MODULE_ALIAS_FS("nfsd");
#ifdef CONFIG_PROC_FS
+
+static int exports_proc_open(struct inode *inode, struct file *file)
+{
+ return exports_net_open(current->nsproxy->net_ns, file);
+}
+
+static const struct proc_ops exports_proc_ops = {
+ .proc_open = exports_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = exports_release,
+};
+
static int create_proc_exports_entry(void)
{
struct proc_dir_entry *entry;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 477828dbfc66..53298bdcfb3d 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -430,11 +430,18 @@ struct nfs4_client_reclaim {
struct xdr_netobj cr_princhash;
};
-/* A reasonable value for REPLAY_ISIZE was estimated as follows:
- * The OPEN response, typically the largest, requires
- * 4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) + 8(verifier) +
- * 4(deleg. type) + 8(deleg. stateid) + 4(deleg. recall flag) +
- * 20(deleg. space limit) + ~32(deleg. ace) = 112 bytes
+/*
+ * REPLAY_ISIZE is sized for an OPEN response with delegation:
+ * 4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) +
+ * 8(verifier) + 4(deleg. type) + 8(deleg. stateid) +
+ * 4(deleg. recall flag) + 20(deleg. space limit) +
+ * ~32(deleg. ace) = 112 bytes
+ *
+ * Some responses can exceed this. A LOCK denial includes the conflicting
+ * lock owner, which can be up to 1024 bytes (NFS4_OPAQUE_LIMIT). Responses
+ * larger than REPLAY_ISIZE are not cached in rp_ibuf; only rp_status is
+ * saved. Enlarging this constant increases the size of every
+ * nfs4_stateowner.
*/
#define NFSD4_REPLAY_ISIZE 112
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index 5062326d0efb..25bf038b880a 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -340,6 +340,9 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer,
if (unlikely(length < 0))
return -EIO;
+ if (unlikely(*offset < 0 || *offset >= SQUASHFS_METADATA_SIZE))
+ return -EIO;
+
while (length) {
entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
if (entry->error) {
diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c
index 984bb480f177..a3b350437db2 100644
--- a/fs/xfs/xfs_bmap_item.c
+++ b/fs/xfs/xfs_bmap_item.c
@@ -273,7 +273,8 @@ xfs_bmap_update_diff_items(
ba = container_of(a, struct xfs_bmap_intent, bi_list);
bb = container_of(b, struct xfs_bmap_intent, bi_list);
- return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
+ return (ba->bi_owner->i_ino > bb->bi_owner->i_ino) -
+ (ba->bi_owner->i_ino < bb->bi_owner->i_ino);
}
/* Set the map extent flags for this mapping. */
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 80c4579d6835..3a2bfc075e90 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -1324,9 +1324,15 @@ xfs_qm_dqflush(
return 0;
out_abort:
+ /*
+ * Shut down the log before removing the dquot item from the AIL.
+ * Otherwise, the log tail may advance past this item's LSN while
+ * log writes are still in progress, making these unflushed changes
+ * unrecoverable on the next mount.
+ */
+ xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
dqp->q_flags &= ~XFS_DQFLAG_DIRTY;
xfs_trans_ail_delete(lip, 0);
- xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
out_unlock:
xfs_dqfunlock(dqp);
return error;
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
index 8ed47b739b6c..f2cef1470373 100644
--- a/fs/xfs/xfs_dquot_item.c
+++ b/fs/xfs/xfs_dquot_item.c
@@ -124,6 +124,7 @@ xfs_qm_dquot_logitem_push(
{
struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
struct xfs_buf *bp = lip->li_buf;
+ struct xfs_ail *ailp = lip->li_ailp;
uint rval = XFS_ITEM_SUCCESS;
int error;
@@ -152,7 +153,7 @@ xfs_qm_dquot_logitem_push(
goto out_unlock;
}
- spin_unlock(&lip->li_ailp->ail_lock);
+ spin_unlock(&ailp->ail_lock);
error = xfs_qm_dqflush(dqp, &bp);
if (!error) {
@@ -162,7 +163,11 @@ xfs_qm_dquot_logitem_push(
} else if (error == -EAGAIN)
rval = XFS_ITEM_LOCKED;
- spin_lock(&lip->li_ailp->ail_lock);
+ /*
+ * The buffer no longer protects the log item from reclaim, so
+ * do not reference lip after this point.
+ */
+ spin_lock(&ailp->ail_lock);
out_unlock:
xfs_dqunlock(dqp);
return rval;
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 3aba4559469f..38b59e8070ac 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -514,6 +514,7 @@ xfs_inode_item_push(
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
struct xfs_inode *ip = iip->ili_inode;
struct xfs_buf *bp = lip->li_buf;
+ struct xfs_ail *ailp = lip->li_ailp;
uint rval = XFS_ITEM_SUCCESS;
int error;
@@ -529,7 +530,7 @@ xfs_inode_item_push(
if (!xfs_buf_trylock(bp))
return XFS_ITEM_LOCKED;
- spin_unlock(&lip->li_ailp->ail_lock);
+ spin_unlock(&ailp->ail_lock);
/*
* We need to hold a reference for flushing the cluster buffer as it may
@@ -553,7 +554,11 @@ xfs_inode_item_push(
rval = XFS_ITEM_LOCKED;
}
- spin_lock(&lip->li_ailp->ail_lock);
+ /*
+ * The buffer no longer protects the log item from reclaim, so
+ * do not reference lip after this point.
+ */
+ spin_lock(&ailp->ail_lock);
return rval;
}
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 402cf828cc91..c408dded40dc 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -652,8 +652,9 @@ xfs_check_summary_counts(
* have been retrying in the background. This will prevent never-ending
* retries in AIL pushing from hanging the unmount.
*
- * Finally, we can push the AIL to clean all the remaining dirty objects, then
- * reclaim the remaining inodes that are still in memory at this point in time.
+ * Stop inodegc and background reclaim before pushing the AIL so that they
+ * are not running while the AIL is being flushed. Then push the AIL to
+ * clean all the remaining dirty objects and reclaim the remaining inodes.
*/
static void
xfs_unmount_flush_inodes(
@@ -665,8 +666,8 @@ xfs_unmount_flush_inodes(
mp->m_flags |= XFS_MOUNT_UNMOUNTING;
- xfs_ail_push_all_sync(mp->m_ail);
cancel_delayed_work_sync(&mp->m_reclaim_work);
+ xfs_ail_push_all_sync(mp->m_ail);
xfs_reclaim_inodes(mp);
xfs_health_unmount(mp);
}
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index be7de305a622..890dbb8cc806 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -587,82 +587,92 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
acpi_install_initialization_handler
(acpi_init_handler handler, u32 function))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
- acpi_install_sci_handler(acpi_sci_handler
- address,
- void *context))
-ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
- acpi_remove_sci_handler(acpi_sci_handler
- address))
+ acpi_install_sci_handler(acpi_sci_handler
+ address,
+ void *context))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
- acpi_install_global_event_handler
- (acpi_gbl_event_handler handler,
- void *context))
+ acpi_remove_sci_handler(acpi_sci_handler
+ address))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
- acpi_install_fixed_event_handler(u32
- acpi_event,
- acpi_event_handler
- handler,
- void
- *context))
+ acpi_install_global_event_handler
+ (acpi_gbl_event_handler handler,
+ void *context))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
- acpi_remove_fixed_event_handler(u32 acpi_event,
+ acpi_install_fixed_event_handler(u32
+ acpi_event,
acpi_event_handler
- handler))
-ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
- acpi_install_gpe_handler(acpi_handle
- gpe_device,
- u32 gpe_number,
- u32 type,
- acpi_gpe_handler
- address,
- void *context))
+ handler,
+ void
+ *context))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
- acpi_install_gpe_raw_handler(acpi_handle
- gpe_device,
- u32 gpe_number,
- u32 type,
- acpi_gpe_handler
- address,
- void *context))
+ acpi_remove_fixed_event_handler(u32 acpi_event,
+ acpi_event_handler
+ handler))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
- acpi_remove_gpe_handler(acpi_handle gpe_device,
+ acpi_install_gpe_handler(acpi_handle
+ gpe_device,
u32 gpe_number,
+ u32 type,
acpi_gpe_handler
- address))
-ACPI_EXTERNAL_RETURN_STATUS(acpi_status
- acpi_install_notify_handler(acpi_handle device,
- u32 handler_type,
- acpi_notify_handler
- handler,
+ address,
void *context))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+ acpi_install_gpe_raw_handler(acpi_handle
+ gpe_device,
+ u32 gpe_number,
+ u32 type,
+ acpi_gpe_handler
+ address,
+ void *context))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+ acpi_remove_gpe_handler(acpi_handle gpe_device,
+ u32 gpe_number,
+ acpi_gpe_handler
+ address))
ACPI_EXTERNAL_RETURN_STATUS(acpi_status
- acpi_remove_notify_handler(acpi_handle device,
+ acpi_install_notify_handler(acpi_handle device,
u32 handler_type,
acpi_notify_handler
- handler))
-ACPI_EXTERNAL_RETURN_STATUS(acpi_status
- acpi_install_address_space_handler(acpi_handle
- device,
- acpi_adr_space_type
- space_id,
- acpi_adr_space_handler
- handler,
- acpi_adr_space_setup
- setup,
- void *context))
-ACPI_EXTERNAL_RETURN_STATUS(acpi_status
- acpi_remove_address_space_handler(acpi_handle
+ handler,
+ void *context))
+ACPI_EXTERNAL_RETURN_STATUS(acpi_status
+ acpi_remove_notify_handler(acpi_handle device,
+ u32 handler_type,
+ acpi_notify_handler
+ handler))
+ACPI_EXTERNAL_RETURN_STATUS(acpi_status
+ acpi_install_address_space_handler(acpi_handle
device,
acpi_adr_space_type
space_id,
acpi_adr_space_handler
- handler))
-ACPI_EXTERNAL_RETURN_STATUS(acpi_status
- acpi_install_exception_handler
- (acpi_exception_handler handler))
-ACPI_EXTERNAL_RETURN_STATUS(acpi_status
- acpi_install_interface_handler
- (acpi_interface_handler handler))
+ handler,
+ acpi_adr_space_setup
+ setup,
+ void *context))
+ACPI_EXTERNAL_RETURN_STATUS(acpi_status
+ acpi_install_address_space_handler_no_reg
+ (acpi_handle device, acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup,
+ void *context))
+ACPI_EXTERNAL_RETURN_STATUS(acpi_status
+ acpi_execute_reg_methods(acpi_handle device,
+ acpi_adr_space_type
+ space_id))
+ACPI_EXTERNAL_RETURN_STATUS(acpi_status
+ acpi_remove_address_space_handler(acpi_handle
+ device,
+ acpi_adr_space_type
+ space_id,
+ acpi_adr_space_handler
+ handler))
+ACPI_EXTERNAL_RETURN_STATUS(acpi_status
+ acpi_install_exception_handler
+ (acpi_exception_handler handler))
+ACPI_EXTERNAL_RETURN_STATUS(acpi_status
+ acpi_install_interface_handler
+ (acpi_interface_handler handler))
/*
* Global Lock interfaces
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index f40c9534f20b..a80accdbcd25 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -46,7 +46,8 @@
*
* The mmu_gather API consists of:
*
- * - tlb_gather_mmu() / tlb_finish_mmu(); start and finish a mmu_gather
+ * - tlb_gather_mmu() / tlb_gather_mmu_vma() / tlb_finish_mmu(); start and
+ * finish a mmu_gather
*
* Finish in particular will issue a (final) TLB invalidate and free
* all (remaining) queued pages.
@@ -291,6 +292,20 @@ struct mmu_gather {
unsigned int vma_exec : 1;
unsigned int vma_huge : 1;
+ /*
+ * Did we unshare (unmap) any shared page tables? For now only
+ * used for hugetlb PMD table sharing.
+ */
+ unsigned int unshared_tables : 1;
+
+ /*
+ * Did we unshare any page tables such that they are now exclusive
+ * and could get reused+modified by the new owner? When setting this
+ * flag, "unshared_tables" will be set as well. For now only used
+ * for hugetlb PMD table sharing.
+ */
+ unsigned int fully_unshared_tables : 1;
+
unsigned int batch_count;
#ifndef CONFIG_MMU_GATHER_NO_GATHER
@@ -327,6 +342,7 @@ static inline void __tlb_reset_range(struct mmu_gather *tlb)
tlb->cleared_pmds = 0;
tlb->cleared_puds = 0;
tlb->cleared_p4ds = 0;
+ tlb->unshared_tables = 0;
/*
* Do not reset mmu_gather::vma_* fields here, we do not
* call into tlb_start_vma() again to set them if there is an
@@ -422,7 +438,7 @@ static inline void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)
* these bits.
*/
if (!(tlb->freed_tables || tlb->cleared_ptes || tlb->cleared_pmds ||
- tlb->cleared_puds || tlb->cleared_p4ds))
+ tlb->cleared_puds || tlb->cleared_p4ds || tlb->unshared_tables))
return;
tlb_flush(tlb);
@@ -660,6 +676,63 @@ static inline void tlb_flush_p4d_range(struct mmu_gather *tlb,
} while (0)
#endif
+#if defined(CONFIG_ARCH_WANT_HUGE_PMD_SHARE) && defined(CONFIG_HUGETLB_PAGE)
+static inline void tlb_unshare_pmd_ptdesc(struct mmu_gather *tlb, struct page *pt,
+ unsigned long addr)
+{
+ /*
+ * The caller must make sure that concurrent unsharing + exclusive
+ * reuse is impossible until tlb_flush_unshared_tables() was called.
+ */
+ VM_WARN_ON_ONCE(!atomic_read(&pt->pt_share_count));
+ atomic_dec(&pt->pt_share_count);
+
+ /* Clearing a PUD pointing at a PMD table with PMD leaves. */
+ tlb_flush_pmd_range(tlb, addr & PUD_MASK, PUD_SIZE);
+
+ /*
+ * If the page table is now exclusively owned, we fully unshared
+ * a page table.
+ */
+ if (!atomic_read(&pt->pt_share_count))
+ tlb->fully_unshared_tables = true;
+ tlb->unshared_tables = true;
+}
+
+static inline void tlb_flush_unshared_tables(struct mmu_gather *tlb)
+{
+ /*
+ * As soon as the caller drops locks to allow for reuse of
+ * previously-shared tables, these tables could get modified and
+ * even reused outside of hugetlb context, so we have to make sure that
+ * any page table walkers (incl. TLB, GUP-fast) are aware of that
+ * change.
+ *
+ * Even if we are not fully unsharing a PMD table, we must
+ * flush the TLB for the unsharer now.
+ */
+ if (tlb->unshared_tables)
+ tlb_flush_mmu_tlbonly(tlb);
+
+ /*
+ * Similarly, we must make sure that concurrent GUP-fast will not
+ * walk previously-shared page tables that are getting modified+reused
+ * elsewhere. So broadcast an IPI to wait for any concurrent GUP-fast.
+ *
+ * We only perform this when we are the last sharer of a page table,
+ * as the IPI will reach all CPUs: any GUP-fast.
+ *
+ * Note that on configs where tlb_remove_table_sync_one() is a NOP,
+ * the expectation is that the tlb_flush_mmu_tlbonly() would have issued
+ * required IPIs already for us.
+ */
+ if (tlb->fully_unshared_tables) {
+ tlb_remove_table_sync_one();
+ tlb->fully_unshared_tables = false;
+ }
+}
+#endif
+
#endif /* CONFIG_MMU */
#endif /* _ASM_GENERIC__TLB_H */
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index fb48f8ba5dcc..d79acecd50df 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -200,8 +200,8 @@ static inline void *dma_alloc_attrs(struct device *dev, size_t size,
{
return NULL;
}
-static void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
- dma_addr_t dma_handle, unsigned long attrs)
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
{
}
static inline void *dmam_alloc_attrs(struct device *dev, size_t size,
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 9506f8ec0974..946eb9d74e39 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -149,12 +149,12 @@ struct fwnode_operations {
struct device *dev);
};
-#define fwnode_has_op(fwnode, op) \
- ((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
+#define fwnode_has_op(fwnode, op) \
+ (!IS_ERR_OR_NULL(fwnode) && (fwnode)->ops && (fwnode)->ops->op)
+
#define fwnode_call_int_op(fwnode, op, ...) \
- (fwnode ? (fwnode_has_op(fwnode, op) ? \
- (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
- -EINVAL)
+ (fwnode_has_op(fwnode, op) ? \
+ (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : (IS_ERR_OR_NULL(fwnode) ? -EINVAL : -ENXIO))
#define fwnode_call_bool_op(fwnode, op, ...) \
(fwnode_has_op(fwnode, op) ? \
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 1c03935aa3d1..dfb1afa3d282 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -166,8 +166,9 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
unsigned long addr, unsigned long sz);
pte_t *huge_pte_offset(struct mm_struct *mm,
unsigned long addr, unsigned long sz);
-int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
- unsigned long *addr, pte_t *ptep);
+int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ unsigned long *addr, pte_t *ptep);
+void huge_pmd_unshare_flush(struct mmu_gather *tlb, struct vm_area_struct *vma);
void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma,
unsigned long *start, unsigned long *end);
struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
@@ -208,13 +209,17 @@ static inline struct address_space *hugetlb_page_mapping_lock_write(
return NULL;
}
-static inline int huge_pmd_unshare(struct mm_struct *mm,
- struct vm_area_struct *vma,
- unsigned long *addr, pte_t *ptep)
+static inline int huge_pmd_unshare(struct mmu_gather *tlb,
+ struct vm_area_struct *vma, unsigned long *addr, pte_t *ptep)
{
return 0;
}
+static inline void huge_pmd_unshare_flush(struct mmu_gather *tlb,
+ struct vm_area_struct *vma)
+{
+}
+
static inline void adjust_range_if_pmd_sharing_possible(
struct vm_area_struct *vma,
unsigned long *start, unsigned long *end)
@@ -955,7 +960,7 @@ static inline __init void hugetlb_cma_check(void)
#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
static inline bool hugetlb_pmd_shared(pte_t *pte)
{
- return page_count(virt_to_page(pte)) > 1;
+ return atomic_read(&virt_to_page(pte)->pt_share_count);
}
#else
static inline bool hugetlb_pmd_shared(pte_t *pte)
diff --git a/include/linux/indirect_call_wrapper.h b/include/linux/indirect_call_wrapper.h
index cfcfef37b2f1..6afdd080c7c1 100644
--- a/include/linux/indirect_call_wrapper.h
+++ b/include/linux/indirect_call_wrapper.h
@@ -16,22 +16,26 @@
*/
#define INDIRECT_CALL_1(f, f1, ...) \
({ \
- likely(f == f1) ? f1(__VA_ARGS__) : f(__VA_ARGS__); \
+ typeof(f) __f1 = (f); \
+ likely(__f1 == f1) ? f1(__VA_ARGS__) : __f1(__VA_ARGS__); \
})
#define INDIRECT_CALL_2(f, f2, f1, ...) \
({ \
- likely(f == f2) ? f2(__VA_ARGS__) : \
- INDIRECT_CALL_1(f, f1, __VA_ARGS__); \
+ typeof(f) __f2 = (f); \
+ likely(__f2 == f2) ? f2(__VA_ARGS__) : \
+ INDIRECT_CALL_1(__f2, f1, __VA_ARGS__); \
})
#define INDIRECT_CALL_3(f, f3, f2, f1, ...) \
({ \
- likely(f == f3) ? f3(__VA_ARGS__) : \
- INDIRECT_CALL_2(f, f2, f1, __VA_ARGS__); \
+ typeof(f) __f3 = (f); \
+ likely(__f3 == f3) ? f3(__VA_ARGS__) : \
+ INDIRECT_CALL_2(__f3, f2, f1, __VA_ARGS__); \
})
#define INDIRECT_CALL_4(f, f4, f3, f2, f1, ...) \
({ \
- likely(f == f4) ? f4(__VA_ARGS__) : \
- INDIRECT_CALL_3(f, f3, f2, f1, __VA_ARGS__); \
+ typeof(f) __f4 = (f); \
+ likely(__f4 == f4) ? f4(__VA_ARGS__) : \
+ INDIRECT_CALL_3(__f4, f3, f2, f1, __VA_ARGS__); \
})
#define INDIRECT_CALLABLE_DECLARE(f) f
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index f6d092fdb93d..4172b0cce684 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -392,6 +392,7 @@
#define GITS_TYPER_VLPIS (1UL << 1)
#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4
#define GITS_TYPER_ITT_ENTRY_SIZE GENMASK_ULL(7, 4)
+#define GITS_TYPER_IDBITS GENMASK_ULL(12, 8)
#define GITS_TYPER_IDBITS_SHIFT 8
#define GITS_TYPER_DEVBITS_SHIFT 13
#define GITS_TYPER_DEVBITS GENMASK_ULL(17, 13)
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index b6cf570dc98c..00a85b64e524 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -610,6 +610,8 @@ static inline cpumask_t *mm_cpumask(struct mm_struct *mm)
struct mmu_gather;
extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm,
unsigned long start, unsigned long end);
+void tlb_gather_mmu_vma(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
extern void tlb_finish_mmu(struct mmu_gather *tlb,
unsigned long start, unsigned long end);
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
index f27894e50ef1..4269b6425278 100644
--- a/include/linux/netfilter/ipset/ip_set.h
+++ b/include/linux/netfilter/ipset/ip_set.h
@@ -306,7 +306,7 @@ enum {
/* register and unregister set references */
extern ip_set_id_t ip_set_get_byname(struct net *net,
- const char *name, struct ip_set **set);
+ const struct nlattr *name, struct ip_set **set);
extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name);
extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
diff --git a/include/linux/property.h b/include/linux/property.h
index 34ac286db88d..0604bb73e628 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -85,9 +85,12 @@ const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_next_parent(
struct fwnode_handle *fwnode);
+struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode);
unsigned int fwnode_count_parents(const struct fwnode_handle *fwn);
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwn,
unsigned int depth);
+bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor,
+ struct fwnode_handle *test_child);
struct fwnode_handle *fwnode_get_next_child_node(
const struct fwnode_handle *fwnode, struct fwnode_handle *child);
struct fwnode_handle *fwnode_get_next_available_child_node(
@@ -116,7 +119,7 @@ struct fwnode_handle *device_get_named_child_node(struct device *dev,
struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode);
void fwnode_handle_put(struct fwnode_handle *fwnode);
-int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index);
+int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index);
unsigned int device_get_child_node_count(struct device *dev);
diff --git a/include/linux/security.h b/include/linux/security.h
index c75dd495be77..2b8a00118903 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -123,6 +123,7 @@ enum lockdown_reason {
LOCKDOWN_XMON_WR,
LOCKDOWN_BPF_WRITE_USER,
LOCKDOWN_DBG_WRITE_KERNEL,
+ LOCKDOWN_XEN_USER_ACTIONS,
LOCKDOWN_INTEGRITY_MAX,
LOCKDOWN_KCORE,
LOCKDOWN_KPROBES,
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 0d429a102d41..e62ef6fe81fa 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -197,6 +197,12 @@ static inline unsigned long migration_entry_to_pfn(swp_entry_t entry)
static inline struct page *migration_entry_to_page(swp_entry_t entry)
{
struct page *p = pfn_to_page(swp_offset(entry));
+ /*
+ * Ensure we do not race with split, which might alter tail pages
+ * into new folios and thus result in observing an unlocked page.
+ * This matches the write barrier in __split_huge_page_tail().
+ */
+ smp_rmb();
/*
* Any use of migration entries may only occur while the
* corresponding page is locked
diff --git a/include/linux/usb.h b/include/linux/usb.h
index bf5f2ead49c4..72937287c3fc 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1798,14 +1798,18 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
* SYNCHRONOUS CALL SUPPORT *
*-------------------------------------------------------------------*/
+/* Maximum value allowed for timeout in synchronous routines below */
+#define USB_MAX_SYNCHRONOUS_TIMEOUT 60000 /* ms */
+
extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value, __u16 index,
void *data, __u16 size, int timeout);
extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout);
extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
- void *data, int len, int *actual_length,
- int timeout);
+ void *data, int len, int *actual_length, int timeout);
+extern int usb_bulk_msg_killable(struct usb_device *usb_dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout);
/* wrappers around usb_control_msg() for the most common standard requests */
int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request,
diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h
index 659b0ea25b4d..16e024ca1587 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/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 25dd157728a3..af9eaab50f05 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1570,6 +1570,11 @@ struct nft_trans_gc {
struct rcu_head rcu;
};
+static inline int nft_trans_gc_space(const struct nft_trans_gc *trans)
+{
+ return NFT_TRANS_GC_BATCHCOUNT - trans->count;
+}
+
struct nft_trans_gc *nft_trans_gc_alloc(struct nft_set *set,
unsigned int gc_seq, gfp_t gfp);
void nft_trans_gc_destroy(struct nft_trans_gc *trans);
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 7356f41d23ba..d3d088dc0ae8 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -181,6 +181,8 @@ enum {
NLA_S64,
NLA_BITFIELD32,
NLA_REJECT,
+ NLA_BE16,
+ NLA_BE32,
__NLA_TYPE_MAX,
};
@@ -231,6 +233,7 @@ enum nla_policy_validation {
* NLA_U32, NLA_U64,
* NLA_S8, NLA_S16,
* NLA_S32, NLA_S64,
+ * NLA_BE16, NLA_BE32,
* NLA_MSECS Leaving the length field zero will verify the
* given type fits, using it verifies minimum length
* just like "All other"
@@ -261,6 +264,8 @@ enum nla_policy_validation {
* NLA_U16,
* NLA_U32,
* NLA_U64,
+ * NLA_BE16,
+ * NLA_BE32,
* NLA_S8,
* NLA_S16,
* NLA_S32,
@@ -317,18 +322,10 @@ struct nla_policy {
u8 validation_type;
u16 len;
union {
- const u32 bitfield32_valid;
- const u32 mask;
- const char *reject_message;
- const struct nla_policy *nested_policy;
- struct netlink_range_validation *range;
- struct netlink_range_validation_signed *range_signed;
- struct {
- s16 min, max;
- };
- int (*validate)(const struct nlattr *attr,
- struct netlink_ext_ack *extack);
- /* This entry is special, and used for the attribute at index 0
+ /**
+ * @strict_start_type: first attribute to validate strictly
+ *
+ * This entry is special, and used for the attribute at index 0
* only, and specifies special data about the policy, namely it
* specifies the "boundary type" where strict length validation
* starts for any attribute types >= this value, also, strict
@@ -347,6 +344,19 @@ struct nla_policy {
* was added to enforce strict validation from thereon.
*/
u16 strict_start_type;
+
+ /* private: use NLA_POLICY_*() to set */
+ const u32 bitfield32_valid;
+ const u32 mask;
+ const char *reject_message;
+ const struct nla_policy *nested_policy;
+ struct netlink_range_validation *range;
+ struct netlink_range_validation_signed *range_signed;
+ struct {
+ s16 min, max;
+ };
+ int (*validate)(const struct nlattr *attr,
+ struct netlink_ext_ack *extack);
};
};
@@ -364,8 +374,9 @@ struct nla_policy {
#define NLA_POLICY_BITFIELD32(valid) \
{ .type = NLA_BITFIELD32, .bitfield32_valid = valid }
-#define __NLA_IS_UINT_TYPE(tp) \
- (tp == NLA_U8 || tp == NLA_U16 || tp == NLA_U32 || tp == NLA_U64)
+#define __NLA_IS_UINT_TYPE(tp) \
+ (tp == NLA_U8 || tp == NLA_U16 || tp == NLA_U32 || \
+ tp == NLA_U64 || tp == NLA_BE16 || tp == NLA_BE32)
#define __NLA_IS_SINT_TYPE(tp) \
(tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64)
diff --git a/include/net/tc_act/tc_gate.h b/include/net/tc_act/tc_gate.h
index 8bc6be81a7ad..d9f91ec43a96 100644
--- a/include/net/tc_act/tc_gate.h
+++ b/include/net/tc_act/tc_gate.h
@@ -32,6 +32,7 @@ struct tcf_gate_params {
s32 tcfg_clockid;
size_t num_entries;
struct list_head entries;
+ struct rcu_head rcu;
};
#define GATE_ACT_GATE_OPEN BIT(0)
@@ -39,7 +40,7 @@ struct tcf_gate_params {
struct tcf_gate {
struct tc_action common;
- struct tcf_gate_params param;
+ struct tcf_gate_params __rcu *param;
u8 current_gate_status;
ktime_t current_close_time;
u32 current_entry_octets;
@@ -65,47 +66,65 @@ static inline u32 tcf_gate_index(const struct tc_action *a)
return a->tcfa_index;
}
+static inline struct tcf_gate_params *tcf_gate_params_locked(const struct tc_action *a)
+{
+ struct tcf_gate *gact = to_gate(a);
+
+ return rcu_dereference_protected(gact->param,
+ lockdep_is_held(&gact->tcf_lock));
+}
+
static inline s32 tcf_gate_prio(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
s32 tcfg_prio;
- tcfg_prio = to_gate(a)->param.tcfg_priority;
+ p = tcf_gate_params_locked(a);
+ tcfg_prio = p->tcfg_priority;
return tcfg_prio;
}
static inline u64 tcf_gate_basetime(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
u64 tcfg_basetime;
- tcfg_basetime = to_gate(a)->param.tcfg_basetime;
+ p = tcf_gate_params_locked(a);
+ tcfg_basetime = p->tcfg_basetime;
return tcfg_basetime;
}
static inline u64 tcf_gate_cycletime(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
u64 tcfg_cycletime;
- tcfg_cycletime = to_gate(a)->param.tcfg_cycletime;
+ p = tcf_gate_params_locked(a);
+ tcfg_cycletime = p->tcfg_cycletime;
return tcfg_cycletime;
}
static inline u64 tcf_gate_cycletimeext(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
u64 tcfg_cycletimeext;
- tcfg_cycletimeext = to_gate(a)->param.tcfg_cycletime_ext;
+ p = tcf_gate_params_locked(a);
+ tcfg_cycletimeext = p->tcfg_cycletime_ext;
return tcfg_cycletimeext;
}
static inline u32 tcf_gate_num_entries(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
u32 num_entries;
- num_entries = to_gate(a)->param.num_entries;
+ p = tcf_gate_params_locked(a);
+ num_entries = p->num_entries;
return num_entries;
}
@@ -119,7 +138,7 @@ static inline struct action_gate_entry
u32 num_entries;
int i = 0;
- p = &to_gate(a)->param;
+ p = tcf_gate_params_locked(a);
num_entries = p->num_entries;
list_for_each_entry(entry, &p->entries, list)
diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h
index 24ece06bad9e..97a739c21f1f 100644
--- a/include/net/udp_tunnel.h
+++ b/include/net/udp_tunnel.h
@@ -47,7 +47,7 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
static inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
struct socket **sockp)
{
- return 0;
+ return -EPFNOSUPPORT;
}
#endif
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index fe86172e8602..2b8ae0c89e3f 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -36,6 +36,22 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J
+/* Describes the possible PCM format */
+/*
+ * use SND_SOC_DAI_FORMAT_xx as eash shift.
+ * see
+ * snd_soc_runtime_get_dai_fmt()
+ */
+#define SND_SOC_POSSIBLE_DAIFMT_FORMAT_SHIFT 0
+#define SND_SOC_POSSIBLE_DAIFMT_FORMAT_MASK (0xFFFF << SND_SOC_POSSIBLE_DAIFMT_FORMAT_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_I2S (1 << SND_SOC_DAI_FORMAT_I2S)
+#define SND_SOC_POSSIBLE_DAIFMT_RIGHT_J (1 << SND_SOC_DAI_FORMAT_RIGHT_J)
+#define SND_SOC_POSSIBLE_DAIFMT_LEFT_J (1 << SND_SOC_DAI_FORMAT_LEFT_J)
+#define SND_SOC_POSSIBLE_DAIFMT_DSP_A (1 << SND_SOC_DAI_FORMAT_DSP_A)
+#define SND_SOC_POSSIBLE_DAIFMT_DSP_B (1 << SND_SOC_DAI_FORMAT_DSP_B)
+#define SND_SOC_POSSIBLE_DAIFMT_AC97 (1 << SND_SOC_DAI_FORMAT_AC97)
+#define SND_SOC_POSSIBLE_DAIFMT_PDM (1 << SND_SOC_DAI_FORMAT_PDM)
+
/*
* DAI Clock gating.
*
@@ -45,6 +61,17 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */
#define SND_SOC_DAIFMT_GATED (0 << 4) /* clock is gated */
+/* Describes the possible PCM format */
+/*
+ * define GATED -> CONT. GATED will be selected if both are selected.
+ * see
+ * snd_soc_runtime_get_dai_fmt()
+ */
+#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT 16
+#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_MASK (0xFFFF << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_GATED (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_CONT (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
+
/*
* DAI hardware signal polarity.
*
@@ -71,22 +98,46 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */
#define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */
+/* Describes the possible PCM format */
+#define SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT 32
+#define SND_SOC_POSSIBLE_DAIFMT_INV_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_NB_NF (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_NB_IF (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_IB_NF (0x4ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_IB_IF (0x8ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
+
/*
- * DAI hardware clock masters.
+ * DAI hardware clock providers/consumers
*
* This is wrt the codec, the inverse is true for the interface
- * i.e. if the codec is clk and FRM master then the interface is
- * clk and frame secondary.
+ * i.e. if the codec is clk and FRM provider then the interface is
+ * clk and frame consumer.
*/
-#define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */
-#define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk secondary & FRM master */
-#define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame secondary */
-#define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM secondary */
-
-#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
-#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
-#define SND_SOC_DAIFMT_INV_MASK 0x0f00
-#define SND_SOC_DAIFMT_MASTER_MASK 0xf000
+#define SND_SOC_DAIFMT_CBP_CFP (1 << 12) /* codec clk provider & frame provider */
+#define SND_SOC_DAIFMT_CBC_CFP (2 << 12) /* codec clk consumer & frame provider */
+#define SND_SOC_DAIFMT_CBP_CFC (3 << 12) /* codec clk provider & frame consumer */
+#define SND_SOC_DAIFMT_CBC_CFC (4 << 12) /* codec clk consumer & frame follower */
+
+/* previous definitions kept for backwards-compatibility, do not use in new contributions */
+#define SND_SOC_DAIFMT_CBM_CFM SND_SOC_DAIFMT_CBP_CFP
+#define SND_SOC_DAIFMT_CBS_CFM SND_SOC_DAIFMT_CBC_CFP
+#define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC
+#define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC
+
+/* Describes the possible PCM format */
+#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT 48
+#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_CBP_CFP (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_CBC_CFP (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_CBP_CFC (0x4ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
+#define SND_SOC_POSSIBLE_DAIFMT_CBC_CFC (0x8ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
+
+#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
+#define SND_SOC_DAIFMT_INV_MASK 0x0f00
+#define SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK 0xf000
+
+#define SND_SOC_DAIFMT_MASTER_MASK SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK
/*
* Master Clock Directions
@@ -123,6 +174,8 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio);
/* Digital Audio interface formatting */
+int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd);
+u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority);
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
@@ -281,6 +334,16 @@ struct snd_soc_dai_ops {
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
struct snd_soc_dai *);
+ /*
+ * Format list for auto selection.
+ * Format will be increased if priority format was
+ * not selected.
+ * see
+ * snd_soc_dai_get_fmt()
+ */
+ u64 *auto_selectable_formats;
+ int num_auto_selectable_formats;
+
/* bit field */
unsigned int no_capture_mute:1;
};
diff --git a/include/sound/soc.h b/include/sound/soc.h
index e973044143bc..ea343235098d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1177,6 +1177,8 @@ struct snd_soc_pcm_runtime {
unsigned int pop_wait:1;
unsigned int fe_compr:1; /* for Dynamic PCM */
+ bool initialized;
+
int num_components;
struct snd_soc_component *components[]; /* CPU/Codec/Platform */
};
diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h
index f65b1f6db22d..67c4ba725dad 100644
--- a/include/trace/events/kmem.h
+++ b/include/trace/events/kmem.h
@@ -352,7 +352,13 @@ TRACE_EVENT(rss_stat,
TP_fast_assign(
__entry->mm_id = mm_ptr_to_hash(mm);
- __entry->curr = !!(current->mm == mm);
+ /*
+ * curr is true if the mm matches the current task's mm_struct.
+ * Since kthreads (PF_KTHREAD) have no mm_struct of their own
+ * but can borrow one via kthread_use_mm(), we must filter them
+ * out to avoid incorrectly attributing the RSS update to them.
+ */
+ __entry->curr = current->mm == mm && !(current->flags & PF_KTHREAD);
__entry->member = member;
__entry->size = (count << PAGE_SHIFT);
),
diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h
index f76d11725c6c..dd9fa80184f3 100644
--- a/include/uapi/linux/dma-buf.h
+++ b/include/uapi/linux/dma-buf.h
@@ -20,6 +20,7 @@
#ifndef _DMA_BUF_UAPI_H_
#define _DMA_BUF_UAPI_H_
+#include <linux/ioctl.h>
#include <linux/types.h>
/* begin/end dma-buf functions used for userspace mmap. */
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h
index 26071021e986..56b6b60a814f 100644
--- a/include/uapi/linux/netfilter/nf_conntrack_common.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
@@ -159,5 +159,9 @@ enum ip_conntrack_expect_events {
#define NF_CT_EXPECT_INACTIVE 0x2
#define NF_CT_EXPECT_USERSPACE 0x4
+#ifdef __KERNEL__
+#define NF_CT_EXPECT_MASK (NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE | \
+ NF_CT_EXPECT_USERSPACE)
+#endif
#endif /* _UAPI_NF_CONNTRACK_COMMON_H */
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h
index a74ca232f1fc..da61398b1f8f 100644
--- a/include/uapi/sound/asoc.h
+++ b/include/uapi/sound/asoc.h
@@ -170,16 +170,22 @@
#define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3)
/* DAI topology BCLK parameter
- * For the backwards capability, by default codec is bclk master
+ * For the backwards capability, by default codec is bclk provider
*/
-#define SND_SOC_TPLG_BCLK_CM 0 /* codec is bclk master */
-#define SND_SOC_TPLG_BCLK_CS 1 /* codec is bclk slave */
+#define SND_SOC_TPLG_BCLK_CP 0 /* codec is bclk provider */
+#define SND_SOC_TPLG_BCLK_CC 1 /* codec is bclk consumer */
+/* keep previous definitions for compatibility */
+#define SND_SOC_TPLG_BCLK_CM SND_SOC_TPLG_BCLK_CP
+#define SND_SOC_TPLG_BCLK_CS SND_SOC_TPLG_BCLK_CC
/* DAI topology FSYNC parameter
- * For the backwards capability, by default codec is fsync master
+ * For the backwards capability, by default codec is fsync provider
*/
-#define SND_SOC_TPLG_FSYNC_CM 0 /* codec is fsync master */
-#define SND_SOC_TPLG_FSYNC_CS 1 /* codec is fsync slave */
+#define SND_SOC_TPLG_FSYNC_CP 0 /* codec is fsync provider */
+#define SND_SOC_TPLG_FSYNC_CC 1 /* codec is fsync consumer */
+/* keep previous definitions for compatibility */
+#define SND_SOC_TPLG_FSYNC_CM SND_SOC_TPLG_FSYNC_CP
+#define SND_SOC_TPLG_FSYNC_CS SND_SOC_TPLG_FSYNC_CC
/*
* Block Header.
@@ -336,8 +342,8 @@ struct snd_soc_tplg_hw_config {
__u8 clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */
__u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */
__u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */
- __u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */
- __u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */
+ __u8 bclk_provider; /* SND_SOC_TPLG_BCLK_ value */
+ __u8 fsync_provider; /* SND_SOC_TPLG_FSYNC_ value */
__u8 mclk_direction; /* SND_SOC_TPLG_MCLK_ value */
__le16 reserved; /* for 32bit alignment */
__le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */
diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c
index c5d249f5d214..926890f5086e 100644
--- a/io_uring/io-wq.c
+++ b/io_uring/io-wq.c
@@ -554,9 +554,9 @@ static void io_worker_handle_work(struct io_worker *worker)
struct io_wqe_acct *acct = io_wqe_get_acct(worker);
struct io_wqe *wqe = worker->wqe;
struct io_wq *wq = wqe->wq;
- bool do_kill = test_bit(IO_WQ_BIT_EXIT, &wq->state);
do {
+ bool do_kill = test_bit(IO_WQ_BIT_EXIT, &wq->state);
struct io_wq_work *work;
get_next:
/*
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 7e228ac3342f..dea1fb22c0ef 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -5980,7 +5980,7 @@ static int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
return 0;
}
-static int io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
+static int __io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_poll_iocb *poll = &req->poll;
struct io_poll_table ipt;
@@ -5992,11 +5992,21 @@ static int io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
if (!ret && ipt.error)
req_set_fail(req);
ret = ret ?: ipt.error;
- if (ret)
+ if (ret > 0) {
__io_req_complete(req, issue_flags, ret, 0);
+ return ret;
+ }
return 0;
}
+static int io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
+{
+ int ret;
+
+ ret = __io_poll_add(req, issue_flags);
+ return ret < 0 ? ret : 0;
+}
+
static int io_poll_update(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_ring_ctx *ctx = req->ctx;
@@ -6012,6 +6022,7 @@ static int io_poll_update(struct io_kiocb *req, unsigned int issue_flags)
ret = preq ? -EALREADY : -ENOENT;
goto out;
}
+ preq->result = -ECANCELED;
spin_unlock(&ctx->completion_lock);
if (req->poll_update.update_events || req->poll_update.update_user_data) {
@@ -6024,16 +6035,17 @@ static int io_poll_update(struct io_kiocb *req, unsigned int issue_flags)
if (req->poll_update.update_user_data)
preq->user_data = req->poll_update.new_user_data;
- ret2 = io_poll_add(preq, issue_flags);
+ ret2 = __io_poll_add(preq, issue_flags);
/* successfully updated, don't complete poll request */
if (!ret2)
goto out;
+ preq->result = ret2;
+
}
- req_set_fail(preq);
- io_req_complete(preq, -ECANCELED);
+ if (preq->result < 0)
+ req_set_fail(preq);
+ io_req_complete(preq, preq->result);
out:
- if (ret < 0)
- req_set_fail(req);
/* complete update request, we're done with it */
io_req_complete(req, ret);
io_ring_submit_unlock(ctx, !(issue_flags & IO_URING_F_NONBLOCK));
@@ -8524,8 +8536,19 @@ static int io_uring_alloc_task_context(struct task_struct *task,
void __io_uring_free(struct task_struct *tsk)
{
struct io_uring_task *tctx = tsk->io_uring;
+ struct io_tctx_node *node;
+ unsigned long index;
- WARN_ON_ONCE(!xa_empty(&tctx->xa));
+ /*
+ * Fault injection forcing allocation errors in the xa_store() path
+ * can lead to xa_empty() returning false, even though no actual
+ * node is stored in the xarray. Until that gets sorted out, attempt
+ * an iteration here and warn if any entries are found.
+ */
+ xa_for_each(&tctx->xa, index, node) {
+ WARN_ON_ONCE(1);
+ break;
+ }
WARN_ON_ONCE(tctx->io_wq);
WARN_ON_ONCE(tctx->cached_refs);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 150aa47b4a9a..e6cf29b117e1 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7823,6 +7823,10 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
}
break;
case BPF_JSET:
+ /* Forget the ranges before narrowing tnums, to avoid invariant
+ * violations if we're on a dead branch.
+ */
+ __mark_reg_unbounded(false_reg);
if (is_jmp32) {
false_32off = tnum_and(false_32off, tnum_const(~val32));
if (is_power_of_2(val32))
@@ -9455,8 +9459,13 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
* since someone could have accessed through (ptr - k), or
* even done ptr -= k in a register, to get a safe access.
*/
- if (rold->range > rcur->range)
+ if (rold->range < 0 || rcur->range < 0) {
+ /* special case for [BEYOND|AT]_PKT_END */
+ if (rold->range != rcur->range)
+ return false;
+ } else if (rold->range > rcur->range) {
return false;
+ }
/* If the offsets don't match, we can't trust our alignment;
* nor can we be sure that we won't fall out of range.
*/
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index d709375d7509..8d420e00d89a 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -2413,6 +2413,7 @@ static void cgroup_migrate_add_task(struct task_struct *task,
mgctx->tset.nr_tasks++;
+ css_set_skip_task_iters(cset, task);
list_move_tail(&task->cg_list, &cset->mg_tasks);
if (list_empty(&cset->mg_node))
list_add_tail(&cset->mg_node,
diff --git a/kernel/fork.c b/kernel/fork.c
index 072fe9d6c47b..531de2d1b3bf 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2989,7 +2989,7 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
return 0;
/* don't need lock here; in the worst case we'll do useless copy */
- if (fs->users == 1)
+ if (!(unshare_flags & CLONE_NEWNS) && fs->users == 1)
return 0;
*new_fsp = copy_fs_struct(fs);
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index cde0ca876b93..df86c0e49418 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -2785,9 +2785,9 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
ktime_t *time, int trylock)
{
struct hrtimer_sleeper timeout, *to;
- struct task_struct *exiting = NULL;
struct rt_mutex_waiter rt_waiter;
struct futex_hash_bucket *hb;
+ struct task_struct *exiting;
struct futex_q q = futex_q_init;
int res, ret;
@@ -2800,6 +2800,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
to = futex_setup_timer(time, &timeout, FLAGS_CLOCKRT, 0);
retry:
+ exiting = NULL;
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, FUTEX_WRITE);
if (unlikely(ret != 0))
goto out;
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index cdc3e690de71..50b18ba9ca9c 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -158,6 +158,14 @@ static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev,
return cpuidle_enter(drv, dev, next_state);
}
+static void idle_call_stop_or_retain_tick(bool stop_tick)
+{
+ if (stop_tick || tick_nohz_tick_stopped())
+ tick_nohz_idle_stop_tick();
+ else
+ tick_nohz_idle_retain_tick();
+}
+
/**
* cpuidle_idle_call - the main idle function
*
@@ -167,7 +175,7 @@ static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* set, and it returns with polling set. If it ever stops polling, it
* must clear the polling bit.
*/
-static void cpuidle_idle_call(void)
+static void cpuidle_idle_call(bool stop_tick)
{
struct cpuidle_device *dev = cpuidle_get_device();
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
@@ -189,7 +197,7 @@ static void cpuidle_idle_call(void)
*/
if (cpuidle_not_available(drv, dev)) {
- tick_nohz_idle_stop_tick();
+ idle_call_stop_or_retain_tick(stop_tick);
default_idle_call();
goto exit_idle;
@@ -223,24 +231,35 @@ static void cpuidle_idle_call(void)
next_state = cpuidle_find_deepest_state(drv, dev, max_latency_ns);
call_cpuidle(drv, dev, next_state);
- } else {
- bool stop_tick = true;
+ } else if (drv->state_count > 1) {
+ /*
+ * stop_tick is expected to be true by default by cpuidle
+ * governors, which allows them to select idle states with
+ * target residency above the tick period length.
+ */
+ stop_tick = true;
/*
* Ask the cpuidle framework to choose a convenient idle state.
*/
next_state = cpuidle_select(drv, dev, &stop_tick);
- if (stop_tick || tick_nohz_tick_stopped())
- tick_nohz_idle_stop_tick();
- else
- tick_nohz_idle_retain_tick();
+ idle_call_stop_or_retain_tick(stop_tick);
entered_state = call_cpuidle(drv, dev, next_state);
/*
* Give the governor an opportunity to reflect on the outcome
*/
cpuidle_reflect(dev, entered_state);
+ } else {
+ idle_call_stop_or_retain_tick(stop_tick);
+
+ /*
+ * If there is only a single idle state (or none), there is
+ * nothing meaningful for the governor to choose. Skip the
+ * governor and always use state 0.
+ */
+ call_cpuidle(drv, dev, 0);
}
exit_idle:
@@ -261,6 +280,7 @@ static void cpuidle_idle_call(void)
static void do_idle(void)
{
int cpu = smp_processor_id();
+ bool got_tick = false;
/*
* Check if we need to update blocked load
@@ -303,8 +323,9 @@ static void do_idle(void)
tick_nohz_idle_restart_tick();
cpu_idle_poll();
} else {
- cpuidle_idle_call();
+ cpuidle_idle_call(got_tick);
}
+ got_tick = tick_nohz_idle_got_tick();
arch_cpu_idle_exit();
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index abe0f16d5364..c2870c9cae14 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1549,7 +1549,7 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
unsigned long bitmap_len = table->maxlen;
unsigned long *bitmap = *(unsigned long **) table->data;
unsigned long *tmp_bitmap = NULL;
- char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c;
+ char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c = 0;
if (!bitmap || !bitmap_len || !left || (*ppos && !write)) {
*lenp = 0;
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 1de426d3f694..771b31018517 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -606,7 +606,7 @@ static s64 alarm_timer_forward(struct k_itimer *timr, ktime_t now)
{
struct alarm *alarm = &timr->it.alarm.alarmtimer;
- return alarm_forward(alarm, timr->it_interval, now);
+ return alarm_forward(alarm, now, timr->it_interval);
}
/**
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 483f8a3e24d0..37c381607f37 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -365,11 +365,14 @@ SYSCALL_DEFINE1(adjtimex_time32, struct old_timex32 __user *, utp)
}
#endif
-/*
- * Convert jiffies to milliseconds and back.
+/**
+ * jiffies_to_msecs - Convert jiffies to milliseconds
+ * @j: jiffies value
*
* Avoid unnecessary multiplications/divisions in the
- * two most common HZ cases:
+ * two most common HZ cases.
+ *
+ * Return: milliseconds value
*/
unsigned int jiffies_to_msecs(const unsigned long j)
{
@@ -388,6 +391,12 @@ unsigned int jiffies_to_msecs(const unsigned long j)
}
EXPORT_SYMBOL(jiffies_to_msecs);
+/**
+ * jiffies_to_usecs - Convert jiffies to microseconds
+ * @j: jiffies value
+ *
+ * Return: microseconds value
+ */
unsigned int jiffies_to_usecs(const unsigned long j)
{
/*
@@ -408,8 +417,15 @@ unsigned int jiffies_to_usecs(const unsigned long j)
}
EXPORT_SYMBOL(jiffies_to_usecs);
-/*
+/**
* mktime64 - Converts date to seconds.
+ * @year0: year to convert
+ * @mon0: month to convert
+ * @day: day to convert
+ * @hour: hour to convert
+ * @min: minute to convert
+ * @sec: second to convert
+ *
* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
@@ -427,6 +443,8 @@ EXPORT_SYMBOL(jiffies_to_usecs);
*
* An encoding of midnight at the end of the day as 24:00:00 - ie. midnight
* tomorrow - (allowable under ISO 8601) is supported.
+ *
+ * Return: seconds since the epoch time for the given input date
*/
time64_t mktime64(const unsigned int year0, const unsigned int mon0,
const unsigned int day, const unsigned int hour,
@@ -471,8 +489,7 @@ EXPORT_SYMBOL(ns_to_kernel_old_timeval);
* Set seconds and nanoseconds field of a timespec variable and
* normalize to the timespec storage format
*
- * Note: The tv_nsec part is always in the range of
- * 0 <= tv_nsec < NSEC_PER_SEC
+ * Note: The tv_nsec part is always in the range of 0 <= tv_nsec < NSEC_PER_SEC.
* For negative values only the tv_sec field is negative !
*/
void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec)
@@ -501,7 +518,7 @@ EXPORT_SYMBOL(set_normalized_timespec64);
* ns_to_timespec64 - Convert nanoseconds to timespec64
* @nsec: the nanoseconds value to be converted
*
- * Returns the timespec64 representation of the nsec parameter.
+ * Return: the timespec64 representation of the nsec parameter.
*/
struct timespec64 ns_to_timespec64(const s64 nsec)
{
@@ -548,6 +565,8 @@ EXPORT_SYMBOL(ns_to_timespec64);
* runtime.
* the _msecs_to_jiffies helpers are the HZ dependent conversion
* routines found in include/linux/jiffies.h
+ *
+ * Return: jiffies value
*/
unsigned long __msecs_to_jiffies(const unsigned int m)
{
@@ -560,6 +579,12 @@ unsigned long __msecs_to_jiffies(const unsigned int m)
}
EXPORT_SYMBOL(__msecs_to_jiffies);
+/**
+ * __usecs_to_jiffies: - convert microseconds to jiffies
+ * @u: time in milliseconds
+ *
+ * Return: jiffies value
+ */
unsigned long __usecs_to_jiffies(const unsigned int u)
{
if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET))
@@ -568,7 +593,10 @@ unsigned long __usecs_to_jiffies(const unsigned int u)
}
EXPORT_SYMBOL(__usecs_to_jiffies);
-/*
+/**
+ * timespec64_to_jiffies - convert a timespec64 value to jiffies
+ * @value: pointer to &struct timespec64
+ *
* The TICK_NSEC - 1 rounds up the value to the next resolution. Note
* that a remainder subtract here would not do the right thing as the
* resolution values don't fall on second boundries. I.e. the line:
@@ -582,8 +610,9 @@ EXPORT_SYMBOL(__usecs_to_jiffies);
*
* The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec
* value to a scaled second value.
+ *
+ * Return: jiffies value
*/
-
unsigned long
timespec64_to_jiffies(const struct timespec64 *value)
{
@@ -601,6 +630,11 @@ timespec64_to_jiffies(const struct timespec64 *value)
}
EXPORT_SYMBOL(timespec64_to_jiffies);
+/**
+ * jiffies_to_timespec64 - convert jiffies value to &struct timespec64
+ * @jiffies: jiffies value
+ * @value: pointer to &struct timespec64
+ */
void
jiffies_to_timespec64(const unsigned long jiffies, struct timespec64 *value)
{
@@ -618,6 +652,13 @@ EXPORT_SYMBOL(jiffies_to_timespec64);
/*
* Convert jiffies/jiffies_64 to clock_t and back.
*/
+
+/**
+ * jiffies_to_clock_t - Convert jiffies to clock_t
+ * @x: jiffies value
+ *
+ * Return: jiffies converted to clock_t (CLOCKS_PER_SEC)
+ */
clock_t jiffies_to_clock_t(unsigned long x)
{
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
@@ -632,6 +673,12 @@ clock_t jiffies_to_clock_t(unsigned long x)
}
EXPORT_SYMBOL(jiffies_to_clock_t);
+/**
+ * clock_t_to_jiffies - Convert clock_t to jiffies
+ * @x: clock_t value
+ *
+ * Return: clock_t value converted to jiffies
+ */
unsigned long clock_t_to_jiffies(unsigned long x)
{
#if (HZ % USER_HZ)==0
@@ -649,7 +696,13 @@ unsigned long clock_t_to_jiffies(unsigned long x)
}
EXPORT_SYMBOL(clock_t_to_jiffies);
-u64 jiffies_64_to_clock_t(u64 x)
+/**
+ * jiffies_64_to_clock_t - Convert jiffies_64 to clock_t
+ * @x: jiffies_64 value
+ *
+ * Return: jiffies_64 value converted to 64-bit "clock_t" (CLOCKS_PER_SEC)
+ */
+notrace u64 jiffies_64_to_clock_t(u64 x)
{
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
# if HZ < USER_HZ
@@ -671,6 +724,12 @@ u64 jiffies_64_to_clock_t(u64 x)
}
EXPORT_SYMBOL(jiffies_64_to_clock_t);
+/**
+ * nsec_to_clock_t - Convert nsec value to clock_t
+ * @x: nsec value
+ *
+ * Return: nsec value converted to 64-bit "clock_t" (CLOCKS_PER_SEC)
+ */
u64 nsec_to_clock_t(u64 x)
{
#if (NSEC_PER_SEC % USER_HZ) == 0
@@ -687,6 +746,12 @@ u64 nsec_to_clock_t(u64 x)
#endif
}
+/**
+ * jiffies64_to_nsecs - Convert jiffies64 to nanoseconds
+ * @j: jiffies64 value
+ *
+ * Return: nanoseconds value
+ */
u64 jiffies64_to_nsecs(u64 j)
{
#if !(NSEC_PER_SEC % HZ)
@@ -697,6 +762,12 @@ u64 jiffies64_to_nsecs(u64 j)
}
EXPORT_SYMBOL(jiffies64_to_nsecs);
+/**
+ * jiffies64_to_msecs - Convert jiffies64 to milliseconds
+ * @j: jiffies64 value
+ *
+ * Return: milliseconds value
+ */
u64 jiffies64_to_msecs(const u64 j)
{
#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
@@ -719,6 +790,8 @@ EXPORT_SYMBOL(jiffies64_to_msecs);
* note:
* NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512)
* ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years
+ *
+ * Return: nsecs converted to jiffies64 value
*/
u64 nsecs_to_jiffies64(u64 n)
{
@@ -750,6 +823,8 @@ EXPORT_SYMBOL(nsecs_to_jiffies64);
* note:
* NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512)
* ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years
+ *
+ * Return: nsecs converted to jiffies value
*/
unsigned long nsecs_to_jiffies(u64 n)
{
@@ -757,10 +832,16 @@ unsigned long nsecs_to_jiffies(u64 n)
}
EXPORT_SYMBOL_GPL(nsecs_to_jiffies);
-/*
- * Add two timespec64 values and do a safety check for overflow.
+/**
+ * timespec64_add_safe - Add two timespec64 values and do a safety check
+ * for overflow.
+ * @lhs: first (left) timespec64 to add
+ * @rhs: second (right) timespec64 to add
+ *
* It's assumed that both values are valid (>= 0).
* And, each timespec64 is in normalized form.
+ *
+ * Return: sum of @lhs + @rhs
*/
struct timespec64 timespec64_add_safe(const struct timespec64 lhs,
const struct timespec64 rhs)
@@ -778,6 +859,15 @@ struct timespec64 timespec64_add_safe(const struct timespec64 lhs,
return res;
}
+/**
+ * get_timespec64 - get user's time value into kernel space
+ * @ts: destination &struct timespec64
+ * @uts: user's time value as &struct __kernel_timespec
+ *
+ * Handles compat or 32-bit modes.
+ *
+ * Return: %0 on success or negative errno on error
+ */
int get_timespec64(struct timespec64 *ts,
const struct __kernel_timespec __user *uts)
{
@@ -801,6 +891,14 @@ int get_timespec64(struct timespec64 *ts,
}
EXPORT_SYMBOL_GPL(get_timespec64);
+/**
+ * put_timespec64 - convert timespec64 value to __kernel_timespec format and
+ * copy the latter to userspace
+ * @ts: input &struct timespec64
+ * @uts: user's &struct __kernel_timespec
+ *
+ * Return: %0 on success or negative errno on error
+ */
int put_timespec64(const struct timespec64 *ts,
struct __kernel_timespec __user *uts)
{
@@ -839,6 +937,15 @@ static int __put_old_timespec32(const struct timespec64 *ts64,
return copy_to_user(cts, &ts, sizeof(ts)) ? -EFAULT : 0;
}
+/**
+ * get_old_timespec32 - get user's old-format time value into kernel space
+ * @ts: destination &struct timespec64
+ * @uts: user's old-format time value (&struct old_timespec32)
+ *
+ * Handles X86_X32_ABI compatibility conversion.
+ *
+ * Return: %0 on success or negative errno on error
+ */
int get_old_timespec32(struct timespec64 *ts, const void __user *uts)
{
if (COMPAT_USE_64BIT_TIME)
@@ -848,6 +955,16 @@ int get_old_timespec32(struct timespec64 *ts, const void __user *uts)
}
EXPORT_SYMBOL_GPL(get_old_timespec32);
+/**
+ * put_old_timespec32 - convert timespec64 value to &struct old_timespec32 and
+ * copy the latter to userspace
+ * @ts: input &struct timespec64
+ * @uts: user's &struct old_timespec32
+ *
+ * Handles X86_X32_ABI compatibility conversion.
+ *
+ * Return: %0 on success or negative errno on error
+ */
int put_old_timespec32(const struct timespec64 *ts, void __user *uts)
{
if (COMPAT_USE_64BIT_TIME)
@@ -857,6 +974,13 @@ int put_old_timespec32(const struct timespec64 *ts, void __user *uts)
}
EXPORT_SYMBOL_GPL(put_old_timespec32);
+/**
+ * get_itimerspec64 - get user's &struct __kernel_itimerspec into kernel space
+ * @it: destination &struct itimerspec64
+ * @uit: user's &struct __kernel_itimerspec
+ *
+ * Return: %0 on success or negative errno on error
+ */
int get_itimerspec64(struct itimerspec64 *it,
const struct __kernel_itimerspec __user *uit)
{
@@ -872,6 +996,14 @@ int get_itimerspec64(struct itimerspec64 *it,
}
EXPORT_SYMBOL_GPL(get_itimerspec64);
+/**
+ * put_itimerspec64 - convert &struct itimerspec64 to __kernel_itimerspec format
+ * and copy the latter to userspace
+ * @it: input &struct itimerspec64
+ * @uit: user's &struct __kernel_itimerspec
+ *
+ * Return: %0 on success or negative errno on error
+ */
int put_itimerspec64(const struct itimerspec64 *it,
struct __kernel_itimerspec __user *uit)
{
@@ -887,6 +1019,13 @@ int put_itimerspec64(const struct itimerspec64 *it,
}
EXPORT_SYMBOL_GPL(put_itimerspec64);
+/**
+ * get_old_itimerspec32 - get user's &struct old_itimerspec32 into kernel space
+ * @its: destination &struct itimerspec64
+ * @uits: user's &struct old_itimerspec32
+ *
+ * Return: %0 on success or negative errno on error
+ */
int get_old_itimerspec32(struct itimerspec64 *its,
const struct old_itimerspec32 __user *uits)
{
@@ -898,6 +1037,14 @@ int get_old_itimerspec32(struct itimerspec64 *its,
}
EXPORT_SYMBOL_GPL(get_old_itimerspec32);
+/**
+ * put_old_itimerspec32 - convert &struct itimerspec64 to &struct
+ * old_itimerspec32 and copy the latter to userspace
+ * @its: input &struct itimerspec64
+ * @uits: user's &struct old_itimerspec32
+ *
+ * Return: %0 on success or negative errno on error
+ */
int put_old_itimerspec32(const struct itimerspec64 *its,
struct old_itimerspec32 __user *uits)
{
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8f4d6c974372..5bcd4cbeeb4f 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -8771,7 +8771,7 @@ static void
init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer);
static int
-allocate_trace_buffer(struct trace_array *tr, struct array_buffer *buf, int size)
+allocate_trace_buffer(struct trace_array *tr, struct array_buffer *buf, unsigned long size)
{
enum ring_buffer_flags rb_flags;
@@ -8797,7 +8797,7 @@ allocate_trace_buffer(struct trace_array *tr, struct array_buffer *buf, int size
return 0;
}
-static int allocate_trace_buffers(struct trace_array *tr, int size)
+static int allocate_trace_buffers(struct trace_array *tr, unsigned long size)
{
int ret;
@@ -9728,7 +9728,7 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
__init static int tracer_alloc_buffers(void)
{
- int ring_buf_size;
+ unsigned long ring_buf_size;
int ret = -ENOMEM;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index da4a69e1929c..b85045161562 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -3393,27 +3393,23 @@ static __init int event_trace_memsetup(void)
return 0;
}
-static __init void
-early_enable_events(struct trace_array *tr, bool disable_first)
+/*
+ * Helper function to enable or disable a comma-separated list of events
+ * from the bootup buffer.
+ */
+static __init void __early_set_events(struct trace_array *tr, bool enable)
{
char *buf = bootup_event_buf;
char *token;
- int ret;
-
- while (true) {
- token = strsep(&buf, ",");
-
- if (!token)
- break;
+ while ((token = strsep(&buf, ","))) {
if (*token) {
- /* Restarting syscalls requires that we stop them first */
- if (disable_first)
+ if (enable) {
+ if (ftrace_set_clr_event(tr, token, 1))
+ pr_warn("Failed to enable trace event: %s\n", token);
+ } else {
ftrace_set_clr_event(tr, token, 0);
-
- ret = ftrace_set_clr_event(tr, token, 1);
- if (ret)
- pr_warn("Failed to enable trace event: %s\n", token);
+ }
}
/* Put back the comma to allow this to be called again */
@@ -3422,6 +3418,31 @@ early_enable_events(struct trace_array *tr, bool disable_first)
}
}
+/**
+ * early_enable_events - enable events from the bootup buffer
+ * @tr: The trace array to enable the events in
+ * @disable_first: If true, disable all events before enabling them
+ *
+ * This function enables events from the bootup buffer. If @disable_first
+ * is true, it will first disable all events in the buffer before enabling
+ * them.
+ *
+ * For syscall events, which rely on a global refcount to register the
+ * SYSCALL_WORK_SYSCALL_TRACEPOINT flag (especially for pid 1), we must
+ * ensure the refcount hits zero before re-enabling them. A simple
+ * "disable then enable" per-event is not enough if multiple syscalls are
+ * used, as the refcount will stay above zero. Thus, we need a two-phase
+ * approach: disable all, then enable all.
+ */
+static __init void
+early_enable_events(struct trace_array *tr, bool disable_first)
+{
+ if (disable_first)
+ __early_set_events(tr, false);
+
+ __early_set_events(tr, true);
+}
+
static __init int event_trace_enable(void)
{
struct trace_array *tr = top_trace_array();
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index 649ed44f199c..b4c0c34cee13 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -250,7 +250,7 @@ int __init xbc_node_compose_key_after(struct xbc_node *root,
depth ? "." : "");
if (ret < 0)
return ret;
- if (ret > size) {
+ if (ret >= size) {
size = 0;
} else {
size -= ret;
@@ -436,9 +436,9 @@ static char *skip_spaces_until_newline(char *p)
static int __init __xbc_open_brace(char *p)
{
/* Push the last key as open brace */
- open_brace[brace_index++] = xbc_node_index(last_parent);
if (brace_index >= XBC_DEPTH_MAX)
return xbc_parse_error("Exceed max depth of braces", p);
+ open_brace[brace_index++] = xbc_node_index(last_parent);
return 0;
}
@@ -685,7 +685,7 @@ static int __init xbc_verify_tree(void)
/* Brace closing */
if (brace_index) {
- n = &xbc_nodes[open_brace[brace_index]];
+ n = &xbc_nodes[open_brace[brace_index - 1]];
return xbc_parse_error("Brace is not closed",
xbc_node_get_data(n));
}
diff --git a/lib/crypto/chacha.c b/lib/crypto/chacha.c
index 4ccbec442469..6b6ca1cba818 100644
--- a/lib/crypto/chacha.c
+++ b/lib/crypto/chacha.c
@@ -86,6 +86,8 @@ void chacha_block_generic(u32 *state, u8 *stream, int nrounds)
put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]);
state[12]++;
+
+ memzero_explicit(x, sizeof(x));
}
EXPORT_SYMBOL(chacha_block_generic);
@@ -110,5 +112,7 @@ void hchacha_block_generic(const u32 *state, u32 *stream, int nrounds)
memcpy(&stream[0], &x[0], 16);
memcpy(&stream[4], &x[12], 16);
+
+ memzero_explicit(x, sizeof(x));
}
EXPORT_SYMBOL(hchacha_block_generic);
diff --git a/lib/nlattr.c b/lib/nlattr.c
index aa8fc4371e93..247426c0af0d 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -30,6 +30,8 @@ static const u8 nla_attr_len[NLA_TYPE_MAX+1] = {
[NLA_S16] = sizeof(s16),
[NLA_S32] = sizeof(s32),
[NLA_S64] = sizeof(s64),
+ [NLA_BE16] = sizeof(__be16),
+ [NLA_BE32] = sizeof(__be32),
};
static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
@@ -43,6 +45,8 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
[NLA_S16] = sizeof(s16),
[NLA_S32] = sizeof(s32),
[NLA_S64] = sizeof(s64),
+ [NLA_BE16] = sizeof(__be16),
+ [NLA_BE32] = sizeof(__be32),
};
/*
@@ -125,10 +129,12 @@ void nla_get_range_unsigned(const struct nla_policy *pt,
range->max = U8_MAX;
break;
case NLA_U16:
+ case NLA_BE16:
case NLA_BINARY:
range->max = U16_MAX;
break;
case NLA_U32:
+ case NLA_BE32:
range->max = U32_MAX;
break;
case NLA_U64:
@@ -179,12 +185,20 @@ static int nla_validate_range_unsigned(const struct nla_policy *pt,
value = nla_get_u32(nla);
break;
case NLA_U64:
+ value = nla_get_u64(nla);
+ break;
case NLA_MSECS:
value = nla_get_u64(nla);
break;
case NLA_BINARY:
value = nla_len(nla);
break;
+ case NLA_BE16:
+ value = ntohs(nla_get_be16(nla));
+ break;
+ case NLA_BE32:
+ value = ntohl(nla_get_be32(nla));
+ break;
default:
return -EINVAL;
}
@@ -312,6 +326,8 @@ static int nla_validate_int_range(const struct nla_policy *pt,
case NLA_U64:
case NLA_MSECS:
case NLA_BINARY:
+ case NLA_BE16:
+ case NLA_BE32:
return nla_validate_range_unsigned(pt, nla, extack, validate);
case NLA_S8:
case NLA_S16:
@@ -343,6 +359,12 @@ static int nla_validate_mask(const struct nla_policy *pt,
case NLA_U64:
value = nla_get_u64(nla);
break;
+ case NLA_BE16:
+ value = ntohs(nla_get_be16(nla));
+ break;
+ case NLA_BE32:
+ value = ntohl(nla_get_be32(nla));
+ break;
default:
return -EINVAL;
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 8efe35ea0baa..27fe947b8c69 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -3827,7 +3827,7 @@ static bool is_hugetlb_entry_hwpoisoned(pte_t pte)
int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
struct vm_area_struct *vma)
{
- pte_t *src_pte, *dst_pte, entry, dst_entry;
+ pte_t *src_pte, *dst_pte, entry;
struct page *ptepage;
unsigned long addr;
int cow;
@@ -3865,29 +3865,19 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
break;
}
- /*
- * If the pagetables are shared don't copy or take references.
- * dst_pte == src_pte is the common case of src/dest sharing.
- *
- * However, src could have 'unshared' and dst shares with
- * another vma. If dst_pte !none, this implies sharing.
- * Check here before taking page table lock, and once again
- * after taking the lock below.
- */
- dst_entry = huge_ptep_get(dst_pte);
- if ((dst_pte == src_pte) || !huge_pte_none(dst_entry))
+#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
+ /* If the pagetables are shared, there is nothing to do */
+ if (atomic_read(&virt_to_page(dst_pte)->pt_share_count))
continue;
+#endif
dst_ptl = huge_pte_lock(h, dst, dst_pte);
src_ptl = huge_pte_lockptr(h, src, src_pte);
spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
entry = huge_ptep_get(src_pte);
- dst_entry = huge_ptep_get(dst_pte);
- if (huge_pte_none(entry) || !huge_pte_none(dst_entry)) {
+ if (huge_pte_none(entry)) {
/*
- * Skip if src entry none. Also, skip in the
- * unlikely case dst entry !none as this implies
- * sharing with another vma.
+ * Skip if src entry none.
*/
;
} else if (unlikely(is_hugetlb_entry_migration(entry) ||
@@ -3948,7 +3938,6 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
struct hstate *h = hstate_vma(vma);
unsigned long sz = huge_page_size(h);
struct mmu_notifier_range range;
- bool force_flush = false;
WARN_ON(!is_vm_hugetlb_page(vma));
BUG_ON(start & ~huge_page_mask(h));
@@ -3975,10 +3964,8 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
continue;
ptl = huge_pte_lock(h, mm, ptep);
- if (huge_pmd_unshare(mm, vma, &address, ptep)) {
+ if (huge_pmd_unshare(tlb, vma, &address, ptep)) {
spin_unlock(ptl);
- tlb_flush_pmd_range(tlb, address & PUD_MASK, PUD_SIZE);
- force_flush = true;
continue;
}
@@ -4036,21 +4023,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
mmu_notifier_invalidate_range_end(&range);
tlb_end_vma(tlb, vma);
- /*
- * If we unshared PMDs, the TLB flush was not recorded in mmu_gather. We
- * could defer the flush until now, since by holding i_mmap_rwsem we
- * guaranteed that the last refernece would not be dropped. But we must
- * do the flushing before we return, as otherwise i_mmap_rwsem will be
- * dropped and the last reference to the shared PMDs page might be
- * dropped as well.
- *
- * In theory we could defer the freeing of the PMD pages as well, but
- * huge_pmd_unshare() relies on the exact page_count for the PMD page to
- * detect sharing, so we cannot defer the release of the page either.
- * Instead, do flush now.
- */
- if (force_flush)
- tlb_flush_mmu_tlbonly(tlb);
+ huge_pmd_unshare_flush(tlb, vma);
}
void __unmap_hugepage_range_final(struct mmu_gather *tlb,
@@ -5060,8 +5033,8 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
pte_t pte;
struct hstate *h = hstate_vma(vma);
unsigned long pages = 0;
- bool shared_pmd = false;
struct mmu_notifier_range range;
+ struct mmu_gather tlb;
/*
* In the case of shared PMDs, the area to flush could be beyond
@@ -5074,6 +5047,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
BUG_ON(address >= end);
flush_cache_range(vma, range.start, range.end);
+ tlb_gather_mmu_vma(&tlb, vma, range.start, range.end);
mmu_notifier_invalidate_range_start(&range);
i_mmap_lock_write(vma->vm_file->f_mapping);
@@ -5083,10 +5057,9 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
if (!ptep)
continue;
ptl = huge_pte_lock(h, mm, ptep);
- if (huge_pmd_unshare(mm, vma, &address, ptep)) {
+ if (huge_pmd_unshare(&tlb, vma, &address, ptep)) {
pages++;
spin_unlock(ptl);
- shared_pmd = true;
continue;
}
pte = huge_ptep_get(ptep);
@@ -5117,22 +5090,15 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
pte = arch_make_huge_pte(pte, vma, NULL, 0);
huge_ptep_modify_prot_commit(vma, address, ptep, old_pte, pte);
pages++;
+ tlb_remove_huge_tlb_entry(h, &tlb, ptep, address);
}
spin_unlock(ptl);
cond_resched();
}
- /*
- * Must flush TLB before releasing i_mmap_rwsem: x86's huge_pmd_unshare
- * may have cleared our pud entry and done put_page on the page table:
- * once we release i_mmap_rwsem, another task can do the final put_page
- * and that page table be reused and filled with junk. If we actually
- * did unshare a page of pmds, flush the range corresponding to the pud.
- */
- if (shared_pmd)
- flush_hugetlb_tlb_range(vma, range.start, range.end);
- else
- flush_hugetlb_tlb_range(vma, start, end);
+
+ tlb_flush_mmu_tlbonly(&tlb);
+ huge_pmd_unshare_flush(&tlb, vma);
/*
* No need to call mmu_notifier_invalidate_range() we are downgrading
* page table protection not changing it to point to a new page.
@@ -5141,6 +5107,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
*/
i_mmap_unlock_write(vma->vm_file->f_mapping);
mmu_notifier_invalidate_range_end(&range);
+ tlb_finish_mmu(&tlb, range.start, range.end);
return pages << h->order;
}
@@ -5467,18 +5434,27 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
return pte;
}
-/*
- * unmap huge page backed by shared pte.
+/**
+ * huge_pmd_unshare - Unmap a pmd table if it is shared by multiple users
+ * @tlb: the current mmu_gather.
+ * @vma: the vma covering the pmd table.
+ * @addr: pointer to the address we are trying to unshare.
+ * @ptep: pointer into the (pmd) page table.
+ *
+ * Called with the page table lock held, the i_mmap_rwsem held in write mode
+ * and the hugetlb vma lock held in write mode.
*
- * Called with page table lock held.
+ * Note: The caller must call huge_pmd_unshare_flush() before dropping the
+ * i_mmap_rwsem.
*
- * returns: 1 successfully unmapped a shared pte page
- * 0 the underlying pte page is not shared, or it is the last user
+ * Returns: 1 if it was a shared PMD table and it got unmapped, or 0 if it
+ * was not a shared PMD table.
*/
-int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
- unsigned long *addr, pte_t *ptep)
+int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ unsigned long *addr, pte_t *ptep)
{
unsigned long sz = huge_page_size(hstate_vma(vma));
+ struct mm_struct *mm = vma->vm_mm;
pgd_t *pgd = pgd_offset(mm, *addr);
p4d_t *p4d = p4d_offset(pgd, *addr);
pud_t *pud = pud_offset(p4d, *addr);
@@ -5490,14 +5466,8 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
return 0;
pud_clear(pud);
- /*
- * Once our caller drops the rmap lock, some other process might be
- * using this page table as a normal, non-hugetlb page table.
- * Wait for pending gup_fast() in other threads to finish before letting
- * that happen.
- */
- tlb_remove_table_sync_one();
- atomic_dec(&virt_to_page(ptep)->pt_share_count);
+ tlb_unshare_pmd_ptdesc(tlb, virt_to_page(ptep), *addr);
+
mm_dec_nr_pmds(mm);
/*
* This update of passed address optimizes loops sequentially
@@ -5509,6 +5479,30 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
*addr |= PUD_SIZE - PMD_SIZE;
return 1;
}
+
+/*
+ * huge_pmd_unshare_flush - Complete a sequence of huge_pmd_unshare() calls
+ * @tlb: the current mmu_gather.
+ * @vma: the vma covering the pmd table.
+ *
+ * Perform necessary TLB flushes or IPI broadcasts to synchronize PMD table
+ * unsharing with concurrent page table walkers.
+ *
+ * This function must be called after a sequence of huge_pmd_unshare()
+ * calls while still holding the i_mmap_rwsem.
+ */
+void huge_pmd_unshare_flush(struct mmu_gather *tlb, struct vm_area_struct *vma)
+{
+ /*
+ * We must synchronize page table unsharing such that nobody will
+ * try reusing a previously-shared page table while it might still
+ * be in use by previous sharers (TLB, GUP_fast).
+ */
+ i_mmap_assert_write_locked(vma->vm_file->f_mapping);
+
+ tlb_flush_unshared_tables(tlb);
+}
+
#define want_pmd_share() (1)
#else /* !CONFIG_ARCH_WANT_HUGE_PMD_SHARE */
pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
@@ -5516,12 +5510,16 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
return NULL;
}
-int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
- unsigned long *addr, pte_t *ptep)
+int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ unsigned long *addr, pte_t *ptep)
{
return 0;
}
+void huge_pmd_unshare_flush(struct mmu_gather *tlb, struct vm_area_struct *vma)
+{
+}
+
void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma,
unsigned long *start, unsigned long *end)
{
@@ -5763,6 +5761,7 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
unsigned long sz = huge_page_size(h);
struct mm_struct *mm = vma->vm_mm;
struct mmu_notifier_range range;
+ struct mmu_gather tlb;
unsigned long address;
spinlock_t *ptl;
pte_t *ptep;
@@ -5774,6 +5773,8 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
return;
flush_cache_range(vma, start, end);
+ tlb_gather_mmu_vma(&tlb, vma, start, end);
+
/*
* No need to call adjust_range_if_pmd_sharing_possible(), because
* we have already done the PUD_SIZE alignment.
@@ -5787,14 +5788,17 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
i_mmap_assert_write_locked(vma->vm_file->f_mapping);
}
for (address = start; address < end; address += PUD_SIZE) {
+ unsigned long tmp = address;
+
ptep = huge_pte_offset(mm, address, sz);
if (!ptep)
continue;
ptl = huge_pte_lock(h, mm, ptep);
- huge_pmd_unshare(mm, vma, &address, ptep);
+ /* We don't want 'address' to be changed */
+ huge_pmd_unshare(&tlb, vma, &tmp, ptep);
spin_unlock(ptl);
}
- flush_hugetlb_tlb_range(vma, start, end);
+ huge_pmd_unshare_flush(&tlb, vma);
if (take_locks) {
i_mmap_unlock_write(vma->vm_file->f_mapping);
}
@@ -5803,6 +5807,7 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
* Documentation/mm/mmu_notifier.rst.
*/
mmu_notifier_invalidate_range_end(&range);
+ tlb_finish_mmu(&tlb, start, end);
}
#ifdef CONFIG_CMA
diff --git a/mm/mmu_gather.c b/mm/mmu_gather.c
index 205fdbb5792a..298972351a60 100644
--- a/mm/mmu_gather.c
+++ b/mm/mmu_gather.c
@@ -7,6 +7,7 @@
#include <linux/rcupdate.h>
#include <linux/smp.h>
#include <linux/swap.h>
+#include <linux/hugetlb.h>
#include <asm/pgalloc.h>
#include <asm/tlb.h>
@@ -281,10 +282,39 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm,
tlb->page_size = 0;
#endif
+ tlb->fully_unshared_tables = 0;
__tlb_reset_range(tlb);
inc_tlb_flush_pending(tlb->mm);
}
+/**
+ * tlb_gather_mmu_vma - initialize an mmu_gather structure for operating on a
+ * single VMA
+ * @tlb: the mmu_gather structure to initialize
+ * @vma: the vm_area_struct
+ * @start: start of the region that will be removed from the page-table
+ * @end: end of the region that will be removed from the page-table
+ *
+ * Called to initialize an (on-stack) mmu_gather structure for operating on
+ * a single VMA. In contrast to tlb_gather_mmu(), calling this function will
+ * not require another call to tlb_start_vma(). In contrast to tlb_start_vma(),
+ * this function will *not* call flush_cache_range().
+ *
+ * For hugetlb VMAs, this function will also initialize the mmu_gather
+ * page_size accordingly, not requiring a separate call to
+ * tlb_change_page_size().
+ *
+ */
+void tlb_gather_mmu_vma(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ tlb_gather_mmu(tlb, vma->vm_mm, start, end);
+ tlb_update_vma_flags(tlb, vma);
+ if (is_vm_hugetlb_page(vma))
+ /* All entries have the same size. */
+ tlb_change_page_size(tlb, huge_page_size(hstate_vma(vma)));
+}
+
/**
* tlb_finish_mmu - finish an mmu_gather structure
* @tlb: the mmu_gather structure to finish
@@ -297,6 +327,12 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm,
void tlb_finish_mmu(struct mmu_gather *tlb,
unsigned long start, unsigned long end)
{
+ /*
+ * We expect an earlier huge_pmd_unshare_flush() call to sort this out,
+ * due to complicated locking requirements with page table unsharing.
+ */
+ VM_WARN_ON_ONCE(tlb->fully_unshared_tables);
+
/*
* If there are parallel threads are doing PTE changes on same range
* under non-exclusive lock (e.g., mmap_lock read-side) but defer TLB
diff --git a/mm/rmap.c b/mm/rmap.c
index e6f840be1890..a5da7abd15d3 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -73,7 +73,7 @@
#include <linux/memremap.h>
#include <linux/userfaultfd_k.h>
-#include <asm/tlbflush.h>
+#include <asm/tlb.h>
#include <trace/events/tlb.h>
@@ -1470,13 +1470,16 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
address = pvmw.address;
if (PageHuge(page) && !PageAnon(page)) {
+ struct mmu_gather tlb;
+
/*
* To call huge_pmd_unshare, i_mmap_rwsem must be
* held in write mode. Caller needs to explicitly
* do this outside rmap routines.
*/
VM_BUG_ON(!(flags & TTU_RMAP_LOCKED));
- if (huge_pmd_unshare(mm, vma, &address, pvmw.pte)) {
+ tlb_gather_mmu_vma(&tlb, vma, range.start, range.end);
+ if (huge_pmd_unshare(&tlb, vma, &address, pvmw.pte)) {
/*
* huge_pmd_unshare unmapped an entire PMD
* page. There is no way of knowing exactly
@@ -1485,22 +1488,19 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
* already adjusted above to cover this range.
*/
flush_cache_range(vma, range.start, range.end);
- flush_tlb_range(vma, range.start, range.end);
+ huge_pmd_unshare_flush(&tlb, vma);
mmu_notifier_invalidate_range(mm, range.start,
range.end);
+ tlb_finish_mmu(&tlb, range.start, range.end);
/*
- * The ref count of the PMD page was dropped
- * which is part of the way map counting
- * is done for shared PMDs. Return 'true'
- * here. When there is no other sharing,
- * huge_pmd_unshare returns false and we will
- * unmap the actual page and drop map count
- * to zero.
+ * The PMD table was unmapped,
+ * consequently unmapping the folio.
*/
page_vma_mapped_walk_done(&pvmw);
break;
}
+ tlb_finish_mmu(&tlb, range.start, range.end);
}
if (IS_ENABLED(CONFIG_MIGRATION) &&
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 73078306504c..a9ff85324c23 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -142,6 +142,7 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
struct sock *sk;
struct sk_buff *skb2;
struct atmlec_msg *mesg;
+ struct atm_vcc *vcc;
skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
if (skb2 == NULL)
@@ -154,10 +155,18 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
/* 0x01 is topology change */
priv = netdev_priv(dev);
- atm_force_charge(priv->lecd, skb2->truesize);
- sk = sk_atm(priv->lecd);
- skb_queue_tail(&sk->sk_receive_queue, skb2);
- sk->sk_data_ready(sk);
+
+ rcu_read_lock();
+ vcc = rcu_dereference(priv->lecd);
+ if (vcc) {
+ atm_force_charge(vcc, skb2->truesize);
+ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb2);
+ sk->sk_data_ready(sk);
+ } else {
+ dev_kfree_skb(skb2);
+ }
+ rcu_read_unlock();
}
}
#endif /* IS_ENABLED(CONFIG_BRIDGE) */
@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
int is_rdesc;
pr_debug("called\n");
- if (!priv->lecd) {
+ if (!rcu_access_pointer(priv->lecd)) {
pr_info("%s:No lecd attached\n", dev->name);
dev->stats.tx_errors++;
netif_stop_queue(dev);
@@ -443,6 +452,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
/* hit from bridge table, send LE_ARP_RESPONSE */
struct sk_buff *skb2;
struct sock *sk;
+ struct atm_vcc *vcc;
pr_debug("%s: entry found, responding to zeppelin\n",
dev->name);
@@ -451,10 +461,18 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
break;
skb2->len = sizeof(struct atmlec_msg);
skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
- atm_force_charge(priv->lecd, skb2->truesize);
- sk = sk_atm(priv->lecd);
- skb_queue_tail(&sk->sk_receive_queue, skb2);
- sk->sk_data_ready(sk);
+
+ rcu_read_lock();
+ vcc = rcu_dereference(priv->lecd);
+ if (vcc) {
+ atm_force_charge(vcc, skb2->truesize);
+ sk = sk_atm(vcc);
+ skb_queue_tail(&sk->sk_receive_queue, skb2);
+ sk->sk_data_ready(sk);
+ } else {
+ dev_kfree_skb(skb2);
+ }
+ rcu_read_unlock();
}
}
#endif /* IS_ENABLED(CONFIG_BRIDGE) */
@@ -470,23 +488,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
static void lec_atm_close(struct atm_vcc *vcc)
{
- struct sk_buff *skb;
struct net_device *dev = (struct net_device *)vcc->proto_data;
struct lec_priv *priv = netdev_priv(dev);
- priv->lecd = NULL;
+ rcu_assign_pointer(priv->lecd, NULL);
+ synchronize_rcu();
/* Do something needful? */
netif_stop_queue(dev);
lec_arp_destroy(priv);
- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
- pr_info("%s closing with messages pending\n", dev->name);
- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
- atm_return(vcc, skb->truesize);
- dev_kfree_skb(skb);
- }
-
pr_info("%s: Shut down!\n", dev->name);
module_put(THIS_MODULE);
}
@@ -512,12 +523,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
const unsigned char *mac_addr, const unsigned char *atm_addr,
struct sk_buff *data)
{
+ struct atm_vcc *vcc;
struct sock *sk;
struct sk_buff *skb;
struct atmlec_msg *mesg;
- if (!priv || !priv->lecd)
+ if (!priv || !rcu_access_pointer(priv->lecd))
return -1;
+
skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
if (!skb)
return -1;
@@ -534,18 +547,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
if (atm_addr)
memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
- atm_force_charge(priv->lecd, skb->truesize);
- sk = sk_atm(priv->lecd);
+ rcu_read_lock();
+ vcc = rcu_dereference(priv->lecd);
+ if (!vcc) {
+ rcu_read_unlock();
+ kfree_skb(skb);
+ return -1;
+ }
+
+ atm_force_charge(vcc, skb->truesize);
+ sk = sk_atm(vcc);
skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk);
if (data != NULL) {
pr_debug("about to send %d bytes of data\n", data->len);
- atm_force_charge(priv->lecd, data->truesize);
+ atm_force_charge(vcc, data->truesize);
skb_queue_tail(&sk->sk_receive_queue, data);
sk->sk_data_ready(sk);
}
+ rcu_read_unlock();
return 0;
}
@@ -620,7 +642,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
atm_return(vcc, skb->truesize);
if (*(__be16 *) skb->data == htons(priv->lecid) ||
- !priv->lecd || !(dev->flags & IFF_UP)) {
+ !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
/*
* Probably looping back, or if lecd is missing,
* lecd has gone down
@@ -755,12 +777,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
priv = netdev_priv(dev_lec[i]);
} else {
priv = netdev_priv(dev_lec[i]);
- if (priv->lecd)
+ if (rcu_access_pointer(priv->lecd))
return -EADDRINUSE;
}
lec_arp_init(priv);
priv->itfnum = i; /* LANE2 addition */
- priv->lecd = vcc;
+ rcu_assign_pointer(priv->lecd, vcc);
vcc->dev = &lecatm_dev;
vcc_insert_socket(sk_atm(vcc));
@@ -1262,24 +1284,28 @@ static void lec_arp_clear_vccs(struct lec_arp_table *entry)
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
struct net_device *dev = (struct net_device *)vcc->proto_data;
- vcc->pop = vpriv->old_pop;
- if (vpriv->xoff)
- netif_wake_queue(dev);
- kfree(vpriv);
- vcc->user_back = NULL;
- vcc->push = entry->old_push;
- vcc_release_async(vcc, -EPIPE);
+ if (vpriv) {
+ vcc->pop = vpriv->old_pop;
+ if (vpriv->xoff)
+ netif_wake_queue(dev);
+ kfree(vpriv);
+ vcc->user_back = NULL;
+ vcc->push = entry->old_push;
+ vcc_release_async(vcc, -EPIPE);
+ }
entry->vcc = NULL;
}
if (entry->recv_vcc) {
struct atm_vcc *vcc = entry->recv_vcc;
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
- kfree(vpriv);
- vcc->user_back = NULL;
+ if (vpriv) {
+ kfree(vpriv);
+ vcc->user_back = NULL;
- entry->recv_vcc->push = entry->old_recv_push;
- vcc_release_async(entry->recv_vcc, -EPIPE);
+ entry->recv_vcc->push = entry->old_recv_push;
+ vcc_release_async(entry->recv_vcc, -EPIPE);
+ }
entry->recv_vcc = NULL;
}
}
diff --git a/net/atm/lec.h b/net/atm/lec.h
index be0e2667bd8c..ec85709bf818 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -91,7 +91,7 @@ struct lec_priv {
*/
spinlock_t lec_arp_lock;
struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
- struct atm_vcc *lecd;
+ struct atm_vcc __rcu *lecd;
struct delayed_work lec_arp_work; /* C10 */
unsigned int maximum_unknown_frame_count;
/*
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index e0b41afa3472..68ac19c75ed1 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -466,6 +466,9 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
!time_after_eq(aggregation_end_time, forw_packet->send_time))
return false;
+ if (skb_tailroom(forw_packet->skb) < packet_len)
+ return false;
+
if (aggregated_bytes > BATADV_MAX_AGGREGATION_BYTES)
return false;
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c
index eacf53161304..236ddc469bc5 100644
--- a/net/batman-adv/bat_v_elp.c
+++ b/net/batman-adv/bat_v_elp.c
@@ -113,7 +113,15 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh,
/* unsupported WiFi driver version */
goto default_throughput;
- real_netdev = batadv_get_real_netdev(hard_iface->net_dev);
+ /* only use rtnl_trylock because the elp worker will be cancelled while
+ * the rntl_lock is held. the cancel_delayed_work_sync() would otherwise
+ * wait forever when the elp work_item was started and it is then also
+ * trying to rtnl_lock
+ */
+ if (!rtnl_trylock())
+ return false;
+ real_netdev = __batadv_get_real_netdev(hard_iface->net_dev);
+ rtnl_unlock();
if (!real_netdev)
goto default_throughput;
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index bc2c19a43d15..5dd94d94e884 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -204,7 +204,7 @@ static bool batadv_is_valid_iface(const struct net_device *net_dev)
}
/**
- * batadv_get_real_netdevice() - check if the given netdev struct is a virtual
+ * __batadv_get_real_netdev() - check if the given netdev struct is a virtual
* interface on top of another 'real' interface
* @netdev: the device to check
*
@@ -214,7 +214,7 @@ static bool batadv_is_valid_iface(const struct net_device *net_dev)
* Return: the 'real' net device or the original net device and NULL in case
* of an error.
*/
-static struct net_device *batadv_get_real_netdevice(struct net_device *netdev)
+struct net_device *__batadv_get_real_netdev(struct net_device *netdev)
{
struct batadv_hard_iface *hard_iface = NULL;
struct net_device *real_netdev = NULL;
@@ -268,7 +268,7 @@ struct net_device *batadv_get_real_netdev(struct net_device *net_device)
struct net_device *real_netdev;
rtnl_lock();
- real_netdev = batadv_get_real_netdevice(net_device);
+ real_netdev = __batadv_get_real_netdev(net_device);
rtnl_unlock();
return real_netdev;
@@ -335,7 +335,7 @@ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device)
if (batadv_is_cfg80211_netdev(net_device))
wifi_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT;
- real_netdev = batadv_get_real_netdevice(net_device);
+ real_netdev = __batadv_get_real_netdev(net_device);
if (!real_netdev)
return wifi_flags;
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index ba5850cfb277..193780dd61cc 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -91,6 +91,7 @@ enum batadv_hard_if_cleanup {
extern struct notifier_block batadv_hard_if_notifier;
+struct net_device *__batadv_get_real_netdev(struct net_device *net_device);
struct net_device *batadv_get_real_netdev(struct net_device *net_device);
bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface);
bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 6589ed581d76..73f1ab4f008c 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -849,8 +849,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;
@@ -868,6 +868,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/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 3ff870599eb7..068c3c250517 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -987,7 +987,8 @@ static void session_free(struct kref *ref)
skb_queue_purge(&session->intr_transmit);
fput(session->intr_sock->file);
fput(session->ctrl_sock->file);
- l2cap_conn_put(session->conn);
+ if (session->conn)
+ l2cap_conn_put(session->conn);
kfree(session);
}
@@ -1165,6 +1166,15 @@ static void hidp_session_remove(struct l2cap_conn *conn,
down_write(&hidp_session_sem);
+ /* Drop L2CAP reference immediately to indicate that
+ * l2cap_unregister_user() shall not be called as it is already
+ * considered removed.
+ */
+ if (session->conn) {
+ l2cap_conn_put(session->conn);
+ session->conn = NULL;
+ }
+
hidp_session_terminate(session);
cancel_work_sync(&session->dev_init);
@@ -1302,7 +1312,9 @@ static int hidp_session_thread(void *arg)
* Instead, this call has the same semantics as if user-space tried to
* delete the session.
*/
- l2cap_unregister_user(session->conn, &session->user);
+ if (session->conn)
+ l2cap_unregister_user(session->conn, &session->user);
+
hidp_session_put(session);
module_put_and_kthread_exit(0);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 696c656e1969..a6efb5b42f9b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2543,6 +2543,9 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
/* Remote device may have requested smaller PDUs */
pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
+ if (!pdu_len)
+ return -EINVAL;
+
if (len <= pdu_len) {
sar = L2CAP_SAR_UNSEGMENTED;
sdu_len = 0;
@@ -4526,14 +4529,16 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
set_default_fcs(chan);
- if (chan->mode == L2CAP_MODE_ERTM ||
- chan->mode == L2CAP_MODE_STREAMING)
- err = l2cap_ertm_init(chan);
+ if (chan->state != BT_CONNECTED) {
+ if (chan->mode == L2CAP_MODE_ERTM ||
+ chan->mode == L2CAP_MODE_STREAMING)
+ err = l2cap_ertm_init(chan);
- if (err < 0)
- l2cap_send_disconn_req(chan, -err);
- else
- l2cap_chan_ready(chan);
+ if (err < 0)
+ l2cap_send_disconn_req(chan, -err);
+ else
+ l2cap_chan_ready(chan);
+ }
goto unlock;
}
@@ -4847,7 +4852,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
switch (type) {
case L2CAP_IT_FEAT_MASK:
- conn->feat_mask = get_unaligned_le32(rsp->data);
+ if (cmd_len >= sizeof(*rsp) + sizeof(u32))
+ conn->feat_mask = get_unaligned_le32(rsp->data);
if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
struct l2cap_info_req req;
@@ -4866,7 +4872,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
break;
case L2CAP_IT_FIXED_CHAN:
- conn->remote_fixed_chan = rsp->data[0];
+ if (cmd_len >= sizeof(*rsp) + sizeof(rsp->data[0]))
+ conn->remote_fixed_chan = rsp->data[0];
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
@@ -6046,7 +6053,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
u16 mtu, mps;
__le16 psm;
u8 result, len = 0;
- int i, num_scid;
+ int i, num_scid = 0;
bool defer = false;
if (!enable_ecred)
@@ -6057,6 +6064,14 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
goto response;
}
+ /* Check if there are no pending channels with the same ident */
+ __l2cap_chan_list_id(conn, cmd->ident, l2cap_ecred_list_defer,
+ &num_scid);
+ if (num_scid) {
+ result = L2CAP_CR_LE_INVALID_PARAMS;
+ goto response;
+ }
+
cmd_len -= sizeof(*req);
num_scid = cmd_len / sizeof(u16);
@@ -6407,7 +6422,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
u8 *data)
{
struct l2cap_chan *chan, *tmp;
- struct l2cap_ecred_conn_rsp *rsp = (void *) data;
+ struct l2cap_ecred_reconf_rsp *rsp = (void *)data;
u16 result;
if (cmd_len < sizeof(*rsp))
@@ -6415,7 +6430,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
result = __le16_to_cpu(rsp->result);
- BT_DBG("result 0x%4.4x", rsp->result);
+ BT_DBG("result 0x%4.4x", result);
if (!result)
return 0;
@@ -7637,8 +7652,10 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
return -ENOBUFS;
}
- if (chan->imtu < skb->len) {
- BT_ERR("Too big LE L2CAP PDU");
+ if (skb->len > chan->imtu) {
+ BT_ERR("Too big LE L2CAP PDU: len %u > %u", skb->len,
+ chan->imtu);
+ l2cap_send_disconn_req(chan, ECONNRESET);
return -ENOBUFS;
}
@@ -7656,6 +7673,11 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
if (!chan->sdu) {
u16 sdu_len;
+ if (!pskb_may_pull(skb, L2CAP_SDULEN_SIZE)) {
+ err = -EINVAL;
+ goto failed;
+ }
+
sdu_len = get_unaligned_le16(skb->data);
skb_pull(skb, L2CAP_SDULEN_SIZE);
@@ -7663,7 +7685,9 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
sdu_len, skb->len, chan->imtu);
if (sdu_len > chan->imtu) {
- BT_ERR("Too big LE L2CAP SDU length received");
+ BT_ERR("Too big LE L2CAP SDU length: len %u > %u",
+ skb->len, sdu_len);
+ l2cap_send_disconn_req(chan, ECONNRESET);
err = -EMSGSIZE;
goto failed;
}
@@ -7699,6 +7723,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
if (chan->sdu->len + skb->len > chan->sdu_len) {
BT_ERR("Too much LE L2CAP data received");
+ l2cap_send_disconn_req(chan, ECONNRESET);
err = -EINVAL;
goto failed;
}
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 5465b537f0e7..9e071db3b649 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1637,6 +1637,9 @@ static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
struct sock *sk = chan->data;
struct sock *parent;
+ if (!sk)
+ return;
+
lock_sock(sk);
parent = bt_sk(sk)->parent;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index fda0bd990dcb..b768abbf2b12 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -5948,6 +5948,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
if (key->initiator != 0x00 && key->initiator != 0x01)
return false;
+ if (key->enc_size > sizeof(key->val))
+ return false;
+
switch (key->addr.type) {
case BDADDR_LE_PUBLIC:
return true;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 79550d115364..64c8dd279932 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -1018,10 +1018,7 @@ static u8 smp_random(struct smp_chan *smp)
smp_s1(smp->tk, smp->prnd, smp->rrnd, stk);
- if (hcon->pending_sec_level == BT_SECURITY_HIGH)
- auth = 1;
- else
- auth = 0;
+ auth = test_bit(SMP_FLAG_MITM_AUTH, &smp->flags) ? 1 : 0;
/* Even though there's no _RESPONDER suffix this is the
* responder STK we're adding for later lookup (the initiator
@@ -1821,7 +1818,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
if (sec_level > conn->hcon->pending_sec_level)
conn->hcon->pending_sec_level = sec_level;
- /* If we need MITM check that it can be achieved */
+ /* If we need MITM check that it can be achieved. */
if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
u8 method;
@@ -1829,6 +1826,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
req->io_capability);
if (method == JUST_WORKS || method == JUST_CFM)
return SMP_AUTH_REQUIREMENTS;
+
+ /* Force MITM bit if it isn't set by the initiator. */
+ auth |= SMP_AUTH_MITM;
+ rsp.auth_req |= SMP_AUTH_MITM;
}
key_size = min(req->max_key_size, rsp.max_key_size);
@@ -2738,7 +2739,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
if (!test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags) &&
!crypto_memneq(key, smp->local_pk, 64)) {
bt_dev_err(hdev, "Remote and local public keys are identical");
- return SMP_UNSPECIFIED;
+ return SMP_DHKEY_CHECK_FAILED;
}
memcpy(smp->remote_pk, key, 64);
diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index 3db1def4437b..de80939d1e10 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -248,12 +248,12 @@ struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *msg)
static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
struct sk_buff *request, struct neighbour *n,
- __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns)
+ __be16 vlan_proto, u16 vlan_tci)
{
struct net_device *dev = request->dev;
struct net_bridge_vlan_group *vg;
+ struct nd_msg *na, *ns;
struct sk_buff *reply;
- struct nd_msg *na;
struct ipv6hdr *pip6;
int na_olen = 8; /* opt hdr + ETH_ALEN for target */
int ns_olen;
@@ -261,7 +261,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
u8 *daddr;
u16 pvid;
- if (!dev)
+ if (!dev || skb_linearize(request))
return;
len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
@@ -278,17 +278,21 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
skb_set_mac_header(reply, 0);
daddr = eth_hdr(request)->h_source;
+ ns = (struct nd_msg *)(skb_network_header(request) +
+ sizeof(struct ipv6hdr));
/* Do we need option processing ? */
ns_olen = request->len - (skb_network_offset(request) +
sizeof(struct ipv6hdr)) - sizeof(*ns);
for (i = 0; i < ns_olen - 1; i += (ns->opt[i + 1] << 3)) {
- if (!ns->opt[i + 1]) {
+ if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) {
kfree_skb(reply);
return;
}
if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
- daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+ if ((ns->opt[i + 1] << 3) >=
+ sizeof(struct nd_opt_hdr) + ETH_ALEN)
+ daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
break;
}
}
@@ -465,9 +469,9 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
if (vid != 0)
br_nd_send(br, p, skb, n,
skb->vlan_proto,
- skb_vlan_tag_get(skb), msg);
+ skb_vlan_tag_get(skb));
else
- br_nd_send(br, p, skb, n, 0, 0, msg);
+ br_nd_send(br, p, skb, n, 0, 0);
replied = true;
}
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 84e37108c6b5..2c59e3f918ca 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -70,7 +70,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
eth_hdr(skb)->h_proto == htons(ETH_P_RARP)) &&
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) {
br_do_proxy_suppress_arp(skb, br, vid, NULL);
- } else if (IS_ENABLED(CONFIG_IPV6) &&
+ } else if (ipv6_mod_enabled() &&
skb->protocol == htons(ETH_P_IPV6) &&
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
pskb_may_pull(skb, sizeof(struct ipv6hdr) +
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index f9d4b86e3186..4d7e99a54778 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -124,7 +124,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
(skb->protocol == htons(ETH_P_ARP) ||
skb->protocol == htons(ETH_P_RARP))) {
br_do_proxy_suppress_arp(skb, br, vid, p);
- } else if (IS_ENABLED(CONFIG_IPV6) &&
+ } else if (ipv6_mod_enabled() &&
skb->protocol == htons(ETH_P_IPV6) &&
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
pskb_may_pull(skb, sizeof(struct ipv6hdr) +
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 3e77a52709aa..97c48f350ce0 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -469,7 +469,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
rcv->can_id = can_id;
rcv->mask = mask;
- rcv->matches = 0;
+ atomic_long_set(&rcv->matches, 0);
rcv->func = func;
rcv->data = data;
rcv->ident = ident;
@@ -573,7 +573,7 @@ EXPORT_SYMBOL(can_rx_unregister);
static inline void deliver(struct sk_buff *skb, struct receiver *rcv)
{
rcv->func(skb, rcv->data);
- rcv->matches++;
+ atomic_long_inc(&rcv->matches);
}
static int can_rcv_filter(struct can_dev_rcv_lists *dev_rcv_lists, struct sk_buff *skb)
diff --git a/net/can/af_can.h b/net/can/af_can.h
index 22f3352c77fe..87887014f562 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -52,7 +52,7 @@ struct receiver {
struct hlist_node list;
canid_t can_id;
canid_t mask;
- unsigned long matches;
+ atomic_long_t matches;
void (*func)(struct sk_buff *skb, void *data);
void *data;
char *ident;
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 200b66e85c1c..414a2bb17397 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1123,6 +1123,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
if (!op)
return -ENOMEM;
+ spin_lock_init(&op->bcm_tx_lock);
op->can_id = msg_head->can_id;
op->nframes = msg_head->nframes;
op->cfsiz = CFSIZ(msg_head->flags);
diff --git a/net/can/gw.c b/net/can/gw.c
index 59b9f3e579f7..c6efa4830ce9 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -312,10 +312,10 @@ static void cgw_csum_crc8_rel(struct canfd_frame *cf,
return;
if (from <= to) {
- for (i = crc8->from_idx; i <= crc8->to_idx; i++)
+ for (i = from; i <= to; i++)
crc = crc8->crctab[crc ^ cf->data[i]];
} else {
- for (i = crc8->from_idx; i >= crc8->to_idx; i--)
+ for (i = from; i >= to; i--)
crc = crc8->crctab[crc ^ cf->data[i]];
}
@@ -334,7 +334,7 @@ static void cgw_csum_crc8_rel(struct canfd_frame *cf,
break;
}
- cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val;
+ cf->data[res] = crc ^ crc8->final_xor_val;
}
static void cgw_csum_crc8_pos(struct canfd_frame *cf,
diff --git a/net/can/proc.c b/net/can/proc.c
index 2be4a239f31e..550d46d1c60a 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -200,7 +200,8 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
" %-5s %03x %08x %pK %pK %8ld %s\n";
seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
- r->func, r->data, r->matches, r->ident);
+ r->func, r->data, atomic_long_read(&r->matches),
+ r->ident);
}
}
diff --git a/net/ceph/auth.c b/net/ceph/auth.c
index fbeee068ea14..842d14929da6 100644
--- a/net/ceph/auth.c
+++ b/net/ceph/auth.c
@@ -185,9 +185,9 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
s32 result;
u64 global_id;
void *payload, *payload_end;
- int payload_len;
+ u32 payload_len;
char *result_msg;
- int result_msg_len;
+ u32 result_msg_len;
int ret = -EINVAL;
mutex_lock(&ac->mutex);
@@ -197,10 +197,12 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
result = ceph_decode_32(&p);
global_id = ceph_decode_64(&p);
payload_len = ceph_decode_32(&p);
+ ceph_decode_need(&p, end, payload_len, bad);
payload = p;
p += payload_len;
ceph_decode_need(&p, end, sizeof(u32), bad);
result_msg_len = ceph_decode_32(&p);
+ ceph_decode_need(&p, end, result_msg_len, bad);
result_msg = p;
p += result_msg_len;
if (p != end)
diff --git a/net/core/dev.c b/net/core/dev.c
index ab0b7df70351..9e1e87536c1e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4318,7 +4318,7 @@ static inline void ____napi_schedule(struct softnet_data *sd,
struct napi_struct *napi)
{
list_add_tail(&napi->poll_list, &sd->poll_list);
- __raise_softirq_irqoff(NET_RX_SOFTIRQ);
+ raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
#ifdef CONFIG_RPS
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 99337557408b..c58510d7ea0d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -501,11 +501,14 @@ static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev)
goto out;
ops = master_dev->rtnl_link_ops;
- if (!ops || !ops->get_slave_size)
+ if (!ops)
+ goto out;
+ size += nla_total_size(strlen(ops->kind) + 1); /* IFLA_INFO_SLAVE_KIND */
+ if (!ops->get_slave_size)
goto out;
/* IFLA_INFO_SLAVE_DATA + nested data */
- size = nla_total_size(sizeof(struct nlattr)) +
- ops->get_slave_size(master_dev, dev);
+ size += nla_total_size(sizeof(struct nlattr)) +
+ ops->get_slave_size(master_dev, dev);
out:
rcu_read_unlock();
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index adfefcd88bbc..0d5fc4f8c6ad 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -275,10 +275,13 @@ static void esp_output_done(struct crypto_async_request *base, int err)
xfrm_dev_resume(skb);
} else {
if (!err &&
- x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
- esp_output_tail_tcp(x, skb);
- else
- xfrm_output_resume(skb->sk, skb, err);
+ x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP) {
+ err = esp_output_tail_tcp(x, skb);
+ if (err != -EINPROGRESS)
+ kfree_skb(skb);
+ } else {
+ xfrm_output_resume(skb_to_full_sk(skb), skb, err);
+ }
}
}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index efeeed4f0517..3c74fecce238 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -844,10 +844,12 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
static bool icmp_tag_validation(int proto)
{
+ const struct net_protocol *ipprot;
bool ok;
rcu_read_lock();
- ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation;
+ ipprot = rcu_dereference(inet_protos[proto]);
+ ok = ipprot ? ipprot->icmp_strict_tag_validation : false;
rcu_read_unlock();
return ok;
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 3dfa856e9926..855cca214a02 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -78,6 +78,7 @@
#include <linux/inetdevice.h>
#include <linux/btf_ids.h>
+#include <crypto/algapi.h>
#include <crypto/hash.h>
#include <linux/scatterlist.h>
@@ -764,7 +765,7 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, skb);
- if (genhash || memcmp(hash_location, newhash, 16) != 0)
+ if (genhash || crypto_memneq(hash_location, newhash, 16))
goto out;
}
@@ -1451,7 +1452,7 @@ static bool tcp_v4_inbound_md5_hash(const struct sock *sk,
hash_expected,
NULL, skb);
- if (genhash || memcmp(hash_location, newhash, 16) != 0) {
+ if (genhash || crypto_memneq(hash_location, newhash, 16)) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
net_info_ratelimited("MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s L3 index %d\n",
&iph->saddr, ntohs(th->source),
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ced20abf4ef8..758cea239e61 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3509,12 +3509,12 @@ static void addrconf_permanent_addr(struct net *net, struct net_device *dev)
if ((ifp->flags & IFA_F_PERMANENT) &&
fixup_permanent_addr(net, idev, ifp) < 0) {
write_unlock_bh(&idev->lock);
- in6_ifa_hold(ifp);
- ipv6_del_addr(ifp);
- write_lock_bh(&idev->lock);
net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
idev->dev->name, &ifp->addr);
+ in6_ifa_hold(ifp);
+ ipv6_del_addr(ifp);
+ write_lock_bh(&idev->lock);
}
}
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index a30ff5d6808a..d8af31805133 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -756,6 +756,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
{
struct in6_pktinfo *src_info;
struct cmsghdr *cmsg;
+ struct ipv6_rt_hdr *orthdr;
struct ipv6_rt_hdr *rthdr;
struct ipv6_opt_hdr *hdr;
struct ipv6_txoptions *opt = ipc6->opt;
@@ -917,9 +918,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
goto exit_f;
}
if (cmsg->cmsg_type == IPV6_DSTOPTS) {
+ if (opt->dst1opt)
+ opt->opt_flen -= ipv6_optlen(opt->dst1opt);
opt->opt_flen += len;
opt->dst1opt = hdr;
} else {
+ if (opt->dst0opt)
+ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
opt->opt_nflen += len;
opt->dst0opt = hdr;
}
@@ -962,12 +967,17 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
goto exit_f;
}
+ orthdr = opt->srcrt;
+ if (orthdr)
+ opt->opt_nflen -= ((orthdr->hdrlen + 1) << 3);
opt->opt_nflen += len;
opt->srcrt = rthdr;
if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+ if (opt->dst0opt)
+ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
opt->opt_nflen += dsthdrlen;
opt->dst0opt = opt->dst1opt;
opt->dst1opt = NULL;
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 39154531d455..a1d20dd4be3c 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -310,10 +310,13 @@ static void esp_output_done(struct crypto_async_request *base, int err)
xfrm_dev_resume(skb);
} else {
if (!err &&
- x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
- esp_output_tail_tcp(x, skb);
- else
- xfrm_output_resume(skb->sk, skb, err);
+ x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP) {
+ err = esp_output_tail_tcp(x, skb);
+ if (err != -EINPROGRESS)
+ kfree_skb(skb);
+ } else {
+ xfrm_output_resume(skb_to_full_sk(skb), skb, err);
+ }
}
}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index d01165bb6a32..65846f445189 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -673,6 +673,9 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
if (!skb2)
return 1;
+ /* Remove debris left by IPv4 stack. */
+ memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
+
skb_dst_drop(skb2);
skb_pull(skb2, nhs);
skb_reset_network_header(skb2);
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index ceb85c67ce39..bb528d0ddb73 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -133,11 +133,6 @@ static void fl_release(struct ip6_flowlabel *fl)
if (time_after(ttd, fl->expires))
fl->expires = ttd;
ttd = fl->expires;
- if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
- struct ipv6_txoptions *opt = fl->opt;
- fl->opt = NULL;
- kfree(opt);
- }
if (!timer_pending(&ip6_fl_gc_timer) ||
time_after(ip6_fl_gc_timer.expires, ttd))
mod_timer(&ip6_fl_gc_timer, ttd);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 855622a6a304..dda90c77f898 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -634,11 +634,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (!skb2)
return 0;
+ /* Remove debris left by IPv6 stack. */
+ memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
+
skb_dst_drop(skb2);
skb_pull(skb2, offset);
skb_reset_network_header(skb2);
eiph = ip_hdr(skb2);
+ if (eiph->version != 4 || eiph->ihl < 5)
+ goto out;
/* Try to guess incoming interface */
rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
@@ -876,7 +881,7 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
skb_reset_network_header(skb);
- if (skb_vlan_inet_prepare(skb, true)) {
+ if (!skb_vlan_inet_prepare(skb, true)) {
DEV_STATS_INC(tunnel->dev, rx_length_errors);
DEV_STATS_INC(tunnel->dev, rx_errors);
goto drop;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 43ad4e5db594..de389b519700 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1155,6 +1155,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
+ ndmsg->nduseropt_pad1 = 0;
+ ndmsg->nduseropt_pad2 = 0;
+ ndmsg->nduseropt_pad3 = 0;
memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index 4ad8b2032f1f..5561bd9cea81 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -157,6 +157,10 @@ static int rt_mt6_check(const struct xt_mtchk_param *par)
pr_debug("unknown flags %X\n", rtinfo->invflags);
return -EINVAL;
}
+ if (rtinfo->addrnr > IP6T_RT_HOPS) {
+ pr_debug("too many addresses specified\n");
+ return -EINVAL;
+ }
if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) &&
(!(rtinfo->flags & IP6T_RT_TYP) ||
(rtinfo->rt_type != 0) ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b47f89600c2f..27736b584737 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1013,7 +1013,8 @@ static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res)
*/
if (netif_is_l3_slave(dev) &&
!rt6_need_strict(&res->f6i->fib6_dst.addr))
- dev = l3mdev_master_dev_rcu(dev);
+ dev = l3mdev_master_dev_rcu(dev) ? :
+ dev_net(dev)->loopback_dev;
else if (!netif_is_l3_master(dev))
dev = dev_net(dev)->loopback_dev;
/* last case is netif_is_l3_master(dev) is true in which
@@ -3407,7 +3408,6 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
{
struct net_device *dev = NULL;
struct inet6_dev *idev = NULL;
- int addr_type;
int err;
fib6_nh->fib_nh_family = AF_INET6;
@@ -3448,11 +3448,10 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
fib6_nh->fib_nh_weight = 1;
- /* We cannot add true routes via loopback here,
- * they would result in kernel looping; promote them to reject routes
+ /* Reset the nexthop device to the loopback device in case of reject
+ * routes.
*/
- addr_type = ipv6_addr_type(&cfg->fc_dst);
- if (fib6_is_reject(cfg->fc_flags, dev, addr_type)) {
+ if (cfg->fc_flags & RTF_REJECT) {
/* hold loopback dev/idev if we haven't done so. */
if (dev != net->loopback_dev) {
if (dev) {
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 986459a85fbd..5da46c76d335 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -45,7 +45,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[];
};
@@ -326,7 +327,7 @@ static int seg6_input(struct sk_buff *skb)
slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
local_bh_disable();
- dst = dst_cache_get(&slwt->cache);
+ dst = dst_cache_get(&slwt->cache_input);
skb_dst_drop(skb);
@@ -334,7 +335,7 @@ static int seg6_input(struct sk_buff *skb)
ip6_route_input(skb);
dst = skb_dst(skb);
if (!dst->error) {
- dst_cache_set_ip6(&slwt->cache, dst,
+ dst_cache_set_ip6(&slwt->cache_input, dst,
&ipv6_hdr(skb)->saddr);
}
} else {
@@ -363,7 +364,7 @@ static int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
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();
if (unlikely(!dst)) {
@@ -384,7 +385,7 @@ static int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
}
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();
}
@@ -461,11 +462,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);
@@ -480,11 +483,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/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 8b9709420c05..523aa2efdc49 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -63,6 +63,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <crypto/algapi.h>
#include <crypto/hash.h>
#include <linux/scatterlist.h>
@@ -810,7 +811,7 @@ static bool tcp_v6_inbound_md5_hash(const struct sock *sk,
hash_expected,
NULL, skb);
- if (genhash || memcmp(hash_location, newhash, 16) != 0) {
+ if (genhash || crypto_memneq(hash_location, newhash, 16)) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
net_info_ratelimited("MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u L3 index %d\n",
genhash ? "failed" : "mismatch",
@@ -1071,7 +1072,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
goto out;
genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, skb);
- if (genhash || memcmp(hash_location, newhash, 16) != 0)
+ if (genhash || crypto_memneq(hash_location, newhash, 16))
goto out;
}
#endif
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index ee349c243878..a8fc778ce465 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -89,14 +89,14 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
toobig = skb->len > mtu && !skb_is_gso(skb);
- if (toobig && xfrm6_local_dontfrag(skb->sk)) {
+ if (toobig && xfrm6_local_dontfrag(sk)) {
xfrm6_local_rxpmtu(skb, mtu);
kfree_skb(skb);
return -EMSGSIZE;
} else if (toobig && xfrm6_noneed_fragment(skb)) {
skb->ignore_df = 1;
goto skip_frag;
- } else if (!skb->ignore_df && toobig && skb->sk) {
+ } else if (!skb->ignore_df && toobig && sk) {
xfrm_local_error(skb, mtu);
kfree_skb(skb);
return -EMSGSIZE;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index de4606d2eb64..95f7e363c2f6 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3522,7 +3522,7 @@ static int set_sadb_kmaddress(struct sk_buff *skb, const struct xfrm_kmaddress *
static int set_ipsecrequest(struct sk_buff *skb,
uint8_t proto, uint8_t mode, int level,
- uint32_t reqid, uint8_t family,
+ uint32_t reqid, sa_family_t family,
const xfrm_address_t *src, const xfrm_address_t *dst)
{
struct sadb_x_ipsecrequest *rq;
@@ -3587,12 +3587,17 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
/* ipsecrequests */
for (i = 0, mp = m; i < num_bundles; i++, mp++) {
- /* old locator pair */
- size_pol += sizeof(struct sadb_x_ipsecrequest) +
- pfkey_sockaddr_pair_size(mp->old_family);
- /* new locator pair */
- size_pol += sizeof(struct sadb_x_ipsecrequest) +
- pfkey_sockaddr_pair_size(mp->new_family);
+ int pair_size;
+
+ pair_size = pfkey_sockaddr_pair_size(mp->old_family);
+ if (!pair_size)
+ return -EINVAL;
+ size_pol += sizeof(struct sadb_x_ipsecrequest) + pair_size;
+
+ pair_size = pfkey_sockaddr_pair_size(mp->new_family);
+ if (!pair_size)
+ return -EINVAL;
+ size_pol += sizeof(struct sadb_x_ipsecrequest) + pair_size;
}
size += sizeof(struct sadb_msg) + size_pol;
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index b1d89c850f68..10ae55b46aa9 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -130,22 +130,12 @@ static const struct ppp_channel_ops pppol2tp_chan_ops = {
static const struct proto_ops pppol2tp_ops;
-/* Retrieves the pppol2tp socket associated to a session.
- * A reference is held on the returned socket, so this function must be paired
- * with sock_put().
- */
+/* Retrieves the pppol2tp socket associated to a session. */
static struct sock *pppol2tp_session_get_sock(struct l2tp_session *session)
{
struct pppol2tp_session *ps = l2tp_session_priv(session);
- struct sock *sk;
- rcu_read_lock();
- sk = rcu_dereference(ps->sk);
- if (sk)
- sock_hold(sk);
- rcu_read_unlock();
-
- return sk;
+ return rcu_dereference(ps->sk);
}
/* Helpers to obtain tunnel/session contexts from sockets.
@@ -212,14 +202,13 @@ static int pppol2tp_recvmsg(struct socket *sock, struct msghdr *msg,
static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len)
{
- struct pppol2tp_session *ps = l2tp_session_priv(session);
- struct sock *sk = NULL;
+ struct sock *sk;
/* If the socket is bound, send it in to PPP's input queue. Otherwise
* queue it on the session socket.
*/
rcu_read_lock();
- sk = rcu_dereference(ps->sk);
+ sk = pppol2tp_session_get_sock(session);
if (!sk)
goto no_sock;
@@ -529,13 +518,14 @@ static void pppol2tp_show(struct seq_file *m, void *arg)
struct l2tp_session *session = arg;
struct sock *sk;
+ rcu_read_lock();
sk = pppol2tp_session_get_sock(session);
if (sk) {
struct pppox_sock *po = pppox_sk(sk);
seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan));
- sock_put(sk);
}
+ rcu_read_unlock();
}
static void pppol2tp_session_init(struct l2tp_session *session)
@@ -1541,6 +1531,7 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
port = ntohs(inet->inet_sport);
}
+ rcu_read_lock();
sk = pppol2tp_session_get_sock(session);
if (sk) {
state = sk->sk_state;
@@ -1576,8 +1567,8 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
struct pppox_sock *po = pppox_sk(sk);
seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan));
- sock_put(sk);
}
+ rcu_read_unlock();
}
static int pppol2tp_seq_show(struct seq_file *m, void *v)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index d3a9ce1f8e53..4b09cd19c4e0 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -75,6 +75,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
* - MDA enabled
* - Power management control on fc
*/
+ if (!ie->mesh_config)
+ return false;
+
if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
(ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
@@ -1435,6 +1438,9 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
if (!mesh_matches_local(sdata, &elems))
return;
+ if (!elems.mesh_chansw_params_ie)
+ return;
+
ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
if (!--ifmsh->chsw_ttl)
fwd_csa = false;
diff --git a/net/ncsi/ncsi-aen.c b/net/ncsi/ncsi-aen.c
index 62fb1031763d..040a31557201 100644
--- a/net/ncsi/ncsi-aen.c
+++ b/net/ncsi/ncsi-aen.c
@@ -224,7 +224,8 @@ int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb)
if (!nah) {
netdev_warn(ndp->ndev.dev, "Invalid AEN (0x%x) received\n",
h->type);
- return -ENOENT;
+ ret = -ENOENT;
+ goto out;
}
ret = ncsi_validate_aen_pkt(h, nah->payload);
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index c1d42bbfdc7e..d11794205183 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -1146,8 +1146,10 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
/* Find the NCSI device */
nd = ncsi_find_dev(orig_dev);
ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL;
- if (!ndp)
- return -ENODEV;
+ if (!ndp) {
+ ret = -ENODEV;
+ goto err_free_skb;
+ }
/* Check if it is AEN packet */
hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb);
@@ -1169,7 +1171,8 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
if (!nrh) {
netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n",
hdr->type);
- return -ENOENT;
+ ret = -ENOENT;
+ goto err_free_skb;
}
/* Associate with the request */
@@ -1177,7 +1180,8 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
nr = &ndp->requests[hdr->id];
if (!nr->used) {
spin_unlock_irqrestore(&ndp->lock, flags);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_free_skb;
}
nr->rsp = skb;
@@ -1231,4 +1235,8 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
out:
ncsi_free_request(nr);
return ret;
+
+err_free_skb:
+ kfree_skb(skb);
+ return ret;
}
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index a265efd31ba9..cf827d72581e 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -823,7 +823,7 @@ EXPORT_SYMBOL_GPL(ip_set_del);
*
*/
ip_set_id_t
-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ip_set_get_byname(struct net *net, const struct nlattr *name, struct ip_set **set)
{
ip_set_id_t i, index = IPSET_INVALID_ID;
struct ip_set *s;
@@ -832,7 +832,7 @@ ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
rcu_read_lock();
for (i = 0; i < inst->ip_set_max; i++) {
s = rcu_dereference(inst->ip_set_list)[i];
- if (s && STRNCMP(s->name, name)) {
+ if (s && nla_strcmp(name, s->name) == 0) {
__ip_set_get(s);
index = i;
*set = s;
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index bac75e3afa96..78f5de3cfc51 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -1108,7 +1108,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (!test_bit(i, n->used))
k++;
}
- if (n->pos == 0 && k == 0) {
+ if (k == n->pos) {
t->hregion[r].ext_size -= ext_size(n->size, dsize);
rcu_assign_pointer(hbucket(t, key), NULL);
kfree_rcu(n, rcu);
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index 5cc35b553a04..7d1ba6ad514f 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -367,7 +367,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
ret = ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
+ e.id = ip_set_get_byname(map->net, tb[IPSET_ATTR_NAME], &s);
if (e.id == IPSET_INVALID_ID)
return -IPSET_ERR_NAME;
/* "Loop detection" */
@@ -389,7 +389,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_NAMEREF]) {
e.refid = ip_set_get_byname(map->net,
- nla_data(tb[IPSET_ATTR_NAMEREF]),
+ tb[IPSET_ATTR_NAMEREF],
&s);
if (e.refid == IPSET_INVALID_ID) {
ret = -IPSET_ERR_NAMEREF;
diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c
index 62aa22a07876..7b1497ed97d2 100644
--- a/net/netfilter/nf_conntrack_h323_asn1.c
+++ b/net/netfilter/nf_conntrack_h323_asn1.c
@@ -331,6 +331,8 @@ static int decode_int(struct bitstr *bs, const struct field_t *f,
if (nf_h323_error_boundary(bs, 0, 2))
return H323_ERROR_BOUND;
len = get_bits(bs, 2) + 1;
+ if (nf_h323_error_boundary(bs, len, 0))
+ return H323_ERROR_BOUND;
BYTE_ALIGN(bs);
if (base && (f->attr & DECODE)) { /* timeToLive */
unsigned int v = get_uint(bs, len) + f->lb;
@@ -922,6 +924,8 @@ int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
break;
p++;
len--;
+ if (len <= 0)
+ break;
return DecodeH323_UserInformation(buf, p, len,
&q931->UUIE);
}
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 89174c91053e..24f3f8d5e699 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -468,7 +468,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
*/
synchronize_rcu();
- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
+ nf_ct_expect_iterate_destroy(expect_iter_me, me);
nf_ct_iterate_destroy(unhelp, me);
/* Maybe someone has gotten the helper already when unhelp above.
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index f622fcad3f50..befc9d2bc0b5 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -860,8 +860,8 @@ struct ctnetlink_filter {
};
static const struct nla_policy cta_filter_nla_policy[CTA_FILTER_MAX + 1] = {
- [CTA_FILTER_ORIG_FLAGS] = { .type = NLA_U32 },
- [CTA_FILTER_REPLY_FLAGS] = { .type = NLA_U32 },
+ [CTA_FILTER_ORIG_FLAGS] = NLA_POLICY_MASK(NLA_U32, CTA_FILTER_F_ALL),
+ [CTA_FILTER_REPLY_FLAGS] = NLA_POLICY_MASK(NLA_U32, CTA_FILTER_F_ALL),
};
static int ctnetlink_parse_filter(const struct nlattr *attr,
@@ -875,17 +875,11 @@ static int ctnetlink_parse_filter(const struct nlattr *attr,
if (ret)
return ret;
- if (tb[CTA_FILTER_ORIG_FLAGS]) {
+ if (tb[CTA_FILTER_ORIG_FLAGS])
filter->orig_flags = nla_get_u32(tb[CTA_FILTER_ORIG_FLAGS]);
- if (filter->orig_flags & ~CTA_FILTER_F_ALL)
- return -EOPNOTSUPP;
- }
- if (tb[CTA_FILTER_REPLY_FLAGS]) {
+ if (tb[CTA_FILTER_REPLY_FLAGS])
filter->reply_flags = nla_get_u32(tb[CTA_FILTER_REPLY_FLAGS]);
- if (filter->reply_flags & ~CTA_FILTER_F_ALL)
- return -EOPNOTSUPP;
- }
return 0;
}
@@ -2618,7 +2612,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
[CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING,
.len = NF_CT_HELPER_NAME_LEN - 1 },
[CTA_EXPECT_ZONE] = { .type = NLA_U16 },
- [CTA_EXPECT_FLAGS] = { .type = NLA_U32 },
+ [CTA_EXPECT_FLAGS] = NLA_POLICY_MASK(NLA_BE32, NF_CT_EXPECT_MASK),
[CTA_EXPECT_CLASS] = { .type = NLA_U32 },
[CTA_EXPECT_NAT] = { .type = NLA_NESTED },
[CTA_EXPECT_FN] = { .type = NLA_NUL_STRING },
@@ -3137,23 +3131,27 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
return 0;
}
#endif
-static int ctnetlink_exp_done(struct netlink_callback *cb)
+
+static unsigned long ctnetlink_exp_id(const struct nf_conntrack_expect *exp)
{
- if (cb->args[1])
- nf_ct_expect_put((struct nf_conntrack_expect *)cb->args[1]);
- return 0;
+ unsigned long id = (unsigned long)exp;
+
+ id += nf_ct_get_id(exp->master);
+ id += exp->class;
+
+ return id ? id : 1;
}
static int
ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
- struct nf_conntrack_expect *exp, *last;
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
+ unsigned long last_id = cb->args[1];
+ struct nf_conntrack_expect *exp;
rcu_read_lock();
- last = (struct nf_conntrack_expect *)cb->args[1];
for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
restart:
hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]],
@@ -3165,7 +3163,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
continue;
if (cb->args[1]) {
- if (exp != last)
+ if (ctnetlink_exp_id(exp) != last_id)
continue;
cb->args[1] = 0;
}
@@ -3174,9 +3172,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
cb->nlh->nlmsg_seq,
IPCTNL_MSG_EXP_NEW,
exp) < 0) {
- if (!refcount_inc_not_zero(&exp->use))
- continue;
- cb->args[1] = (unsigned long)exp;
+ cb->args[1] = ctnetlink_exp_id(exp);
goto out;
}
}
@@ -3187,32 +3183,34 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
}
out:
rcu_read_unlock();
- if (last)
- nf_ct_expect_put(last);
-
return skb->len;
}
static int
ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct nf_conntrack_expect *exp, *last;
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
struct nf_conn *ct = cb->data;
- struct nf_conn_help *help = nfct_help(ct);
+ struct nf_conn_help *help;
u_int8_t l3proto = nfmsg->nfgen_family;
+ unsigned long last_id = cb->args[1];
+ struct nf_conntrack_expect *exp;
if (cb->args[0])
return 0;
+ help = nfct_help(ct);
+ if (!help)
+ return 0;
+
rcu_read_lock();
- last = (struct nf_conntrack_expect *)cb->args[1];
+
restart:
hlist_for_each_entry_rcu(exp, &help->expectations, lnode) {
if (l3proto && exp->tuple.src.l3num != l3proto)
continue;
if (cb->args[1]) {
- if (exp != last)
+ if (ctnetlink_exp_id(exp) != last_id)
continue;
cb->args[1] = 0;
}
@@ -3220,9 +3218,7 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
cb->nlh->nlmsg_seq,
IPCTNL_MSG_EXP_NEW,
exp) < 0) {
- if (!refcount_inc_not_zero(&exp->use))
- continue;
- cb->args[1] = (unsigned long)exp;
+ cb->args[1] = ctnetlink_exp_id(exp);
goto out;
}
}
@@ -3233,12 +3229,27 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[0] = 1;
out:
rcu_read_unlock();
- if (last)
- nf_ct_expect_put(last);
-
return skb->len;
}
+static int ctnetlink_dump_exp_ct_start(struct netlink_callback *cb)
+{
+ struct nf_conn *ct = cb->data;
+
+ if (!refcount_inc_not_zero(&ct->ct_general.use))
+ return -ENOENT;
+ return 0;
+}
+
+static int ctnetlink_dump_exp_ct_done(struct netlink_callback *cb)
+{
+ struct nf_conn *ct = cb->data;
+
+ if (ct)
+ nf_ct_put(ct);
+ return 0;
+}
+
static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
@@ -3254,7 +3265,8 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
struct nf_conntrack_zone zone;
struct netlink_dump_control c = {
.dump = ctnetlink_exp_ct_dump_table,
- .done = ctnetlink_exp_done,
+ .start = ctnetlink_dump_exp_ct_start,
+ .done = ctnetlink_dump_exp_ct_done,
};
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER,
@@ -3305,7 +3317,6 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
else {
struct netlink_dump_control c = {
.dump = ctnetlink_exp_dump_table,
- .done = ctnetlink_exp_done,
};
return netlink_dump_start(ctnl, skb, nlh, &c);
}
@@ -3557,6 +3568,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
exp, nf_ct_l3num(ct));
if (err < 0)
goto err_out;
+#if IS_ENABLED(CONFIG_NF_NAT)
+ } else {
+ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
+ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
+ exp->dir = 0;
+#endif
}
return exp;
err_out:
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index c1d02c0b4f00..c43d9819df06 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -1249,9 +1249,9 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
}
static const struct nla_policy tcp_nla_policy[CTA_PROTOINFO_TCP_MAX+1] = {
- [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 },
- [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 },
- [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 },
+ [CTA_PROTOINFO_TCP_STATE] = NLA_POLICY_MAX(NLA_U8, TCP_CONNTRACK_SYN_SENT2),
+ [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = NLA_POLICY_MAX(NLA_U8, TCP_MAX_WSCALE),
+ [CTA_PROTOINFO_TCP_WSCALE_REPLY] = NLA_POLICY_MAX(NLA_U8, TCP_MAX_WSCALE),
[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .len = sizeof(struct nf_ct_tcp_flags) },
[CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .len = sizeof(struct nf_ct_tcp_flags) },
};
@@ -1278,10 +1278,6 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
if (err < 0)
return err;
- if (tb[CTA_PROTOINFO_TCP_STATE] &&
- nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]) >= TCP_CONNTRACK_MAX)
- return -EINVAL;
-
spin_lock_bh(&ct->lock);
if (tb[CTA_PROTOINFO_TCP_STATE])
ct->proto.tcp.state = nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]);
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 751df19fe0f8..dcb0a5e59277 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -1040,6 +1040,7 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
unsigned int port;
const struct sdp_media_type *t;
int ret = NF_ACCEPT;
+ bool have_rtp_addr = false;
hooks = rcu_dereference(nf_nat_sip_hooks);
@@ -1056,8 +1057,11 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
caddr_len = 0;
if (ct_sip_parse_sdp_addr(ct, *dptr, sdpoff, *datalen,
SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
- &matchoff, &matchlen, &caddr) > 0)
+ &matchoff, &matchlen, &caddr) > 0) {
caddr_len = matchlen;
+ memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
+ have_rtp_addr = true;
+ }
mediaoff = sdpoff;
for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) {
@@ -1091,9 +1095,11 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
&matchoff, &matchlen, &maddr) > 0) {
maddr_len = matchlen;
memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
- } else if (caddr_len)
+ have_rtp_addr = true;
+ } else if (caddr_len) {
memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
- else {
+ have_rtp_addr = true;
+ } else {
nf_ct_helper_log(skb, ct, "cannot parse SDP message");
return NF_DROP;
}
@@ -1125,7 +1131,7 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
/* Update session connection and owner addresses */
hooks = rcu_dereference(nf_nat_sip_hooks);
- if (hooks && ct->status & IPS_NAT_MASK)
+ if (hooks && ct->status & IPS_NAT_MASK && have_rtp_addr)
ret = hooks->sdp_session(skb, protoff, dataoff,
dptr, datalen, sdpoff,
&rtp_addr);
@@ -1529,11 +1535,12 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
{
struct tcphdr *th, _tcph;
unsigned int dataoff, datalen;
- unsigned int matchoff, matchlen, clen;
+ unsigned int matchoff, matchlen;
unsigned int msglen, origlen;
const char *dptr, *end;
s16 diff, tdiff = 0;
int ret = NF_ACCEPT;
+ unsigned long clen;
bool term;
if (ctinfo != IP_CT_ESTABLISHED &&
@@ -1568,6 +1575,9 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
if (dptr + matchoff == end)
break;
+ if (clen > datalen)
+ break;
+
term = false;
for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) {
if (end[0] == '\r' && end[1] == '\n' &&
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index dcb35be8b2af..15486d3051f6 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -8334,11 +8334,6 @@ static void nft_trans_gc_queue_work(struct nft_trans_gc *trans)
schedule_work(&trans_gc_work);
}
-static int nft_trans_gc_space(struct nft_trans_gc *trans)
-{
- return NFT_TRANS_GC_BATCHCOUNT - trans->count;
-}
-
struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc,
unsigned int gc_seq, gfp_t gfp)
{
@@ -9367,8 +9362,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
switch (data->verdict.code) {
case NF_ACCEPT:
case NF_DROP:
- case NF_QUEUE:
- break;
case NFT_CONTINUE:
case NFT_BREAK:
case NFT_RETURN:
@@ -9403,6 +9396,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
data->verdict.chain = chain;
break;
+ case NF_QUEUE:
+ /* The nft_queue expression is used for this purpose, an
+ * immediate NF_QUEUE verdict should not ever be seen here.
+ */
+ fallthrough;
default:
return -EINVAL;
}
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index 52d5f2411834..8edad41e4db6 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -601,10 +601,10 @@ nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
goto out;
}
}
- }
- if (cb->args[1]) {
- cb->args[1] = 0;
- goto restart;
+ if (cb->args[1]) {
+ cb->args[1] = 0;
+ goto restart;
+ }
}
out:
rcu_read_unlock();
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 80c09070ea9f..d41560d4812d 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -632,15 +632,11 @@ __build_packet_message(struct nfnl_log_net *log,
if (data_len) {
struct nlattr *nla;
- int size = nla_attr_size(data_len);
- if (skb_tailroom(inst->skb) < nla_total_size(data_len))
+ nla = nla_reserve(inst->skb, NFULA_PAYLOAD, data_len);
+ if (!nla)
goto nla_put_failure;
- nla = skb_put(inst->skb, nla_total_size(data_len));
- nla->nla_type = NFULA_PAYLOAD;
- nla->nla_len = size;
-
if (skb_copy_bits(skb, 0, nla_data(nla), data_len))
BUG();
}
@@ -715,7 +711,7 @@ nfulnl_log_packet(struct net *net,
+ nla_total_size(plen) /* prefix */
+ nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
+ nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp))
- + nla_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
+ + nlmsg_total_size(sizeof(struct nfgenmsg)); /* NLMSG_DONE */
if (in && skb_mac_header_was_set(skb)) {
size += nla_total_size(skb->dev->hard_header_len)
diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c
index 573a372e760f..a2d7bfb4c1a6 100644
--- a/net/netfilter/nfnetlink_osf.c
+++ b/net/netfilter/nfnetlink_osf.c
@@ -303,7 +303,9 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
{
struct nf_osf_user_finger *f;
struct nf_osf_finger *kf = NULL, *sf;
+ unsigned int tot_opt_len = 0;
int err = 0;
+ int i;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -319,6 +321,17 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
if (f->opt_num > ARRAY_SIZE(f->opt))
return -EINVAL;
+ for (i = 0; i < f->opt_num; i++) {
+ if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN)
+ return -EINVAL;
+ if (f->opt[i].kind == OSFOPT_MSS && f->opt[i].length < 4)
+ return -EINVAL;
+
+ tot_opt_len += f->opt[i].length;
+ if (tot_opt_len > MAX_IPOPTLEN)
+ return -EINVAL;
+ }
+
if (!memchr(f->genre, 0, MAXGENRELEN) ||
!memchr(f->subtype, 0, MAXGENRELEN) ||
!memchr(f->version, 0, MAXGENRELEN))
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index dc6af1919dea..bfe909267c9d 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1209,8 +1209,10 @@ static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
if (entry->state.pf == PF_BRIDGE) {
err = nfqa_parse_bridge(entry, nfqa);
- if (err < 0)
+ if (err < 0) {
+ nfqnl_reinject(entry, NF_DROP);
return err;
+ }
}
if (nfqa[NFQA_PAYLOAD]) {
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index f95f1dbc48de..241d99b061d8 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -22,6 +22,8 @@
#include <net/netfilter/nf_conntrack_timeout.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_expect.h>
+#include <net/netfilter/nf_conntrack_seqadj.h>
+#include "nf_internals.h"
struct nft_ct {
enum nft_ct_keys key:8;
@@ -532,6 +534,7 @@ static void __nft_ct_set_destroy(const struct nft_ctx *ctx, struct nft_ct *priv)
#endif
#ifdef CONFIG_NF_CONNTRACK_ZONES
case NFT_CT_ZONE:
+ nf_queue_nf_hook_drop(ctx->net);
mutex_lock(&nft_ct_pcpu_mutex);
if (--nft_ct_pcpu_template_refcnt == 0)
nft_ct_tmpl_put_pcpu();
@@ -929,9 +932,10 @@ static void nft_ct_timeout_obj_destroy(const struct nft_ctx *ctx,
struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
struct nf_ct_timeout *timeout = priv->timeout;
+ 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,
@@ -1061,6 +1065,7 @@ static void nft_ct_helper_obj_destroy(const struct nft_ctx *ctx,
{
struct nft_ct_helper_obj *priv = nft_obj_data(obj);
+ nf_queue_nf_hook_drop(ctx->net);
if (priv->helper4)
nf_conntrack_helper_put(priv->helper4);
if (priv->helper6)
@@ -1106,6 +1111,10 @@ static void nft_ct_helper_obj_eval(struct nft_object *obj,
if (help) {
rcu_assign_pointer(help->helper, to_assign);
set_bit(IPS_HELPER_BIT, &ct->status);
+
+ if ((ct->status & IPS_NAT_MASK) && !nfct_seqadj(ct))
+ if (!nfct_seqadj_ext_add(ct))
+ regs->verdict.code = NF_DROP;
}
}
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index f607cd7f203a..ae0c4cd2dd1c 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -119,10 +119,10 @@ static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = {
[NFTA_PAYLOAD_SREG] = { .type = NLA_U32 },
[NFTA_PAYLOAD_DREG] = { .type = NLA_U32 },
[NFTA_PAYLOAD_BASE] = { .type = NLA_U32 },
- [NFTA_PAYLOAD_OFFSET] = { .type = NLA_U32 },
- [NFTA_PAYLOAD_LEN] = { .type = NLA_U32 },
+ [NFTA_PAYLOAD_OFFSET] = NLA_POLICY_MAX(NLA_BE32, 255),
+ [NFTA_PAYLOAD_LEN] = NLA_POLICY_MAX(NLA_BE32, 255),
[NFTA_PAYLOAD_CSUM_TYPE] = { .type = NLA_U32 },
- [NFTA_PAYLOAD_CSUM_OFFSET] = { .type = NLA_U32 },
+ [NFTA_PAYLOAD_CSUM_OFFSET] = NLA_POLICY_MAX(NLA_BE32, 255),
[NFTA_PAYLOAD_CSUM_FLAGS] = { .type = NLA_U32 },
};
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index a4fdd1587bb3..baabbfe62a27 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -1539,6 +1539,7 @@ static void pipapo_drop(struct nft_pipapo_match *m,
int i;
nft_pipapo_for_each_field(f, i, m) {
+ bool last = i == m->field_count - 1;
int g;
for (g = 0; g < f->groups; g++) {
@@ -1558,7 +1559,7 @@ static void pipapo_drop(struct nft_pipapo_match *m,
}
pipapo_unmap(f->mt, f->rules, rulemap[i].to, rulemap[i].n,
- rulemap[i + 1].n, i == m->field_count - 1);
+ last ? 0 : rulemap[i + 1].n, last);
if (pipapo_resize(f, f->rules, f->rules - rulemap[i].n)) {
/* We can ignore this, a failure to shrink tables down
* doesn't make tables invalid.
@@ -1582,11 +1583,11 @@ static void nft_pipapo_gc_deactivate(struct net *net, struct nft_set *set,
}
/**
- * pipapo_gc() - Drop expired entries from set, destroy start and end elements
+ * pipapo_gc_scan() - Drop expired entries from set and link them to gc list
* @_set: nftables API set representation
* @m: Matching data
*/
-static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
+static void pipapo_gc_scan(const struct nft_set *_set, struct nft_pipapo_match *m)
{
struct nft_set *set = (struct nft_set *) _set;
struct nft_pipapo *priv = nft_set_priv(set);
@@ -1599,6 +1600,8 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
if (!gc)
return;
+ list_add(&gc->list, &priv->gc_head);
+
while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
struct nft_pipapo_field *f;
@@ -1628,9 +1631,13 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
if (__nft_set_elem_expired(&e->ext, tstamp)) {
priv->dirty = true;
- gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
- if (!gc)
- return;
+ if (!nft_trans_gc_space(gc)) {
+ gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL);
+ if (!gc)
+ return;
+
+ list_add(&gc->list, &priv->gc_head);
+ }
nft_pipapo_gc_deactivate(net, set, e);
pipapo_drop(m, rulemap);
@@ -1644,9 +1651,21 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
}
}
- if (gc) {
+ priv->last_gc = jiffies;
+}
+
+/**
+ * pipapo_gc_queue() - Free expired elements after pointer swap
+ * @_set: nftables API set representation
+ */
+static void pipapo_gc_queue(const struct nft_set *_set)
+{
+ struct nft_pipapo *priv = nft_set_priv(_set);
+ struct nft_trans_gc *gc, *next;
+
+ list_for_each_entry_safe(gc, next, &priv->gc_head, list) {
+ list_del(&gc->list);
nft_trans_gc_queue_sync_done(gc);
- priv->last_gc = jiffies;
}
}
@@ -1707,14 +1726,14 @@ static void nft_pipapo_commit(const struct nft_set *set)
struct nft_pipapo_match *new_clone, *old;
if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
- pipapo_gc(set, priv->clone);
+ pipapo_gc_scan(set, priv->clone);
if (!priv->dirty)
- return;
+ goto out;
new_clone = pipapo_clone(priv->clone);
if (IS_ERR(new_clone))
- return;
+ goto out;
priv->dirty = false;
@@ -1724,6 +1743,8 @@ static void nft_pipapo_commit(const struct nft_set *set)
call_rcu(&old->rcu, pipapo_reclaim_match);
priv->clone = new_clone;
+out:
+ pipapo_gc_queue(set);
}
static void nft_pipapo_abort(const struct nft_set *set)
@@ -2188,6 +2209,7 @@ static int nft_pipapo_init(const struct nft_set *set,
priv->dirty = false;
+ INIT_LIST_HEAD(&priv->gc_head);
rcu_assign_pointer(priv->match, m);
return 0;
@@ -2240,6 +2262,8 @@ static void nft_pipapo_destroy(const struct nft_ctx *ctx,
struct nft_pipapo_match *m;
int cpu;
+ WARN_ON_ONCE(!list_empty(&priv->gc_head));
+
m = rcu_dereference_protected(priv->match, true);
if (m) {
rcu_barrier();
diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h
index 8f8f58af4e34..ca90be37bc71 100644
--- a/net/netfilter/nft_set_pipapo.h
+++ b/net/netfilter/nft_set_pipapo.h
@@ -165,6 +165,7 @@ struct nft_pipapo_match {
* @width: Total bytes to be matched for one packet, including padding
* @dirty: Working copy has pending insertions or deletions
* @last_gc: Timestamp of last garbage collection run, jiffies
+ * @gc_head: list of nft_trans_gc to queue for deferred reclaim
*/
struct nft_pipapo {
struct nft_pipapo_match __rcu *match;
@@ -172,6 +173,7 @@ struct nft_pipapo {
int width;
bool dirty;
unsigned long last_gc;
+ struct list_head gc_head;
};
struct nft_pipapo_elem;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 92e9d4ebc5e8..94778fae2d91 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -481,6 +481,17 @@ int xt_check_match(struct xt_mtchk_param *par,
par->match->table, par->table);
return -EINVAL;
}
+
+ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
+ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
+ * support.
+ */
+ if (par->family == NFPROTO_ARP &&
+ par->match->family != NFPROTO_ARP) {
+ pr_info_ratelimited("%s_tables: %s match: not valid for this family\n",
+ xt_prefix[par->family], par->match->name);
+ return -EINVAL;
+ }
if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
char used[64], allow[64];
@@ -996,6 +1007,18 @@ int xt_check_target(struct xt_tgchk_param *par,
par->target->table, par->table);
return -EINVAL;
}
+
+ /* NFPROTO_UNSPEC implies NF_INET_* hooks which do not overlap with
+ * NF_ARP_IN,OUT,FORWARD, allow explicit extensions with NFPROTO_ARP
+ * support.
+ */
+ if (par->family == NFPROTO_ARP &&
+ par->target->family != NFPROTO_ARP) {
+ pr_info_ratelimited("%s_tables: %s target: not valid for this family\n",
+ xt_prefix[par->family], par->target->name);
+ return -EINVAL;
+ }
+
if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
char used[64], allow[64];
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index ffff1e1f79b9..6ad76f3a956c 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -16,6 +16,7 @@
#include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_conntrack_timeout.h>
#include <net/netfilter/nf_conntrack_zones.h>
+#include "nf_internals.h"
static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
{
@@ -270,6 +271,9 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
struct nf_conn_help *help;
if (ct) {
+ if (info->helper[0] || info->timeout[0])
+ nf_queue_nf_hook_drop(par->net);
+
help = nfct_help(ct);
if (help)
nf_conntrack_helper_put(help->helper);
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
index 2f7cf5ecebf4..d35ff0a2cad8 100644
--- a/net/netfilter/xt_IDLETIMER.c
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -320,6 +320,12 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
info->timer = __idletimer_tg_find_by_label(info->label);
if (info->timer) {
+ if (info->timer->timer_type & XT_IDLETIMER_ALARM) {
+ pr_debug("Adding/Replacing rule with same label and different timer type is not allowed\n");
+ mutex_unlock(&list_mutex);
+ return -EINVAL;
+ }
+
info->timer->refcnt++;
mod_timer(&info->timer->timer,
msecs_to_jiffies(info->timeout * 1000) + jiffies);
diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
index c0f5e9a4f3c6..bfc98719684e 100644
--- a/net/netfilter/xt_cgroup.c
+++ b/net/netfilter/xt_cgroup.c
@@ -53,6 +53,9 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
info->priv = NULL;
if (info->has_path) {
+ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
+ return -ENAMETOOLONG;
+
cgrp = cgroup_get_from_path(info->path);
if (IS_ERR(cgrp)) {
pr_info_ratelimited("invalid path, errno=%ld\n",
@@ -85,6 +88,9 @@ static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
info->priv = NULL;
if (info->has_path) {
+ if (strnlen(info->path, sizeof(info->path)) >= sizeof(info->path))
+ return -ENAMETOOLONG;
+
cgrp = cgroup_get_from_path(info->path);
if (IS_ERR(cgrp)) {
pr_info_ratelimited("invalid path, errno=%ld\n",
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
index e5a13ecbe67a..037ab93e25d0 100644
--- a/net/netfilter/xt_dccp.c
+++ b/net/netfilter/xt_dccp.c
@@ -62,10 +62,10 @@ dccp_find_option(u_int8_t option,
return true;
}
- if (op[i] < 2)
+ if (op[i] < 2 || i == optlen - 1)
i++;
else
- i += op[i+1]?:1;
+ i += op[i + 1] ? : 1;
}
spin_unlock_bh(&dccp_buflock);
diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
index 72324bd976af..b1d736c15fcb 100644
--- a/net/netfilter/xt_rateest.c
+++ b/net/netfilter/xt_rateest.c
@@ -91,6 +91,11 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
goto err1;
}
+ if (strnlen(info->name1, sizeof(info->name1)) >= sizeof(info->name1))
+ return -ENAMETOOLONG;
+ if (strnlen(info->name2, sizeof(info->name2)) >= sizeof(info->name2))
+ return -ENAMETOOLONG;
+
ret = -ENOENT;
est1 = xt_rateest_lookup(par->net, info->name1);
if (!est1)
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c
index 11ec2abf0c72..73f50dc01b19 100644
--- a/net/netfilter/xt_tcpudp.c
+++ b/net/netfilter/xt_tcpudp.c
@@ -56,8 +56,10 @@ tcp_find_option(u_int8_t option,
for (i = 0; i < optlen; ) {
if (op[i] == option) return !invert;
- if (op[i] < 2) i++;
- else i += op[i+1]?:1;
+ if (op[i] < 2 || i == optlen - 1)
+ i++;
+ else
+ i += op[i + 1] ? : 1;
}
return invert;
diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c
index 6aa12d0f54e2..61de85e02a40 100644
--- a/net/netfilter/xt_time.c
+++ b/net/netfilter/xt_time.c
@@ -227,13 +227,13 @@ time_mt(const struct sk_buff *skb, struct xt_action_param *par)
localtime_2(¤t_time, stamp);
- if (!(info->weekdays_match & (1 << current_time.weekday)))
+ if (!(info->weekdays_match & (1U << current_time.weekday)))
return false;
/* Do not spend time computing monthday if all days match anyway */
if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) {
localtime_3(¤t_time, stamp);
- if (!(info->monthdays_match & (1 << current_time.monthday)))
+ if (!(info->monthdays_match & (1U << current_time.monthday)))
return false;
}
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 3514686eb53f..78472b192970 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -562,8 +562,7 @@ static int nci_close_device(struct nci_dev *ndev)
skb_queue_purge(&ndev->rx_q);
skb_queue_purge(&ndev->tx_q);
- /* Flush RX and TX wq */
- flush_workqueue(ndev->rx_wq);
+ /* Flush TX wq, RX wq flush can't be under the lock */
flush_workqueue(ndev->tx_wq);
/* Reset device */
@@ -575,13 +574,13 @@ static int nci_close_device(struct nci_dev *ndev)
msecs_to_jiffies(NCI_RESET_TIMEOUT));
/* After this point our queues are empty
- * and no works are scheduled.
+ * rx work may be running but will see that NCI_UP was cleared
*/
ndev->ops->close(ndev);
clear_bit(NCI_INIT, &ndev->flags);
- /* Flush cmd wq */
+ /* Flush cmd and tx wq */
flush_workqueue(ndev->cmd_wq);
del_timer_sync(&ndev->cmd_timer);
@@ -591,6 +590,9 @@ static int nci_close_device(struct nci_dev *ndev)
mutex_unlock(&ndev->req_lock);
+ /* rx_work may take req_lock via nci_deactivate_target */
+ flush_workqueue(ndev->rx_wq);
+
return 0;
}
@@ -1014,18 +1016,23 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct nci_conn_info *conn_info;
conn_info = ndev->rf_conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ kfree_skb(skb);
return -EPROTO;
+ }
pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
if (!ndev->target_active_prot) {
pr_err("unable to exchange data, no active target\n");
+ kfree_skb(skb);
return -EINVAL;
}
- if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+ if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags)) {
+ kfree_skb(skb);
return -EBUSY;
+ }
/* store cb and context to be used on receiving data */
conn_info->data_exchange_cb = cb;
@@ -1460,10 +1467,20 @@ static bool nci_valid_size(struct sk_buff *skb)
BUILD_BUG_ON(NCI_CTRL_HDR_SIZE != NCI_DATA_HDR_SIZE);
if (skb->len < hdr_size ||
- !nci_plen(skb->data) ||
skb->len < hdr_size + nci_plen(skb->data)) {
return false;
}
+
+ if (!nci_plen(skb->data)) {
+ /* Allow zero length in proprietary notifications (0x20 - 0x3F). */
+ if (nci_opcode_oid(nci_opcode(skb->data)) >= 0x20 &&
+ nci_mt(skb->data) == NCI_MT_NTF_PKT)
+ return true;
+
+ /* Disallow zero length otherwise. */
+ return false;
+ }
+
return true;
}
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index b4548d887489..4f06a2903ae7 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -33,7 +33,8 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
if (!conn_info) {
kfree_skb(skb);
- goto exit;
+ clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+ return;
}
cb = conn_info->data_exchange_cb;
@@ -45,6 +46,12 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
del_timer_sync(&ndev->data_timer);
clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
+ /* Mark the exchange as done before calling the callback.
+ * The callback (e.g. rawsock_data_exchange_complete) may
+ * want to immediately queue another data exchange.
+ */
+ clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+
if (cb) {
/* forward skb to nfc core */
cb(cb_context, skb, err);
@@ -54,9 +61,6 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
/* no waiting callback, free skb */
kfree_skb(skb);
}
-
-exit:
- clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
}
/* ----------------- NCI TX Data ----------------- */
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index 5f1d438a0a23..0e59706e4e8a 100644
--- a/net/nfc/rawsock.c
+++ b/net/nfc/rawsock.c
@@ -66,6 +66,17 @@ static int rawsock_release(struct socket *sock)
if (sock->type == SOCK_RAW)
nfc_sock_unlink(&raw_sk_list, sk);
+ if (sk->sk_state == TCP_ESTABLISHED) {
+ /* Prevent rawsock_tx_work from starting new transmits and
+ * wait for any in-progress work to finish. This must happen
+ * before the socket is orphaned to avoid a race where
+ * rawsock_tx_work runs after the NCI device has been freed.
+ */
+ sk->sk_shutdown |= SEND_SHUTDOWN;
+ cancel_work_sync(&nfc_rawsock(sk)->tx_work);
+ rawsock_write_queue_purge(sk);
+ }
+
sock_orphan(sk);
sock_put(sk);
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 54f952620b21..2185fd5596fc 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -2911,6 +2911,8 @@ static int validate_set(const struct nlattr *a,
case OVS_KEY_ATTR_MPLS:
if (!eth_p_mpls(eth_type))
return -EINVAL;
+ if (key_len != sizeof(struct ovs_key_mpls))
+ return -EINVAL;
break;
case OVS_KEY_ATTR_SCTP:
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c
index 72cf13bbf3dd..70cc8854b8d5 100644
--- a/net/openvswitch/vport-netdev.c
+++ b/net/openvswitch/vport-netdev.c
@@ -146,11 +146,15 @@ static void vport_netdev_free(struct rcu_head *rcu)
void ovs_netdev_detach_dev(struct vport *vport)
{
ASSERT_RTNL();
- vport->dev->priv_flags &= ~IFF_OVS_DATAPATH;
netdev_rx_handler_unregister(vport->dev);
netdev_upper_dev_unlink(vport->dev,
netdev_master_upper_dev_get(vport->dev));
dev_set_promiscuity(vport->dev, -1);
+
+ /* paired with smp_mb() in netdev_destroy() */
+ smp_wmb();
+
+ vport->dev->priv_flags &= ~IFF_OVS_DATAPATH;
}
static void netdev_destroy(struct vport *vport)
@@ -169,6 +173,9 @@ static void netdev_destroy(struct vport *vport)
rtnl_unlock();
}
+ /* paired with smp_wmb() in ovs_netdev_detach_dev() */
+ smp_mb();
+
call_rcu(&vport->rcu, vport_netdev_free);
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 4614fae54ed7..1c9b2d67c3ed 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3147,6 +3147,7 @@ static int packet_release(struct socket *sock)
spin_lock(&po->bind_lock);
unregister_prot_hook(sk, false);
+ WRITE_ONCE(po->num, 0);
packet_cached_dev_reset(po);
if (po->prot_hook.dev) {
diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
index 8476a229bce0..fdb7a5a12f03 100644
--- a/net/qrtr/af_qrtr.c
+++ b/net/qrtr/af_qrtr.c
@@ -116,7 +116,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
* @ep: endpoint
* @ref: reference count for node
* @nid: node id
- * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
+ * @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
* @qrtr_tx_lock: lock for qrtr_tx_flow inserts
* @rx_queue: receive queue
* @item: list item for broadcast list
@@ -127,7 +127,7 @@ struct qrtr_node {
struct kref ref;
unsigned int nid;
- struct radix_tree_root qrtr_tx_flow;
+ struct xarray qrtr_tx_flow;
struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
struct sk_buff_head rx_queue;
@@ -170,10 +170,16 @@ static void __qrtr_node_release(struct kref *kref)
struct qrtr_tx_flow *flow;
unsigned long flags;
void __rcu **slot;
+ unsigned long index;
spin_lock_irqsave(&qrtr_nodes_lock, flags);
- if (node->nid != QRTR_EP_NID_AUTO)
- radix_tree_delete(&qrtr_nodes, node->nid);
+ /* If the node is a bridge for other nodes, there are possibly
+ * multiple entries pointing to our released node, delete them all.
+ */
+ radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) {
+ if (*slot == node)
+ radix_tree_iter_delete(&qrtr_nodes, &iter, slot);
+ }
spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
list_del(&node->item);
@@ -182,11 +188,9 @@ static void __qrtr_node_release(struct kref *kref)
skb_queue_purge(&node->rx_queue);
/* Free tx flow counters */
- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
- flow = *slot;
- radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
+ xa_for_each(&node->qrtr_tx_flow, index, flow)
kfree(flow);
- }
+ xa_destroy(&node->qrtr_tx_flow);
kfree(node);
}
@@ -221,9 +225,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
key = remote_node << 32 | remote_port;
- rcu_read_lock();
- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
- rcu_read_unlock();
+ flow = xa_load(&node->qrtr_tx_flow, key);
if (flow) {
spin_lock(&flow->resume_tx.lock);
flow->pending = 0;
@@ -262,12 +264,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
return 0;
mutex_lock(&node->qrtr_tx_lock);
- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
+ flow = xa_load(&node->qrtr_tx_flow, key);
if (!flow) {
flow = kzalloc(sizeof(*flow), GFP_KERNEL);
if (flow) {
init_waitqueue_head(&flow->resume_tx);
- if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
+ if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
+ GFP_KERNEL))) {
kfree(flow);
flow = NULL;
}
@@ -319,9 +322,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
unsigned long key = (u64)dest_node << 32 | dest_port;
struct qrtr_tx_flow *flow;
- rcu_read_lock();
- flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
- rcu_read_unlock();
+ flow = xa_load(&node->qrtr_tx_flow, key);
if (flow) {
spin_lock_irq(&flow->resume_tx.lock);
flow->tx_failed = 1;
@@ -540,18 +541,20 @@ EXPORT_SYMBOL_GPL(qrtr_endpoint_post);
/**
* qrtr_alloc_ctrl_packet() - allocate control packet skb
* @pkt: reference to qrtr_ctrl_pkt pointer
+ * @flags: the type of memory to allocate
*
* Returns newly allocated sk_buff, or NULL on failure
*
* This function allocates a sk_buff large enough to carry a qrtr_ctrl_pkt and
* on success returns a reference to the control packet in @pkt.
*/
-static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt)
+static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt,
+ gfp_t flags)
{
const int pkt_len = sizeof(struct qrtr_ctrl_pkt);
struct sk_buff *skb;
- skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, GFP_KERNEL);
+ skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, flags);
if (!skb)
return NULL;
@@ -586,7 +589,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
node->nid = QRTR_EP_NID_AUTO;
node->ep = ep;
- INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
+ xa_init(&node->qrtr_tx_flow);
mutex_init(&node->qrtr_tx_lock);
qrtr_node_assign(node, nid);
@@ -613,6 +616,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
struct qrtr_ctrl_pkt *pkt;
struct qrtr_tx_flow *flow;
struct sk_buff *skb;
+ unsigned long flags;
+ unsigned long index;
void __rcu **slot;
mutex_lock(&node->ep_lock);
@@ -620,18 +625,23 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
mutex_unlock(&node->ep_lock);
/* Notify the local controller about the event */
- skb = qrtr_alloc_ctrl_packet(&pkt);
- if (skb) {
- pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
- qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) {
+ if (*slot != node)
+ continue;
+ src.sq_node = iter.index;
+ skb = qrtr_alloc_ctrl_packet(&pkt, GFP_ATOMIC);
+ if (skb) {
+ pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
+ qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
+ }
}
+ spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
/* Wake up any transmitters waiting for resume-tx from the node */
mutex_lock(&node->qrtr_tx_lock);
- radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
- flow = *slot;
+ xa_for_each(&node->qrtr_tx_flow, index, flow)
wake_up_interruptible_all(&flow->resume_tx);
- }
mutex_unlock(&node->qrtr_tx_lock);
qrtr_node_release(node);
@@ -677,7 +687,7 @@ static void qrtr_port_remove(struct qrtr_sock *ipc)
to.sq_node = QRTR_NODE_BCAST;
to.sq_port = QRTR_PORT_CTRL;
- skb = qrtr_alloc_ctrl_packet(&pkt);
+ skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
if (skb) {
pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT);
pkt->client.node = cpu_to_le32(ipc->us.sq_node);
@@ -992,7 +1002,7 @@ static int qrtr_send_resume_tx(struct qrtr_cb *cb)
if (!node)
return -EINVAL;
- skb = qrtr_alloc_ctrl_packet(&pkt);
+ skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
if (!skb)
return -ENOMEM;
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
index 8f070ee7e742..30fca2169aa7 100644
--- a/net/rds/ib_rdma.c
+++ b/net/rds/ib_rdma.c
@@ -608,8 +608,13 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
return ibmr;
}
- if (conn)
+ if (conn) {
ic = conn->c_transport_data;
+ if (!ic || !ic->i_cm_id || !ic->i_cm_id->qp) {
+ ret = -ENODEV;
+ goto out;
+ }
+ }
if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
ret = -ENODEV;
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 97101c55763d..7a39454b731a 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -71,11 +71,14 @@ struct rfkill_int_event {
struct rfkill_event 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;
};
@@ -252,9 +255,12 @@ static void rfkill_global_led_trigger_unregister(void)
}
#endif /* CONFIG_RFKILL_LEDS */
-static void rfkill_fill_event(struct rfkill_event *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 *ev = &int_ev->ev;
unsigned long flags;
ev->idx = rfkill->idx;
@@ -266,6 +272,16 @@ static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill,
ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW |
RFKILL_BLOCK_SW_PREV));
spin_unlock_irqrestore(&rfkill->lock, flags);
+
+ mutex_lock(&data->mtx);
+ if (data->event_count++ > MAX_RFKILL_EVENT) {
+ data->event_count--;
+ mutex_unlock(&data->mtx);
+ return -ENOSPC;
+ }
+ list_add_tail(&int_ev->list, &data->events);
+ mutex_unlock(&data->mtx);
+ return 0;
}
static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
@@ -277,10 +293,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);
}
}
@@ -1118,21 +1134,19 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
init_waitqueue_head(&data->read_wait);
mutex_lock(&rfkill_global_mutex);
- mutex_lock(&data->mtx);
/*
- * start getting events from elsewhere but hold mtx to get
- * startup events added first
+ * start getting events from elsewhere but hold rfkill_global_mutex
+ * to get startup events added first
*/
list_for_each_entry(rfkill, &rfkill_list, node) {
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
goto free;
- rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD);
- list_add_tail(&ev->list, &data->events);
+ if (rfkill_fill_event(ev, rfkill, data, RFKILL_OP_ADD))
+ kfree(ev);
}
list_add(&data->list, &rfkill_fds);
- mutex_unlock(&data->mtx);
mutex_unlock(&rfkill_global_mutex);
file->private_data = data;
@@ -1140,7 +1154,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
return stream_open(inode, file);
free:
- mutex_unlock(&data->mtx);
mutex_unlock(&rfkill_global_mutex);
mutex_destroy(&data->mtx);
list_for_each_entry_safe(ev, tmp, &data->events, list)
@@ -1200,6 +1213,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/rose/af_rose.c b/net/rose/af_rose.c
index 04173c85d92b..0130c13f7355 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -808,6 +808,11 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
goto out_release;
}
+ if (sk->sk_state == TCP_SYN_SENT) {
+ err = -EALREADY;
+ goto out_release;
+ }
+
sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 0354f90dc93a..dd6207ef2266 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -614,9 +614,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;
@@ -624,9 +621,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/key.c b/net/rxrpc/key.c
index 979338a64c0c..ca4417127b10 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -903,7 +903,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/sched/act_gate.c b/net/sched/act_gate.c
index 0e7568a06351..30bd6eefb461 100644
--- a/net/sched/act_gate.c
+++ b/net/sched/act_gate.c
@@ -32,9 +32,12 @@ static ktime_t gate_get_time(struct tcf_gate *gact)
return KTIME_MAX;
}
-static void gate_get_start_time(struct tcf_gate *gact, ktime_t *start)
+static void tcf_gate_params_free_rcu(struct rcu_head *head);
+
+static void gate_get_start_time(struct tcf_gate *gact,
+ const struct tcf_gate_params *param,
+ ktime_t *start)
{
- struct tcf_gate_params *param = &gact->param;
ktime_t now, base, cycle;
u64 n;
@@ -69,12 +72,14 @@ static enum hrtimer_restart gate_timer_func(struct hrtimer *timer)
{
struct tcf_gate *gact = container_of(timer, struct tcf_gate,
hitimer);
- struct tcf_gate_params *p = &gact->param;
struct tcfg_gate_entry *next;
+ struct tcf_gate_params *p;
ktime_t close_time, now;
spin_lock(&gact->tcf_lock);
+ p = rcu_dereference_protected(gact->param,
+ lockdep_is_held(&gact->tcf_lock));
next = gact->next_entry;
/* cycle start, clear pending bit, clear total octets */
@@ -227,6 +232,35 @@ static void release_entry_list(struct list_head *entries)
}
}
+static int tcf_gate_copy_entries(struct tcf_gate_params *dst,
+ const struct tcf_gate_params *src,
+ struct netlink_ext_ack *extack)
+{
+ struct tcfg_gate_entry *entry;
+ int i = 0;
+
+ list_for_each_entry(entry, &src->entries, list) {
+ struct tcfg_gate_entry *new;
+
+ new = kzalloc(sizeof(*new), GFP_ATOMIC);
+ if (!new) {
+ NL_SET_ERR_MSG(extack, "Not enough memory for entry");
+ return -ENOMEM;
+ }
+
+ new->index = entry->index;
+ new->gate_state = entry->gate_state;
+ new->interval = entry->interval;
+ new->ipv = entry->ipv;
+ new->maxoctets = entry->maxoctets;
+ list_add_tail(&new->list, &dst->entries);
+ i++;
+ }
+
+ dst->num_entries = i;
+ return 0;
+}
+
static int parse_gate_list(struct nlattr *list_attr,
struct tcf_gate_params *sched,
struct netlink_ext_ack *extack)
@@ -272,23 +306,42 @@ static int parse_gate_list(struct nlattr *list_attr,
return err;
}
-static void gate_setup_timer(struct tcf_gate *gact, u64 basetime,
- enum tk_offsets tko, s32 clockid,
- bool do_init)
+static bool gate_timer_needs_cancel(u64 basetime, u64 old_basetime,
+ enum tk_offsets tko,
+ enum tk_offsets old_tko,
+ s32 clockid, s32 old_clockid)
{
- if (!do_init) {
- if (basetime == gact->param.tcfg_basetime &&
- tko == gact->tk_offset &&
- clockid == gact->param.tcfg_clockid)
- return;
+ return basetime != old_basetime ||
+ clockid != old_clockid ||
+ tko != old_tko;
+}
- spin_unlock_bh(&gact->tcf_lock);
- hrtimer_cancel(&gact->hitimer);
- spin_lock_bh(&gact->tcf_lock);
+static int gate_clock_resolve(s32 clockid, enum tk_offsets *tko,
+ struct netlink_ext_ack *extack)
+{
+ switch (clockid) {
+ case CLOCK_REALTIME:
+ *tko = TK_OFFS_REAL;
+ return 0;
+ case CLOCK_MONOTONIC:
+ *tko = TK_OFFS_MAX;
+ return 0;
+ case CLOCK_BOOTTIME:
+ *tko = TK_OFFS_BOOT;
+ return 0;
+ case CLOCK_TAI:
+ *tko = TK_OFFS_TAI;
+ return 0;
+ default:
+ NL_SET_ERR_MSG(extack, "Invalid 'clockid'");
+ return -EINVAL;
}
- gact->param.tcfg_basetime = basetime;
- gact->param.tcfg_clockid = clockid;
- gact->tk_offset = tko;
+}
+
+static void gate_setup_timer(struct tcf_gate *gact, s32 clockid,
+ enum tk_offsets tko)
+{
+ WRITE_ONCE(gact->tk_offset, tko);
hrtimer_init(&gact->hitimer, clockid, HRTIMER_MODE_ABS_SOFT);
gact->hitimer.function = gate_timer_func;
}
@@ -300,14 +353,21 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
struct netlink_ext_ack *extack)
{
struct tc_action_net *tn = net_generic(net, gate_net_id);
- enum tk_offsets tk_offset = TK_OFFS_TAI;
+ u64 cycletime = 0, basetime = 0, cycletime_ext = 0;
+ struct tcf_gate_params *p = NULL, *old_p = NULL;
+ enum tk_offsets old_tk_offset = TK_OFFS_TAI;
+ const struct tcf_gate_params *cur_p = NULL;
struct nlattr *tb[TCA_GATE_MAX + 1];
+ enum tk_offsets tko = TK_OFFS_TAI;
struct tcf_chain *goto_ch = NULL;
- u64 cycletime = 0, basetime = 0;
- struct tcf_gate_params *p;
+ s32 timer_clockid = CLOCK_TAI;
+ bool use_old_entries = false;
+ s32 old_clockid = CLOCK_TAI;
+ bool need_cancel = false;
s32 clockid = CLOCK_TAI;
struct tcf_gate *gact;
struct tc_gate *parm;
+ u64 old_basetime = 0;
int ret = 0, err;
u32 gflags = 0;
s32 prio = -1;
@@ -324,26 +384,8 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
if (!tb[TCA_GATE_PARMS])
return -EINVAL;
- if (tb[TCA_GATE_CLOCKID]) {
+ if (tb[TCA_GATE_CLOCKID])
clockid = nla_get_s32(tb[TCA_GATE_CLOCKID]);
- switch (clockid) {
- case CLOCK_REALTIME:
- tk_offset = TK_OFFS_REAL;
- break;
- case CLOCK_MONOTONIC:
- tk_offset = TK_OFFS_MAX;
- break;
- case CLOCK_BOOTTIME:
- tk_offset = TK_OFFS_BOOT;
- break;
- case CLOCK_TAI:
- tk_offset = TK_OFFS_TAI;
- break;
- default:
- NL_SET_ERR_MSG(extack, "Invalid 'clockid'");
- return -EINVAL;
- }
- }
parm = nla_data(tb[TCA_GATE_PARMS]);
index = parm->index;
@@ -369,6 +411,60 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
return -EEXIST;
}
+ gact = to_gate(*a);
+
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
+ if (err < 0)
+ goto release_idr;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ err = -ENOMEM;
+ goto chain_put;
+ }
+ INIT_LIST_HEAD(&p->entries);
+
+ use_old_entries = !tb[TCA_GATE_ENTRY_LIST];
+ if (!use_old_entries) {
+ err = parse_gate_list(tb[TCA_GATE_ENTRY_LIST], p, extack);
+ if (err < 0)
+ goto err_free;
+ use_old_entries = !err;
+ }
+
+ if (ret == ACT_P_CREATED && use_old_entries) {
+ NL_SET_ERR_MSG(extack, "The entry list is empty");
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ if (ret != ACT_P_CREATED) {
+ rcu_read_lock();
+ cur_p = rcu_dereference(gact->param);
+
+ old_basetime = cur_p->tcfg_basetime;
+ old_clockid = cur_p->tcfg_clockid;
+ old_tk_offset = READ_ONCE(gact->tk_offset);
+
+ basetime = old_basetime;
+ cycletime_ext = cur_p->tcfg_cycletime_ext;
+ prio = cur_p->tcfg_priority;
+ gflags = cur_p->tcfg_flags;
+
+ if (!tb[TCA_GATE_CLOCKID])
+ clockid = old_clockid;
+
+ err = 0;
+ if (use_old_entries) {
+ err = tcf_gate_copy_entries(p, cur_p, extack);
+ if (!err && !tb[TCA_GATE_CYCLE_TIME])
+ cycletime = cur_p->tcfg_cycletime;
+ }
+ rcu_read_unlock();
+ if (err)
+ goto err_free;
+ }
+
if (tb[TCA_GATE_PRIORITY])
prio = nla_get_s32(tb[TCA_GATE_PRIORITY]);
@@ -378,25 +474,26 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
if (tb[TCA_GATE_FLAGS])
gflags = nla_get_u32(tb[TCA_GATE_FLAGS]);
- gact = to_gate(*a);
- if (ret == ACT_P_CREATED)
- INIT_LIST_HEAD(&gact->param.entries);
+ if (tb[TCA_GATE_CYCLE_TIME])
+ cycletime = nla_get_u64(tb[TCA_GATE_CYCLE_TIME]);
- err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
- if (err < 0)
- goto release_idr;
+ if (tb[TCA_GATE_CYCLE_TIME_EXT])
+ cycletime_ext = nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]);
- spin_lock_bh(&gact->tcf_lock);
- p = &gact->param;
+ err = gate_clock_resolve(clockid, &tko, extack);
+ if (err)
+ goto err_free;
+ timer_clockid = clockid;
- if (tb[TCA_GATE_CYCLE_TIME])
- cycletime = nla_get_u64(tb[TCA_GATE_CYCLE_TIME]);
+ need_cancel = ret != ACT_P_CREATED &&
+ gate_timer_needs_cancel(basetime, old_basetime,
+ tko, old_tk_offset,
+ timer_clockid, old_clockid);
- if (tb[TCA_GATE_ENTRY_LIST]) {
- err = parse_gate_list(tb[TCA_GATE_ENTRY_LIST], p, extack);
- if (err < 0)
- goto chain_put;
- }
+ if (need_cancel)
+ hrtimer_cancel(&gact->hitimer);
+
+ spin_lock_bh(&gact->tcf_lock);
if (!cycletime) {
struct tcfg_gate_entry *entry;
@@ -405,22 +502,20 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
list_for_each_entry(entry, &p->entries, list)
cycle = ktime_add_ns(cycle, entry->interval);
cycletime = cycle;
- if (!cycletime) {
- err = -EINVAL;
- goto chain_put;
- }
}
p->tcfg_cycletime = cycletime;
+ p->tcfg_cycletime_ext = cycletime_ext;
- if (tb[TCA_GATE_CYCLE_TIME_EXT])
- p->tcfg_cycletime_ext =
- nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]);
-
- gate_setup_timer(gact, basetime, tk_offset, clockid,
- ret == ACT_P_CREATED);
+ if (need_cancel || ret == ACT_P_CREATED)
+ gate_setup_timer(gact, timer_clockid, tko);
p->tcfg_priority = prio;
p->tcfg_flags = gflags;
- gate_get_start_time(gact, &start);
+ p->tcfg_basetime = basetime;
+ p->tcfg_clockid = timer_clockid;
+ gate_get_start_time(gact, p, &start);
+
+ old_p = rcu_replace_pointer(gact->param, p,
+ lockdep_is_held(&gact->tcf_lock));
gact->current_close_time = start;
gact->current_gate_status = GATE_ACT_GATE_OPEN | GATE_ACT_PENDING;
@@ -437,11 +532,15 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
if (goto_ch)
tcf_chain_put_by_act(goto_ch);
+ if (old_p)
+ call_rcu(&old_p->rcu, tcf_gate_params_free_rcu);
+
return ret;
+err_free:
+ release_entry_list(&p->entries);
+ kfree(p);
chain_put:
- spin_unlock_bh(&gact->tcf_lock);
-
if (goto_ch)
tcf_chain_put_by_act(goto_ch);
release_idr:
@@ -449,21 +548,29 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
* without taking tcf_lock.
*/
if (ret == ACT_P_CREATED)
- gate_setup_timer(gact, gact->param.tcfg_basetime,
- gact->tk_offset, gact->param.tcfg_clockid,
- true);
+ gate_setup_timer(gact, timer_clockid, tko);
+
tcf_idr_release(*a, bind);
return err;
}
+static void tcf_gate_params_free_rcu(struct rcu_head *head)
+{
+ struct tcf_gate_params *p = container_of(head, struct tcf_gate_params, rcu);
+
+ release_entry_list(&p->entries);
+ kfree(p);
+}
+
static void tcf_gate_cleanup(struct tc_action *a)
{
struct tcf_gate *gact = to_gate(a);
struct tcf_gate_params *p;
- p = &gact->param;
hrtimer_cancel(&gact->hitimer);
- release_entry_list(&p->entries);
+ p = rcu_dereference_protected(gact->param, 1);
+ if (p)
+ call_rcu(&p->rcu, tcf_gate_params_free_rcu);
}
static int dumping_entry(struct sk_buff *skb,
@@ -512,10 +619,9 @@ static int tcf_gate_dump(struct sk_buff *skb, struct tc_action *a,
struct nlattr *entry_list;
struct tcf_t t;
- spin_lock_bh(&gact->tcf_lock);
- opt.action = gact->tcf_action;
-
- p = &gact->param;
+ rcu_read_lock();
+ opt.action = READ_ONCE(gact->tcf_action);
+ p = rcu_dereference(gact->param);
if (nla_put(skb, TCA_GATE_PARMS, sizeof(opt), &opt))
goto nla_put_failure;
@@ -555,12 +661,12 @@ static int tcf_gate_dump(struct sk_buff *skb, struct tc_action *a,
tcf_tm_dump(&t, &gact->tcf_tm);
if (nla_put_64bit(skb, TCA_GATE_TM, sizeof(t), &t, TCA_GATE_PAD))
goto nla_put_failure;
- spin_unlock_bh(&gact->tcf_lock);
+ rcu_read_unlock();
return skb->len;
nla_put_failure:
- spin_unlock_bh(&gact->tcf_lock);
+ rcu_read_unlock();
nlmsg_trim(skb, b);
return -1;
}
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index beedd0d2b509..27847fae053d 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -2669,6 +2669,7 @@ static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
tcm->tcm__pad1 = 0;
tcm->tcm__pad2 = 0;
tcm->tcm_handle = 0;
+ tcm->tcm_info = 0;
if (block->q) {
tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
tcm->tcm_parent = block->q->handle;
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 117c7b038591..7918ecdcfe69 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -501,8 +501,16 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
}
if (TC_H_MAJ(baseclass) == 0) {
- struct Qdisc *q = tcf_block_q(tp->chain->block);
+ struct tcf_block *block = tp->chain->block;
+ struct Qdisc *q;
+ if (tcf_block_shared(block)) {
+ NL_SET_ERR_MSG(extack,
+ "Must specify baseclass when attaching flow filter to block");
+ goto err2;
+ }
+
+ q = tcf_block_q(block);
baseclass = TC_H_MAKE(q->handle, baseclass);
}
if (TC_H_MIN(baseclass) == 0)
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 08c41f1976c4..23cf4f711117 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -246,8 +246,18 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
struct nlattr *tb[TCA_FW_MAX + 1];
int err;
- if (!opt)
- return handle ? -EINVAL : 0; /* Succeed if it is old method. */
+ if (!opt) {
+ if (handle)
+ return -EINVAL;
+
+ if (tcf_block_shared(tp->chain->block)) {
+ NL_SET_ERR_MSG(extack,
+ "Must specify mark when attaching fw filter to block");
+ return -EINVAL;
+ }
+
+ return 0; /* Succeed if it is old method. */
+ }
err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
NULL);
diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
index c939937b2b81..cecd7209a86c 100644
--- a/net/sched/sch_ets.c
+++ b/net/sched/sch_ets.c
@@ -115,12 +115,12 @@ static void ets_offload_change(struct Qdisc *sch)
struct ets_sched *q = qdisc_priv(sch);
struct tc_ets_qopt_offload qopt;
unsigned int w_psum_prev = 0;
- unsigned int q_psum = 0;
- unsigned int q_sum = 0;
unsigned int quantum;
unsigned int w_psum;
unsigned int weight;
unsigned int i;
+ u64 q_psum = 0;
+ u64 q_sum = 0;
if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
return;
@@ -138,8 +138,12 @@ static void ets_offload_change(struct Qdisc *sch)
for (i = 0; i < q->nbands; i++) {
quantum = q->classes[i].quantum;
- q_psum += quantum;
- w_psum = quantum ? q_psum * 100 / q_sum : 0;
+ if (quantum) {
+ q_psum += quantum;
+ w_psum = div64_u64(q_psum * 100, q_sum);
+ } else {
+ w_psum = 0;
+ }
weight = w_psum - w_psum_prev;
w_psum_prev = w_psum;
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 25360061ad28..3a271ad16443 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -556,7 +556,7 @@ static void
rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
{
u64 y1, y2, dx, dy;
- u32 dsm;
+ u64 dsm;
if (isc->sm1 <= isc->sm2) {
/* service curve is convex */
@@ -599,7 +599,7 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
*/
dx = (y1 - y) << SM_SHIFT;
dsm = isc->sm1 - isc->sm2;
- do_div(dx, dsm);
+ dx = div64_u64(dx, dsm);
/*
* check if (x, y1) belongs to the 1st segment of rtsc.
* if so, add the offset.
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index e9dfa140799c..4c65b4ed5ccd 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -315,6 +315,7 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
if (__netif_tx_trylock(slave_txq)) {
unsigned int length = qdisc_pkt_len(skb);
+ skb->dev = slave;
if (!netif_xmit_frozen_or_stopped(slave_txq) &&
netdev_start_xmit(skb, slave, slave_txq, false) ==
NETDEV_TX_OK) {
diff --git a/net/smc/smc_rx.c b/net/smc/smc_rx.c
index 5f20538cbf99..0845905520f8 100644
--- a/net/smc/smc_rx.c
+++ b/net/smc/smc_rx.c
@@ -129,9 +129,16 @@ static void smc_rx_pipe_buf_release(struct pipe_inode_info *pipe,
sock_put(sk);
}
+static bool smc_rx_pipe_buf_get(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+{
+ /* smc_spd_priv in buf->private is not shareable; disallow cloning. */
+ return false;
+}
+
static const struct pipe_buf_operations smc_pipe_ops = {
.release = smc_rx_pipe_buf_release,
- .get = generic_pipe_buf_get
+ .get = smc_rx_pipe_buf_get,
};
static void smc_rx_spd_release(struct splice_pipe_desc *spd,
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 81a780c1226c..03583ab411bb 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -1056,14 +1056,25 @@ static int cache_release(struct inode *inode, struct file *filp,
struct cache_reader *rp = filp->private_data;
if (rp) {
+ struct cache_request *rq = NULL;
+
spin_lock(&queue_lock);
if (rp->offset) {
struct cache_queue *cq;
- for (cq= &rp->q; &cq->list != &cd->queue;
- cq = list_entry(cq->list.next, struct cache_queue, list))
+ for (cq = &rp->q; &cq->list != &cd->queue;
+ cq = list_entry(cq->list.next,
+ struct cache_queue, list))
if (!cq->reader) {
- container_of(cq, struct cache_request, q)
- ->readers--;
+ struct cache_request *cr =
+ container_of(cq,
+ struct cache_request, q);
+ cr->readers--;
+ if (cr->readers == 0 &&
+ !test_bit(CACHE_PENDING,
+ &cr->item->flags)) {
+ list_del(&cr->q.list);
+ rq = cr;
+ }
break;
}
rp->offset = 0;
@@ -1071,9 +1082,14 @@ static int cache_release(struct inode *inode, struct file *filp,
list_del(&rp->q.list);
spin_unlock(&queue_lock);
+ if (rq) {
+ cache_put(rq->item, cd);
+ kfree(rq->buf);
+ kfree(rq);
+ }
+
filp->private_data = NULL;
kfree(rp);
-
}
if (filp->f_mode & FMODE_WRITE) {
atomic_dec(&cd->writers);
diff --git a/net/tipc/group.c b/net/tipc/group.c
index b1fcd2ad5ecf..cae497418dc9 100644
--- a/net/tipc/group.c
+++ b/net/tipc/group.c
@@ -745,6 +745,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;
@@ -797,7 +798,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/tipc/socket.c b/net/tipc/socket.c
index 7cf9b40b5c73..5adfd0d854a2 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2233,6 +2233,8 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb,
if (skb_queue_empty(&sk->sk_write_queue))
break;
get_random_bytes(&delay, 2);
+ if (tsk->conn_timeout < 4)
+ tsk->conn_timeout = 4;
delay %= (tsk->conn_timeout / 4);
delay = msecs_to_jiffies(delay + 100);
sk_reset_timer(sk, &sk->sk_timer, jiffies + delay);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index cc2093f75468..019f9767eda5 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1046,6 +1046,7 @@ void wiphy_unregister(struct wiphy *wiphy)
rtnl_unlock();
flush_work(&rdev->scan_done_wk);
+ cancel_work_sync(&rdev->rfkill_block);
cancel_work_sync(&rdev->conn_work);
flush_work(&rdev->event_work);
cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
index 36f1b59a78bf..bd3cae412e52 100644
--- a/net/wireless/radiotap.c
+++ b/net/wireless/radiotap.c
@@ -240,14 +240,14 @@ int ieee80211_radiotap_iterator_next(
default:
if (!iterator->current_namespace ||
iterator->_arg_index >= iterator->current_namespace->n_bits) {
- if (iterator->current_namespace == &radiotap_ns)
- return -ENOENT;
align = 0;
} else {
align = iterator->current_namespace->align_size[iterator->_arg_index].align;
size = iterator->current_namespace->align_size[iterator->_arg_index].size;
}
if (!align) {
+ if (iterator->current_namespace == &radiotap_ns)
+ return -ENOENT;
/* skip all subsequent data */
iterator->_arg = iterator->_next_ns_data;
/* give up on this namespace */
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index e1c4197af468..956e05680307 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -34,6 +34,10 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
struct sk_buff *skbo, *skbn = skb;
struct x25_sock *x25 = x25_sk(sk);
+ /* make sure we don't overflow */
+ if (x25->fraglen + skb->len > USHRT_MAX)
+ return 1;
+
if (more) {
x25->fraglen += skb->len;
skb_queue_tail(&x25->fragment_queue, skb);
@@ -44,10 +48,9 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
if (!more && x25->fraglen > 0) { /* End of fragment */
int len = x25->fraglen + skb->len;
- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
- kfree_skb(skb);
+ skbn = alloc_skb(len, GFP_ATOMIC);
+ if (!skbn)
return 1;
- }
skb_queue_tail(&x25->fragment_queue, skb);
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index 0285aaa1e93c..159708d9ad20 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -40,6 +40,7 @@ void x25_clear_queues(struct sock *sk)
skb_queue_purge(&x25->interrupt_in_queue);
skb_queue_purge(&x25->interrupt_out_queue);
skb_queue_purge(&x25->fragment_queue);
+ x25->fraglen = 0;
}
diff --git a/net/xfrm/xfrm_interface_core.c b/net/xfrm/xfrm_interface_core.c
index 9eaf0174d998..fc5967ccaddc 100644
--- a/net/xfrm/xfrm_interface_core.c
+++ b/net/xfrm/xfrm_interface_core.c
@@ -368,7 +368,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
skb_dst_set(skb, dst);
skb->dev = tdev;
- err = dst_output(xi->net, skb->sk, skb);
+ err = dst_output(xi->net, skb_to_full_sk(skb), skb);
if (net_xmit_eval(err) == 0) {
struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 40f7a98abdd1..7c588973cfa1 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -645,7 +645,7 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
!skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) {
skb->protocol = htons(ETH_P_IP);
- if (skb->sk)
+ if (skb->sk && sk_fullsock(skb->sk))
xfrm_local_error(skb, mtu);
else
icmp_send(skb, ICMP_DEST_UNREACH,
@@ -681,6 +681,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
struct dst_entry *dst = skb_dst(skb);
+ struct sock *sk = skb_to_full_sk(skb);
if (skb->ignore_df)
goto out;
@@ -695,9 +696,9 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
skb->dev = dst->dev;
skb->protocol = htons(ETH_P_IPV6);
- if (xfrm6_local_dontfrag(skb->sk))
+ if (xfrm6_local_dontfrag(sk))
ipv6_stub->xfrm6_local_rxpmtu(skb, mtu);
- else if (skb->sk)
+ else if (sk)
xfrm_local_error(skb, mtu);
else
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 64b971bb1d36..c4ebfaa0b2ed 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2858,7 +2858,7 @@ static void xfrm_policy_queue_process(struct timer_list *t)
skb_dst_drop(skb);
skb_dst_set(skb, dst);
- dst_output(net, skb->sk, skb);
+ dst_output(net, skb_to_full_sk(skb), skb);
}
out:
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index b1243edf7f3a..02d1d8d1fdea 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1736,6 +1736,7 @@ int xfrm_state_update(struct xfrm_state *x)
err = 0;
x->km.state = XFRM_STATE_DEAD;
+ xfrm_dev_state_delete(x);
__xfrm_state_put(x);
}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 480da22b7ef8..a55f8fe3e052 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -3445,6 +3445,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/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index e736936f4f0b..c957cd618808 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -32,6 +32,7 @@
#include "include/crypto.h"
#include "include/ipc.h"
#include "include/label.h"
+#include "include/lib.h"
#include "include/policy.h"
#include "include/policy_ns.h"
#include "include/resource.h"
@@ -61,6 +62,7 @@
* securityfs and apparmorfs filesystems.
*/
+#define IREF_POISON 101
/*
* support fns
@@ -77,7 +79,7 @@ static void rawdata_f_data_free(struct rawdata_f_data *private)
if (!private)
return;
- aa_put_loaddata(private->loaddata);
+ aa_put_i_loaddata(private->loaddata);
kvfree(private);
}
@@ -150,6 +152,71 @@ static int aafs_show_path(struct seq_file *seq, struct dentry *dentry)
return 0;
}
+static struct aa_ns *get_ns_common_ref(struct aa_common_ref *ref)
+{
+ if (ref) {
+ struct aa_label *reflabel = container_of(ref, struct aa_label,
+ count);
+ return aa_get_ns(labels_ns(reflabel));
+ }
+
+ return NULL;
+}
+
+static struct aa_proxy *get_proxy_common_ref(struct aa_common_ref *ref)
+{
+ if (ref)
+ return aa_get_proxy(container_of(ref, struct aa_proxy, count));
+
+ return NULL;
+}
+
+static struct aa_loaddata *get_loaddata_common_ref(struct aa_common_ref *ref)
+{
+ if (ref)
+ return aa_get_i_loaddata(container_of(ref, struct aa_loaddata,
+ count));
+ return NULL;
+}
+
+static void aa_put_common_ref(struct aa_common_ref *ref)
+{
+ if (!ref)
+ return;
+
+ switch (ref->reftype) {
+ case REF_RAWDATA:
+ aa_put_i_loaddata(container_of(ref, struct aa_loaddata,
+ count));
+ break;
+ case REF_PROXY:
+ aa_put_proxy(container_of(ref, struct aa_proxy,
+ count));
+ break;
+ case REF_NS:
+ /* ns count is held on its unconfined label */
+ aa_put_ns(labels_ns(container_of(ref, struct aa_label, count)));
+ break;
+ default:
+ AA_BUG(true, "unknown refcount type");
+ break;
+ }
+}
+
+static void aa_get_common_ref(struct aa_common_ref *ref)
+{
+ kref_get(&ref->count);
+}
+
+static void aafs_evict(struct inode *inode)
+{
+ struct aa_common_ref *ref = inode->i_private;
+
+ clear_inode(inode);
+ aa_put_common_ref(ref);
+ inode->i_private = (void *) IREF_POISON;
+}
+
static void aafs_free_inode(struct inode *inode)
{
if (S_ISLNK(inode->i_mode))
@@ -159,6 +226,7 @@ static void aafs_free_inode(struct inode *inode)
static const struct super_operations aafs_super_ops = {
.statfs = simple_statfs,
+ .evict_inode = aafs_evict,
.free_inode = aafs_free_inode,
.show_path = aafs_show_path,
};
@@ -259,7 +327,8 @@ static int __aafs_setup_d_inode(struct inode *dir, struct dentry *dentry,
* aafs_remove(). Will return ERR_PTR on failure.
*/
static struct dentry *aafs_create(const char *name, umode_t mode,
- struct dentry *parent, void *data, void *link,
+ struct dentry *parent,
+ struct aa_common_ref *data, void *link,
const struct file_operations *fops,
const struct inode_operations *iops)
{
@@ -296,6 +365,9 @@ static struct dentry *aafs_create(const char *name, umode_t mode,
goto fail_dentry;
inode_unlock(dir);
+ if (data)
+ aa_get_common_ref(data);
+
return dentry;
fail_dentry:
@@ -320,7 +392,8 @@ static struct dentry *aafs_create(const char *name, umode_t mode,
* see aafs_create
*/
static struct dentry *aafs_create_file(const char *name, umode_t mode,
- struct dentry *parent, void *data,
+ struct dentry *parent,
+ struct aa_common_ref *data,
const struct file_operations *fops)
{
return aafs_create(name, mode, parent, data, NULL, fops, NULL);
@@ -401,7 +474,9 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
data->size = copy_size;
if (copy_from_user(data->data, userbuf, copy_size)) {
- aa_put_loaddata(data);
+ /* trigger free - don't need to put pcount */
+ aa_put_i_loaddata(data);
+
return ERR_PTR(-EFAULT);
}
@@ -409,7 +484,8 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
}
static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
- loff_t *pos, struct aa_ns *ns)
+ loff_t *pos, struct aa_ns *ns,
+ const struct cred *ocred)
{
struct aa_loaddata *data;
struct aa_label *label;
@@ -420,7 +496,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
/* high level check about policy management - fine grained in
* below after unpack
*/
- error = aa_may_manage_policy(label, ns, mask);
+ error = aa_may_manage_policy(current_cred(), label, ns, ocred, mask);
if (error)
goto end_section;
@@ -428,7 +504,10 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
error = PTR_ERR(data);
if (!IS_ERR(data)) {
error = aa_replace_profiles(ns, label, mask, data);
- aa_put_loaddata(data);
+ /* put pcount, which will put count and free if no
+ * profiles referencing it.
+ */
+ aa_put_profile_loaddata(data);
}
end_section:
end_current_label_crit_section(label);
@@ -440,8 +519,9 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
loff_t *pos)
{
- struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
- int error = policy_update(AA_MAY_LOAD_POLICY, buf, size, pos, ns);
+ struct aa_ns *ns = get_ns_common_ref(f->f_inode->i_private);
+ int error = policy_update(AA_MAY_LOAD_POLICY, buf, size, pos, ns,
+ f->f_cred);
aa_put_ns(ns);
@@ -457,9 +537,9 @@ static const struct file_operations aa_fs_profile_load = {
static ssize_t profile_replace(struct file *f, const char __user *buf,
size_t size, loff_t *pos)
{
- struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
+ struct aa_ns *ns = get_ns_common_ref(f->f_inode->i_private);
int error = policy_update(AA_MAY_LOAD_POLICY | AA_MAY_REPLACE_POLICY,
- buf, size, pos, ns);
+ buf, size, pos, ns, f->f_cred);
aa_put_ns(ns);
return error;
@@ -477,13 +557,14 @@ static ssize_t profile_remove(struct file *f, const char __user *buf,
struct aa_loaddata *data;
struct aa_label *label;
ssize_t error;
- struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
+ struct aa_ns *ns = get_ns_common_ref(f->f_inode->i_private);
label = begin_current_label_crit_section();
/* high level check about policy management - fine grained in
* below after unpack
*/
- error = aa_may_manage_policy(label, ns, AA_MAY_REMOVE_POLICY);
+ error = aa_may_manage_policy(current_cred(), label, ns,
+ f->f_cred, AA_MAY_REMOVE_POLICY);
if (error)
goto out;
@@ -497,7 +578,7 @@ static ssize_t profile_remove(struct file *f, const char __user *buf,
if (!IS_ERR(data)) {
data->data[size] = 0;
error = aa_remove_profiles(ns, label, data->data, size);
- aa_put_loaddata(data);
+ aa_put_profile_loaddata(data);
}
out:
end_current_label_crit_section(label);
@@ -566,7 +647,7 @@ static int ns_revision_open(struct inode *inode, struct file *file)
if (!rev)
return -ENOMEM;
- rev->ns = aa_get_ns(inode->i_private);
+ rev->ns = get_ns_common_ref(inode->i_private);
if (!rev->ns)
rev->ns = aa_get_current_ns();
file->private_data = rev;
@@ -1044,7 +1125,7 @@ static const struct file_operations seq_profile_ ##NAME ##_fops = { \
static int seq_profile_open(struct inode *inode, struct file *file,
int (*show)(struct seq_file *, void *))
{
- struct aa_proxy *proxy = aa_get_proxy(inode->i_private);
+ struct aa_proxy *proxy = get_proxy_common_ref(inode->i_private);
int error = single_open(file, show, proxy);
if (error) {
@@ -1222,18 +1303,17 @@ static const struct file_operations seq_rawdata_ ##NAME ##_fops = { \
static int seq_rawdata_open(struct inode *inode, struct file *file,
int (*show)(struct seq_file *, void *))
{
- struct aa_loaddata *data = __aa_get_loaddata(inode->i_private);
+ struct aa_loaddata *data = get_loaddata_common_ref(inode->i_private);
int error;
if (!data)
- /* lost race this ent is being reaped */
return -ENOENT;
error = single_open(file, show, data);
if (error) {
AA_BUG(file->private_data &&
((struct seq_file *)file->private_data)->private);
- aa_put_loaddata(data);
+ aa_put_i_loaddata(data);
}
return error;
@@ -1244,7 +1324,7 @@ static int seq_rawdata_release(struct inode *inode, struct file *file)
struct seq_file *seq = (struct seq_file *) file->private_data;
if (seq)
- aa_put_loaddata(seq->private);
+ aa_put_i_loaddata(seq->private);
return single_release(inode, file);
}
@@ -1363,9 +1443,8 @@ static int rawdata_open(struct inode *inode, struct file *file)
if (!policy_view_capable(NULL))
return -EACCES;
- loaddata = __aa_get_loaddata(inode->i_private);
+ loaddata = get_loaddata_common_ref(inode->i_private);
if (!loaddata)
- /* lost race: this entry is being reaped */
return -ENOENT;
private = rawdata_f_data_alloc(loaddata->size);
@@ -1390,7 +1469,7 @@ static int rawdata_open(struct inode *inode, struct file *file)
return error;
fail_private_alloc:
- aa_put_loaddata(loaddata);
+ aa_put_i_loaddata(loaddata);
return error;
}
@@ -1407,7 +1486,6 @@ static void remove_rawdata_dents(struct aa_loaddata *rawdata)
for (i = 0; i < AAFS_LOADDATA_NDENTS; i++) {
if (!IS_ERR_OR_NULL(rawdata->dents[i])) {
- /* no refcounts on i_private */
aafs_remove(rawdata->dents[i]);
rawdata->dents[i] = NULL;
}
@@ -1450,35 +1528,37 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata)
return PTR_ERR(dir);
rawdata->dents[AAFS_LOADDATA_DIR] = dir;
- dent = aafs_create_file("abi", S_IFREG | 0444, dir, rawdata,
+ dent = aafs_create_file("abi", S_IFREG | 0444, dir, &rawdata->count,
&seq_rawdata_abi_fops);
if (IS_ERR(dent))
goto fail;
rawdata->dents[AAFS_LOADDATA_ABI] = dent;
- dent = aafs_create_file("revision", S_IFREG | 0444, dir, rawdata,
- &seq_rawdata_revision_fops);
+ dent = aafs_create_file("revision", S_IFREG | 0444, dir,
+ &rawdata->count,
+ &seq_rawdata_revision_fops);
if (IS_ERR(dent))
goto fail;
rawdata->dents[AAFS_LOADDATA_REVISION] = dent;
if (aa_g_hash_policy) {
dent = aafs_create_file("sha1", S_IFREG | 0444, dir,
- rawdata, &seq_rawdata_hash_fops);
+ &rawdata->count,
+ &seq_rawdata_hash_fops);
if (IS_ERR(dent))
goto fail;
rawdata->dents[AAFS_LOADDATA_HASH] = dent;
}
dent = aafs_create_file("compressed_size", S_IFREG | 0444, dir,
- rawdata,
+ &rawdata->count,
&seq_rawdata_compressed_size_fops);
if (IS_ERR(dent))
goto fail;
rawdata->dents[AAFS_LOADDATA_COMPRESSED_SIZE] = dent;
- dent = aafs_create_file("raw_data", S_IFREG | 0444,
- dir, rawdata, &rawdata_fops);
+ dent = aafs_create_file("raw_data", S_IFREG | 0444, dir,
+ &rawdata->count, &rawdata_fops);
if (IS_ERR(dent))
goto fail;
rawdata->dents[AAFS_LOADDATA_DATA] = dent;
@@ -1486,13 +1566,11 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata)
rawdata->ns = aa_get_ns(ns);
list_add(&rawdata->list, &ns->rawdata_list);
- /* no refcount on inode rawdata */
return 0;
fail:
remove_rawdata_dents(rawdata);
-
return PTR_ERR(dent);
}
@@ -1514,13 +1592,10 @@ void __aafs_profile_rmdir(struct aa_profile *profile)
__aafs_profile_rmdir(child);
for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
- struct aa_proxy *proxy;
if (!profile->dents[i])
continue;
- proxy = d_inode(profile->dents[i])->i_private;
aafs_remove(profile->dents[i]);
- aa_put_proxy(proxy);
profile->dents[i] = NULL;
}
}
@@ -1550,14 +1625,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name,
struct aa_profile *profile,
const struct file_operations *fops)
{
- struct aa_proxy *proxy = aa_get_proxy(profile->label.proxy);
- struct dentry *dent;
-
- dent = aafs_create_file(name, S_IFREG | 0444, dir, proxy, fops);
- if (IS_ERR(dent))
- aa_put_proxy(proxy);
-
- return dent;
+ return aafs_create_file(name, S_IFREG | 0444, dir, &profile->label.proxy->count, fops);
}
static int profile_depth(struct aa_profile *profile)
@@ -1607,7 +1675,8 @@ static const char *rawdata_get_link_base(struct dentry *dentry,
struct delayed_call *done,
const char *name)
{
- struct aa_proxy *proxy = inode->i_private;
+ struct aa_common_ref *ref = inode->i_private;
+ struct aa_proxy *proxy = container_of(ref, struct aa_proxy, count);
struct aa_label *label;
struct aa_profile *profile;
char *target;
@@ -1747,27 +1816,23 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
if (profile->rawdata) {
dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir,
- profile->label.proxy, NULL, NULL,
+ &profile->label.proxy->count, NULL, NULL,
&rawdata_link_sha1_iops);
if (IS_ERR(dent))
goto fail;
- aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_HASH] = dent;
-
dent = aafs_create("raw_abi", S_IFLNK | 0444, dir,
- profile->label.proxy, NULL, NULL,
+ &profile->label.proxy->count, NULL, NULL,
&rawdata_link_abi_iops);
if (IS_ERR(dent))
goto fail;
- aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_ABI] = dent;
dent = aafs_create("raw_data", S_IFLNK | 0444, dir,
- profile->label.proxy, NULL, NULL,
+ &profile->label.proxy->count, NULL, NULL,
&rawdata_link_data_iops);
if (IS_ERR(dent))
goto fail;
- aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_DATA] = dent;
}
@@ -1796,12 +1861,13 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode)
int error;
label = begin_current_label_crit_section();
- error = aa_may_manage_policy(label, NULL, AA_MAY_LOAD_POLICY);
+ error = aa_may_manage_policy(current_cred(), label, NULL, NULL,
+ AA_MAY_LOAD_POLICY);
end_current_label_crit_section(label);
if (error)
return error;
- parent = aa_get_ns(dir->i_private);
+ parent = get_ns_common_ref(dir->i_private);
AA_BUG(d_inode(ns_subns_dir(parent)) != dir);
/* we have to unlock and then relock to get locking order right
@@ -1845,12 +1911,13 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry)
int error;
label = begin_current_label_crit_section();
- error = aa_may_manage_policy(label, NULL, AA_MAY_LOAD_POLICY);
+ error = aa_may_manage_policy(current_cred(), label, NULL, NULL,
+ AA_MAY_LOAD_POLICY);
end_current_label_crit_section(label);
if (error)
return error;
- parent = aa_get_ns(dir->i_private);
+ parent = get_ns_common_ref(dir->i_private);
/* rmdir calls the generic securityfs functions to remove files
* from the apparmor dir. It is up to the apparmor ns locking
* to avoid races.
@@ -1920,27 +1987,6 @@ void __aafs_ns_rmdir(struct aa_ns *ns)
__aa_fs_list_remove_rawdata(ns);
- if (ns_subns_dir(ns)) {
- sub = d_inode(ns_subns_dir(ns))->i_private;
- aa_put_ns(sub);
- }
- if (ns_subload(ns)) {
- sub = d_inode(ns_subload(ns))->i_private;
- aa_put_ns(sub);
- }
- if (ns_subreplace(ns)) {
- sub = d_inode(ns_subreplace(ns))->i_private;
- aa_put_ns(sub);
- }
- if (ns_subremove(ns)) {
- sub = d_inode(ns_subremove(ns))->i_private;
- aa_put_ns(sub);
- }
- if (ns_subrevision(ns)) {
- sub = d_inode(ns_subrevision(ns))->i_private;
- aa_put_ns(sub);
- }
-
for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
aafs_remove(ns->dents[i]);
ns->dents[i] = NULL;
@@ -1965,40 +2011,40 @@ static int __aafs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir)
return PTR_ERR(dent);
ns_subdata_dir(ns) = dent;
- dent = aafs_create_file("revision", 0444, dir, ns,
+ dent = aafs_create_file("revision", 0444, dir,
+ &ns->unconfined->label.count,
&aa_fs_ns_revision_fops);
if (IS_ERR(dent))
return PTR_ERR(dent);
- aa_get_ns(ns);
ns_subrevision(ns) = dent;
- dent = aafs_create_file(".load", 0640, dir, ns,
- &aa_fs_profile_load);
+ dent = aafs_create_file(".load", 0640, dir,
+ &ns->unconfined->label.count,
+ &aa_fs_profile_load);
if (IS_ERR(dent))
return PTR_ERR(dent);
- aa_get_ns(ns);
ns_subload(ns) = dent;
- dent = aafs_create_file(".replace", 0640, dir, ns,
- &aa_fs_profile_replace);
+ dent = aafs_create_file(".replace", 0640, dir,
+ &ns->unconfined->label.count,
+ &aa_fs_profile_replace);
if (IS_ERR(dent))
return PTR_ERR(dent);
- aa_get_ns(ns);
ns_subreplace(ns) = dent;
- dent = aafs_create_file(".remove", 0640, dir, ns,
- &aa_fs_profile_remove);
+ dent = aafs_create_file(".remove", 0640, dir,
+ &ns->unconfined->label.count,
+ &aa_fs_profile_remove);
if (IS_ERR(dent))
return PTR_ERR(dent);
- aa_get_ns(ns);
ns_subremove(ns) = dent;
/* use create_dentry so we can supply private data */
- dent = aafs_create("namespaces", S_IFDIR | 0755, dir, ns, NULL, NULL,
- &ns_dir_inode_operations);
+ dent = aafs_create("namespaces", S_IFDIR | 0755, dir,
+ &ns->unconfined->label.count,
+ NULL, NULL, &ns_dir_inode_operations);
if (IS_ERR(dent))
return PTR_ERR(dent);
- aa_get_ns(ns);
ns_subns_dir(ns) = dent;
return 0;
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
index 1e90384b1523..55986388dfae 100644
--- a/security/apparmor/include/label.h
+++ b/security/apparmor/include/label.h
@@ -103,7 +103,7 @@ enum label_flags {
struct aa_label;
struct aa_proxy {
- struct kref count;
+ struct aa_common_ref count;
struct aa_label __rcu *label;
};
@@ -123,7 +123,7 @@ struct label_it {
* @ent: set of profiles for label, actual size determined by @size
*/
struct aa_label {
- struct kref count;
+ struct aa_common_ref count;
struct rb_node node;
struct rcu_head rcu;
struct aa_proxy *proxy;
@@ -373,7 +373,7 @@ int aa_label_match(struct aa_profile *profile, struct aa_label *label,
*/
static inline struct aa_label *__aa_get_label(struct aa_label *l)
{
- if (l && kref_get_unless_zero(&l->count))
+ if (l && kref_get_unless_zero(&l->count.count))
return l;
return NULL;
@@ -382,7 +382,7 @@ static inline struct aa_label *__aa_get_label(struct aa_label *l)
static inline struct aa_label *aa_get_label(struct aa_label *l)
{
if (l)
- kref_get(&(l->count));
+ kref_get(&(l->count.count));
return l;
}
@@ -402,7 +402,7 @@ static inline struct aa_label *aa_get_label_rcu(struct aa_label __rcu **l)
rcu_read_lock();
do {
c = rcu_dereference(*l);
- } while (c && !kref_get_unless_zero(&c->count));
+ } while (c && !kref_get_unless_zero(&c->count.count));
rcu_read_unlock();
return c;
@@ -442,7 +442,7 @@ static inline struct aa_label *aa_get_newest_label(struct aa_label *l)
static inline void aa_put_label(struct aa_label *l)
{
if (l)
- kref_put(&l->count, aa_label_kref);
+ kref_put(&l->count.count, aa_label_kref);
}
@@ -452,7 +452,7 @@ void aa_proxy_kref(struct kref *kref);
static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *proxy)
{
if (proxy)
- kref_get(&(proxy->count));
+ kref_get(&(proxy->count.count));
return proxy;
}
@@ -460,7 +460,7 @@ static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *proxy)
static inline void aa_put_proxy(struct aa_proxy *proxy)
{
if (proxy)
- kref_put(&proxy->count, aa_proxy_kref);
+ kref_put(&proxy->count.count, aa_proxy_kref);
}
void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new);
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index ac5054899f6f..624178827fd2 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -60,6 +60,18 @@ void aa_info_message(const char *str);
/* Security blob offsets */
extern struct lsm_blob_sizes apparmor_blob_sizes;
+enum reftype {
+ REF_NS,
+ REF_PROXY,
+ REF_RAWDATA,
+};
+
+/* common reference count used by data the shows up in aafs */
+struct aa_common_ref {
+ struct kref count;
+ enum reftype reftype;
+};
+
/**
* aa_strneq - compare null terminated @str to a non null terminated substring
* @str: a null terminated string
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
index 29306ec87fd1..611ae908469b 100644
--- a/security/apparmor/include/match.h
+++ b/security/apparmor/include/match.h
@@ -190,6 +190,7 @@ static inline void aa_put_dfa(struct aa_dfa *dfa)
#define MATCH_FLAG_DIFF_ENCODE 0x80000000
#define MARK_DIFF_ENCODE 0x40000000
#define MATCH_FLAG_OOB_TRANSITION 0x20000000
+#define MARK_DIFF_ENCODE_VERIFIED 0x10000000
#define MATCH_FLAGS_MASK 0xff000000
#define MATCH_FLAGS_VALID (MATCH_FLAG_DIFF_ENCODE | MATCH_FLAG_OOB_TRANSITION)
#define MATCH_FLAGS_INVALID (MATCH_FLAGS_MASK & ~MATCH_FLAGS_VALID)
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index b5aa4231af68..278c8ec2afd0 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -243,7 +243,7 @@ static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile,
static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
{
if (p)
- kref_get(&(p->label.count));
+ kref_get(&(p->label.count.count));
return p;
}
@@ -257,7 +257,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
*/
static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p)
{
- if (p && kref_get_unless_zero(&p->label.count))
+ if (p && kref_get_unless_zero(&p->label.count.count))
return p;
return NULL;
@@ -277,7 +277,7 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
rcu_read_lock();
do {
c = rcu_dereference(*p);
- } while (c && !kref_get_unless_zero(&c->label.count));
+ } while (c && !kref_get_unless_zero(&c->label.count.count));
rcu_read_unlock();
return c;
@@ -290,7 +290,7 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
static inline void aa_put_profile(struct aa_profile *p)
{
if (p)
- kref_put(&p->label.count, aa_label_kref);
+ kref_put(&p->label.count.count, aa_label_kref);
}
static inline int AUDIT_MODE(struct aa_profile *profile)
@@ -303,7 +303,8 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
bool policy_view_capable(struct aa_ns *ns);
bool policy_admin_capable(struct aa_ns *ns);
-int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns,
- u32 mask);
+int aa_may_manage_policy(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns,
+ const struct cred *ocred, u32 mask);
#endif /* __AA_POLICY_H */
diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h
index 3df6f804922d..e5704947e86e 100644
--- a/security/apparmor/include/policy_ns.h
+++ b/security/apparmor/include/policy_ns.h
@@ -18,6 +18,8 @@
#include "label.h"
#include "policy.h"
+/* Match max depth of user namespaces */
+#define MAX_NS_DEPTH 32
/* struct aa_ns_acct - accounting of profiles in namespace
* @max_size: maximum space allowed for all profiles in namespace
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
index e0e1ca7ebc38..61cc9b5b8a1f 100644
--- a/security/apparmor/include/policy_unpack.h
+++ b/security/apparmor/include/policy_unpack.h
@@ -46,17 +46,29 @@ enum {
AAFS_LOADDATA_NDENTS /* count of entries */
};
-/*
- * struct aa_loaddata - buffer of policy raw_data set
+/* struct aa_loaddata - buffer of policy raw_data set
+ * @count: inode/filesystem refcount - use aa_get_i_loaddata()
+ * @pcount: profile refcount - use aa_get_profile_loaddata()
+ * @list: list the loaddata is on
+ * @work: used to do a delayed cleanup
+ * @dents: refs to dents created in aafs
+ * @ns: the namespace this loaddata was loaded into
+ * @name:
+ * @size: the size of the data that was loaded
+ * @compressed_size: the size of the data when it is compressed
+ * @revision: unique revision count that this data was loaded as
+ * @abi: the abi number the loaddata uses
+ * @hash: a hash of the loaddata, used to help dedup data
*
- * there is no loaddata ref for being on ns list, nor a ref from
- * d_inode(@dentry) when grab a ref from these, @ns->lock must be held
- * && __aa_get_loaddata() needs to be used, and the return value
- * checked, if NULL the loaddata is already being reaped and should be
- * considered dead.
+ * There is no loaddata ref for being on ns->rawdata_list, so
+ * @ns->lock must be held when walking the list. Dentries and
+ * inode opens hold refs on @count; profiles hold refs on @pcount.
+ * When the last @pcount drops, do_ploaddata_rmfs() removes the
+ * fs entries and drops the associated @count ref.
*/
struct aa_loaddata {
- struct kref count;
+ struct aa_common_ref count;
+ struct kref pcount;
struct list_head list;
struct work_struct work;
struct dentry *dents[AAFS_LOADDATA_NDENTS];
@@ -78,50 +90,53 @@ struct aa_loaddata {
int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns);
/**
- * __aa_get_loaddata - get a reference count to uncounted data reference
+ * aa_get_loaddata - get a reference count from a counted data reference
* @data: reference to get a count on
*
- * Returns: pointer to reference OR NULL if race is lost and reference is
- * being repeated.
- * Requires: @data->ns->lock held, and the return code MUST be checked
- *
- * Use only from inode->i_private and @data->list found references
+ * Returns: pointer to reference
+ * Requires: @data to have a valid reference count on it. It is a bug
+ * if the race to reap can be encountered when it is used.
*/
static inline struct aa_loaddata *
-__aa_get_loaddata(struct aa_loaddata *data)
+aa_get_i_loaddata(struct aa_loaddata *data)
{
- if (data && kref_get_unless_zero(&(data->count)))
- return data;
- return NULL;
+ if (data)
+ kref_get(&(data->count.count));
+ return data;
}
+
/**
- * aa_get_loaddata - get a reference count from a counted data reference
+ * aa_get_profile_loaddata - get a profile reference count on loaddata
* @data: reference to get a count on
*
- * Returns: point to reference
- * Requires: @data to have a valid reference count on it. It is a bug
- * if the race to reap can be encountered when it is used.
+ * Returns: pointer to reference
+ * Requires: @data to have a valid reference count on it.
*/
static inline struct aa_loaddata *
-aa_get_loaddata(struct aa_loaddata *data)
+aa_get_profile_loaddata(struct aa_loaddata *data)
{
- struct aa_loaddata *tmp = __aa_get_loaddata(data);
-
- AA_BUG(data && !tmp);
-
- return tmp;
+ if (data)
+ kref_get(&(data->pcount));
+ return data;
}
void __aa_loaddata_update(struct aa_loaddata *data, long revision);
bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r);
void aa_loaddata_kref(struct kref *kref);
+void aa_ploaddata_kref(struct kref *kref);
struct aa_loaddata *aa_loaddata_alloc(size_t size);
-static inline void aa_put_loaddata(struct aa_loaddata *data)
+static inline void aa_put_i_loaddata(struct aa_loaddata *data)
+{
+ if (data)
+ kref_put(&data->count.count, aa_loaddata_kref);
+}
+
+static inline void aa_put_profile_loaddata(struct aa_loaddata *data)
{
if (data)
- kref_put(&data->count, aa_loaddata_kref);
+ kref_put(&data->pcount, aa_ploaddata_kref);
}
#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index 66bc4704f804..7cae71daa0f9 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -52,7 +52,8 @@ static void free_proxy(struct aa_proxy *proxy)
void aa_proxy_kref(struct kref *kref)
{
- struct aa_proxy *proxy = container_of(kref, struct aa_proxy, count);
+ struct aa_proxy *proxy = container_of(kref, struct aa_proxy,
+ count.count);
free_proxy(proxy);
}
@@ -63,7 +64,8 @@ struct aa_proxy *aa_alloc_proxy(struct aa_label *label, gfp_t gfp)
new = kzalloc(sizeof(struct aa_proxy), gfp);
if (new) {
- kref_init(&new->count);
+ kref_init(&new->count.count);
+ new->count.reftype = REF_PROXY;
rcu_assign_pointer(new->label, aa_get_label(label));
}
return new;
@@ -366,7 +368,8 @@ static void label_free_rcu(struct rcu_head *head)
void aa_label_kref(struct kref *kref)
{
- struct aa_label *label = container_of(kref, struct aa_label, count);
+ struct aa_label *label = container_of(kref, struct aa_label,
+ count.count);
struct aa_ns *ns = labels_ns(label);
if (!ns) {
@@ -403,7 +406,8 @@ bool aa_label_init(struct aa_label *label, int size, gfp_t gfp)
label->size = size; /* doesn't include null */
label->vec[size] = NULL; /* null terminate */
- kref_init(&label->count);
+ kref_init(&label->count.count);
+ label->count.reftype = REF_NS; /* for aafs purposes */
RB_CLEAR_NODE(&label->node);
return true;
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index 0e683ee323e3..8972d1b57b7a 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -204,9 +204,10 @@ static int verify_dfa(struct aa_dfa *dfa)
if (state_count == 0)
goto out;
for (i = 0; i < state_count; i++) {
- if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) &&
- (DEFAULT_TABLE(dfa)[i] >= state_count))
+ if (DEFAULT_TABLE(dfa)[i] >= state_count) {
+ pr_err("AppArmor DFA default state out of bounds");
goto out;
+ }
if (BASE_TABLE(dfa)[i] & MATCH_FLAGS_INVALID) {
pr_err("AppArmor DFA state with invalid match flags");
goto out;
@@ -245,16 +246,31 @@ static int verify_dfa(struct aa_dfa *dfa)
size_t j, k;
for (j = i;
- (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
- !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE);
+ ((BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
+ !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE_VERIFIED));
j = k) {
+ if (BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE)
+ /* loop in current chain */
+ goto out;
k = DEFAULT_TABLE(dfa)[j];
if (j == k)
+ /* self loop */
goto out;
- if (k < j)
- break; /* already verified */
BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE;
}
+ /* move mark to verified */
+ for (j = i;
+ (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE);
+ j = k) {
+ k = DEFAULT_TABLE(dfa)[j];
+ if (j < i)
+ /* jumps to state/chain that has been
+ * verified
+ */
+ break;
+ BASE_TABLE(dfa)[j] &= ~MARK_DIFF_ENCODE;
+ BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE_VERIFIED;
+ }
}
error = 0;
@@ -452,13 +468,18 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
if (dfa->tables[YYTD_ID_EC]) {
/* Equivalence class table defined */
u8 *equiv = EQUIV_TABLE(dfa);
- for (; len; len--)
- match_char(state, def, base, next, check,
- equiv[(u8) *str++]);
+ for (; len; len--) {
+ u8 c = equiv[(u8) *str];
+
+ match_char(state, def, base, next, check, c);
+ str++;
+ }
} else {
/* default is direct to next state */
- for (; len; len--)
- match_char(state, def, base, next, check, (u8) *str++);
+ for (; len; len--) {
+ match_char(state, def, base, next, check, (u8) *str);
+ str++;
+ }
}
return state;
@@ -493,13 +514,18 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
/* Equivalence class table defined */
u8 *equiv = EQUIV_TABLE(dfa);
/* default is direct to next state */
- while (*str)
- match_char(state, def, base, next, check,
- equiv[(u8) *str++]);
+ while (*str) {
+ u8 c = equiv[(u8) *str];
+
+ match_char(state, def, base, next, check, c);
+ str++;
+ }
} else {
/* default is direct to next state */
- while (*str)
- match_char(state, def, base, next, check, (u8) *str++);
+ while (*str) {
+ match_char(state, def, base, next, check, (u8) *str);
+ str++;
+ }
}
return state;
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index e59bdb750ef0..62ac50db5f80 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -146,19 +146,43 @@ static void __list_remove_profile(struct aa_profile *profile)
}
/**
- * __remove_profile - remove old profile, and children
- * @profile: profile to be replaced (NOT NULL)
+ * __remove_profile - remove profile, and children
+ * @profile: profile to be removed (NOT NULL)
*
* Requires: namespace list lock be held, or list not be shared
*/
static void __remove_profile(struct aa_profile *profile)
{
+ struct aa_profile *curr, *to_remove;
+
AA_BUG(!profile);
AA_BUG(!profile->ns);
AA_BUG(!mutex_is_locked(&profile->ns->lock));
/* release any children lists first */
- __aa_profile_list_release(&profile->base.profiles);
+ if (!list_empty(&profile->base.profiles)) {
+ curr = list_first_entry(&profile->base.profiles, struct aa_profile, base.list);
+
+ while (curr != profile) {
+
+ while (!list_empty(&curr->base.profiles))
+ curr = list_first_entry(&curr->base.profiles,
+ struct aa_profile, base.list);
+
+ to_remove = curr;
+ if (!list_is_last(&to_remove->base.list,
+ &aa_deref_parent(curr)->base.profiles))
+ curr = list_next_entry(to_remove, base.list);
+ else
+ curr = aa_deref_parent(curr);
+
+ /* released by free_profile */
+ aa_label_remove(&to_remove->label);
+ __aafs_profile_rmdir(to_remove);
+ __list_remove_profile(to_remove);
+ }
+ }
+
/* released by free_profile */
aa_label_remove(&profile->label);
__aafs_profile_rmdir(profile);
@@ -241,7 +265,7 @@ void aa_free_profile(struct aa_profile *profile)
}
kfree_sensitive(profile->hash);
- aa_put_loaddata(profile->rawdata);
+ aa_put_profile_loaddata(profile->rawdata);
aa_label_destroy(&profile->label);
kfree_sensitive(profile);
@@ -671,14 +695,44 @@ bool policy_admin_capable(struct aa_ns *ns)
return policy_view_capable(ns) && capable && !aa_g_lock_policy;
}
+static bool is_subset_of_obj_privilege(const struct cred *cred,
+ struct aa_label *label,
+ const struct cred *ocred)
+{
+ if (cred == ocred)
+ return true;
+
+ if (!aa_label_is_subset(label, cred_label(ocred)))
+ return false;
+ /* don't allow crossing userns for now */
+ if (cred->user_ns != ocred->user_ns)
+ return false;
+ if (!cap_issubset(cred->cap_inheritable, ocred->cap_inheritable))
+ return false;
+ if (!cap_issubset(cred->cap_permitted, ocred->cap_permitted))
+ return false;
+ if (!cap_issubset(cred->cap_effective, ocred->cap_effective))
+ return false;
+ if (!cap_issubset(cred->cap_bset, ocred->cap_bset))
+ return false;
+ if (!cap_issubset(cred->cap_ambient, ocred->cap_ambient))
+ return false;
+ return true;
+}
+
+
/**
* aa_may_manage_policy - can the current task manage policy
+ * @subj_cred; subjects cred
* @label: label to check if it can manage policy
- * @op: the policy manipulation operation being done
+ * @ns: namespace being managed by @label (may be NULL if @label's ns)
+ * @ocred: object cred if request is coming from an open object
+ * @mask: contains the policy manipulation operation being done
*
* Returns: 0 if the task is allowed to manipulate policy else error
*/
-int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask)
+int aa_may_manage_policy(const struct cred *subj_cred, struct aa_label *label,
+ struct aa_ns *ns, const struct cred *ocred, u32 mask)
{
const char *op;
@@ -694,6 +748,11 @@ int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask)
return audit_policy(label, op, NULL, NULL, "policy_locked",
-EACCES);
+ if (ocred && !is_subset_of_obj_privilege(subj_cred, label, ocred))
+ return audit_policy(label, op, NULL, NULL,
+ "not privileged for target profile",
+ -EACCES);
+
if (!policy_admin_capable(ns))
return audit_policy(label, op, NULL, NULL, "not policy admin",
-EACCES);
@@ -866,7 +925,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
LIST_HEAD(lh);
op = mask & AA_MAY_REPLACE_POLICY ? OP_PROF_REPL : OP_PROF_LOAD;
- aa_get_loaddata(udata);
+ aa_get_profile_loaddata(udata);
/* released below */
error = aa_unpack(udata, &lh, &ns_name);
if (error)
@@ -893,6 +952,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
goto fail;
}
ns_name = ent->ns_name;
+ ent->ns_name = NULL;
} else
count++;
}
@@ -916,10 +976,10 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
if (aa_rawdata_eq(rawdata_ent, udata)) {
struct aa_loaddata *tmp;
- tmp = __aa_get_loaddata(rawdata_ent);
+ tmp = aa_get_profile_loaddata(rawdata_ent);
/* check we didn't fail the race */
if (tmp) {
- aa_put_loaddata(udata);
+ aa_put_profile_loaddata(udata);
udata = tmp;
break;
}
@@ -929,7 +989,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
list_for_each_entry(ent, &lh, list) {
struct aa_policy *policy;
- ent->new->rawdata = aa_get_loaddata(udata);
+ ent->new->rawdata = aa_get_profile_loaddata(udata);
error = __lookup_replace(ns, ent->new->base.hname,
!(mask & AA_MAY_REPLACE_POLICY),
&ent->old, &info);
@@ -1043,7 +1103,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
out:
aa_put_ns(ns);
- aa_put_loaddata(udata);
+ aa_put_profile_loaddata(udata);
kfree(ns_name);
if (error)
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
index 53d24cf63893..5d342ef078e9 100644
--- a/security/apparmor/policy_ns.c
+++ b/security/apparmor/policy_ns.c
@@ -249,6 +249,8 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
AA_BUG(!name);
AA_BUG(!mutex_is_locked(&parent->lock));
+ if (parent->level > MAX_NS_DEPTH)
+ return ERR_PTR(-ENOSPC);
ns = alloc_ns(parent->base.hname, name);
if (!ns)
return ERR_PTR(-ENOMEM);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 93fcafdaa548..a512fde9267e 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -147,34 +147,48 @@ bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r)
return memcmp(l->data, r->data, r->compressed_size ?: r->size) == 0;
}
+static void do_loaddata_free(struct aa_loaddata *d)
+{
+ kfree_sensitive(d->hash);
+ kfree_sensitive(d->name);
+ kvfree(d->data);
+ kfree_sensitive(d);
+}
+
+void aa_loaddata_kref(struct kref *kref)
+{
+ struct aa_loaddata *d = container_of(kref, struct aa_loaddata,
+ count.count);
+
+ do_loaddata_free(d);
+}
+
/*
* need to take the ns mutex lock which is NOT safe most places that
* put_loaddata is called, so we have to delay freeing it
*/
-static void do_loaddata_free(struct work_struct *work)
+static void do_ploaddata_rmfs(struct work_struct *work)
{
struct aa_loaddata *d = container_of(work, struct aa_loaddata, work);
struct aa_ns *ns = aa_get_ns(d->ns);
if (ns) {
mutex_lock_nested(&ns->lock, ns->level);
+ /* remove fs ref to loaddata */
__aa_fs_remove_rawdata(d);
mutex_unlock(&ns->lock);
aa_put_ns(ns);
}
-
- kfree_sensitive(d->hash);
- kfree_sensitive(d->name);
- kvfree(d->data);
- kfree_sensitive(d);
+ /* called by dropping last pcount, so drop its associated icount */
+ aa_put_i_loaddata(d);
}
-void aa_loaddata_kref(struct kref *kref)
+void aa_ploaddata_kref(struct kref *kref)
{
- struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count);
+ struct aa_loaddata *d = container_of(kref, struct aa_loaddata, pcount);
if (d) {
- INIT_WORK(&d->work, do_loaddata_free);
+ INIT_WORK(&d->work, do_ploaddata_rmfs);
schedule_work(&d->work);
}
}
@@ -191,7 +205,9 @@ struct aa_loaddata *aa_loaddata_alloc(size_t size)
kfree(d);
return ERR_PTR(-ENOMEM);
}
- kref_init(&d->count);
+ kref_init(&d->count.count);
+ d->count.reftype = REF_RAWDATA;
+ kref_init(&d->pcount);
INIT_LIST_HEAD(&d->list);
return d;
@@ -841,9 +857,18 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
error = -EPROTO;
goto fail;
}
- if (!unpack_u32(e, &profile->policy.start[0], "start"))
+ if (!unpack_u32(e, &profile->policy.start[0], "start")) {
/* default start state */
profile->policy.start[0] = DFA_START;
+ } else {
+ size_t state_count = profile->policy.dfa->tables[YYTD_ID_BASE]->td_lolen;
+
+ if (profile->policy.start[0] >= state_count) {
+ info = "invalid dfa start state";
+ goto fail;
+ }
+ }
+
/* setup class index */
for (i = AA_CLASS_FILE; i <= AA_CLASS_LAST; i++) {
profile->policy.start[i] =
@@ -864,9 +889,17 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
info = "failed to unpack profile file rules";
goto fail;
} else if (profile->file.dfa) {
- if (!unpack_u32(e, &profile->file.start, "dfa_start"))
+ if (!unpack_u32(e, &profile->file.start, "dfa_start")) {
/* default start state */
profile->file.start = DFA_START;
+ } else {
+ size_t state_count = profile->file.dfa->tables[YYTD_ID_BASE]->td_lolen;
+
+ if (profile->file.start >= state_count) {
+ info = "invalid dfa start state";
+ goto fail;
+ }
+ }
} else if (profile->policy.dfa &&
profile->policy.start[AA_CLASS_FILE]) {
profile->file.dfa = aa_get_dfa(profile->policy.dfa);
@@ -959,7 +992,6 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
{
int error = -EPROTONOSUPPORT;
const char *name = NULL;
- *ns = NULL;
/* get the interface version */
if (!unpack_u32(e, &e->version, "version")) {
diff --git a/security/security.c b/security/security.c
index f836f292ea16..6de10b6699a4 100644
--- a/security/security.c
+++ b/security/security.c
@@ -60,6 +60,7 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
[LOCKDOWN_XMON_WR] = "xmon write access",
[LOCKDOWN_BPF_WRITE_USER] = "use of bpf to write user RAM",
[LOCKDOWN_DBG_WRITE_KERNEL] = "use of kgdb/kdb to write kernel RAM",
+ [LOCKDOWN_XEN_USER_ACTIONS] = "Xen guest user action",
[LOCKDOWN_INTEGRITY_MAX] = "integrity",
[LOCKDOWN_KCORE] = "/proc/kcore access",
[LOCKDOWN_KPROBES] = "use of kprobes",
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 289f52af15b9..c28c91d4e705 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1843,15 +1843,14 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
if (substream->wait_time) {
wait_time = substream->wait_time;
} else {
- wait_time = 10;
+ wait_time = 100;
if (runtime->rate) {
- long t = runtime->period_size * 2 /
- runtime->rate;
+ long t = runtime->buffer_size * 1100 / runtime->rate;
wait_time = max(t, wait_time);
}
- wait_time = msecs_to_jiffies(wait_time * 1000);
}
+ wait_time = msecs_to_jiffies(wait_time);
}
for (;;) {
@@ -1899,8 +1898,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
}
if (!tout) {
pcm_dbg(substream->pcm,
- "%s write error (DMA or IRQ trouble?)\n",
- is_playback ? "playback" : "capture");
+ "%s timeout (DMA or IRQ trouble?)\n",
+ is_playback ? "playback write" : "capture read");
err = -EIO;
break;
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a6a3e8909be7..09b4ad414ffb 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2129,6 +2129,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
for (;;) {
long tout;
struct snd_pcm_runtime *to_check;
+ unsigned int drain_rate;
+ snd_pcm_uframes_t drain_bufsz;
+ bool drain_no_period_wakeup;
+
if (signal_pending(current)) {
result = -ERESTARTSYS;
break;
@@ -2148,19 +2152,28 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
snd_pcm_group_unref(group, substream);
if (!to_check)
break; /* all drained */
+ /*
+ * Cache the runtime fields needed after unlock.
+ * A concurrent close() on the linked stream may free
+ * its runtime via snd_pcm_detach_substream() once we
+ * release the stream lock below.
+ */
+ drain_no_period_wakeup = to_check->no_period_wakeup;
+ drain_rate = to_check->rate;
+ drain_bufsz = to_check->buffer_size;
init_waitqueue_entry(&wait, current);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&to_check->sleep, &wait);
snd_pcm_stream_unlock_irq(substream);
- if (runtime->no_period_wakeup)
+ if (drain_no_period_wakeup)
tout = MAX_SCHEDULE_TIMEOUT;
else {
- tout = 10;
- if (runtime->rate) {
- long t = runtime->period_size * 2 / runtime->rate;
+ tout = 100;
+ if (drain_rate) {
+ long t = drain_bufsz * 1100 / drain_rate;
tout = max(t, tout);
}
- tout = msecs_to_jiffies(tout * 1000);
+ tout = msecs_to_jiffies(tout);
}
tout = schedule_timeout(tout);
@@ -2183,7 +2196,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
result = -ESTRPIPE;
else {
dev_dbg(substream->pcm->card->dev,
- "playback drain error (DMA or IRQ trouble?)\n");
+ "playback drain timeout (DMA or IRQ trouble?)\n");
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
result = -EIO;
}
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index aae544dff886..11cb0d886e95 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -119,6 +119,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
switch (type) {
case SPDIFOO: return 0;
case SPDIFIO: return 0;
+ case SPDIFI1: return 1;
case LINEO1: return 4;
case LINEO2: return 7;
case LINEO3: return 5;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index d1430ee34485..4d0bd1903ccb 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -239,6 +239,7 @@ enum {
CXT_PINCFG_SWS_JS201D,
CXT_PINCFG_TOP_SPEAKER,
CXT_FIXUP_HP_A_U,
+ CXT_FIXUP_ACER_SWIFT_HP,
};
/* for hda_fixup_thinkpad_acpi() */
@@ -969,6 +970,14 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_hp_a_u,
},
+ [CXT_FIXUP_ACER_SWIFT_HP] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x16, 0x0321403f }, /* Headphone */
+ { 0x19, 0x40f001f0 }, /* Mic */
+ { }
+ },
+ },
};
static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -1018,6 +1027,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x136d, "Acer Swift SF314", CXT_FIXUP_ACER_SWIFT_HP),
SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
@@ -1026,6 +1036,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x8231, "HP ProBook 450 G4", CXT_FIXUP_MUTE_LED_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x826b, "HP ZBook Studio G4", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b8c7f4c8593b..7ea036f820f5 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -9527,6 +9527,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x2288, "Thinkpad X390", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22c1, "Thinkpad P1 Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c
index 1a4e8ca0f99c..7e2f8d628cbb 100644
--- a/sound/soc/amd/acp3x-rt5682-max9836.c
+++ b/sound/soc/amd/acp3x-rt5682-max9836.c
@@ -83,8 +83,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk");
- rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk");
+ rt5682_dai_wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
+ if (IS_ERR(rt5682_dai_wclk))
+ return PTR_ERR(rt5682_dai_wclk);
+
+ rt5682_dai_bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
+ if (IS_ERR(rt5682_dai_bclk))
+ return PTR_ERR(rt5682_dai_bclk);
ret = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index acd500c3b9d0..6af5c1735e2e 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -52,10 +52,13 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol,
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
unsigned int regval = ucontrol->value.integer.value[0];
+ int ret;
+
+ ret = (easrc_priv->bps_iec958[mc->regbase] != regval);
easrc_priv->bps_iec958[mc->regbase] = regval;
- return 0;
+ return ret;
}
static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol,
@@ -93,14 +96,17 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
+ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component);
unsigned int regval = ucontrol->value.integer.value[0];
+ bool changed;
int ret;
- ret = snd_soc_component_write(component, mc->regbase, regval);
- if (ret < 0)
+ ret = regmap_update_bits_check(easrc->regmap, mc->regbase,
+ GENMASK(31, 0), regval, &changed);
+ if (ret != 0)
return ret;
- return 0;
+ return changed;
}
#define SOC_SINGLE_REG_RW(xname, xreg) \
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
index a70179959795..db67509f051a 100644
--- a/sound/soc/intel/catpt/device.c
+++ b/sound/soc/intel/catpt/device.c
@@ -263,7 +263,15 @@ static int catpt_acpi_probe(struct platform_device *pdev)
if (IS_ERR(cdev->pci_ba))
return PTR_ERR(cdev->pci_ba);
- /* alloc buffer for storing DRAM context during dx transitions */
+ /*
+ * As per design HOST is responsible for preserving firmware's runtime
+ * context during D0 -> D3 -> D0 transitions. Addresses used for DMA
+ * to/from HOST memory shall be outside the reserved range of 0xFFFxxxxx.
+ */
+ ret = dma_coerce_mask_and_coherent(cdev->dev, DMA_BIT_MASK(31));
+ if (ret)
+ return ret;
+
cdev->dxbuf_vaddr = dmam_alloc_coherent(dev, catpt_dram_size(cdev),
&cdev->dxbuf_paddr, GFP_KERNEL);
if (!cdev->dxbuf_vaddr)
diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c
index 38a92bbc1ed5..2c67d2d35cda 100644
--- a/sound/soc/intel/catpt/dsp.c
+++ b/sound/soc/intel/catpt/dsp.c
@@ -125,9 +125,6 @@ int catpt_dmac_probe(struct catpt_dev *cdev)
dmac->dev = cdev->dev;
dmac->irq = cdev->irq;
- ret = dma_coerce_mask_and_coherent(cdev->dev, DMA_BIT_MASK(31));
- if (ret)
- return ret;
/*
* Caller is responsible for putting device in D0 to allow
* for I/O and memory access before probing DW.
diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c
index d07270d17cee..2870cfad813a 100644
--- a/sound/soc/meson/meson-codec-glue.c
+++ b/sound/soc/meson/meson-codec-glue.c
@@ -113,9 +113,6 @@ int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
/* Replace link params with the input params */
rtd->dai_link->params = &in_data->params;
- if (!in_data->fmt)
- return 0;
-
return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
}
EXPORT_SYMBOL_GPL(meson_codec_glue_output_startup);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 1120d669fe2e..e7310642be6a 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -401,8 +401,7 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
list_del(&rtd->list);
- if (delayed_work_pending(&rtd->delayed_work))
- flush_delayed_work(&rtd->delayed_work);
+ flush_delayed_work(&rtd->delayed_work);
snd_soc_pcm_component_free(rtd);
/*
@@ -963,9 +962,6 @@ void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
lockdep_assert_held(&client_mutex);
- /* release machine specific resources */
- snd_soc_link_exit(rtd);
-
/*
* Notify the machine driver for extra destruction
*/
@@ -1056,6 +1052,234 @@ int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(snd_soc_add_pcm_runtime);
+static void snd_soc_runtime_get_dai_fmt(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_soc_dai *dai, *not_used;
+ struct device *dev = rtd->dev;
+ u64 pos, possible_fmt;
+ unsigned int mask = 0, dai_fmt = 0;
+ int i, j, priority, pri, until;
+
+ /*
+ * Get selectable format from each DAIs.
+ *
+ ****************************
+ * NOTE
+ * Using .auto_selectable_formats is not mandatory,
+ * we can select format manually from Sound Card.
+ * When use it, driver should list well tested format only.
+ ****************************
+ *
+ * ex)
+ * auto_selectable_formats (= SND_SOC_POSSIBLE_xxx)
+ * (A) (B) (C)
+ * DAI0_: { 0x000F, 0x00F0, 0x0F00 };
+ * DAI1 : { 0xF000, 0x0F00 };
+ * (X) (Y)
+ *
+ * "until" will be 3 in this case (MAX array size from DAI0 and DAI1)
+ * Here is dev_dbg() message and comments
+ *
+ * priority = 1
+ * DAI0: (pri, fmt) = (1, 000000000000000F) // 1st check (A) DAI1 is not selected
+ * DAI1: (pri, fmt) = (0, 0000000000000000) // Necessary Waste
+ * DAI0: (pri, fmt) = (1, 000000000000000F) // 2nd check (A)
+ * DAI1: (pri, fmt) = (1, 000000000000F000) // (X)
+ * priority = 2
+ * DAI0: (pri, fmt) = (2, 00000000000000FF) // 3rd check (A) + (B)
+ * DAI1: (pri, fmt) = (1, 000000000000F000) // (X)
+ * DAI0: (pri, fmt) = (2, 00000000000000FF) // 4th check (A) + (B)
+ * DAI1: (pri, fmt) = (2, 000000000000FF00) // (X) + (Y)
+ * priority = 3
+ * DAI0: (pri, fmt) = (3, 0000000000000FFF) // 5th check (A) + (B) + (C)
+ * DAI1: (pri, fmt) = (2, 000000000000FF00) // (X) + (Y)
+ * found auto selected format: 0000000000000F00
+ */
+ until = snd_soc_dai_get_fmt_max_priority(rtd);
+ for (priority = 1; priority <= until; priority++) {
+
+ dev_dbg(dev, "priority = %d\n", priority);
+ for_each_rtd_dais(rtd, j, not_used) {
+
+ possible_fmt = ULLONG_MAX;
+ for_each_rtd_dais(rtd, i, dai) {
+ u64 fmt = 0;
+
+ pri = (j >= i) ? priority : priority - 1;
+ fmt = snd_soc_dai_get_fmt(dai, pri);
+ dev_dbg(dev, "%s: (pri, fmt) = (%d, %016llX)\n", dai->name, pri, fmt);
+ possible_fmt &= fmt;
+ }
+ if (possible_fmt)
+ goto found;
+ }
+ }
+ /* Not Found */
+ return;
+found:
+ dev_dbg(dev, "found auto selected format: %016llX\n", possible_fmt);
+
+ /*
+ * convert POSSIBLE_DAIFMT to DAIFMT
+ *
+ * Some basic/default settings on each is defined as 0.
+ * see
+ * SND_SOC_DAIFMT_NB_NF
+ * SND_SOC_DAIFMT_GATED
+ *
+ * SND_SOC_DAIFMT_xxx_MASK can't notice it if Sound Card specify
+ * these value, and will be overwrite to auto selected value.
+ *
+ * To avoid such issue, loop from 63 to 0 here.
+ * Small number of SND_SOC_POSSIBLE_xxx will be Hi priority.
+ * Basic/Default settings of each part and aboves are defined
+ * as Hi priority (= small number) of SND_SOC_POSSIBLE_xxx.
+ */
+ for (i = 63; i >= 0; i--) {
+ pos = 1ULL << i;
+ switch (possible_fmt & pos) {
+ /*
+ * for format
+ */
+ case SND_SOC_POSSIBLE_DAIFMT_I2S:
+ case SND_SOC_POSSIBLE_DAIFMT_RIGHT_J:
+ case SND_SOC_POSSIBLE_DAIFMT_LEFT_J:
+ case SND_SOC_POSSIBLE_DAIFMT_DSP_A:
+ case SND_SOC_POSSIBLE_DAIFMT_DSP_B:
+ case SND_SOC_POSSIBLE_DAIFMT_AC97:
+ case SND_SOC_POSSIBLE_DAIFMT_PDM:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | i;
+ break;
+ /*
+ * for clock
+ */
+ case SND_SOC_POSSIBLE_DAIFMT_CONT:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_MASK) | SND_SOC_DAIFMT_CONT;
+ break;
+ case SND_SOC_POSSIBLE_DAIFMT_GATED:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_MASK) | SND_SOC_DAIFMT_GATED;
+ break;
+ /*
+ * for clock invert
+ */
+ case SND_SOC_POSSIBLE_DAIFMT_NB_NF:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_NB_NF;
+ break;
+ case SND_SOC_POSSIBLE_DAIFMT_NB_IF:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_NB_IF;
+ break;
+ case SND_SOC_POSSIBLE_DAIFMT_IB_NF:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_IB_NF;
+ break;
+ case SND_SOC_POSSIBLE_DAIFMT_IB_IF:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_IB_IF;
+ break;
+ /*
+ * for clock provider / consumer
+ */
+ case SND_SOC_POSSIBLE_DAIFMT_CBP_CFP:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBP_CFP;
+ break;
+ case SND_SOC_POSSIBLE_DAIFMT_CBC_CFP:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBC_CFP;
+ break;
+ case SND_SOC_POSSIBLE_DAIFMT_CBP_CFC:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBP_CFC;
+ break;
+ case SND_SOC_POSSIBLE_DAIFMT_CBC_CFC:
+ dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBC_CFC;
+ break;
+ }
+ }
+
+ /*
+ * Some driver might have very complex limitation.
+ * In such case, user want to auto-select non-limitation part,
+ * and want to manually specify complex part.
+ *
+ * Or for example, if both CPU and Codec can be clock provider,
+ * but because of its quality, user want to specify it manually.
+ *
+ * Use manually specified settings if sound card did.
+ */
+ if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK))
+ mask |= SND_SOC_DAIFMT_FORMAT_MASK;
+ if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_CLOCK_MASK))
+ mask |= SND_SOC_DAIFMT_CLOCK_MASK;
+ if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_INV_MASK))
+ mask |= SND_SOC_DAIFMT_INV_MASK;
+ if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK))
+ mask |= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
+
+ dai_link->dai_fmt |= (dai_fmt & mask);
+}
+
+/**
+ * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
+ * @rtd: The runtime for which the DAI link format should be changed
+ * @dai_fmt: The new DAI link format
+ *
+ * This function updates the DAI link format for all DAIs connected to the DAI
+ * link for the specified runtime.
+ *
+ * Note: For setups with a static format set the dai_fmt field in the
+ * corresponding snd_dai_link struct instead of using this function.
+ *
+ * Returns 0 on success, otherwise a negative error code.
+ */
+int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
+ unsigned int dai_fmt)
+{
+ struct snd_soc_dai *cpu_dai;
+ struct snd_soc_dai *codec_dai;
+ unsigned int inv_dai_fmt;
+ unsigned int i;
+ int ret;
+
+ if (!dai_fmt)
+ return 0;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
+ if (ret != 0 && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ /*
+ * Flip the polarity for the "CPU" end of a CODEC<->CODEC link
+ * the component which has non_legacy_dai_naming is Codec
+ */
+ inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
+ switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+ break;
+ }
+ for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
+ unsigned int fmt = dai_fmt;
+
+ if (cpu_dai->component->driver->non_legacy_dai_naming)
+ fmt = inv_dai_fmt;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret != 0 && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
+
static int soc_init_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd)
{
@@ -1072,11 +1296,10 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
if (ret < 0)
return ret;
- if (dai_link->dai_fmt) {
- ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
- if (ret)
- return ret;
- }
+ snd_soc_runtime_get_dai_fmt(rtd);
+ ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
+ if (ret)
+ goto err;
/* add DPCM sysfs entries */
soc_dpcm_debugfs_add(rtd);
@@ -1100,22 +1323,27 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
/* create compress_device if possible */
ret = snd_soc_dai_compress_new(cpu_dai, rtd, num);
- if (ret != -ENOTSUPP) {
- if (ret < 0)
- dev_err(card->dev, "ASoC: can't create compress %s\n",
- dai_link->stream_name);
- return ret;
- }
+ if (ret != -ENOTSUPP)
+ goto err;
/* create the pcm */
ret = soc_new_pcm(rtd, num);
if (ret < 0) {
dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
dai_link->stream_name, ret);
- return ret;
+ goto err;
}
- return snd_soc_pcm_dai_new(rtd);
+ ret = snd_soc_pcm_dai_new(rtd);
+ if (ret < 0)
+ goto err;
+
+ rtd->initialized = true;
+
+ return 0;
+err:
+ snd_soc_link_exit(rtd);
+ return ret;
}
static void soc_set_name_prefix(struct snd_soc_card *card,
@@ -1409,74 +1637,6 @@ static void soc_remove_aux_devices(struct snd_soc_card *card)
}
}
-/**
- * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
- * @rtd: The runtime for which the DAI link format should be changed
- * @dai_fmt: The new DAI link format
- *
- * This function updates the DAI link format for all DAIs connected to the DAI
- * link for the specified runtime.
- *
- * Note: For setups with a static format set the dai_fmt field in the
- * corresponding snd_dai_link struct instead of using this function.
- *
- * Returns 0 on success, otherwise a negative error code.
- */
-int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
- unsigned int dai_fmt)
-{
- struct snd_soc_dai *cpu_dai;
- struct snd_soc_dai *codec_dai;
- unsigned int inv_dai_fmt;
- unsigned int i;
- int ret;
-
- for_each_rtd_codec_dais(rtd, i, codec_dai) {
- ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
- if (ret != 0 && ret != -ENOTSUPP) {
- dev_warn(codec_dai->dev,
- "ASoC: Failed to set DAI format: %d\n", ret);
- return ret;
- }
- }
-
- /*
- * Flip the polarity for the "CPU" end of a CODEC<->CODEC link
- * the component which has non_legacy_dai_naming is Codec
- */
- inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
- switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
- break;
- case SND_SOC_DAIFMT_CBM_CFS:
- inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
- break;
- case SND_SOC_DAIFMT_CBS_CFM:
- inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
- break;
- }
- for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- unsigned int fmt = dai_fmt;
-
- if (cpu_dai->component->driver->non_legacy_dai_naming)
- fmt = inv_dai_fmt;
-
- ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
- if (ret != 0 && ret != -ENOTSUPP) {
- dev_warn(cpu_dai->dev,
- "ASoC: Failed to set DAI format: %d\n", ret);
- return ret;
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
-
#ifdef CONFIG_DMI
/*
* If a DMI filed contain strings in this blacklist (e.g.
@@ -1515,12 +1675,15 @@ static void cleanup_dmi_name(char *name)
/*
* Check if a DMI field is valid, i.e. not containing any string
- * in the black list.
+ * in the black list and not the empty string.
*/
static int is_dmi_valid(const char *field)
{
int i = 0;
+ if (!field[0])
+ return 0;
+
while (dmi_blacklist[i]) {
if (strstr(field, dmi_blacklist[i]))
return 0;
@@ -1774,6 +1937,13 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
snd_soc_dapm_shutdown(card);
+ /* release machine specific resources */
+ for_each_card_rtds(card, rtd)
+ if (rtd->initialized)
+ snd_soc_link_exit(rtd);
+ /* flush delayed work before removing DAIs and DAPM widgets */
+ snd_soc_flush_all_delayed_work(card);
+
/* remove and free each DAI */
soc_remove_link_dais(card);
soc_remove_link_components(card);
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 583b18d0f446..a76d876f6729 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -134,6 +134,69 @@ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
+int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai;
+ int i, max = 0;
+
+ /*
+ * return max num if *ALL* DAIs have .auto_selectable_formats
+ */
+ for_each_rtd_dais(rtd, i, dai) {
+ if (dai->driver->ops &&
+ dai->driver->ops->num_auto_selectable_formats)
+ max = max(max, dai->driver->ops->num_auto_selectable_formats);
+ else
+ return 0;
+ }
+
+ return max;
+}
+
+/**
+ * snd_soc_dai_get_fmt - get supported audio format.
+ * @dai: DAI
+ * @priority: priority level of supported audio format.
+ *
+ * This should return only formats implemented with high
+ * quality by the DAI so that the core can configure a
+ * format which will work well with other devices.
+ * For example devices which don't support both edges of the
+ * LRCLK signal in I2S style formats should only list DSP
+ * modes. This will mean that sometimes fewer formats
+ * are reported here than are supported by set_fmt().
+ */
+u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority)
+{
+ const struct snd_soc_dai_ops *ops = dai->driver->ops;
+ u64 fmt = 0;
+ int i, max = 0, until = priority;
+
+ /*
+ * Collect auto_selectable_formats until priority
+ *
+ * ex)
+ * auto_selectable_formats[] = { A, B, C };
+ * (A, B, C = SND_SOC_POSSIBLE_DAIFMT_xxx)
+ *
+ * priority = 1 : A
+ * priority = 2 : A | B
+ * priority = 3 : A | B | C
+ * priority = 4 : A | B | C
+ * ...
+ */
+ if (ops)
+ max = ops->num_auto_selectable_formats;
+
+ if (max < until)
+ until = max;
+
+ for (i = 0; i < until; i++)
+ fmt |= ops->auto_selectable_formats[i];
+
+ return fmt;
+}
+
/**
* snd_soc_dai_set_fmt - configure DAI hardware audio format.
* @dai: DAI
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 175c8c264b62..a3bebea5879b 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3856,11 +3856,9 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
source = path->source->priv;
ret = snd_soc_dai_startup(source, substream);
- if (ret < 0) {
- dev_err(source->dev,
- "ASoC: startup() failed: %d\n", ret);
+ if (ret < 0)
goto out;
- }
+
snd_soc_dai_activate(source, substream->stream);
}
@@ -3869,11 +3867,9 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
sink = path->sink->priv;
ret = snd_soc_dai_startup(sink, substream);
- if (ret < 0) {
- dev_err(sink->dev,
- "ASoC: startup() failed: %d\n", ret);
+ if (ret < 0)
goto out;
- }
+
snd_soc_dai_activate(sink, substream->stream);
}
@@ -3968,11 +3964,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
snd_soc_dapm_widget_for_each_sink_path(w, path) {
sink = path->sink->priv;
- ret = snd_soc_dai_digital_mute(sink, 0,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret != 0 && ret != -ENOTSUPP)
- dev_warn(sink->dev,
- "ASoC: Failed to unmute: %d\n", ret);
+ snd_soc_dai_digital_mute(sink, 0, SNDRV_PCM_STREAM_PLAYBACK);
ret = 0;
}
break;
@@ -3981,11 +3973,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
snd_soc_dapm_widget_for_each_sink_path(w, path) {
sink = path->sink->priv;
- ret = snd_soc_dai_digital_mute(sink, 1,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret != 0 && ret != -ENOTSUPP)
- dev_warn(sink->dev,
- "ASoC: Failed to mute: %d\n", ret);
+ snd_soc_dai_digital_mute(sink, 1, SNDRV_PCM_STREAM_PLAYBACK);
ret = 0;
}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index e52c030bd17a..c82d653e6c37 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -821,10 +821,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
goto out;
ret = snd_soc_pcm_dai_prepare(substream);
- if (ret < 0) {
- dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret);
+ if (ret < 0)
goto out;
- }
/* cancel any delayed stream shutdown that is pending */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
@@ -2414,8 +2412,6 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
fe->dai_link->name);
err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
- if (err < 0)
- dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err);
} else {
dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
fe->dai_link->name);
@@ -2492,10 +2488,8 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
fe->dai_link->name);
ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
- if (ret < 0) {
- dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret);
+ if (ret < 0)
goto hw_free;
- }
} else {
dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
fe->dai_link->name);
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index aa57f796e9dd..b9ef95c99c6e 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -2173,7 +2173,7 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
struct snd_soc_tplg_link_config *cfg)
{
struct snd_soc_tplg_hw_config *hw_config;
- unsigned char bclk_master, fsync_master;
+ unsigned char bclk_provider, fsync_provider;
unsigned char invert_bclk, invert_fsync;
int i;
@@ -2213,18 +2213,18 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
link->dai_fmt |= SND_SOC_DAIFMT_IB_IF;
/* clock masters */
- bclk_master = (hw_config->bclk_master ==
- SND_SOC_TPLG_BCLK_CM);
- fsync_master = (hw_config->fsync_master ==
- SND_SOC_TPLG_FSYNC_CM);
- if (bclk_master && fsync_master)
- link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
- else if (!bclk_master && fsync_master)
- link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
- else if (bclk_master && !fsync_master)
- link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+ bclk_provider = (hw_config->bclk_provider ==
+ SND_SOC_TPLG_BCLK_CP);
+ fsync_provider = (hw_config->fsync_provider ==
+ SND_SOC_TPLG_FSYNC_CP);
+ if (bclk_provider && fsync_provider)
+ link->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
+ else if (!bclk_provider && fsync_provider)
+ link->dai_fmt |= SND_SOC_DAIFMT_CBC_CFP;
+ else if (bclk_provider && !fsync_provider)
+ link->dai_fmt |= SND_SOC_DAIFMT_CBP_CFC;
else
- link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+ link->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
}
}
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 6b398ffabb02..104d5ec13550 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -97,6 +97,34 @@ static const struct snd_soc_component_driver dummy_codec = {
SNDRV_PCM_FMTBIT_S32_LE | \
SNDRV_PCM_FMTBIT_U32_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
+
+/*
+ * Select these from Sound Card Manually
+ * SND_SOC_POSSIBLE_DAIFMT_CBP_CFP
+ * SND_SOC_POSSIBLE_DAIFMT_CBP_CFC
+ * SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
+ * SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
+ */
+static u64 dummy_dai_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B |
+ SND_SOC_POSSIBLE_DAIFMT_AC97 |
+ SND_SOC_POSSIBLE_DAIFMT_PDM |
+ SND_SOC_POSSIBLE_DAIFMT_GATED |
+ SND_SOC_POSSIBLE_DAIFMT_CONT |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
+static const struct snd_soc_dai_ops dummy_dai_ops = {
+ .auto_selectable_formats = &dummy_dai_formats,
+ .num_auto_selectable_formats = 1,
+};
+
/*
* The dummy CODEC is only meant to be used in situations where there is no
* actual hardware.
@@ -122,6 +150,7 @@ static struct snd_soc_dai_driver dummy_dai = {
.rates = STUB_RATES,
.formats = STUB_FORMATS,
},
+ .ops = &dummy_dai_ops,
};
int snd_soc_dai_is_dummy(struct snd_soc_dai *dai)
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index b6327c30c2b5..e3aa9fa0f112 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -2786,15 +2786,15 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
struct sof_ipc_dai_config *config)
{
/* clock directions wrt codec */
- if (hw_config->bclk_master == SND_SOC_TPLG_BCLK_CM) {
+ if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CM) {
/* codec is bclk master */
- if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
+ if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CM)
config->format |= SOF_DAI_FMT_CBM_CFM;
else
config->format |= SOF_DAI_FMT_CBM_CFS;
} else {
/* codec is bclk slave */
- if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
+ if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CM)
config->format |= SOF_DAI_FMT_CBS_CFM;
else
config->format |= SOF_DAI_FMT_CBS_CFS;
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index b3f36515cbc1..75fcda35c079 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -111,6 +111,9 @@ int tegra_pcm_open(struct snd_soc_component *component,
return ret;
}
+ /* Set wait time to 500ms by default */
+ substream->wait_time = 500;
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra_pcm_open);
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 482d4915e0a7..8a449f61d214 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -502,7 +502,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
memset(id, 0, sizeof(id));
for (c = card->shortname, len = 0;
- *c && len < sizeof(card->id); c++)
+ *c && len < sizeof(card->id) - 1; c++)
if (*c != ' ')
id[len++] = *c;
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 21bcdc811a81..8e2b90cb5b95 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -1099,6 +1099,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
return -EINVAL;
}
+ ep->packsize[0] = min(ep->packsize[0], ep->maxframesize);
+ ep->packsize[1] = min(ep->packsize[1], ep->maxframesize);
+
/* calculate the frequency in 16.16 format */
ep->freqm = ep->freqn;
ep->freqshift = INT_MIN;
diff --git a/sound/usb/validate.c b/sound/usb/validate.c
index 4bb4893f6e74..f62b7cc041dc 100644
--- a/sound/usb/validate.c
+++ b/sound/usb/validate.c
@@ -281,7 +281,7 @@ static const struct usb_desc_validator audio_validators[] = {
/* UAC_VERSION_2, UAC2_SAMPLE_RATE_CONVERTER: not implemented yet */
/* UAC3 */
- FIXED(UAC_VERSION_2, UAC_HEADER, struct uac3_ac_header_descriptor),
+ FIXED(UAC_VERSION_3, UAC_HEADER, struct uac3_ac_header_descriptor),
FIXED(UAC_VERSION_3, UAC_INPUT_TERMINAL,
struct uac3_input_terminal_descriptor),
FIXED(UAC_VERSION_3, UAC_OUTPUT_TERMINAL,
diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c
index 365c022fb7cd..387cb91862df 100644
--- a/tools/bootconfig/main.c
+++ b/tools/bootconfig/main.c
@@ -138,8 +138,11 @@ static int load_xbc_file(const char *path, char **buf)
if (fd < 0)
return -errno;
ret = fstat(fd, &stat);
- if (ret < 0)
- return -errno;
+ if (ret < 0) {
+ ret = -errno;
+ close(fd);
+ return ret;
+ }
ret = load_xbc_fd(fd, buf, stat.st_size);
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 20ccdd60353b..ac4bd2d4fdda 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1664,12 +1664,11 @@ static void mark_func_jump_tables(struct objtool_file *file,
last = insn;
/*
- * Store back-pointers for unconditional forward jumps such
+ * Store back-pointers for forward jumps such
* that find_jump_table() can back-track using those and
* avoid some potentially confusing code.
*/
- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
- insn->offset > last->offset &&
+ if (insn->jump_dest &&
insn->jump_dest->offset > insn->offset &&
!insn->jump_dest->first_jump_src) {
diff --git a/tools/testing/selftests/net/mptcp/simult_flows.sh b/tools/testing/selftests/net/mptcp/simult_flows.sh
index b51afba244be..4a693c4654e0 100755
--- a/tools/testing/selftests/net/mptcp/simult_flows.sh
+++ b/tools/testing/selftests/net/mptcp/simult_flows.sh
@@ -235,10 +235,13 @@ run_test()
for dev in ns2eth1 ns2eth2; do
tc -n $ns2 qdisc del dev $dev root >/dev/null 2>&1
done
- tc -n $ns1 qdisc add dev ns1eth1 root netem rate ${rate1}mbit $delay1
- tc -n $ns1 qdisc add dev ns1eth2 root netem rate ${rate2}mbit $delay2
- tc -n $ns2 qdisc add dev ns2eth1 root netem rate ${rate1}mbit $delay1
- tc -n $ns2 qdisc add dev ns2eth2 root netem rate ${rate2}mbit $delay2
+
+ # keep the queued pkts number low, or the RTT estimator will see
+ # increasing latency over time.
+ tc -n $ns1 qdisc add dev ns1eth1 root netem rate ${rate1}mbit $delay1 limit 50
+ tc -n $ns1 qdisc add dev ns1eth2 root netem rate ${rate2}mbit $delay2 limit 50
+ tc -n $ns2 qdisc add dev ns2eth1 root netem rate ${rate1}mbit $delay1 limit 50
+ tc -n $ns2 qdisc add dev ns2eth2 root netem rate ${rate2}mbit $delay2 limit 50
# time is measure in ms
local time=$((size * 8 * 1000 / (( $rate1 + $rate2) * 1024 *1024) ))
^ permalink raw reply related [flat|nested] 2+ messages in thread