diff --git a/patch/kernel/archive/odroidxu4-5.4/patch-5.4.230-231.patch b/patch/kernel/archive/odroidxu4-5.4/patch-5.4.230-231.patch new file mode 100644 index 0000000000..72049c2a72 --- /dev/null +++ b/patch/kernel/archive/odroidxu4-5.4/patch-5.4.230-231.patch @@ -0,0 +1,4958 @@ +diff --git a/Documentation/ABI/testing/sysfs-kernel-oops_count b/Documentation/ABI/testing/sysfs-kernel-oops_count +new file mode 100644 +index 0000000000000..156cca9dbc960 +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-kernel-oops_count +@@ -0,0 +1,6 @@ ++What: /sys/kernel/oops_count ++Date: November 2022 ++KernelVersion: 6.2.0 ++Contact: Linux Kernel Hardening List ++Description: ++ Shows how many times the system has Oopsed since last boot. +diff --git a/Documentation/ABI/testing/sysfs-kernel-warn_count b/Documentation/ABI/testing/sysfs-kernel-warn_count +new file mode 100644 +index 0000000000000..90a029813717d +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-kernel-warn_count +@@ -0,0 +1,6 @@ ++What: /sys/kernel/warn_count ++Date: November 2022 ++KernelVersion: 6.2.0 ++Contact: Linux Kernel Hardening List ++Description: ++ Shows how many times the system has Warned since last boot. +diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst +index 9715685be6e3b..568c24ff00a72 100644 +--- a/Documentation/admin-guide/sysctl/kernel.rst ++++ b/Documentation/admin-guide/sysctl/kernel.rst +@@ -557,6 +557,15 @@ numa_balancing_scan_size_mb is how many megabytes worth of pages are + scanned for a given scan. + + ++oops_limit ++========== ++ ++Number of kernel oopses after which the kernel should panic when ++``panic_on_oops`` is not set. Setting this to 0 disables checking ++the count. Setting this to 1 has the same effect as setting ++``panic_on_oops=1``. The default value is 10000. ++ ++ + osrelease, ostype & version: + ============================ + +@@ -1177,6 +1186,16 @@ entry will default to 2 instead of 0. + 2 Unprivileged calls to ``bpf()`` are disabled + = ============================================================= + ++ ++warn_limit ++========== ++ ++Number of kernel warnings after which the kernel should panic when ++``panic_on_warn`` is not set. Setting this to 0 disables checking ++the warning count. Setting this to 1 has the same effect as setting ++``panic_on_warn=1``. The default value is 0. ++ ++ + watchdog: + ========= + +diff --git a/MAINTAINERS b/MAINTAINERS +index 973fcc9143d1e..ea8f1c8850892 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -14661,6 +14661,7 @@ L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/phy/phylink.c + F: drivers/net/phy/sfp* ++F: include/linux/mdio/mdio-i2c.h + F: include/linux/phylink.h + F: include/linux/sfp.h + K: phylink +diff --git a/Makefile b/Makefile +index 6a947b4ed5dc4..3cbbc82e2ddf2 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 5 + PATCHLEVEL = 4 +-SUBLEVEL = 230 ++SUBLEVEL = 231 + EXTRAVERSION = + NAME = Kleptomaniac Octopus + +diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c +index f6b9664ac5042..f87d8e1fcfe42 100644 +--- a/arch/alpha/kernel/traps.c ++++ b/arch/alpha/kernel/traps.c +@@ -192,7 +192,7 @@ die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15) + local_irq_enable(); + while (1); + } +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + #ifndef CONFIG_MATHEMU +@@ -577,7 +577,7 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg, + + printk("Bad unaligned kernel access at %016lx: %p %lx %lu\n", + pc, va, opcode, reg); +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + + got_exception: + /* Ok, we caught the exception, but we don't want it. Is there +@@ -632,7 +632,7 @@ got_exception: + local_irq_enable(); + while (1); + } +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + /* +diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c +index 741e61ef9d3fe..a86286d2d3f3f 100644 +--- a/arch/alpha/mm/fault.c ++++ b/arch/alpha/mm/fault.c +@@ -206,7 +206,7 @@ retry: + printk(KERN_ALERT "Unable to handle kernel paging request at " + "virtual address %016lx\n", address); + die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16); +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + + /* We ran out of memory, or some other thing happened to us that + made us unable to handle the page fault gracefully. */ +diff --git a/arch/arm/boot/dts/imx53-ppd.dts b/arch/arm/boot/dts/imx53-ppd.dts +index c80d1700e0949..c01dc571b55cd 100644 +--- a/arch/arm/boot/dts/imx53-ppd.dts ++++ b/arch/arm/boot/dts/imx53-ppd.dts +@@ -461,7 +461,7 @@ + scl-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + status = "okay"; + +- i2c-switch@70 { ++ i2c-mux@70 { + compatible = "nxp,pca9547"; + #address-cells = <1>; + #size-cells = <0>; +diff --git a/arch/arm/boot/dts/imx6qdl-gw560x.dtsi b/arch/arm/boot/dts/imx6qdl-gw560x.dtsi +index e8e36dfd0a6b0..c951834f49847 100644 +--- a/arch/arm/boot/dts/imx6qdl-gw560x.dtsi ++++ b/arch/arm/boot/dts/imx6qdl-gw560x.dtsi +@@ -464,7 +464,6 @@ + &uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; +- uart-has-rtscts; + rts-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; +diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c +index 207ef9a797bd4..03dfeb1208431 100644 +--- a/arch/arm/kernel/traps.c ++++ b/arch/arm/kernel/traps.c +@@ -341,7 +341,7 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, int signr) + if (panic_on_oops) + panic("Fatal exception"); + if (signr) +- do_exit(signr); ++ make_task_dead(signr); + } + + /* +diff --git a/arch/arm/mach-imx/cpu-imx25.c b/arch/arm/mach-imx/cpu-imx25.c +index b2e1963f473de..2ee2d2813d577 100644 +--- a/arch/arm/mach-imx/cpu-imx25.c ++++ b/arch/arm/mach-imx/cpu-imx25.c +@@ -23,6 +23,7 @@ static int mx25_read_cpu_rev(void) + + np = of_find_compatible_node(NULL, NULL, "fsl,imx25-iim"); + iim_base = of_iomap(np, 0); ++ of_node_put(np); + BUG_ON(!iim_base); + rev = readl(iim_base + MXC_IIMSREV); + iounmap(iim_base); +diff --git a/arch/arm/mach-imx/cpu-imx27.c b/arch/arm/mach-imx/cpu-imx27.c +index a969aa71b60fc..1d28939083683 100644 +--- a/arch/arm/mach-imx/cpu-imx27.c ++++ b/arch/arm/mach-imx/cpu-imx27.c +@@ -9,6 +9,7 @@ + */ + + #include ++#include + #include + + #include "hardware.h" +@@ -17,16 +18,24 @@ static int mx27_cpu_rev = -1; + static int mx27_cpu_partnumber; + + #define SYS_CHIP_ID 0x00 /* The offset of CHIP ID register */ ++#define SYSCTRL_OFFSET 0x800 /* Offset from CCM base address */ + + static int mx27_read_cpu_rev(void) + { ++ void __iomem *ccm_base; ++ struct device_node *np; + u32 val; ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx27-ccm"); ++ ccm_base = of_iomap(np, 0); ++ of_node_put(np); ++ BUG_ON(!ccm_base); + /* + * now we have access to the IO registers. As we need + * the silicon revision very early we read it here to + * avoid any further hooks + */ +- val = imx_readl(MX27_IO_ADDRESS(MX27_SYSCTRL_BASE_ADDR + SYS_CHIP_ID)); ++ val = imx_readl(ccm_base + SYSCTRL_OFFSET + SYS_CHIP_ID); + + mx27_cpu_partnumber = (int)((val >> 12) & 0xFFFF); + +diff --git a/arch/arm/mach-imx/cpu-imx31.c b/arch/arm/mach-imx/cpu-imx31.c +index 3ee684b71006f..35c544924e509 100644 +--- a/arch/arm/mach-imx/cpu-imx31.c ++++ b/arch/arm/mach-imx/cpu-imx31.c +@@ -6,6 +6,7 @@ + */ + + #include ++#include + #include + + #include "common.h" +@@ -32,10 +33,17 @@ static struct { + + static int mx31_read_cpu_rev(void) + { ++ void __iomem *iim_base; ++ struct device_node *np; + u32 i, srev; + ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx31-iim"); ++ iim_base = of_iomap(np, 0); ++ of_node_put(np); ++ BUG_ON(!iim_base); ++ + /* read SREV register from IIM module */ +- srev = imx_readl(MX31_IO_ADDRESS(MX31_IIM_BASE_ADDR + MXC_IIMSREV)); ++ srev = imx_readl(iim_base + MXC_IIMSREV); + srev &= 0xff; + + for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++) +diff --git a/arch/arm/mach-imx/cpu-imx35.c b/arch/arm/mach-imx/cpu-imx35.c +index ebb3cdabd5068..1fe75b39c2d99 100644 +--- a/arch/arm/mach-imx/cpu-imx35.c ++++ b/arch/arm/mach-imx/cpu-imx35.c +@@ -5,6 +5,7 @@ + * Copyright (c) 2009 Daniel Mack + */ + #include ++#include + #include + + #include "hardware.h" +@@ -14,9 +15,16 @@ static int mx35_cpu_rev = -1; + + static int mx35_read_cpu_rev(void) + { ++ void __iomem *iim_base; ++ struct device_node *np; + u32 rev; + +- rev = imx_readl(MX35_IO_ADDRESS(MX35_IIM_BASE_ADDR + MXC_IIMSREV)); ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx35-iim"); ++ iim_base = of_iomap(np, 0); ++ of_node_put(np); ++ BUG_ON(!iim_base); ++ ++ rev = imx_readl(iim_base + MXC_IIMSREV); + switch (rev) { + case 0x00: + return IMX_CHIP_REVISION_1_0; +diff --git a/arch/arm/mach-imx/cpu-imx5.c b/arch/arm/mach-imx/cpu-imx5.c +index ad56263778f93..a67c89bf155dd 100644 +--- a/arch/arm/mach-imx/cpu-imx5.c ++++ b/arch/arm/mach-imx/cpu-imx5.c +@@ -28,6 +28,7 @@ static u32 imx5_read_srev_reg(const char *compat) + + np = of_find_compatible_node(NULL, NULL, compat); + iim_base = of_iomap(np, 0); ++ of_node_put(np); + WARN_ON(!iim_base); + + srev = readl(iim_base + IIM_SREV) & 0xff; +diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c +index bd0f4821f7e11..d623932437208 100644 +--- a/arch/arm/mm/fault.c ++++ b/arch/arm/mm/fault.c +@@ -124,7 +124,7 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, + show_pte(KERN_ALERT, mm, addr); + die("Oops", regs, fsr); + bust_spinlocks(0); +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + } + + /* +diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c +index a3ad8a1b0e079..74a24e6e9a2d9 100644 +--- a/arch/arm/mm/nommu.c ++++ b/arch/arm/mm/nommu.c +@@ -161,7 +161,7 @@ void __init paging_init(const struct machine_desc *mdesc) + mpu_setup(); + + /* allocate the zero page. */ +- zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE); ++ zero_page = (void *)memblock_alloc(PAGE_SIZE, PAGE_SIZE); + if (!zero_page) + panic("%s: Failed to allocate %lu bytes align=0x%lx\n", + __func__, PAGE_SIZE, PAGE_SIZE); +diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c +index 4e3e9d9c81517..a436a6972ced7 100644 +--- a/arch/arm64/kernel/traps.c ++++ b/arch/arm64/kernel/traps.c +@@ -202,7 +202,7 @@ void die(const char *str, struct pt_regs *regs, int err) + raw_spin_unlock_irqrestore(&die_lock, flags); + + if (ret != NOTIFY_STOP) +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + static void arm64_show_signal(int signo, const char *str) +diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c +index 2a7339aeb1ad4..a8e9c98147a19 100644 +--- a/arch/arm64/mm/fault.c ++++ b/arch/arm64/mm/fault.c +@@ -296,7 +296,7 @@ static void die_kernel_fault(const char *msg, unsigned long addr, + show_pte(addr); + die("Oops", regs, esr); + bust_spinlocks(0); +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + } + + static void __do_kernel_fault(unsigned long addr, unsigned int esr, +diff --git a/arch/csky/abiv1/alignment.c b/arch/csky/abiv1/alignment.c +index cb2a0d94a144d..2df115d0e2105 100644 +--- a/arch/csky/abiv1/alignment.c ++++ b/arch/csky/abiv1/alignment.c +@@ -294,7 +294,7 @@ bad_area: + __func__, opcode, rz, rx, imm, addr); + show_regs(regs); + bust_spinlocks(0); +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + } + + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr); +diff --git a/arch/csky/kernel/traps.c b/arch/csky/kernel/traps.c +index 63715cb90ee99..8cdbbcb5ed875 100644 +--- a/arch/csky/kernel/traps.c ++++ b/arch/csky/kernel/traps.c +@@ -85,7 +85,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, int nr) + pr_err("%s: %08x\n", str, nr); + show_regs(regs); + add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + void buserr(struct pt_regs *regs) +diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c +index e47a9e0dc278f..090adaee4b84c 100644 +--- a/arch/h8300/kernel/traps.c ++++ b/arch/h8300/kernel/traps.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -110,7 +111,7 @@ void die(const char *str, struct pt_regs *fp, unsigned long err) + dump(fp); + + spin_unlock_irq(&die_lock); +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + static int kstack_depth_to_print = 24; +diff --git a/arch/h8300/mm/fault.c b/arch/h8300/mm/fault.c +index fabffb83930af..573825c3cb708 100644 +--- a/arch/h8300/mm/fault.c ++++ b/arch/h8300/mm/fault.c +@@ -52,7 +52,7 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + printk(" at virtual address %08lx\n", address); + if (!user_mode(regs)) + die("Oops", regs, error_code); +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + + return 1; + } +diff --git a/arch/hexagon/kernel/traps.c b/arch/hexagon/kernel/traps.c +index 69c623b14ddd2..f69eae3f32bd2 100644 +--- a/arch/hexagon/kernel/traps.c ++++ b/arch/hexagon/kernel/traps.c +@@ -221,7 +221,7 @@ int die(const char *str, struct pt_regs *regs, long err) + panic("Fatal exception"); + + oops_exit(); +- do_exit(err); ++ make_task_dead(err); + return 0; + } + +diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig +index 16714477eef42..6a6036f16abe6 100644 +--- a/arch/ia64/Kconfig ++++ b/arch/ia64/Kconfig +@@ -360,7 +360,7 @@ config ARCH_PROC_KCORE_TEXT + depends on PROC_KCORE + + config IA64_MCA_RECOVERY +- tristate "MCA recovery from errors other than TLB." ++ bool "MCA recovery from errors other than TLB." + + config PERFMON + bool "Performance monitor support" +diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c +index 2a40268c3d494..c8a87798618ed 100644 +--- a/arch/ia64/kernel/mca_drv.c ++++ b/arch/ia64/kernel/mca_drv.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -176,7 +177,7 @@ mca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr) + spin_unlock(&mca_bh_lock); + + /* This process is about to be killed itself */ +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + } + + /** +diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c +index e13cb905930fb..753642366e12e 100644 +--- a/arch/ia64/kernel/traps.c ++++ b/arch/ia64/kernel/traps.c +@@ -85,7 +85,7 @@ die (const char *str, struct pt_regs *regs, long err) + if (panic_on_oops) + panic("Fatal exception"); + +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + return 0; + } + +diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c +index c2f299fe9e04a..7f8c49579a2c2 100644 +--- a/arch/ia64/mm/fault.c ++++ b/arch/ia64/mm/fault.c +@@ -272,7 +272,7 @@ retry: + regs = NULL; + bust_spinlocks(0); + if (regs) +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + return; + + out_of_memory: +diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c +index 344f93d36a9a0..a245c1933d418 100644 +--- a/arch/m68k/kernel/traps.c ++++ b/arch/m68k/kernel/traps.c +@@ -1139,7 +1139,7 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr) + pr_crit("%s: %08x\n", str, nr); + show_registers(fp); + add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + asmlinkage void set_esp0(unsigned long ssp) +diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c +index e9b1d7585b43b..03ebb67b413ef 100644 +--- a/arch/m68k/mm/fault.c ++++ b/arch/m68k/mm/fault.c +@@ -48,7 +48,7 @@ int send_fault_sig(struct pt_regs *regs) + pr_alert("Unable to handle kernel access"); + pr_cont(" at virtual address %p\n", addr); + die_if_kernel("Oops", regs, 0 /*error_code*/); +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + } + + return 1; +diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c +index cf99c411503e3..6d3a6a6442205 100644 +--- a/arch/microblaze/kernel/exceptions.c ++++ b/arch/microblaze/kernel/exceptions.c +@@ -44,10 +44,10 @@ void die(const char *str, struct pt_regs *fp, long err) + pr_warn("Oops: %s, sig: %ld\n", str, err); + show_regs(fp); + spin_unlock_irq(&die_lock); +- /* do_exit() should take care of panic'ing from an interrupt ++ /* make_task_dead() should take care of panic'ing from an interrupt + * context so we don't handle it here + */ +- do_exit(err); ++ make_task_dead(err); + } + + /* for user application debugging */ +diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c +index 749089c25d5e6..5a491eca456fc 100644 +--- a/arch/mips/kernel/traps.c ++++ b/arch/mips/kernel/traps.c +@@ -415,7 +415,7 @@ void __noreturn die(const char *str, struct pt_regs *regs) + if (regs && kexec_should_crash(current)) + crash_kexec(regs); + +- do_exit(sig); ++ make_task_dead(sig); + } + + extern struct exception_table_entry __start___dbe_table[]; +diff --git a/arch/nds32/kernel/fpu.c b/arch/nds32/kernel/fpu.c +index 62bdafbc53f4c..26c62d5a55c15 100644 +--- a/arch/nds32/kernel/fpu.c ++++ b/arch/nds32/kernel/fpu.c +@@ -223,7 +223,7 @@ inline void handle_fpu_exception(struct pt_regs *regs) + } + } else if (fpcsr & FPCSR_mskRIT) { + if (!user_mode(regs)) +- do_exit(SIGILL); ++ make_task_dead(SIGILL); + si_signo = SIGILL; + } + +diff --git a/arch/nds32/kernel/traps.c b/arch/nds32/kernel/traps.c +index f4d386b526227..f6648845aae76 100644 +--- a/arch/nds32/kernel/traps.c ++++ b/arch/nds32/kernel/traps.c +@@ -184,7 +184,7 @@ void die(const char *str, struct pt_regs *regs, int err) + + bust_spinlocks(0); + spin_unlock_irq(&die_lock); +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + EXPORT_SYMBOL(die); +@@ -288,7 +288,7 @@ void unhandled_interruption(struct pt_regs *regs) + pr_emerg("unhandled_interruption\n"); + show_regs(regs); + if (!user_mode(regs)) +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + force_sig(SIGKILL); + } + +@@ -299,7 +299,7 @@ void unhandled_exceptions(unsigned long entry, unsigned long addr, + addr, type); + show_regs(regs); + if (!user_mode(regs)) +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + force_sig(SIGKILL); + } + +@@ -326,7 +326,7 @@ void do_revinsn(struct pt_regs *regs) + pr_emerg("Reserved Instruction\n"); + show_regs(regs); + if (!user_mode(regs)) +- do_exit(SIGILL); ++ make_task_dead(SIGILL); + force_sig(SIGILL); + } + +diff --git a/arch/nios2/kernel/traps.c b/arch/nios2/kernel/traps.c +index 486db793923c0..8e192d6564261 100644 +--- a/arch/nios2/kernel/traps.c ++++ b/arch/nios2/kernel/traps.c +@@ -37,10 +37,10 @@ void die(const char *str, struct pt_regs *regs, long err) + show_regs(regs); + spin_unlock_irq(&die_lock); + /* +- * do_exit() should take care of panic'ing from an interrupt ++ * make_task_dead() should take care of panic'ing from an interrupt + * context so we don't handle it here + */ +- do_exit(err); ++ make_task_dead(err); + } + + void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr) +diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c +index 932a8ec2b520e..2804852a55924 100644 +--- a/arch/openrisc/kernel/traps.c ++++ b/arch/openrisc/kernel/traps.c +@@ -218,7 +218,7 @@ void die(const char *str, struct pt_regs *regs, long err) + __asm__ __volatile__("l.nop 1"); + do {} while (1); + #endif +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + /* This is normally the 'Oops' routine */ +diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c +index 2a1060d747a5d..37988f7f3abcb 100644 +--- a/arch/parisc/kernel/traps.c ++++ b/arch/parisc/kernel/traps.c +@@ -268,7 +268,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) + panic("Fatal exception"); + + oops_exit(); +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + /* gdb uses break 4,8 */ +diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c +index ecfa460f66d17..70b99246dec46 100644 +--- a/arch/powerpc/kernel/traps.c ++++ b/arch/powerpc/kernel/traps.c +@@ -246,7 +246,7 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, + + if (panic_on_oops) + panic("Fatal exception"); +- do_exit(signr); ++ make_task_dead(signr); + } + NOKPROBE_SYMBOL(oops_end); + +diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c +index ae462037910be..c28d4debf5926 100644 +--- a/arch/riscv/kernel/traps.c ++++ b/arch/riscv/kernel/traps.c +@@ -57,7 +57,7 @@ void die(struct pt_regs *regs, const char *str) + if (panic_on_oops) + panic("Fatal exception"); + if (ret != NOTIFY_STOP) +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr) +diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c +index 247b8c859c448..1cfce62caa119 100644 +--- a/arch/riscv/mm/fault.c ++++ b/arch/riscv/mm/fault.c +@@ -189,7 +189,7 @@ no_context: + (addr < PAGE_SIZE) ? "NULL pointer dereference" : + "paging request", addr); + die(regs, "Oops"); +- do_exit(SIGKILL); ++ make_task_dead(SIGKILL); + + /* + * We ran out of memory, call the OOM killer, and return the userspace +diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h +index 3101340155417..54f4bc5d1108b 100644 +--- a/arch/s390/include/asm/debug.h ++++ b/arch/s390/include/asm/debug.h +@@ -4,8 +4,8 @@ + * + * Copyright IBM Corp. 1999, 2000 + */ +-#ifndef DEBUG_H +-#define DEBUG_H ++#ifndef _ASM_S390_DEBUG_H ++#define _ASM_S390_DEBUG_H + + #include + #include +@@ -416,4 +416,4 @@ int debug_unregister_view(debug_info_t *id, struct debug_view *view); + #define PRINT_FATAL(x...) printk(KERN_DEBUG PRINTK_HEADER x) + #endif /* DASD_DEBUG */ + +-#endif /* DEBUG_H */ ++#endif /* _ASM_S390_DEBUG_H */ +diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c +index 34bdc60c0b11d..2100833adfb69 100644 +--- a/arch/s390/kernel/dumpstack.c ++++ b/arch/s390/kernel/dumpstack.c +@@ -210,5 +210,5 @@ void die(struct pt_regs *regs, const char *str) + if (panic_on_oops) + panic("Fatal exception: panic_on_oops"); + oops_exit(); +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } +diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c +index 0a487fae763ee..d8951274658bd 100644 +--- a/arch/s390/kernel/nmi.c ++++ b/arch/s390/kernel/nmi.c +@@ -179,7 +179,7 @@ void s390_handle_mcck(void) + "malfunction (code 0x%016lx).\n", mcck.mcck_code); + printk(KERN_EMERG "mcck: task: %s, pid: %d.\n", + current->comm, current->pid); +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + } + EXPORT_SYMBOL_GPL(s390_handle_mcck); +diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c +index 8be5750fe5ac3..a180fe54dc687 100644 +--- a/arch/s390/kvm/interrupt.c ++++ b/arch/s390/kvm/interrupt.c +@@ -81,8 +81,9 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id) + struct esca_block *sca = vcpu->kvm->arch.sca; + union esca_sigp_ctrl *sigp_ctrl = + &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); +- union esca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl; ++ union esca_sigp_ctrl new_val = {0}, old_val; + ++ old_val = READ_ONCE(*sigp_ctrl); + new_val.scn = src_id; + new_val.c = 1; + old_val.c = 0; +@@ -93,8 +94,9 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id) + struct bsca_block *sca = vcpu->kvm->arch.sca; + union bsca_sigp_ctrl *sigp_ctrl = + &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); +- union bsca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl; ++ union bsca_sigp_ctrl new_val = {0}, old_val; + ++ old_val = READ_ONCE(*sigp_ctrl); + new_val.scn = src_id; + new_val.c = 1; + old_val.c = 0; +@@ -124,16 +126,18 @@ static void sca_clear_ext_call(struct kvm_vcpu *vcpu) + struct esca_block *sca = vcpu->kvm->arch.sca; + union esca_sigp_ctrl *sigp_ctrl = + &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); +- union esca_sigp_ctrl old = *sigp_ctrl; ++ union esca_sigp_ctrl old; + ++ old = READ_ONCE(*sigp_ctrl); + expect = old.value; + rc = cmpxchg(&sigp_ctrl->value, old.value, 0); + } else { + struct bsca_block *sca = vcpu->kvm->arch.sca; + union bsca_sigp_ctrl *sigp_ctrl = + &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); +- union bsca_sigp_ctrl old = *sigp_ctrl; ++ union bsca_sigp_ctrl old; + ++ old = READ_ONCE(*sigp_ctrl); + expect = old.value; + rc = cmpxchg(&sigp_ctrl->value, old.value, 0); + } +diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c +index 63cf17bc760da..6a228c00b73f4 100644 +--- a/arch/sh/kernel/traps.c ++++ b/arch/sh/kernel/traps.c +@@ -57,7 +57,7 @@ void die(const char *str, struct pt_regs *regs, long err) + if (panic_on_oops) + panic("Fatal exception"); + +- do_exit(SIGSEGV); ++ make_task_dead(SIGSEGV); + } + + void die_if_kernel(const char *str, struct pt_regs *regs, long err) +diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c +index 4ceecad556a9f..dbf068ac54ff3 100644 +--- a/arch/sparc/kernel/traps_32.c ++++ b/arch/sparc/kernel/traps_32.c +@@ -86,9 +86,7 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs) + } + printk("Instruction DUMP:"); + instruction_dump ((unsigned long *) regs->pc); +- if(regs->psr & PSR_PS) +- do_exit(SIGKILL); +- do_exit(SIGSEGV); ++ make_task_dead((regs->psr & PSR_PS) ? SIGKILL : SIGSEGV); + } + + void do_hw_interrupt(struct pt_regs *regs, unsigned long type) +diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c +index f2b22c496fb97..17768680cbaeb 100644 +--- a/arch/sparc/kernel/traps_64.c ++++ b/arch/sparc/kernel/traps_64.c +@@ -2564,9 +2564,7 @@ void __noreturn die_if_kernel(char *str, struct pt_regs *regs) + } + if (panic_on_oops) + panic("Fatal exception"); +- if (regs->tstate & TSTATE_PRIV) +- do_exit(SIGKILL); +- do_exit(SIGSEGV); ++ make_task_dead((regs->tstate & TSTATE_PRIV)? SIGKILL : SIGSEGV); + } + EXPORT_SYMBOL(die_if_kernel); + +diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S +index 2d837fb54c31b..740df9cc21963 100644 +--- a/arch/x86/entry/entry_32.S ++++ b/arch/x86/entry/entry_32.S +@@ -1659,13 +1659,13 @@ ENTRY(async_page_fault) + END(async_page_fault) + #endif + +-ENTRY(rewind_stack_do_exit) ++ENTRY(rewind_stack_and_make_dead) + /* Prevent any naive code from trying to unwind to our caller. */ + xorl %ebp, %ebp + + movl PER_CPU_VAR(cpu_current_top_of_stack), %esi + leal -TOP_OF_KERNEL_STACK_PADDING-PTREGS_SIZE(%esi), %esp + +- call do_exit ++ call make_task_dead + 1: jmp 1b +-END(rewind_stack_do_exit) ++END(rewind_stack_and_make_dead) +diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S +index c82136030d58f..bd7a4ad0937c4 100644 +--- a/arch/x86/entry/entry_64.S ++++ b/arch/x86/entry/entry_64.S +@@ -1757,7 +1757,7 @@ ENTRY(ignore_sysret) + END(ignore_sysret) + #endif + +-ENTRY(rewind_stack_do_exit) ++ENTRY(rewind_stack_and_make_dead) + UNWIND_HINT_FUNC + /* Prevent any naive code from trying to unwind to our caller. */ + xorl %ebp, %ebp +@@ -1766,5 +1766,5 @@ ENTRY(rewind_stack_do_exit) + leaq -PTREGS_SIZE(%rax), %rsp + UNWIND_HINT_REGS + +- call do_exit +-END(rewind_stack_do_exit) ++ call make_task_dead ++END(rewind_stack_and_make_dead) +diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c +index 3ea8056148d84..c3555e5237cf6 100644 +--- a/arch/x86/events/amd/core.c ++++ b/arch/x86/events/amd/core.c +@@ -969,7 +969,7 @@ static int __init amd_core_pmu_init(void) + * numbered counter following it. + */ + for (i = 0; i < x86_pmu.num_counters - 1; i += 2) +- even_ctr_mask |= 1 << i; ++ even_ctr_mask |= BIT_ULL(i); + + pair_constraint = (struct event_constraint) + __EVENT_CONSTRAINT(0, even_ctr_mask, 0, +diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c +index e07424e19274b..e72042dc9487c 100644 +--- a/arch/x86/kernel/dumpstack.c ++++ b/arch/x86/kernel/dumpstack.c +@@ -326,7 +326,7 @@ unsigned long oops_begin(void) + } + NOKPROBE_SYMBOL(oops_begin); + +-void __noreturn rewind_stack_do_exit(int signr); ++void __noreturn rewind_stack_and_make_dead(int signr); + + void oops_end(unsigned long flags, struct pt_regs *regs, int signr) + { +@@ -361,7 +361,7 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr) + * reuse the task stack and that existing poisons are invalid. + */ + kasan_unpoison_task_stack(current); +- rewind_stack_do_exit(signr); ++ rewind_stack_and_make_dead(signr); + } + NOKPROBE_SYMBOL(oops_end); + +diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c +index fe522691ac717..8821d0ab0a08c 100644 +--- a/arch/x86/kernel/i8259.c ++++ b/arch/x86/kernel/i8259.c +@@ -114,6 +114,7 @@ static void make_8259A_irq(unsigned int irq) + disable_irq_nosync(irq); + io_apic_irqs &= ~(1<init(0); + +- for (i = 0; i < nr_legacy_irqs(); i++) ++ for (i = 0; i < nr_legacy_irqs(); i++) { + irq_set_chip_and_handler(i, chip, handle_level_irq); ++ irq_set_status_flags(i, IRQ_LEVEL); ++ } + } + + void __init init_IRQ(void) +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index df77207d93b06..a8c8073654cf1 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -3241,18 +3241,15 @@ static u32 vmx_segment_access_rights(struct kvm_segment *var) + { + u32 ar; + +- if (var->unusable || !var->present) +- ar = 1 << 16; +- else { +- ar = var->type & 15; +- ar |= (var->s & 1) << 4; +- ar |= (var->dpl & 3) << 5; +- ar |= (var->present & 1) << 7; +- ar |= (var->avl & 1) << 12; +- ar |= (var->l & 1) << 13; +- ar |= (var->db & 1) << 14; +- ar |= (var->g & 1) << 15; +- } ++ ar = var->type & 15; ++ ar |= (var->s & 1) << 4; ++ ar |= (var->dpl & 3) << 5; ++ ar |= (var->present & 1) << 7; ++ ar |= (var->avl & 1) << 12; ++ ar |= (var->l & 1) << 13; ++ ar |= (var->db & 1) << 14; ++ ar |= (var->g & 1) << 15; ++ ar |= (var->unusable || !var->present) << 16; + + return ar; + } +diff --git a/arch/x86/lib/iomap_copy_64.S b/arch/x86/lib/iomap_copy_64.S +index a9bdf0805be04..1329d7ca05b5f 100644 +--- a/arch/x86/lib/iomap_copy_64.S ++++ b/arch/x86/lib/iomap_copy_64.S +@@ -10,6 +10,6 @@ + */ + ENTRY(__iowrite32_copy) + movl %edx,%ecx +- rep movsd ++ rep movsl + ret + ENDPROC(__iowrite32_copy) +diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c +index 4a6c495ce9b6d..16af8e514cb3b 100644 +--- a/arch/xtensa/kernel/traps.c ++++ b/arch/xtensa/kernel/traps.c +@@ -543,5 +543,5 @@ void die(const char * str, struct pt_regs * regs, long err) + if (panic_on_oops) + panic("Fatal exception"); + +- do_exit(err); ++ make_task_dead(err); + } +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index dde8d0acfb34f..cd085a0e5e4a7 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -1445,6 +1445,10 @@ retry: + list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) + pol->pd_init_fn(blkg->pd[pol->plid]); + ++ if (pol->pd_online_fn) ++ list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) ++ pol->pd_online_fn(blkg->pd[pol->plid]); ++ + __set_bit(pol->plid, q->blkcg_pols); + ret = 0; + +diff --git a/block/blk-core.c b/block/blk-core.c +index 5808baa950c35..030de4fdf9b1d 100644 +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -793,10 +793,7 @@ static inline bool bio_check_ro(struct bio *bio, struct hd_struct *part) + + if (op_is_flush(bio->bi_opf) && !bio_sectors(bio)) + return false; +- +- WARN_ONCE(1, +- "generic_make_request: Trying to write " +- "to read-only block-device %s (partno %d)\n", ++ pr_warn("Trying to write to read-only block-device %s (partno %d)\n", + bio_devname(bio, b), part->partno); + /* Older lvm-tools actually trigger this */ + return false; +diff --git a/drivers/base/test/test_async_driver_probe.c b/drivers/base/test/test_async_driver_probe.c +index 3bb7beb127a96..c157a912d6739 100644 +--- a/drivers/base/test/test_async_driver_probe.c ++++ b/drivers/base/test/test_async_driver_probe.c +@@ -146,7 +146,7 @@ static int __init test_async_probe_init(void) + calltime = ktime_get(); + for_each_online_cpu(cpu) { + nid = cpu_to_node(cpu); +- pdev = &sync_dev[sync_id]; ++ pdev = &async_dev[async_id]; + + *pdev = test_platform_device_register_node("test_async_driver", + async_id, +diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c +index f9d5b73343417..4fb4fd4b06bda 100644 +--- a/drivers/clk/clk-devres.c ++++ b/drivers/clk/clk-devres.c +@@ -4,42 +4,101 @@ + #include + #include + ++struct devm_clk_state { ++ struct clk *clk; ++ void (*exit)(struct clk *clk); ++}; ++ + static void devm_clk_release(struct device *dev, void *res) + { +- clk_put(*(struct clk **)res); ++ struct devm_clk_state *state = res; ++ ++ if (state->exit) ++ state->exit(state->clk); ++ ++ clk_put(state->clk); + } + +-struct clk *devm_clk_get(struct device *dev, const char *id) ++static struct clk *__devm_clk_get(struct device *dev, const char *id, ++ struct clk *(*get)(struct device *dev, const char *id), ++ int (*init)(struct clk *clk), ++ void (*exit)(struct clk *clk)) + { +- struct clk **ptr, *clk; ++ struct devm_clk_state *state; ++ struct clk *clk; ++ int ret; + +- ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); +- if (!ptr) ++ state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL); ++ if (!state) + return ERR_PTR(-ENOMEM); + +- clk = clk_get(dev, id); +- if (!IS_ERR(clk)) { +- *ptr = clk; +- devres_add(dev, ptr); +- } else { +- devres_free(ptr); ++ clk = get(dev, id); ++ if (IS_ERR(clk)) { ++ ret = PTR_ERR(clk); ++ goto err_clk_get; + } + ++ if (init) { ++ ret = init(clk); ++ if (ret) ++ goto err_clk_init; ++ } ++ ++ state->clk = clk; ++ state->exit = exit; ++ ++ devres_add(dev, state); ++ + return clk; ++ ++err_clk_init: ++ ++ clk_put(clk); ++err_clk_get: ++ ++ devres_free(state); ++ return ERR_PTR(ret); ++} ++ ++struct clk *devm_clk_get(struct device *dev, const char *id) ++{ ++ return __devm_clk_get(dev, id, clk_get, NULL, NULL); + } + EXPORT_SYMBOL(devm_clk_get); + +-struct clk *devm_clk_get_optional(struct device *dev, const char *id) ++struct clk *devm_clk_get_prepared(struct device *dev, const char *id) + { +- struct clk *clk = devm_clk_get(dev, id); ++ return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare); ++} ++EXPORT_SYMBOL_GPL(devm_clk_get_prepared); + +- if (clk == ERR_PTR(-ENOENT)) +- return NULL; ++struct clk *devm_clk_get_enabled(struct device *dev, const char *id) ++{ ++ return __devm_clk_get(dev, id, clk_get, ++ clk_prepare_enable, clk_disable_unprepare); ++} ++EXPORT_SYMBOL_GPL(devm_clk_get_enabled); + +- return clk; ++struct clk *devm_clk_get_optional(struct device *dev, const char *id) ++{ ++ return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL); + } + EXPORT_SYMBOL(devm_clk_get_optional); + ++struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id) ++{ ++ return __devm_clk_get(dev, id, clk_get_optional, ++ clk_prepare, clk_unprepare); ++} ++EXPORT_SYMBOL_GPL(devm_clk_get_optional_prepared); ++ ++struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id) ++{ ++ return __devm_clk_get(dev, id, clk_get_optional, ++ clk_prepare_enable, clk_disable_unprepare); ++} ++EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled); ++ + struct clk_bulk_devres { + struct clk_bulk_data *clks; + int num_clks; +diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c +index 2de7fd18f66a1..f0be8a43ec496 100644 +--- a/drivers/cpufreq/armada-37xx-cpufreq.c ++++ b/drivers/cpufreq/armada-37xx-cpufreq.c +@@ -443,7 +443,7 @@ static int __init armada37xx_cpufreq_driver_init(void) + return -ENODEV; + } + +- clk = clk_get(cpu_dev, 0); ++ clk = clk_get(cpu_dev, NULL); + if (IS_ERR(clk)) { + dev_err(cpu_dev, "Cannot get clock for CPU0\n"); + return PTR_ERR(clk); +diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c +index 1200842c3da42..5d28553b69f5b 100644 +--- a/drivers/cpufreq/cpufreq-dt-platdev.c ++++ b/drivers/cpufreq/cpufreq-dt-platdev.c +@@ -126,6 +126,7 @@ static const struct of_device_id blacklist[] __initconst = { + + { .compatible = "nvidia,tegra124", }, + { .compatible = "nvidia,tegra210", }, ++ { .compatible = "nvidia,tegra234", }, + + { .compatible = "qcom,apq8096", }, + { .compatible = "qcom,msm8996", }, +diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c +index 4b604086b1b3a..a8996faa85a9f 100644 +--- a/drivers/dma/dmaengine.c ++++ b/drivers/dma/dmaengine.c +@@ -212,7 +212,8 @@ static int dma_chan_get(struct dma_chan *chan) + /* The channel is already in use, update client count */ + if (chan->client_count) { + __module_get(owner); +- goto out; ++ chan->client_count++; ++ return 0; + } + + if (!try_module_get(owner)) +@@ -225,11 +226,11 @@ static int dma_chan_get(struct dma_chan *chan) + goto err_out; + } + ++ chan->client_count++; ++ + if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) + balance_ref_count(chan); + +-out: +- chan->client_count++; + return 0; + + err_out: +diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c +index 8ec7a7041e840..8dbff2f6c3b8d 100644 +--- a/drivers/dma/imx-sdma.c ++++ b/drivers/dma/imx-sdma.c +@@ -1360,10 +1360,12 @@ static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac, + sdma_config_ownership(sdmac, false, true, false); + + if (sdma_load_context(sdmac)) +- goto err_desc_out; ++ goto err_bd_out; + + return desc; + ++err_bd_out: ++ sdma_free_bd(desc); + err_desc_out: + kfree(desc); + err_out: +diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c +index 3bb711e735ab9..be44c86a1e037 100644 +--- a/drivers/dma/xilinx/xilinx_dma.c ++++ b/drivers/dma/xilinx/xilinx_dma.c +@@ -2626,7 +2626,6 @@ static int xilinx_dma_probe(struct platform_device *pdev) + struct device_node *node = pdev->dev.of_node; + struct xilinx_dma_device *xdev; + struct device_node *child, *np = pdev->dev.of_node; +- struct resource *io; + u32 num_frames, addr_width, len_width; + int i, err; + +@@ -2652,11 +2651,11 @@ static int xilinx_dma_probe(struct platform_device *pdev) + return err; + + /* Request and map I/O memory */ +- io = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- xdev->regs = devm_ioremap_resource(&pdev->dev, io); +- if (IS_ERR(xdev->regs)) +- return PTR_ERR(xdev->regs); +- ++ xdev->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(xdev->regs)) { ++ err = PTR_ERR(xdev->regs); ++ goto disable_clks; ++ } + /* Retrieve the DMA engine properties from the device tree */ + xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0); + +@@ -2748,8 +2747,10 @@ static int xilinx_dma_probe(struct platform_device *pdev) + /* Initialize the channels */ + for_each_child_of_node(node, child) { + err = xilinx_dma_child_probe(xdev, child); +- if (err < 0) +- goto disable_clks; ++ if (err < 0) { ++ of_node_put(child); ++ goto error; ++ } + } + + if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { +@@ -2782,12 +2783,12 @@ static int xilinx_dma_probe(struct platform_device *pdev) + + return 0; + +-disable_clks: +- xdma_disable_allclks(xdev); + error: + for (i = 0; i < xdev->nr_channels; i++) + if (xdev->chan[i]) + xilinx_dma_chan_remove(xdev->chan[i]); ++disable_clks: ++ xdma_disable_allclks(xdev); + + return err; + } +diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c +index 93d6e6319b3cc..0ac6c49ecdbf4 100644 +--- a/drivers/edac/edac_device.c ++++ b/drivers/edac/edac_device.c +@@ -34,6 +34,9 @@ + static DEFINE_MUTEX(device_ctls_mutex); + static LIST_HEAD(edac_device_list); + ++/* Default workqueue processing interval on this instance, in msecs */ ++#define DEFAULT_POLL_INTERVAL 1000 ++ + #ifdef CONFIG_EDAC_DEBUG + static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) + { +@@ -366,7 +369,7 @@ static void edac_device_workq_function(struct work_struct *work_req) + * whole one second to save timers firing all over the period + * between integral seconds + */ +- if (edac_dev->poll_msec == 1000) ++ if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL) + edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay)); + else + edac_queue_work(&edac_dev->work, edac_dev->delay); +@@ -396,7 +399,7 @@ static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, + * timers firing on sub-second basis, while they are happy + * to fire together on the 1 second exactly + */ +- if (edac_dev->poll_msec == 1000) ++ if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL) + edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay)); + else + edac_queue_work(&edac_dev->work, edac_dev->delay); +@@ -430,7 +433,7 @@ void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, + edac_dev->delay = msecs_to_jiffies(msec); + + /* See comment in edac_device_workq_setup() above */ +- if (edac_dev->poll_msec == 1000) ++ if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL) + edac_mod_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay)); + else + edac_mod_work(&edac_dev->work, edac_dev->delay); +@@ -472,11 +475,7 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev) + /* This instance is NOW RUNNING */ + edac_dev->op_state = OP_RUNNING_POLL; + +- /* +- * enable workq processing on this instance, +- * default = 1000 msec +- */ +- edac_device_workq_setup(edac_dev, 1000); ++ edac_device_workq_setup(edac_dev, edac_dev->poll_msec ?: DEFAULT_POLL_INTERVAL); + } else { + edac_dev->op_state = OP_RUNNING_INTERRUPT; + } +diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c +index 61b76ec226af1..19fba258ae108 100644 +--- a/drivers/edac/highbank_mc_edac.c ++++ b/drivers/edac/highbank_mc_edac.c +@@ -174,8 +174,10 @@ static int highbank_mc_probe(struct platform_device *pdev) + drvdata = mci->pvt_info; + platform_set_drvdata(pdev, mci); + +- if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) +- return -ENOMEM; ++ if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { ++ res = -ENOMEM; ++ goto free; ++ } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { +@@ -243,6 +245,7 @@ err2: + edac_mc_del_mc(&pdev->dev); + err: + devres_release_group(&pdev->dev, NULL); ++free: + edac_mc_free(mci); + return res; + } +diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c +index 97a27e42dd610..c45519f59dc11 100644 +--- a/drivers/edac/qcom_edac.c ++++ b/drivers/edac/qcom_edac.c +@@ -252,7 +252,7 @@ clear: + static int + dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank) + { +- struct llcc_drv_data *drv = edev_ctl->pvt_info; ++ struct llcc_drv_data *drv = edev_ctl->dev->platform_data; + int ret; + + ret = dump_syn_reg_values(drv, bank, err_type); +@@ -289,7 +289,7 @@ static irqreturn_t + llcc_ecc_irq_handler(int irq, void *edev_ctl) + { + struct edac_device_ctl_info *edac_dev_ctl = edev_ctl; +- struct llcc_drv_data *drv = edac_dev_ctl->pvt_info; ++ struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data; + irqreturn_t irq_rc = IRQ_NONE; + u32 drp_error, trp_error, i; + int ret; +@@ -358,7 +358,6 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev) + edev_ctl->dev_name = dev_name(dev); + edev_ctl->ctl_name = "llcc"; + edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE; +- edev_ctl->pvt_info = llcc_driv_data; + + rc = edac_device_add_device(edev_ctl); + if (rc) +diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c +index c77d474185f31..2e4b6b176875d 100644 +--- a/drivers/gpio/gpio-mxc.c ++++ b/drivers/gpio/gpio-mxc.c +@@ -229,7 +229,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) + + writel(1 << gpio_idx, port->base + GPIO_ISR); + +- return 0; ++ return port->gc.direction_input(&port->gc, gpio_idx); + } + + static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) +diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c +index ca0fefeaab20b..ce739ba45c551 100644 +--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c ++++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c +@@ -272,6 +272,12 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGM"), + }, + .driver_data = (void *)&lcd1200x1920_rightside_up, ++ }, { /* Lenovo Ideapad D330-10IGL (HD) */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGL"), ++ }, ++ .driver_data = (void *)&lcd800x1280_rightside_up, + }, { /* Lenovo Yoga Book X90F / X91F / X91L */ + .matches = { + /* Non exact match to match all versions */ +diff --git a/drivers/gpu/drm/panfrost/Kconfig b/drivers/gpu/drm/panfrost/Kconfig +index 86cdc0ce79e65..77f4d32e52045 100644 +--- a/drivers/gpu/drm/panfrost/Kconfig ++++ b/drivers/gpu/drm/panfrost/Kconfig +@@ -3,7 +3,8 @@ + config DRM_PANFROST + tristate "Panfrost (DRM support for ARM Mali Midgard/Bifrost GPUs)" + depends on DRM +- depends on ARM || ARM64 || (COMPILE_TEST && !GENERIC_ATOMIC64) ++ depends on ARM || ARM64 || COMPILE_TEST ++ depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE + depends on MMU + select DRM_SCHED + select IOMMU_SUPPORT +diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c +index 467d789f9bc2d..25ed7b9a917e4 100644 +--- a/drivers/hid/hid-betopff.c ++++ b/drivers/hid/hid-betopff.c +@@ -60,7 +60,6 @@ static int betopff_init(struct hid_device *hid) + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev; +- int field_count = 0; + int error; + int i, j; + +@@ -86,19 +85,21 @@ static int betopff_init(struct hid_device *hid) + * ----------------------------------------- + * Do init them with default value. + */ ++ if (report->maxfield < 4) { ++ hid_err(hid, "not enough fields in the report: %d\n", ++ report->maxfield); ++ return -ENODEV; ++ } + for (i = 0; i < report->maxfield; i++) { ++ if (report->field[i]->report_count < 1) { ++ hid_err(hid, "no values in the field\n"); ++ return -ENODEV; ++ } + for (j = 0; j < report->field[i]->report_count; j++) { + report->field[i]->value[j] = 0x00; +- field_count++; + } + } + +- if (field_count < 4) { +- hid_err(hid, "not enough fields in the report: %d\n", +- field_count); +- return -ENODEV; +- } +- + betopff = kzalloc(sizeof(*betopff), GFP_KERNEL); + if (!betopff) + return -ENOMEM; +diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c +index e8c5e3ac9fff1..e8b16665860d6 100644 +--- a/drivers/hid/hid-bigbenff.c ++++ b/drivers/hid/hid-bigbenff.c +@@ -344,6 +344,11 @@ static int bigben_probe(struct hid_device *hid, + } + + report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; ++ if (list_empty(report_list)) { ++ hid_err(hid, "no output report found\n"); ++ error = -ENODEV; ++ goto error_hw_stop; ++ } + bigben->report = list_entry(report_list->next, + struct hid_report, list); + +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index eda96c92977b3..2888bd5502f3f 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -981,8 +981,8 @@ struct hid_report *hid_validate_values(struct hid_device *hid, + * Validating on id 0 means we should examine the first + * report in the list. + */ +- report = list_entry( +- hid->report_enum[type].report_list.next, ++ report = list_first_entry_or_null( ++ &hid->report_enum[type].report_list, + struct hid_report, list); + } else { + report = hid->report_enum[type].report_id_hash[id]; +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 222f525c3d045..1c034c397e3e7 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -259,7 +259,6 @@ + #define USB_DEVICE_ID_CH_AXIS_295 0x001c + + #define USB_VENDOR_ID_CHERRY 0x046a +-#define USB_DEVICE_ID_CHERRY_MOUSE_000C 0x000c + #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 + #define USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR 0x0027 + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index baad65fcdff70..e5dcc47586ee4 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -54,7 +54,6 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE), HID_QUIRK_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS), HID_QUIRK_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE), HID_QUIRK_NOGET }, +- { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_MOUSE_000C), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB), HID_QUIRK_NO_INIT_REPORTS }, +diff --git a/drivers/hid/intel-ish-hid/ishtp/dma-if.c b/drivers/hid/intel-ish-hid/ishtp/dma-if.c +index 40554c8daca07..00046cbfd4ed0 100644 +--- a/drivers/hid/intel-ish-hid/ishtp/dma-if.c ++++ b/drivers/hid/intel-ish-hid/ishtp/dma-if.c +@@ -104,6 +104,11 @@ void *ishtp_cl_get_dma_send_buf(struct ishtp_device *dev, + int required_slots = (size / DMA_SLOT_SIZE) + + 1 * (size % DMA_SLOT_SIZE != 0); + ++ if (!dev->ishtp_dma_tx_map) { ++ dev_err(dev->devc, "Fail to allocate Tx map\n"); ++ return NULL; ++ } ++ + spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags); + for (i = 0; i <= (dev->ishtp_dma_num_slots - required_slots); i++) { + free = 1; +@@ -150,6 +155,11 @@ void ishtp_cl_release_dma_acked_mem(struct ishtp_device *dev, + return; + } + ++ if (!dev->ishtp_dma_tx_map) { ++ dev_err(dev->devc, "Fail to allocate Tx map\n"); ++ return; ++ } ++ + i = (msg_addr - dev->ishtp_host_dma_tx_buf) / DMA_SLOT_SIZE; + spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags); + for (j = 0; j < acked_slots; j++) { +diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c +index 5d896f6b2b617..93a7ff1bd02c7 100644 +--- a/drivers/infiniband/core/verbs.c ++++ b/drivers/infiniband/core/verbs.c +@@ -2840,15 +2840,18 @@ EXPORT_SYMBOL(__rdma_block_iter_start); + bool __rdma_block_iter_next(struct ib_block_iter *biter) + { + unsigned int block_offset; ++ unsigned int sg_delta; + + if (!biter->__sg_nents || !biter->__sg) + return false; + + biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance; + block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1); +- biter->__sg_advance += BIT_ULL(biter->__pg_bit) - block_offset; ++ sg_delta = BIT_ULL(biter->__pg_bit) - block_offset; + +- if (biter->__sg_advance >= sg_dma_len(biter->__sg)) { ++ if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) { ++ biter->__sg_advance += sg_delta; ++ } else { + biter->__sg_advance = 0; + biter->__sg = sg_next(biter->__sg); + biter->__sg_nents--; +diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c +index 4d732353379df..e7daa65589ab9 100644 +--- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c ++++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c +@@ -325,6 +325,8 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd, + + if (!PAGE_ALIGNED(tinfo->vaddr)) + return -EINVAL; ++ if (tinfo->length == 0) ++ return -EINVAL; + + tidbuf = kzalloc(sizeof(*tidbuf), GFP_KERNEL); + if (!tidbuf) +@@ -335,40 +337,38 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd, + tidbuf->psets = kcalloc(uctxt->expected_count, sizeof(*tidbuf->psets), + GFP_KERNEL); + if (!tidbuf->psets) { +- kfree(tidbuf); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto fail_release_mem; + } + + pinned = pin_rcv_pages(fd, tidbuf); + if (pinned <= 0) { +- kfree(tidbuf->psets); +- kfree(tidbuf); +- return pinned; ++ ret = (pinned < 0) ? pinned : -ENOSPC; ++ goto fail_unpin; + } + + /* Find sets of physically contiguous pages */ + tidbuf->n_psets = find_phys_blocks(tidbuf, pinned); + +- /* +- * We don't need to access this under a lock since tid_used is per +- * process and the same process cannot be in hfi1_user_exp_rcv_clear() +- * and hfi1_user_exp_rcv_setup() at the same time. +- */ ++ /* Reserve the number of expected tids to be used. */ + spin_lock(&fd->tid_lock); + if (fd->tid_used + tidbuf->n_psets > fd->tid_limit) + pageset_count = fd->tid_limit - fd->tid_used; + else + pageset_count = tidbuf->n_psets; ++ fd->tid_used += pageset_count; + spin_unlock(&fd->tid_lock); + +- if (!pageset_count) +- goto bail; ++ if (!pageset_count) { ++ ret = -ENOSPC; ++ goto fail_unreserve; ++ } + + ngroups = pageset_count / dd->rcv_entries.group_size; + tidlist = kcalloc(pageset_count, sizeof(*tidlist), GFP_KERNEL); + if (!tidlist) { + ret = -ENOMEM; +- goto nomem; ++ goto fail_unreserve; + } + + tididx = 0; +@@ -464,43 +464,60 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd, + } + unlock: + mutex_unlock(&uctxt->exp_mutex); +-nomem: + hfi1_cdbg(TID, "total mapped: tidpairs:%u pages:%u (%d)", tididx, + mapped_pages, ret); +- if (tididx) { +- spin_lock(&fd->tid_lock); +- fd->tid_used += tididx; +- spin_unlock(&fd->tid_lock); +- tinfo->tidcnt = tididx; +- tinfo->length = mapped_pages * PAGE_SIZE; +- +- if (copy_to_user(u64_to_user_ptr(tinfo->tidlist), +- tidlist, sizeof(tidlist[0]) * tididx)) { +- /* +- * On failure to copy to the user level, we need to undo +- * everything done so far so we don't leak resources. +- */ +- tinfo->tidlist = (unsigned long)&tidlist; +- hfi1_user_exp_rcv_clear(fd, tinfo); +- tinfo->tidlist = 0; +- ret = -EFAULT; +- goto bail; +- } ++ ++ /* fail if nothing was programmed, set error if none provided */ ++ if (tididx == 0) { ++ if (ret >= 0) ++ ret = -ENOSPC; ++ goto fail_unreserve; + } + +- /* +- * If not everything was mapped (due to insufficient RcvArray entries, +- * for example), unpin all unmapped pages so we can pin them nex time. +- */ +- if (mapped_pages != pinned) +- unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages, +- (pinned - mapped_pages), false); +-bail: ++ /* adjust reserved tid_used to actual count */ ++ spin_lock(&fd->tid_lock); ++ fd->tid_used -= pageset_count - tididx; ++ spin_unlock(&fd->tid_lock); ++ ++ /* unpin all pages not covered by a TID */ ++ unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages, pinned - mapped_pages, ++ false); ++ ++ tinfo->tidcnt = tididx; ++ tinfo->length = mapped_pages * PAGE_SIZE; ++ ++ if (copy_to_user(u64_to_user_ptr(tinfo->tidlist), ++ tidlist, sizeof(tidlist[0]) * tididx)) { ++ ret = -EFAULT; ++ goto fail_unprogram; ++ } ++ ++ kfree(tidbuf->pages); + kfree(tidbuf->psets); ++ kfree(tidbuf); + kfree(tidlist); ++ return 0; ++ ++fail_unprogram: ++ /* unprogram, unmap, and unpin all allocated TIDs */ ++ tinfo->tidlist = (unsigned long)tidlist; ++ hfi1_user_exp_rcv_clear(fd, tinfo); ++ tinfo->tidlist = 0; ++ pinned = 0; /* nothing left to unpin */ ++ pageset_count = 0; /* nothing left reserved */ ++fail_unreserve: ++ spin_lock(&fd->tid_lock); ++ fd->tid_used -= pageset_count; ++ spin_unlock(&fd->tid_lock); ++fail_unpin: ++ if (pinned > 0) ++ unpin_rcv_pages(fd, tidbuf, NULL, 0, pinned, false); ++fail_release_mem: + kfree(tidbuf->pages); ++ kfree(tidbuf->psets); + kfree(tidbuf); +- return ret > 0 ? 0 : ret; ++ kfree(tidlist); ++ return ret; + } + + int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd, +diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c +index 05b007d0a89b1..4b81b2d0fe067 100644 +--- a/drivers/input/mouse/synaptics.c ++++ b/drivers/input/mouse/synaptics.c +@@ -189,7 +189,6 @@ static const char * const smbus_pnp_ids[] = { + "SYN3221", /* HP 15-ay000 */ + "SYN323d", /* HP Spectre X360 13-w013dx */ + "SYN3257", /* HP Envy 13-ad105ng */ +- "SYN3286", /* HP Laptop 15-da3001TU */ + NULL + }; + +diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c +index 9c49d00c2a966..ea6e9e1eaf046 100644 +--- a/drivers/memory/atmel-sdramc.c ++++ b/drivers/memory/atmel-sdramc.c +@@ -47,19 +47,17 @@ static int atmel_ramc_probe(struct platform_device *pdev) + caps = of_device_get_match_data(&pdev->dev); + + if (caps->has_ddrck) { +- clk = devm_clk_get(&pdev->dev, "ddrck"); ++ clk = devm_clk_get_enabled(&pdev->dev, "ddrck"); + if (IS_ERR(clk)) + return PTR_ERR(clk); +- clk_prepare_enable(clk); + } + + if (caps->has_mpddr_clk) { +- clk = devm_clk_get(&pdev->dev, "mpddr"); ++ clk = devm_clk_get_enabled(&pdev->dev, "mpddr"); + if (IS_ERR(clk)) { + pr_err("AT91 RAMC: couldn't get mpddr clock\n"); + return PTR_ERR(clk); + } +- clk_prepare_enable(clk); + } + + return 0; +diff --git a/drivers/memory/mvebu-devbus.c b/drivers/memory/mvebu-devbus.c +index 095f8a3b2cfcc..9bf477b000c0d 100644 +--- a/drivers/memory/mvebu-devbus.c ++++ b/drivers/memory/mvebu-devbus.c +@@ -282,10 +282,9 @@ static int mvebu_devbus_probe(struct platform_device *pdev) + if (IS_ERR(devbus->base)) + return PTR_ERR(devbus->base); + +- clk = devm_clk_get(&pdev->dev, NULL); ++ clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); +- clk_prepare_enable(clk); + + /* + * Obtain clock period in picoseconds, +diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c +index 96cad561e1d8d..b3f761eca8299 100644 +--- a/drivers/mmc/host/sdhci-esdhc-imx.c ++++ b/drivers/mmc/host/sdhci-esdhc-imx.c +@@ -89,6 +89,8 @@ + /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ + #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 + #define ESDHC_TUNING_START_TAP_MASK 0x7f ++#define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE (1 << 7) ++#define ESDHC_TUNING_STEP_DEFAULT 0x1 + #define ESDHC_TUNING_STEP_MASK 0x00070000 + #define ESDHC_TUNING_STEP_SHIFT 16 + +@@ -1180,7 +1182,8 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); +- int tmp; ++ struct cqhci_host *cq_host = host->mmc->cqe_private; ++ u32 tmp; + + if (esdhc_is_usdhc(imx_data)) { + /* +@@ -1233,18 +1236,37 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) + + if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { + tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); +- tmp |= ESDHC_STD_TUNING_EN | +- ESDHC_TUNING_START_TAP_DEFAULT; +- if (imx_data->boarddata.tuning_start_tap) { +- tmp &= ~ESDHC_TUNING_START_TAP_MASK; ++ tmp |= ESDHC_STD_TUNING_EN; ++ ++ /* ++ * ROM code or bootloader may config the start tap ++ * and step, unmask them first. ++ */ ++ tmp &= ~(ESDHC_TUNING_START_TAP_MASK | ESDHC_TUNING_STEP_MASK); ++ if (imx_data->boarddata.tuning_start_tap) + tmp |= imx_data->boarddata.tuning_start_tap; +- } ++ else ++ tmp |= ESDHC_TUNING_START_TAP_DEFAULT; + + if (imx_data->boarddata.tuning_step) { +- tmp &= ~ESDHC_TUNING_STEP_MASK; + tmp |= imx_data->boarddata.tuning_step + << ESDHC_TUNING_STEP_SHIFT; ++ } else { ++ tmp |= ESDHC_TUNING_STEP_DEFAULT ++ << ESDHC_TUNING_STEP_SHIFT; + } ++ ++ /* Disable the CMD CRC check for tuning, if not, need to ++ * add some delay after every tuning command, because ++ * hardware standard tuning logic will directly go to next ++ * step once it detect the CMD CRC error, will not wait for ++ * the card side to finally send out the tuning data, trigger ++ * the buffer read ready interrupt immediately. If usdhc send ++ * the next tuning command some eMMC card will stuck, can't ++ * response, block the tuning procedure or the first command ++ * after the whole tuning procedure always can't get any response. ++ */ ++ tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; + writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); + } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { + /* +@@ -1256,6 +1278,21 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) + tmp &= ~ESDHC_STD_TUNING_EN; + writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); + } ++ ++ /* ++ * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card ++ * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the ++ * the 1st linux configure power/clock for the 2nd Linux. ++ * ++ * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux ++ * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump. ++ * After we clear the pending interrupt and halt CQCTL, issue gone. ++ */ ++ if (cq_host) { ++ tmp = cqhci_readl(cq_host, CQHCI_IS); ++ cqhci_writel(cq_host, tmp, CQHCI_IS); ++ cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL); ++ } + } + } + +@@ -1571,8 +1608,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) + if (err) + goto disable_ahb_clk; + +- host->tuning_delay = 1; +- + sdhci_esdhc_imx_hwinit(host); + + err = sdhci_add_host(host); +diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c +index c66e78b2870d7..ba2dc01e0f6bf 100644 +--- a/drivers/net/dsa/microchip/ksz9477.c ++++ b/drivers/net/dsa/microchip/ksz9477.c +@@ -682,10 +682,10 @@ static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port, + ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]); + + /* clear forwarding port */ +- alu_table[2] &= ~BIT(port); ++ alu_table[1] &= ~BIT(port); + + /* if there is no port to forward, clear table */ +- if ((alu_table[2] & ALU_V_PORT_MAP) == 0) { ++ if ((alu_table[1] & ALU_V_PORT_MAP) == 0) { + alu_table[0] = 0; + alu_table[1] = 0; + alu_table[2] = 0; +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +index d5fd49dd25f33..decc1c09a031b 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +@@ -524,19 +524,28 @@ static void xgbe_disable_vxlan(struct xgbe_prv_data *pdata) + netif_dbg(pdata, drv, pdata->netdev, "VXLAN acceleration disabled\n"); + } + ++static unsigned int xgbe_get_fc_queue_count(struct xgbe_prv_data *pdata) ++{ ++ unsigned int max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; ++ ++ /* From MAC ver 30H the TFCR is per priority, instead of per queue */ ++ if (XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER) >= 0x30) ++ return max_q_count; ++ else ++ return min_t(unsigned int, pdata->tx_q_count, max_q_count); ++} ++ + static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata) + { +- unsigned int max_q_count, q_count; + unsigned int reg, reg_val; +- unsigned int i; ++ unsigned int i, q_count; + + /* Clear MTL flow control */ + for (i = 0; i < pdata->rx_q_count; i++) + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0); + + /* Clear MAC flow control */ +- max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; +- q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count); ++ q_count = xgbe_get_fc_queue_count(pdata); + reg = MAC_Q0TFCR; + for (i = 0; i < q_count; i++) { + reg_val = XGMAC_IOREAD(pdata, reg); +@@ -553,9 +562,8 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata) + { + struct ieee_pfc *pfc = pdata->pfc; + struct ieee_ets *ets = pdata->ets; +- unsigned int max_q_count, q_count; + unsigned int reg, reg_val; +- unsigned int i; ++ unsigned int i, q_count; + + /* Set MTL flow control */ + for (i = 0; i < pdata->rx_q_count; i++) { +@@ -579,8 +587,7 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata) + } + + /* Set MAC flow control */ +- max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; +- q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count); ++ q_count = xgbe_get_fc_queue_count(pdata); + reg = MAC_Q0TFCR; + for (i = 0; i < q_count; i++) { + reg_val = XGMAC_IOREAD(pdata, reg); +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +index 97167fc9bebe7..7840eb4cdb8da 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +@@ -496,6 +496,7 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata, + reg |= XGBE_KR_TRAINING_ENABLE; + reg |= XGBE_KR_TRAINING_START; + XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); ++ pdata->kr_start_time = jiffies; + + netif_dbg(pdata, link, pdata->netdev, + "KR training initiated\n"); +@@ -632,6 +633,8 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) + + xgbe_switch_mode(pdata); + ++ pdata->an_result = XGBE_AN_READY; ++ + xgbe_an_restart(pdata); + + return XGBE_AN_INCOMPAT_LINK; +@@ -1275,9 +1278,30 @@ static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata) + static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata) + { + unsigned long link_timeout; ++ unsigned long kr_time; ++ int wait; + + link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ); + if (time_after(jiffies, link_timeout)) { ++ if ((xgbe_cur_mode(pdata) == XGBE_MODE_KR) && ++ pdata->phy.autoneg == AUTONEG_ENABLE) { ++ /* AN restart should not happen while KR training is in progress. ++ * The while loop ensures no AN restart during KR training, ++ * waits up to 500ms and AN restart is triggered only if KR ++ * training is failed. ++ */ ++ wait = XGBE_KR_TRAINING_WAIT_ITER; ++ while (wait--) { ++ kr_time = pdata->kr_start_time + ++ msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); ++ if (time_after(jiffies, kr_time)) ++ break; ++ /* AN restart is not required, if AN result is COMPLETE */ ++ if (pdata->an_result == XGBE_AN_COMPLETE) ++ return; ++ usleep_range(10000, 11000); ++ } ++ } + netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n"); + xgbe_phy_config_aneg(pdata); + } +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h +index 0c93a552b921d..729307a96c50d 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe.h ++++ b/drivers/net/ethernet/amd/xgbe/xgbe.h +@@ -290,6 +290,7 @@ + /* Auto-negotiation */ + #define XGBE_AN_MS_TIMEOUT 500 + #define XGBE_LINK_TIMEOUT 5 ++#define XGBE_KR_TRAINING_WAIT_ITER 50 + + #define XGBE_SGMII_AN_LINK_STATUS BIT(1) + #define XGBE_SGMII_AN_LINK_SPEED (BIT(2) | BIT(3)) +@@ -1266,6 +1267,7 @@ struct xgbe_prv_data { + unsigned int parallel_detect; + unsigned int fec_ability; + unsigned long an_start; ++ unsigned long kr_start_time; + enum xgbe_an_mode an_mode; + + /* I2C support */ +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +index 18f4923b1723b..6a253f81c5552 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -26,7 +27,6 @@ + #include "xgene_enet_hw.h" + #include "xgene_enet_cle.h" + #include "xgene_enet_ring2.h" +-#include "../../../phy/mdio-xgene.h" + + #define XGENE_DRV_VERSION "v1.0" + #define ETHER_MIN_PACKET 64 +diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c +index a9962474d551d..d0cd86af29d9f 100644 +--- a/drivers/net/ethernet/broadcom/tg3.c ++++ b/drivers/net/ethernet/broadcom/tg3.c +@@ -11195,7 +11195,7 @@ static void tg3_reset_task(struct work_struct *work) + rtnl_lock(); + tg3_full_lock(tp, 0); + +- if (!netif_running(tp->dev)) { ++ if (tp->pcierr_recovery || !netif_running(tp->dev)) { + tg3_flag_clear(tp, RESET_TASK_PENDING); + tg3_full_unlock(tp); + rtnl_unlock(); +@@ -18187,6 +18187,9 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, + + netdev_info(netdev, "PCI I/O error detected\n"); + ++ /* Want to make sure that the reset task doesn't run */ ++ tg3_reset_task_cancel(tp); ++ + rtnl_lock(); + + /* Could be second call or maybe we don't have netdev yet */ +@@ -18203,9 +18206,6 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, + + tg3_timer_stop(tp); + +- /* Want to make sure that the reset task doesn't run */ +- tg3_reset_task_cancel(tp); +- + netif_device_detach(netdev); + + /* Clean up software state, even if MMIO is blocked */ +diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c +index 78219a9943a73..d948b582f4c97 100644 +--- a/drivers/net/ethernet/cadence/macb_main.c ++++ b/drivers/net/ethernet/cadence/macb_main.c +@@ -1752,7 +1752,6 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev) + bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) || + skb_is_nonlinear(*skb); + int padlen = ETH_ZLEN - (*skb)->len; +- int headroom = skb_headroom(*skb); + int tailroom = skb_tailroom(*skb); + struct sk_buff *nskb; + u32 fcs; +@@ -1766,9 +1765,6 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev) + /* FCS could be appeded to tailroom. */ + if (tailroom >= ETH_FCS_LEN) + goto add_fcs; +- /* FCS could be appeded by moving data to headroom. */ +- else if (!cloned && headroom + tailroom >= ETH_FCS_LEN) +- padlen = 0; + /* No room for FCS, need to reallocate skb. */ + else + padlen = ETH_FCS_LEN; +@@ -1777,10 +1773,7 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev) + padlen += ETH_FCS_LEN; + } + +- if (!cloned && headroom + tailroom >= padlen) { +- (*skb)->data = memmove((*skb)->head, (*skb)->data, (*skb)->len); +- skb_set_tail_pointer(*skb, (*skb)->len); +- } else { ++ if (cloned || tailroom < padlen) { + nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC); + if (!nskb) + return -ENOMEM; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c +index f2657cd3ffa4f..83ee9429e7c65 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c +@@ -1640,7 +1640,7 @@ static void mlx5_core_verify_params(void) + } + } + +-static int __init init(void) ++static int __init mlx5_init(void) + { + int err; + +@@ -1665,7 +1665,7 @@ err_debug: + return err; + } + +-static void __exit cleanup(void) ++static void __exit mlx5_cleanup(void) + { + #ifdef CONFIG_MLX5_CORE_EN + mlx5e_cleanup(); +@@ -1674,5 +1674,5 @@ static void __exit cleanup(void) + mlx5_unregister_debugfs(); + } + +-module_init(init); +-module_exit(cleanup); ++module_init(mlx5_init); ++module_exit(mlx5_cleanup); +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index 3fd5155bdd5fa..231a1295c4700 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -736,14 +736,14 @@ static void ravb_error_interrupt(struct net_device *ndev) + ravb_write(ndev, ~(EIS_QFS | EIS_RESERVED), EIS); + if (eis & EIS_QFS) { + ris2 = ravb_read(ndev, RIS2); +- ravb_write(ndev, ~(RIS2_QFF0 | RIS2_RFFF | RIS2_RESERVED), ++ ravb_write(ndev, ~(RIS2_QFF0 | RIS2_QFF1 | RIS2_RFFF | RIS2_RESERVED), + RIS2); + + /* Receive Descriptor Empty int */ + if (ris2 & RIS2_QFF0) + priv->stats[RAVB_BE].rx_over_errors++; + +- /* Receive Descriptor Empty int */ ++ /* Receive Descriptor Empty int */ + if (ris2 & RIS2_QFF1) + priv->stats[RAVB_NC].rx_over_errors++; + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 9931724c4727d..3079e52546663 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -998,6 +998,11 @@ static int stmmac_init_phy(struct net_device *dev) + int addr = priv->plat->phy_addr; + struct phy_device *phydev; + ++ if (addr < 0) { ++ netdev_err(priv->dev, "no phy found\n"); ++ return -ENODEV; ++ } ++ + phydev = mdiobus_get_phy(priv->mii, addr); + if (!phydev) { + netdev_err(priv->dev, "no phy at addr %d\n", addr); +diff --git a/drivers/net/phy/mdio-i2c.c b/drivers/net/phy/mdio-i2c.c +index 0dce676725488..5969878e0aa7c 100644 +--- a/drivers/net/phy/mdio-i2c.c ++++ b/drivers/net/phy/mdio-i2c.c +@@ -10,10 +10,9 @@ + * of their settings. + */ + #include ++#include + #include + +-#include "mdio-i2c.h" +- + /* + * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is + * specified to be present in SFP modules. These correspond with PHY +diff --git a/drivers/net/phy/mdio-i2c.h b/drivers/net/phy/mdio-i2c.h +deleted file mode 100644 +index 751dab281f57e..0000000000000 +--- a/drivers/net/phy/mdio-i2c.h ++++ /dev/null +@@ -1,16 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/* +- * MDIO I2C bridge +- * +- * Copyright (C) 2015 Russell King +- */ +-#ifndef MDIO_I2C_H +-#define MDIO_I2C_H +- +-struct device; +-struct i2c_adapter; +-struct mii_bus; +- +-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c); +- +-#endif +diff --git a/drivers/net/phy/mdio-mux-meson-g12a.c b/drivers/net/phy/mdio-mux-meson-g12a.c +index 7a9ad54582e19..aa3ad38e37d7b 100644 +--- a/drivers/net/phy/mdio-mux-meson-g12a.c ++++ b/drivers/net/phy/mdio-mux-meson-g12a.c +@@ -4,6 +4,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -148,6 +149,7 @@ static const struct clk_ops g12a_ephy_pll_ops = { + + static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv) + { ++ u32 value; + int ret; + + /* Enable the phy clock */ +@@ -161,18 +163,25 @@ static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv) + + /* Initialize ephy control */ + writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0); +- writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) | +- FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) | +- FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) | +- PHY_CNTL1_CLK_EN | +- PHY_CNTL1_CLKFREQ | +- PHY_CNTL1_PHY_ENB, +- priv->regs + ETH_PHY_CNTL1); ++ ++ /* Make sure we get a 0 -> 1 transition on the enable bit */ ++ value = FIELD_PREP(PHY_CNTL1_ST_MODE, 3) | ++ FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) | ++ FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) | ++ PHY_CNTL1_CLK_EN | ++ PHY_CNTL1_CLKFREQ; ++ writel(value, priv->regs + ETH_PHY_CNTL1); + writel(PHY_CNTL2_USE_INTERNAL | + PHY_CNTL2_SMI_SRC_MAC | + PHY_CNTL2_RX_CLK_EPHY, + priv->regs + ETH_PHY_CNTL2); + ++ value |= PHY_CNTL1_PHY_ENB; ++ writel(value, priv->regs + ETH_PHY_CNTL1); ++ ++ /* The phy needs a bit of time to power up */ ++ mdelay(10); ++ + return 0; + } + +diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c +index 34990eaa3298c..461207cdf5d6e 100644 +--- a/drivers/net/phy/mdio-xgene.c ++++ b/drivers/net/phy/mdio-xgene.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -18,7 +19,6 @@ + #include + #include + #include +-#include "mdio-xgene.h" + + static bool xgene_mdio_status; + +diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h +deleted file mode 100644 +index b1f5ccb4ad9c3..0000000000000 +--- a/drivers/net/phy/mdio-xgene.h ++++ /dev/null +@@ -1,130 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0+ +-/* Applied Micro X-Gene SoC MDIO Driver +- * +- * Copyright (c) 2016, Applied Micro Circuits Corporation +- * Author: Iyappan Subramanian +- */ +- +-#ifndef __MDIO_XGENE_H__ +-#define __MDIO_XGENE_H__ +- +-#define BLOCK_XG_MDIO_CSR_OFFSET 0x5000 +-#define BLOCK_DIAG_CSR_OFFSET 0xd000 +-#define XGENET_CONFIG_REG_ADDR 0x20 +- +-#define MAC_ADDR_REG_OFFSET 0x00 +-#define MAC_COMMAND_REG_OFFSET 0x04 +-#define MAC_WRITE_REG_OFFSET 0x08 +-#define MAC_READ_REG_OFFSET 0x0c +-#define MAC_COMMAND_DONE_REG_OFFSET 0x10 +- +-#define CLKEN_OFFSET 0x08 +-#define SRST_OFFSET 0x00 +- +-#define MENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70 +-#define MENET_BLOCK_MEM_RDY_ADDR 0x74 +- +-#define MAC_CONFIG_1_ADDR 0x00 +-#define MII_MGMT_COMMAND_ADDR 0x24 +-#define MII_MGMT_ADDRESS_ADDR 0x28 +-#define MII_MGMT_CONTROL_ADDR 0x2c +-#define MII_MGMT_STATUS_ADDR 0x30 +-#define MII_MGMT_INDICATORS_ADDR 0x34 +-#define SOFT_RESET BIT(31) +- +-#define MII_MGMT_CONFIG_ADDR 0x20 +-#define MII_MGMT_COMMAND_ADDR 0x24 +-#define MII_MGMT_ADDRESS_ADDR 0x28 +-#define MII_MGMT_CONTROL_ADDR 0x2c +-#define MII_MGMT_STATUS_ADDR 0x30 +-#define MII_MGMT_INDICATORS_ADDR 0x34 +- +-#define MIIM_COMMAND_ADDR 0x20 +-#define MIIM_FIELD_ADDR 0x24 +-#define MIIM_CONFIGURATION_ADDR 0x28 +-#define MIIM_LINKFAILVECTOR_ADDR 0x2c +-#define MIIM_INDICATOR_ADDR 0x30 +-#define MIIMRD_FIELD_ADDR 0x34 +- +-#define MDIO_CSR_OFFSET 0x5000 +- +-#define REG_ADDR_POS 0 +-#define REG_ADDR_LEN 5 +-#define PHY_ADDR_POS 8 +-#define PHY_ADDR_LEN 5 +- +-#define HSTMIIMWRDAT_POS 0 +-#define HSTMIIMWRDAT_LEN 16 +-#define HSTPHYADX_POS 23 +-#define HSTPHYADX_LEN 5 +-#define HSTREGADX_POS 18 +-#define HSTREGADX_LEN 5 +-#define HSTLDCMD BIT(3) +-#define HSTMIIMCMD_POS 0 +-#define HSTMIIMCMD_LEN 3 +- +-#define BUSY_MASK BIT(0) +-#define READ_CYCLE_MASK BIT(0) +- +-enum xgene_enet_cmd { +- XGENE_ENET_WR_CMD = BIT(31), +- XGENE_ENET_RD_CMD = BIT(30) +-}; +- +-enum { +- MIIM_CMD_IDLE, +- MIIM_CMD_LEGACY_WRITE, +- MIIM_CMD_LEGACY_READ, +-}; +- +-enum xgene_mdio_id { +- XGENE_MDIO_RGMII = 1, +- XGENE_MDIO_XFI +-}; +- +-struct xgene_mdio_pdata { +- struct clk *clk; +- struct device *dev; +- void __iomem *mac_csr_addr; +- void __iomem *diag_csr_addr; +- void __iomem *mdio_csr_addr; +- struct mii_bus *mdio_bus; +- int mdio_id; +- spinlock_t mac_lock; /* mac lock */ +-}; +- +-/* Set the specified value into a bit-field defined by its starting position +- * and length within a single u64. +- */ +-static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) +-{ +- return (val & ((1ULL << len) - 1)) << pos; +-} +- +-#define SET_VAL(field, val) \ +- xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) +- +-#define SET_BIT(field) \ +- xgene_enet_set_field_value(field ## _POS, 1, 1) +- +-/* Get the value from a bit-field defined by its starting position +- * and length within the specified u64. +- */ +-static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) +-{ +- return (src >> pos) & ((1ULL << len) - 1); +-} +- +-#define GET_VAL(field, src) \ +- xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) +- +-#define GET_BIT(field, src) \ +- xgene_enet_get_field_value(field ## _POS, 1, src) +- +-u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr); +-void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data); +-int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg); +-int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data); +-struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr); +- +-#endif /* __MDIO_XGENE_H__ */ +diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c +index 757763735e1f5..fdf8221f46fa5 100644 +--- a/drivers/net/phy/mdio_bus.c ++++ b/drivers/net/phy/mdio_bus.c +@@ -117,7 +117,12 @@ EXPORT_SYMBOL(mdiobus_unregister_device); + + struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr) + { +- struct mdio_device *mdiodev = bus->mdio_map[addr]; ++ struct mdio_device *mdiodev; ++ ++ if (addr < 0 || addr >= ARRAY_SIZE(bus->mdio_map)) ++ return NULL; ++ ++ mdiodev = bus->mdio_map[addr]; + + if (!mdiodev) + return NULL; +diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c +index beaa00342a13f..9639aa1819685 100644 +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -16,7 +17,6 @@ + #include + #include + +-#include "mdio-i2c.h" + #include "sfp.h" + #include "swphy.h" + +diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c +index fce6713e970ba..811c8751308c6 100644 +--- a/drivers/net/usb/sr9700.c ++++ b/drivers/net/usb/sr9700.c +@@ -410,7 +410,7 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + /* ignore the CRC length */ + len = (skb->data[1] | (skb->data[2] << 8)) - 4; + +- if (len > ETH_FRAME_LEN || len > skb->len) ++ if (len > ETH_FRAME_LEN || len > skb->len || len < 0) + return 0; + + /* the last packet of current skb */ +diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c +index 034eb6535ab7d..46077cef855b2 100644 +--- a/drivers/net/wan/fsl_ucc_hdlc.c ++++ b/drivers/net/wan/fsl_ucc_hdlc.c +@@ -1249,9 +1249,11 @@ static int ucc_hdlc_probe(struct platform_device *pdev) + free_dev: + free_netdev(dev); + undo_uhdlc_init: +- iounmap(utdm->siram); ++ if (utdm) ++ iounmap(utdm->siram); + unmap_si_regs: +- iounmap(utdm->si_regs); ++ if (utdm) ++ iounmap(utdm->si_regs); + free_utdm: + if (uhdlc_priv->tsa) + kfree(utdm); +diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c +index c8f8fe5497a8c..ace016967ff0e 100644 +--- a/drivers/net/wireless/rndis_wlan.c ++++ b/drivers/net/wireless/rndis_wlan.c +@@ -700,8 +700,8 @@ static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len) + struct rndis_query *get; + struct rndis_query_c *get_c; + } u; +- int ret, buflen; +- int resplen, respoffs, copylen; ++ int ret; ++ size_t buflen, resplen, respoffs, copylen; + + buflen = *len + sizeof(*u.get); + if (buflen < CONTROL_BUFFER_SIZE) +@@ -736,22 +736,15 @@ static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len) + + if (respoffs > buflen) { + /* Device returned data offset outside buffer, error. */ +- netdev_dbg(dev->net, "%s(%s): received invalid " +- "data offset: %d > %d\n", __func__, +- oid_to_string(oid), respoffs, buflen); ++ netdev_dbg(dev->net, ++ "%s(%s): received invalid data offset: %zu > %zu\n", ++ __func__, oid_to_string(oid), respoffs, buflen); + + ret = -EINVAL; + goto exit_unlock; + } + +- if ((resplen + respoffs) > buflen) { +- /* Device would have returned more data if buffer would +- * have been big enough. Copy just the bits that we got. +- */ +- copylen = buflen - respoffs; +- } else { +- copylen = resplen; +- } ++ copylen = min(resplen, buflen - respoffs); + + if (copylen > *len) + copylen = *len; +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index eae865ff312c1..b5f7a93543b05 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -467,8 +467,10 @@ static int rockchip_usb2phy_power_on(struct phy *phy) + return ret; + + ret = property_enable(base, &rport->port_cfg->phy_sus, false); +- if (ret) ++ if (ret) { ++ clk_disable_unprepare(rphy->clk480m); + return ret; ++ } + + /* waiting for the utmi_clk to become stable */ + usleep_range(1500, 2000); +diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c +index 59b78a181723b..6424bdb33d2f0 100644 +--- a/drivers/platform/x86/asus-nb-wmi.c ++++ b/drivers/platform/x86/asus-nb-wmi.c +@@ -528,6 +528,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { + { KE_KEY, 0x30, { KEY_VOLUMEUP } }, + { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, + { KE_KEY, 0x32, { KEY_MUTE } }, ++ { KE_KEY, 0x33, { KEY_SCREENLOCK } }, + { KE_KEY, 0x35, { KEY_SCREENLOCK } }, + { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, + { KE_KEY, 0x41, { KEY_NEXTSONG } }, +diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c +index 515c66ca1aecb..61cb1a4a8257c 100644 +--- a/drivers/platform/x86/touchscreen_dmi.c ++++ b/drivers/platform/x86/touchscreen_dmi.c +@@ -169,6 +169,23 @@ static const struct ts_dmi_data connect_tablet9_data = { + .properties = connect_tablet9_props, + }; + ++static const struct property_entry csl_panther_tab_hd_props[] = { ++ PROPERTY_ENTRY_U32("touchscreen-min-x", 1), ++ PROPERTY_ENTRY_U32("touchscreen-min-y", 20), ++ PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), ++ PROPERTY_ENTRY_U32("touchscreen-size-y", 1526), ++ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), ++ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), ++ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-csl-panther-tab-hd.fw"), ++ PROPERTY_ENTRY_U32("silead,max-fingers", 10), ++ { } ++}; ++ ++static const struct ts_dmi_data csl_panther_tab_hd_data = { ++ .acpi_name = "MSSL1680:00", ++ .properties = csl_panther_tab_hd_props, ++}; ++ + static const struct property_entry cube_iwork8_air_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 1), + PROPERTY_ENTRY_U32("touchscreen-min-y", 3), +@@ -721,6 +738,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Tablet 9"), + }, + }, ++ { ++ /* CSL Panther Tab HD */ ++ .driver_data = (void *)&csl_panther_tab_hd_data, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "CSL Computer GmbH & Co. KG"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "CSL Panther Tab HD"), ++ }, ++ }, + { + /* CUBE iwork8 Air */ + .driver_data = (void *)&cube_iwork8_air_data, +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index 031aa4043c5ea..7135bbe5abb8a 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -1397,7 +1397,7 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) + device->linkrate = phy->sas_phy.linkrate; + + hisi_hba->hw->setup_itct(hisi_hba, sas_dev); +- } else ++ } else if (!port->port_attached) + port->id = 0xff; + } + } +diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c +index ba125ed7e06a7..e670cce0cb6ef 100644 +--- a/drivers/scsi/hpsa.c ++++ b/drivers/scsi/hpsa.c +@@ -5810,7 +5810,7 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h) + { + struct Scsi_Host *sh; + +- sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h)); ++ sh = scsi_host_alloc(&hpsa_driver_template, sizeof(struct ctlr_info)); + if (sh == NULL) { + dev_err(&h->pdev->dev, "scsi_host_alloc failed\n"); + return -ENOMEM; +diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c +index 2478ae471f4ee..6d6fc7de9cf3c 100644 +--- a/drivers/spi/spidev.c ++++ b/drivers/spi/spidev.c +@@ -588,7 +588,6 @@ static int spidev_open(struct inode *inode, struct file *filp) + if (!spidev->tx_buffer) { + spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); + if (!spidev->tx_buffer) { +- dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); + status = -ENOMEM; + goto err_find_dev; + } +@@ -597,7 +596,6 @@ static int spidev_open(struct inode *inode, struct file *filp) + if (!spidev->rx_buffer) { + spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); + if (!spidev->rx_buffer) { +- dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); + status = -ENOMEM; + goto err_alloc_rx_buf; + } +diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c +index c313c4f0e8563..9090f87b44913 100644 +--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c ++++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c +@@ -43,11 +43,13 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, + int trip, int *temp) + { + struct int34x_thermal_zone *d = zone->devdata; +- int i; ++ int i, ret = 0; + + if (d->override_ops && d->override_ops->get_trip_temp) + return d->override_ops->get_trip_temp(zone, trip, temp); + ++ mutex_lock(&d->trip_mutex); ++ + if (trip < d->aux_trip_nr) + *temp = d->aux_trips[trip]; + else if (trip == d->crt_trip_id) +@@ -65,10 +67,12 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, + } + } + if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) +- return -EINVAL; ++ ret = -EINVAL; + } + +- return 0; ++ mutex_unlock(&d->trip_mutex); ++ ++ return ret; + } + + static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, +@@ -76,11 +80,13 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, + enum thermal_trip_type *type) + { + struct int34x_thermal_zone *d = zone->devdata; +- int i; ++ int i, ret = 0; + + if (d->override_ops && d->override_ops->get_trip_type) + return d->override_ops->get_trip_type(zone, trip, type); + ++ mutex_lock(&d->trip_mutex); ++ + if (trip < d->aux_trip_nr) + *type = THERMAL_TRIP_PASSIVE; + else if (trip == d->crt_trip_id) +@@ -98,10 +104,12 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, + } + } + if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) +- return -EINVAL; ++ ret = -EINVAL; + } + +- return 0; ++ mutex_unlock(&d->trip_mutex); ++ ++ return ret; + } + + static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, +@@ -173,6 +181,8 @@ int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) + int trip_cnt = int34x_zone->aux_trip_nr; + int i; + ++ mutex_lock(&int34x_zone->trip_mutex); ++ + int34x_zone->crt_trip_id = -1; + if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT", + &int34x_zone->crt_temp)) +@@ -200,6 +210,8 @@ int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) + int34x_zone->act_trips[i].valid = true; + } + ++ mutex_unlock(&int34x_zone->trip_mutex); ++ + return trip_cnt; + } + EXPORT_SYMBOL_GPL(int340x_thermal_read_trips); +@@ -223,6 +235,8 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, + if (!int34x_thermal_zone) + return ERR_PTR(-ENOMEM); + ++ mutex_init(&int34x_thermal_zone->trip_mutex); ++ + int34x_thermal_zone->adev = adev; + int34x_thermal_zone->override_ops = override_ops; + +@@ -269,6 +283,7 @@ err_thermal_zone: + acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); + kfree(int34x_thermal_zone->aux_trips); + err_trip_alloc: ++ mutex_destroy(&int34x_thermal_zone->trip_mutex); + kfree(int34x_thermal_zone); + return ERR_PTR(ret); + } +@@ -280,6 +295,7 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone + thermal_zone_device_unregister(int34x_thermal_zone->zone); + acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); + kfree(int34x_thermal_zone->aux_trips); ++ mutex_destroy(&int34x_thermal_zone->trip_mutex); + kfree(int34x_thermal_zone); + } + EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); +diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h +index 3b4971df1b33b..8f9872afd0d3c 100644 +--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h ++++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h +@@ -32,6 +32,7 @@ struct int34x_thermal_zone { + struct thermal_zone_device_ops *override_ops; + void *priv_data; + struct acpi_lpat_conversion_table *lpat_table; ++ struct mutex trip_mutex; + }; + + struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, +diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c +index 5fd4fc49aef9f..431ab6d07497f 100644 +--- a/drivers/usb/gadget/function/f_fs.c ++++ b/drivers/usb/gadget/function/f_fs.c +@@ -278,6 +278,9 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) + struct usb_request *req = ffs->ep0req; + int ret; + ++ if (!req) ++ return -EINVAL; ++ + req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); + + spin_unlock_irq(&ffs->ev.waitq.lock); +@@ -1900,10 +1903,14 @@ static void functionfs_unbind(struct ffs_data *ffs) + ENTER(); + + if (!WARN_ON(!ffs->gadget)) { ++ /* dequeue before freeing ep0req */ ++ usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req); ++ mutex_lock(&ffs->mutex); + usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req); + ffs->ep0req = NULL; + ffs->gadget = NULL; + clear_bit(FFS_FL_BOUND, &ffs->flags); ++ mutex_unlock(&ffs->mutex); + ffs_data_put(ffs); + } + } +diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c +index 84cfa85442852..fa320006b04d2 100644 +--- a/drivers/usb/host/xhci-plat.c ++++ b/drivers/usb/host/xhci-plat.c +@@ -276,7 +276,7 @@ static int xhci_plat_probe(struct platform_device *pdev) + *priv = *priv_match; + } + +- device_wakeup_enable(hcd->self.controller); ++ device_set_wakeup_capable(&pdev->dev, true); + + xhci->main_hcd = hcd; + xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 35d96796854d6..b8915790a20af 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -693,6 +693,7 @@ int xhci_run(struct usb_hcd *hcd) + if (ret) + xhci_free_command(xhci, command); + } ++ set_bit(HCD_FLAG_DEFER_RH_REGISTER, &hcd->flags); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Finished xhci_run for USB2 roothub"); + +diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c +index e58c7592008d7..2a7970a10533e 100644 +--- a/drivers/w1/w1.c ++++ b/drivers/w1/w1.c +@@ -1131,6 +1131,8 @@ int w1_process(void *data) + /* remainder if it woke up early */ + unsigned long jremain = 0; + ++ atomic_inc(&dev->refcnt); ++ + for (;;) { + + if (!jremain && dev->search_count) { +@@ -1158,8 +1160,10 @@ int w1_process(void *data) + */ + mutex_unlock(&dev->list_mutex); + +- if (kthread_should_stop()) ++ if (kthread_should_stop()) { ++ __set_current_state(TASK_RUNNING); + break; ++ } + + /* Only sleep when the search is active. */ + if (dev->search_count) { +diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c +index b3e1792d9c49f..3a71c5eb2f837 100644 +--- a/drivers/w1/w1_int.c ++++ b/drivers/w1/w1_int.c +@@ -51,10 +51,9 @@ static struct w1_master *w1_alloc_dev(u32 id, int slave_count, int slave_ttl, + dev->search_count = w1_search_count; + dev->enable_pullup = w1_enable_pullup; + +- /* 1 for w1_process to decrement +- * 1 for __w1_remove_master_device to decrement ++ /* For __w1_remove_master_device to decrement + */ +- atomic_set(&dev->refcnt, 2); ++ atomic_set(&dev->refcnt, 1); + + INIT_LIST_HEAD(&dev->slist); + INIT_LIST_HEAD(&dev->async_list); +diff --git a/fs/affs/file.c b/fs/affs/file.c +index ba084b0b214b9..82bb38370aa9a 100644 +--- a/fs/affs/file.c ++++ b/fs/affs/file.c +@@ -878,7 +878,7 @@ affs_truncate(struct inode *inode) + if (inode->i_size > AFFS_I(inode)->mmu_private) { + struct address_space *mapping = inode->i_mapping; + struct page *page; +- void *fsdata; ++ void *fsdata = NULL; + loff_t isize = inode->i_size; + int res; + +diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c +index 5b1b97e9e0c9b..2cea6c25d1b0e 100644 +--- a/fs/cifs/smbdirect.c ++++ b/fs/cifs/smbdirect.c +@@ -1478,6 +1478,7 @@ void smbd_destroy(struct TCP_Server_Info *server) + destroy_workqueue(info->workqueue); + log_rdma_event(INFO, "rdma session destroyed\n"); + kfree(info); ++ server->smbd_conn = NULL; + } + + /* +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index ed53e206a2996..82329b5102c69 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -42,9 +42,6 @@ struct nfsd_net { + bool grace_ended; + time_t boot_time; + +- /* internal mount of the "nfsd" pseudofilesystem: */ +- struct vfsmount *nfsd_mnt; +- + struct dentry *nfsd_client_dir; + + /* +@@ -121,6 +118,9 @@ struct nfsd_net { + wait_queue_head_t ntf_wq; + atomic_t ntf_refcnt; + ++ /* Allow umount to wait for nfsd state cleanup */ ++ struct completion nfsd_shutdown_complete; ++ + /* + * clientid and stateid data for construction of net unique COPY + * stateids. +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index de2c3809d15aa..5922eceb01762 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -7754,14 +7754,9 @@ nfs4_state_start_net(struct net *net) + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + int ret; + +- ret = get_nfsdfs(net); +- if (ret) +- return ret; + ret = nfs4_state_create_net(net); +- if (ret) { +- mntput(nn->nfsd_mnt); ++ if (ret) + return ret; +- } + locks_start_grace(net, &nn->nfsd4_manager); + nfsd4_client_tracking_init(net); + if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) +@@ -7830,7 +7825,6 @@ nfs4_state_shutdown_net(struct net *net) + + nfsd4_client_tracking_exit(net); + nfs4_state_destroy_net(net); +- mntput(nn->nfsd_mnt); + } + + void +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 055cc0458f270..a2454739b1cfa 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1417,6 +1417,8 @@ static void nfsd_umount(struct super_block *sb) + { + struct net *net = sb->s_fs_info; + ++ nfsd_shutdown_threads(net); ++ + kill_litter_super(sb); + put_net(net); + } +@@ -1429,18 +1431,6 @@ static struct file_system_type nfsd_fs_type = { + }; + MODULE_ALIAS_FS("nfsd"); + +-int get_nfsdfs(struct net *net) +-{ +- struct nfsd_net *nn = net_generic(net, nfsd_net_id); +- struct vfsmount *mnt; +- +- mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL); +- if (IS_ERR(mnt)) +- return PTR_ERR(mnt); +- nn->nfsd_mnt = mnt; +- return 0; +-} +- + #ifdef CONFIG_PROC_FS + static int create_proc_exports_entry(void) + { +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 4ff0c5318a02b..3ae9811c0bb98 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -84,11 +84,10 @@ int nfsd_get_nrthreads(int n, int *, struct net *); + int nfsd_set_nrthreads(int n, int *, struct net *); + int nfsd_pool_stats_open(struct inode *, struct file *); + int nfsd_pool_stats_release(struct inode *, struct file *); ++void nfsd_shutdown_threads(struct net *net); + + void nfsd_destroy(struct net *net); + +-int get_nfsdfs(struct net *); +- + struct nfsdfs_client { + struct kref cl_ref; + void (*cl_release)(struct kref *kref); +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 70684c7ae94bd..969a227186fa8 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -594,6 +594,37 @@ static const struct svc_serv_ops nfsd_thread_sv_ops = { + .svo_module = THIS_MODULE, + }; + ++static void nfsd_complete_shutdown(struct net *net) ++{ ++ struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ ++ WARN_ON(!mutex_is_locked(&nfsd_mutex)); ++ ++ nn->nfsd_serv = NULL; ++ complete(&nn->nfsd_shutdown_complete); ++} ++ ++void nfsd_shutdown_threads(struct net *net) ++{ ++ struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct svc_serv *serv; ++ ++ mutex_lock(&nfsd_mutex); ++ serv = nn->nfsd_serv; ++ if (serv == NULL) { ++ mutex_unlock(&nfsd_mutex); ++ return; ++ } ++ ++ svc_get(serv); ++ /* Kill outstanding nfsd threads */ ++ serv->sv_ops->svo_setup(serv, NULL, 0); ++ nfsd_destroy(net); ++ mutex_unlock(&nfsd_mutex); ++ /* Wait for shutdown of nfsd_serv to complete */ ++ wait_for_completion(&nn->nfsd_shutdown_complete); ++} ++ + int nfsd_create_serv(struct net *net) + { + int error; +@@ -611,11 +642,13 @@ int nfsd_create_serv(struct net *net) + &nfsd_thread_sv_ops); + if (nn->nfsd_serv == NULL) + return -ENOMEM; ++ init_completion(&nn->nfsd_shutdown_complete); + + nn->nfsd_serv->sv_maxconn = nn->max_connections; + error = svc_bind(nn->nfsd_serv, net); + if (error < 0) { + svc_destroy(nn->nfsd_serv); ++ nfsd_complete_shutdown(net); + return error; + } + +@@ -664,7 +697,7 @@ void nfsd_destroy(struct net *net) + svc_shutdown_net(nn->nfsd_serv, net); + svc_destroy(nn->nfsd_serv); + if (destroy) +- nn->nfsd_serv = NULL; ++ nfsd_complete_shutdown(net); + } + + int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) +diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c +index d80989b6c3448..f4264dd4ea31b 100644 +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include "internal.h" + + static const struct dentry_operations proc_sys_dentry_operations; +@@ -1397,6 +1398,38 @@ struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *tab + } + EXPORT_SYMBOL(register_sysctl); + ++/** ++ * __register_sysctl_init() - register sysctl table to path ++ * @path: path name for sysctl base ++ * @table: This is the sysctl table that needs to be registered to the path ++ * @table_name: The name of sysctl table, only used for log printing when ++ * registration fails ++ * ++ * The sysctl interface is used by userspace to query or modify at runtime ++ * a predefined value set on a variable. These variables however have default ++ * values pre-set. Code which depends on these variables will always work even ++ * if register_sysctl() fails. If register_sysctl() fails you'd just loose the ++ * ability to query or modify the sysctls dynamically at run time. Chances of ++ * register_sysctl() failing on init are extremely low, and so for both reasons ++ * this function does not return any error as it is used by initialization code. ++ * ++ * Context: Can only be called after your respective sysctl base path has been ++ * registered. So for instance, most base directories are registered early on ++ * init before init levels are processed through proc_sys_init() and ++ * sysctl_init(). ++ */ ++void __init __register_sysctl_init(const char *path, struct ctl_table *table, ++ const char *table_name) ++{ ++ struct ctl_table_header *hdr = register_sysctl(path, table); ++ ++ if (unlikely(!hdr)) { ++ pr_err("failed when register_sysctl %s to %s\n", table_name, path); ++ return; ++ } ++ kmemleak_not_leak(hdr); ++} ++ + static char *append_path(const char *path, char *pos, const char *name) + { + int namelen; +diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c +index 913f5af9bf248..0ebb6e6849082 100644 +--- a/fs/reiserfs/super.c ++++ b/fs/reiserfs/super.c +@@ -1437,7 +1437,6 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) + unsigned long safe_mask = 0; + unsigned int commit_max_age = (unsigned int)-1; + struct reiserfs_journal *journal = SB_JOURNAL(s); +- char *new_opts; + int err; + char *qf_names[REISERFS_MAXQUOTAS]; + unsigned int qfmt = 0; +@@ -1445,10 +1444,6 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) + int i; + #endif + +- new_opts = kstrdup(arg, GFP_KERNEL); +- if (arg && !new_opts) +- return -ENOMEM; +- + sync_filesystem(s); + reiserfs_write_lock(s); + +@@ -1599,7 +1594,6 @@ out_ok_unlocked: + out_err_unlock: + reiserfs_write_unlock(s); + out_err: +- kfree(new_opts); + return err; + } + +diff --git a/include/linux/clk.h b/include/linux/clk.h +index 18b7b95a8253c..87730337e28f8 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -418,6 +418,47 @@ int __must_check devm_clk_bulk_get_all(struct device *dev, + */ + struct clk *devm_clk_get(struct device *dev, const char *id); + ++/** ++ * devm_clk_get_prepared - devm_clk_get() + clk_prepare() ++ * @dev: device for clock "consumer" ++ * @id: clock consumer ID ++ * ++ * Context: May sleep. ++ * ++ * Return: a struct clk corresponding to the clock producer, or ++ * valid IS_ERR() condition containing errno. The implementation ++ * uses @dev and @id to determine the clock consumer, and thereby ++ * the clock producer. (IOW, @id may be identical strings, but ++ * clk_get may return different clock producers depending on @dev.) ++ * ++ * The returned clk (if valid) is prepared. Drivers must however assume ++ * that the clock is not enabled. ++ * ++ * The clock will automatically be unprepared and freed when the device ++ * is unbound from the bus. ++ */ ++struct clk *devm_clk_get_prepared(struct device *dev, const char *id); ++ ++/** ++ * devm_clk_get_enabled - devm_clk_get() + clk_prepare_enable() ++ * @dev: device for clock "consumer" ++ * @id: clock consumer ID ++ * ++ * Context: May sleep. ++ * ++ * Return: a struct clk corresponding to the clock producer, or ++ * valid IS_ERR() condition containing errno. The implementation ++ * uses @dev and @id to determine the clock consumer, and thereby ++ * the clock producer. (IOW, @id may be identical strings, but ++ * clk_get may return different clock producers depending on @dev.) ++ * ++ * The returned clk (if valid) is prepared and enabled. ++ * ++ * The clock will automatically be disabled, unprepared and freed ++ * when the device is unbound from the bus. ++ */ ++struct clk *devm_clk_get_enabled(struct device *dev, const char *id); ++ + /** + * devm_clk_get_optional - lookup and obtain a managed reference to an optional + * clock producer. +@@ -429,6 +470,50 @@ struct clk *devm_clk_get(struct device *dev, const char *id); + */ + struct clk *devm_clk_get_optional(struct device *dev, const char *id); + ++/** ++ * devm_clk_get_optional_prepared - devm_clk_get_optional() + clk_prepare() ++ * @dev: device for clock "consumer" ++ * @id: clock consumer ID ++ * ++ * Context: May sleep. ++ * ++ * Return: a struct clk corresponding to the clock producer, or ++ * valid IS_ERR() condition containing errno. The implementation ++ * uses @dev and @id to determine the clock consumer, and thereby ++ * the clock producer. If no such clk is found, it returns NULL ++ * which serves as a dummy clk. That's the only difference compared ++ * to devm_clk_get_prepared(). ++ * ++ * The returned clk (if valid) is prepared. Drivers must however ++ * assume that the clock is not enabled. ++ * ++ * The clock will automatically be unprepared and freed when the ++ * device is unbound from the bus. ++ */ ++struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id); ++ ++/** ++ * devm_clk_get_optional_enabled - devm_clk_get_optional() + ++ * clk_prepare_enable() ++ * @dev: device for clock "consumer" ++ * @id: clock consumer ID ++ * ++ * Context: May sleep. ++ * ++ * Return: a struct clk corresponding to the clock producer, or ++ * valid IS_ERR() condition containing errno. The implementation ++ * uses @dev and @id to determine the clock consumer, and thereby ++ * the clock producer. If no such clk is found, it returns NULL ++ * which serves as a dummy clk. That's the only difference compared ++ * to devm_clk_get_enabled(). ++ * ++ * The returned clk (if valid) is prepared and enabled. ++ * ++ * The clock will automatically be disabled, unprepared and freed ++ * when the device is unbound from the bus. ++ */ ++struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id); ++ + /** + * devm_get_clk_from_child - lookup and obtain a managed reference to a + * clock producer from child node. +@@ -770,12 +855,36 @@ static inline struct clk *devm_clk_get(struct device *dev, const char *id) + return NULL; + } + ++static inline struct clk *devm_clk_get_prepared(struct device *dev, ++ const char *id) ++{ ++ return NULL; ++} ++ ++static inline struct clk *devm_clk_get_enabled(struct device *dev, ++ const char *id) ++{ ++ return NULL; ++} ++ + static inline struct clk *devm_clk_get_optional(struct device *dev, + const char *id) + { + return NULL; + } + ++static inline struct clk *devm_clk_get_optional_prepared(struct device *dev, ++ const char *id) ++{ ++ return NULL; ++} ++ ++static inline struct clk *devm_clk_get_optional_enabled(struct device *dev, ++ const char *id) ++{ ++ return NULL; ++} ++ + static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, + struct clk_bulk_data *clks) + { +diff --git a/include/linux/kernel.h b/include/linux/kernel.h +index 77c86a2236daf..1fdb251947ed4 100644 +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -321,6 +321,7 @@ extern long (*panic_blink)(int state); + __printf(1, 2) + void panic(const char *fmt, ...) __noreturn __cold; + void nmi_panic(struct pt_regs *regs, const char *msg); ++void check_panic_on_warn(const char *origin); + extern void oops_enter(void); + extern void oops_exit(void); + void print_oops_end_marker(void); +diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h +new file mode 100644 +index 0000000000000..751dab281f57e +--- /dev/null ++++ b/include/linux/mdio/mdio-i2c.h +@@ -0,0 +1,16 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * MDIO I2C bridge ++ * ++ * Copyright (C) 2015 Russell King ++ */ ++#ifndef MDIO_I2C_H ++#define MDIO_I2C_H ++ ++struct device; ++struct i2c_adapter; ++struct mii_bus; ++ ++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c); ++ ++#endif +diff --git a/include/linux/mdio/mdio-xgene.h b/include/linux/mdio/mdio-xgene.h +new file mode 100644 +index 0000000000000..b1f5ccb4ad9c3 +--- /dev/null ++++ b/include/linux/mdio/mdio-xgene.h +@@ -0,0 +1,130 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Applied Micro X-Gene SoC MDIO Driver ++ * ++ * Copyright (c) 2016, Applied Micro Circuits Corporation ++ * Author: Iyappan Subramanian ++ */ ++ ++#ifndef __MDIO_XGENE_H__ ++#define __MDIO_XGENE_H__ ++ ++#define BLOCK_XG_MDIO_CSR_OFFSET 0x5000 ++#define BLOCK_DIAG_CSR_OFFSET 0xd000 ++#define XGENET_CONFIG_REG_ADDR 0x20 ++ ++#define MAC_ADDR_REG_OFFSET 0x00 ++#define MAC_COMMAND_REG_OFFSET 0x04 ++#define MAC_WRITE_REG_OFFSET 0x08 ++#define MAC_READ_REG_OFFSET 0x0c ++#define MAC_COMMAND_DONE_REG_OFFSET 0x10 ++ ++#define CLKEN_OFFSET 0x08 ++#define SRST_OFFSET 0x00 ++ ++#define MENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70 ++#define MENET_BLOCK_MEM_RDY_ADDR 0x74 ++ ++#define MAC_CONFIG_1_ADDR 0x00 ++#define MII_MGMT_COMMAND_ADDR 0x24 ++#define MII_MGMT_ADDRESS_ADDR 0x28 ++#define MII_MGMT_CONTROL_ADDR 0x2c ++#define MII_MGMT_STATUS_ADDR 0x30 ++#define MII_MGMT_INDICATORS_ADDR 0x34 ++#define SOFT_RESET BIT(31) ++ ++#define MII_MGMT_CONFIG_ADDR 0x20 ++#define MII_MGMT_COMMAND_ADDR 0x24 ++#define MII_MGMT_ADDRESS_ADDR 0x28 ++#define MII_MGMT_CONTROL_ADDR 0x2c ++#define MII_MGMT_STATUS_ADDR 0x30 ++#define MII_MGMT_INDICATORS_ADDR 0x34 ++ ++#define MIIM_COMMAND_ADDR 0x20 ++#define MIIM_FIELD_ADDR 0x24 ++#define MIIM_CONFIGURATION_ADDR 0x28 ++#define MIIM_LINKFAILVECTOR_ADDR 0x2c ++#define MIIM_INDICATOR_ADDR 0x30 ++#define MIIMRD_FIELD_ADDR 0x34 ++ ++#define MDIO_CSR_OFFSET 0x5000 ++ ++#define REG_ADDR_POS 0 ++#define REG_ADDR_LEN 5 ++#define PHY_ADDR_POS 8 ++#define PHY_ADDR_LEN 5 ++ ++#define HSTMIIMWRDAT_POS 0 ++#define HSTMIIMWRDAT_LEN 16 ++#define HSTPHYADX_POS 23 ++#define HSTPHYADX_LEN 5 ++#define HSTREGADX_POS 18 ++#define HSTREGADX_LEN 5 ++#define HSTLDCMD BIT(3) ++#define HSTMIIMCMD_POS 0 ++#define HSTMIIMCMD_LEN 3 ++ ++#define BUSY_MASK BIT(0) ++#define READ_CYCLE_MASK BIT(0) ++ ++enum xgene_enet_cmd { ++ XGENE_ENET_WR_CMD = BIT(31), ++ XGENE_ENET_RD_CMD = BIT(30) ++}; ++ ++enum { ++ MIIM_CMD_IDLE, ++ MIIM_CMD_LEGACY_WRITE, ++ MIIM_CMD_LEGACY_READ, ++}; ++ ++enum xgene_mdio_id { ++ XGENE_MDIO_RGMII = 1, ++ XGENE_MDIO_XFI ++}; ++ ++struct xgene_mdio_pdata { ++ struct clk *clk; ++ struct device *dev; ++ void __iomem *mac_csr_addr; ++ void __iomem *diag_csr_addr; ++ void __iomem *mdio_csr_addr; ++ struct mii_bus *mdio_bus; ++ int mdio_id; ++ spinlock_t mac_lock; /* mac lock */ ++}; ++ ++/* Set the specified value into a bit-field defined by its starting position ++ * and length within a single u64. ++ */ ++static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) ++{ ++ return (val & ((1ULL << len) - 1)) << pos; ++} ++ ++#define SET_VAL(field, val) \ ++ xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) ++ ++#define SET_BIT(field) \ ++ xgene_enet_set_field_value(field ## _POS, 1, 1) ++ ++/* Get the value from a bit-field defined by its starting position ++ * and length within the specified u64. ++ */ ++static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) ++{ ++ return (src >> pos) & ((1ULL << len) - 1); ++} ++ ++#define GET_VAL(field, src) \ ++ xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) ++ ++#define GET_BIT(field, src) \ ++ xgene_enet_get_field_value(field ## _POS, 1, src) ++ ++u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr); ++void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data); ++int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg); ++int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data); ++struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr); ++ ++#endif /* __MDIO_XGENE_H__ */ +diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h +index 36f3011ab6013..6f33a07858cf6 100644 +--- a/include/linux/sched/task.h ++++ b/include/linux/sched/task.h +@@ -51,6 +51,7 @@ extern int sched_fork(unsigned long clone_flags, struct task_struct *p); + extern void sched_dead(struct task_struct *p); + + void __noreturn do_task_dead(void); ++void __noreturn make_task_dead(int signr); + + extern void proc_caches_init(void); + +diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h +index 6df477329b76e..aa615a0863f5c 100644 +--- a/include/linux/sysctl.h ++++ b/include/linux/sysctl.h +@@ -208,6 +208,9 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, + void unregister_sysctl_table(struct ctl_table_header * table); + + extern int sysctl_init(void); ++extern void __register_sysctl_init(const char *path, struct ctl_table *table, ++ const char *table_name); ++#define register_sysctl_init(path, table) __register_sysctl_init(path, table, #table) + + extern struct ctl_table sysctl_mount_point[]; + +diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h +index 1ee396ce0eda8..e8034756cbf8e 100644 +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -1334,4 +1334,11 @@ static inline void skb_tc_reinsert(struct sk_buff *skb, struct tcf_result *res) + qstats_overlimit_inc(res->qstats); + } + ++/* Make sure qdisc is no longer in SCHED state. */ ++static inline void qdisc_synchronize(const struct Qdisc *q) ++{ ++ while (test_bit(__QDISC_STATE_SCHED, &q->state)) ++ msleep(1); ++} ++ + #endif +diff --git a/include/net/sock.h b/include/net/sock.h +index f508e86a2021a..5fa255b1e0a65 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -300,7 +300,7 @@ struct bpf_sk_storage; + * @sk_tskey: counter to disambiguate concurrent tstamp requests + * @sk_zckey: counter to order MSG_ZEROCOPY notifications + * @sk_socket: Identd and reporting IO signals +- * @sk_user_data: RPC layer private data ++ * @sk_user_data: RPC layer private data. Write-protected by @sk_callback_lock. + * @sk_frag: cached page frag + * @sk_peek_off: current peek_offset value + * @sk_send_head: front of stuff to transmit +diff --git a/include/uapi/linux/netfilter/nf_conntrack_sctp.h b/include/uapi/linux/netfilter/nf_conntrack_sctp.h +index edc6ddab0de6a..2d6f80d75ae74 100644 +--- a/include/uapi/linux/netfilter/nf_conntrack_sctp.h ++++ b/include/uapi/linux/netfilter/nf_conntrack_sctp.h +@@ -15,7 +15,7 @@ enum sctp_conntrack { + SCTP_CONNTRACK_SHUTDOWN_RECD, + SCTP_CONNTRACK_SHUTDOWN_ACK_SENT, + SCTP_CONNTRACK_HEARTBEAT_SENT, +- SCTP_CONNTRACK_HEARTBEAT_ACKED, ++ SCTP_CONNTRACK_HEARTBEAT_ACKED, /* no longer used */ + SCTP_CONNTRACK_MAX + }; + +diff --git a/include/uapi/linux/netfilter/nfnetlink_cttimeout.h b/include/uapi/linux/netfilter/nfnetlink_cttimeout.h +index 6b20fb22717b2..aa805e6d4e284 100644 +--- a/include/uapi/linux/netfilter/nfnetlink_cttimeout.h ++++ b/include/uapi/linux/netfilter/nfnetlink_cttimeout.h +@@ -94,7 +94,7 @@ enum ctattr_timeout_sctp { + CTA_TIMEOUT_SCTP_SHUTDOWN_RECD, + CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT, + CTA_TIMEOUT_SCTP_HEARTBEAT_SENT, +- CTA_TIMEOUT_SCTP_HEARTBEAT_ACKED, ++ CTA_TIMEOUT_SCTP_HEARTBEAT_ACKED, /* no longer used */ + __CTA_TIMEOUT_SCTP_MAX + }; + #define CTA_TIMEOUT_SCTP_MAX (__CTA_TIMEOUT_SCTP_MAX - 1) +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 32b32ecad770d..ca7e05ddbb46e 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -1924,7 +1924,9 @@ static int check_stack_write(struct bpf_verifier_env *env, + bool sanitize = reg && is_spillable_regtype(reg->type); + + for (i = 0; i < size; i++) { +- if (state->stack[spi].slot_type[i] == STACK_INVALID) { ++ u8 type = state->stack[spi].slot_type[i]; ++ ++ if (type != STACK_MISC && type != STACK_ZERO) { + sanitize = true; + break; + } +diff --git a/kernel/exit.c b/kernel/exit.c +index ece64771a31f5..563bdaa766945 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -63,12 +63,59 @@ + #include + #include + #include ++#include + + #include + #include + #include + #include + ++/* ++ * The default value should be high enough to not crash a system that randomly ++ * crashes its kernel from time to time, but low enough to at least not permit ++ * overflowing 32-bit refcounts or the ldsem writer count. ++ */ ++static unsigned int oops_limit = 10000; ++ ++#ifdef CONFIG_SYSCTL ++static struct ctl_table kern_exit_table[] = { ++ { ++ .procname = "oops_limit", ++ .data = &oops_limit, ++ .maxlen = sizeof(oops_limit), ++ .mode = 0644, ++ .proc_handler = proc_douintvec, ++ }, ++ { } ++}; ++ ++static __init int kernel_exit_sysctls_init(void) ++{ ++ register_sysctl_init("kernel", kern_exit_table); ++ return 0; ++} ++late_initcall(kernel_exit_sysctls_init); ++#endif ++ ++static atomic_t oops_count = ATOMIC_INIT(0); ++ ++#ifdef CONFIG_SYSFS ++static ssize_t oops_count_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *page) ++{ ++ return sysfs_emit(page, "%d\n", atomic_read(&oops_count)); ++} ++ ++static struct kobj_attribute oops_count_attr = __ATTR_RO(oops_count); ++ ++static __init int kernel_exit_sysfs_init(void) ++{ ++ sysfs_add_file_to_group(kernel_kobj, &oops_count_attr.attr, NULL); ++ return 0; ++} ++late_initcall(kernel_exit_sysfs_init); ++#endif ++ + static void __unhash_process(struct task_struct *p, bool group_dead) + { + nr_threads--; +@@ -864,6 +911,31 @@ void __noreturn do_exit(long code) + } + EXPORT_SYMBOL_GPL(do_exit); + ++void __noreturn make_task_dead(int signr) ++{ ++ /* ++ * Take the task off the cpu after something catastrophic has ++ * happened. ++ */ ++ unsigned int limit; ++ ++ /* ++ * Every time the system oopses, if the oops happens while a reference ++ * to an object was held, the reference leaks. ++ * If the oops doesn't also leak memory, repeated oopsing can cause ++ * reference counters to wrap around (if they're not using refcount_t). ++ * This means that repeated oopsing can make unexploitable-looking bugs ++ * exploitable through repeated oopsing. ++ * To make sure this can't happen, place an upper bound on how often the ++ * kernel may oops without panic(). ++ */ ++ limit = READ_ONCE(oops_limit); ++ if (atomic_inc_return(&oops_count) >= limit && limit) ++ panic("Oopsed too often (kernel.oops_limit is %d)", limit); ++ ++ do_exit(signr); ++} ++ + void complete_and_exit(struct completion *comp, long code) + { + if (comp) +diff --git a/kernel/module.c b/kernel/module.c +index 7c724356aca31..30ac7514bd2bf 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -3654,7 +3654,8 @@ static bool finished_loading(const char *name) + sched_annotate_sleep(); + mutex_lock(&module_mutex); + mod = find_module_all(name, strlen(name), true); +- ret = !mod || mod->state == MODULE_STATE_LIVE; ++ ret = !mod || mod->state == MODULE_STATE_LIVE ++ || mod->state == MODULE_STATE_GOING; + mutex_unlock(&module_mutex); + + return ret; +@@ -3820,20 +3821,35 @@ static int add_unformed_module(struct module *mod) + + mod->state = MODULE_STATE_UNFORMED; + +-again: + mutex_lock(&module_mutex); + old = find_module_all(mod->name, strlen(mod->name), true); + if (old != NULL) { +- if (old->state != MODULE_STATE_LIVE) { ++ if (old->state == MODULE_STATE_COMING ++ || old->state == MODULE_STATE_UNFORMED) { + /* Wait in case it fails to load. */ + mutex_unlock(&module_mutex); + err = wait_event_interruptible(module_wq, + finished_loading(mod->name)); + if (err) + goto out_unlocked; +- goto again; ++ ++ /* The module might have gone in the meantime. */ ++ mutex_lock(&module_mutex); ++ old = find_module_all(mod->name, strlen(mod->name), ++ true); + } +- err = -EEXIST; ++ ++ /* ++ * We are here only when the same module was being loaded. Do ++ * not try to load it again right now. It prevents long delays ++ * caused by serialized module load failures. It might happen ++ * when more devices of the same type trigger load of ++ * a particular module. ++ */ ++ if (old && old->state == MODULE_STATE_LIVE) ++ err = -EEXIST; ++ else ++ err = -EBUSY; + goto out; + } + mod_update_bounds(mod); +diff --git a/kernel/panic.c b/kernel/panic.c +index f470a038b05bd..cef79466f9417 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + + #define PANIC_TIMER_STEP 100 +@@ -44,6 +45,7 @@ static int pause_on_oops_flag; + static DEFINE_SPINLOCK(pause_on_oops_lock); + bool crash_kexec_post_notifiers; + int panic_on_warn __read_mostly; ++static unsigned int warn_limit __read_mostly; + + int panic_timeout = CONFIG_PANIC_TIMEOUT; + EXPORT_SYMBOL_GPL(panic_timeout); +@@ -60,6 +62,45 @@ ATOMIC_NOTIFIER_HEAD(panic_notifier_list); + + EXPORT_SYMBOL(panic_notifier_list); + ++#ifdef CONFIG_SYSCTL ++static struct ctl_table kern_panic_table[] = { ++ { ++ .procname = "warn_limit", ++ .data = &warn_limit, ++ .maxlen = sizeof(warn_limit), ++ .mode = 0644, ++ .proc_handler = proc_douintvec, ++ }, ++ { } ++}; ++ ++static __init int kernel_panic_sysctls_init(void) ++{ ++ register_sysctl_init("kernel", kern_panic_table); ++ return 0; ++} ++late_initcall(kernel_panic_sysctls_init); ++#endif ++ ++static atomic_t warn_count = ATOMIC_INIT(0); ++ ++#ifdef CONFIG_SYSFS ++static ssize_t warn_count_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *page) ++{ ++ return sysfs_emit(page, "%d\n", atomic_read(&warn_count)); ++} ++ ++static struct kobj_attribute warn_count_attr = __ATTR_RO(warn_count); ++ ++static __init int kernel_panic_sysfs_init(void) ++{ ++ sysfs_add_file_to_group(kernel_kobj, &warn_count_attr.attr, NULL); ++ return 0; ++} ++late_initcall(kernel_panic_sysfs_init); ++#endif ++ + static long no_blink(int state) + { + return 0; +@@ -156,6 +197,19 @@ static void panic_print_sys_info(void) + ftrace_dump(DUMP_ALL); + } + ++void check_panic_on_warn(const char *origin) ++{ ++ unsigned int limit; ++ ++ if (panic_on_warn) ++ panic("%s: panic_on_warn set ...\n", origin); ++ ++ limit = READ_ONCE(warn_limit); ++ if (atomic_inc_return(&warn_count) >= limit && limit) ++ panic("%s: system warned too often (kernel.warn_limit is %d)", ++ origin, limit); ++} ++ + /** + * panic - halt the system + * @fmt: The text string to print +@@ -173,6 +227,16 @@ void panic(const char *fmt, ...) + int old_cpu, this_cpu; + bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers; + ++ if (panic_on_warn) { ++ /* ++ * This thread may hit another WARN() in the panic path. ++ * Resetting this prevents additional WARN() from panicking the ++ * system on this thread. Other threads are blocked by the ++ * panic_mutex in panic(). ++ */ ++ panic_on_warn = 0; ++ } ++ + /* + * Disable local interrupts. This will prevent panic_smp_self_stop + * from deadlocking the first cpu that invokes the panic, since +@@ -571,16 +635,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint, + if (args) + vprintk(args->fmt, args->args); + +- if (panic_on_warn) { +- /* +- * This thread may hit another WARN() in the panic path. +- * Resetting this prevents additional WARN() from panicking the +- * system on this thread. Other threads are blocked by the +- * panic_mutex in panic(). +- */ +- panic_on_warn = 0; +- panic("panic_on_warn set ...\n"); +- } ++ check_panic_on_warn("kernel"); + + print_modules(); + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 06b686ef36e68..8ab239fd1c8d3 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -3964,8 +3964,7 @@ static noinline void __schedule_bug(struct task_struct *prev) + print_ip_sym(preempt_disable_ip); + pr_cont("\n"); + } +- if (panic_on_warn) +- panic("scheduling while atomic\n"); ++ check_panic_on_warn("scheduling while atomic"); + + dump_stack(); + add_taint(TAINT_WARN, LOCKDEP_STILL_OK); +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 4d9f818029112..1e1345cd21b4f 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -649,6 +649,9 @@ BPF_CALL_1(bpf_send_signal, u32, sig) + return -EPERM; + if (unlikely(!nmi_uaccess_okay())) + return -EPERM; ++ /* Task should not be pid=1 to avoid kernel panic. */ ++ if (unlikely(is_global_init(current))) ++ return -EPERM; + + if (irqs_disabled()) { + /* Do an early check on signal validity. Otherwise, +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 1090b24041104..8b87f1f74e325 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -9317,6 +9317,8 @@ void __init early_trace_init(void) + static_key_enable(&tracepoint_printk_key.key); + } + tracer_alloc_buffers(); ++ ++ init_events(); + } + + void __init trace_init(void) +diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h +index 1d514a1a31554..f2ff39353e037 100644 +--- a/kernel/trace/trace.h ++++ b/kernel/trace/trace.h +@@ -1590,6 +1590,7 @@ extern void trace_event_enable_cmd_record(bool enable); + extern void trace_event_enable_tgid_record(bool enable); + + extern int event_trace_init(void); ++extern int init_events(void); + extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr); + extern int event_trace_del_tracer(struct trace_array *tr); + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 7b648fb9ff115..50b6fb641e5b3 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -2552,6 +2552,8 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data, + unsigned long fl = flags & ~HIST_FIELD_FL_LOG2; + hist_field->fn = hist_field_log2; + hist_field->operands[0] = create_hist_field(hist_data, field, fl, NULL); ++ if (!hist_field->operands[0]) ++ goto free; + hist_field->size = hist_field->operands[0]->size; + hist_field->type = kstrdup(hist_field->operands[0]->type, GFP_KERNEL); + if (!hist_field->type) +diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c +index a0a45901dc027..b194dd1c8420f 100644 +--- a/kernel/trace/trace_output.c ++++ b/kernel/trace/trace_output.c +@@ -1366,7 +1366,7 @@ static struct trace_event *events[] __initdata = { + NULL + }; + +-__init static int init_events(void) ++__init int init_events(void) + { + struct trace_event *event; + int i, ret; +@@ -1384,4 +1384,3 @@ __init static int init_events(void) + + return 0; + } +-early_initcall(init_events); +diff --git a/lib/lockref.c b/lib/lockref.c +index 5b34bbd3eba81..81ac5f3552428 100644 +--- a/lib/lockref.c ++++ b/lib/lockref.c +@@ -24,7 +24,6 @@ + } \ + if (!--retry) \ + break; \ +- cpu_relax(); \ + } \ + } while (0) + +diff --git a/lib/nlattr.c b/lib/nlattr.c +index 0d84f79cb4b54..b5ce5e46c06e0 100644 +--- a/lib/nlattr.c ++++ b/lib/nlattr.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -169,6 +170,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype, + if (type <= 0 || type > maxtype) + return 0; + ++ type = array_index_nospec(type, maxtype + 1); + pt = &policy[type]; + + BUG_ON(pt->type > NLA_TYPE_MAX); +@@ -377,6 +379,7 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype, + } + continue; + } ++ type = array_index_nospec(type, maxtype + 1); + if (policy) { + int err = validate_nla(nla, maxtype, policy, + validate, extack); +diff --git a/mm/kasan/report.c b/mm/kasan/report.c +index 621782100eaa0..4d87df96acc1e 100644 +--- a/mm/kasan/report.c ++++ b/mm/kasan/report.c +@@ -92,8 +92,8 @@ static void end_report(unsigned long *flags) + pr_err("==================================================================\n"); + add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); + spin_unlock_irqrestore(&report_lock, *flags); +- if (panic_on_warn) +- panic("panic_on_warn set ...\n"); ++ if (!test_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags)) ++ check_panic_on_warn("KASAN"); + kasan_enable_current(); + } + +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index e5e1c139f2118..eb5b2f45deec9 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -1582,6 +1582,7 @@ setup_failed: + hdev->flush(hdev); + + if (hdev->sent_cmd) { ++ cancel_delayed_work_sync(&hdev->cmd_timer); + kfree_skb(hdev->sent_cmd); + hdev->sent_cmd = NULL; + } +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index ff6625493c9f8..84b430986b1de 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -4177,6 +4177,19 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, + struct hci_ev_sync_conn_complete *ev = (void *) skb->data; + struct hci_conn *conn; + ++ switch (ev->link_type) { ++ case SCO_LINK: ++ case ESCO_LINK: ++ break; ++ default: ++ /* As per Core 5.3 Vol 4 Part E 7.7.35 (p.2219), Link_Type ++ * for HCI_Synchronous_Connection_Complete is limited to ++ * either SCO or eSCO ++ */ ++ bt_dev_err(hdev, "Ignoring connect complete event for invalid link type"); ++ return; ++ } ++ + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); + + hci_dev_lock(hdev); +diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c +index b96df54d00365..534a53124d14c 100644 +--- a/net/core/net_namespace.c ++++ b/net/core/net_namespace.c +@@ -140,12 +140,12 @@ static int ops_init(const struct pernet_operations *ops, struct net *net) + return 0; + + if (ops->id && ops->size) { +-cleanup: + ng = rcu_dereference_protected(net->gen, + lockdep_is_held(&pernet_ops_rwsem)); + ng->ptr[*ops->id] = NULL; + } + ++cleanup: + kfree(data); + + out: +diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c +index f45b9daf62cf3..42a4ee192f8dc 100644 +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1009,6 +1010,7 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi) + if (type > RTAX_MAX) + return false; + ++ type = array_index_nospec(type, RTAX_MAX + 1); + if (type == RTAX_CC_ALGO) { + char tmp[TCP_CA_NAME_MAX]; + bool ecn_ca = false; +diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c +index 25334aa3da04e..33292983b8cfb 100644 +--- a/net/ipv4/inet_hashtables.c ++++ b/net/ipv4/inet_hashtables.c +@@ -536,8 +536,20 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk, bool *found_dup_sk) + spin_lock(lock); + if (osk) { + WARN_ON_ONCE(sk->sk_hash != osk->sk_hash); +- ret = sk_nulls_del_node_init_rcu(osk); +- } else if (found_dup_sk) { ++ ret = sk_hashed(osk); ++ if (ret) { ++ /* Before deleting the node, we insert a new one to make ++ * sure that the look-up-sk process would not miss either ++ * of them and that at least one node would exist in ehash ++ * table all the time. Otherwise there's a tiny chance ++ * that lookup process could find nothing in ehash table. ++ */ ++ __sk_nulls_add_node_tail_rcu(sk, list); ++ sk_nulls_del_node_init_rcu(osk); ++ } ++ goto unlock; ++ } ++ if (found_dup_sk) { + *found_dup_sk = inet_ehash_lookup_by_sk(sk, list); + if (*found_dup_sk) + ret = false; +@@ -546,6 +558,7 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk, bool *found_dup_sk) + if (ret) + __sk_nulls_add_node_rcu(sk, list); + ++unlock: + spin_unlock(lock); + + return ret; +diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c +index c411c87ae865f..a00102d7c7fd4 100644 +--- a/net/ipv4/inet_timewait_sock.c ++++ b/net/ipv4/inet_timewait_sock.c +@@ -81,10 +81,10 @@ void inet_twsk_put(struct inet_timewait_sock *tw) + } + EXPORT_SYMBOL_GPL(inet_twsk_put); + +-static void inet_twsk_add_node_rcu(struct inet_timewait_sock *tw, +- struct hlist_nulls_head *list) ++static void inet_twsk_add_node_tail_rcu(struct inet_timewait_sock *tw, ++ struct hlist_nulls_head *list) + { +- hlist_nulls_add_head_rcu(&tw->tw_node, list); ++ hlist_nulls_add_tail_rcu(&tw->tw_node, list); + } + + static void inet_twsk_add_bind_node(struct inet_timewait_sock *tw, +@@ -120,7 +120,7 @@ void inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, + + spin_lock(lock); + +- inet_twsk_add_node_rcu(tw, &ehead->chain); ++ inet_twsk_add_node_tail_rcu(tw, &ehead->chain); + + /* Step 3: Remove SK from hash chain */ + if (__sk_nulls_del_node_init_rcu(sk)) +diff --git a/net/ipv4/metrics.c b/net/ipv4/metrics.c +index 3205d5f7c8c94..4966ac2aaf87d 100644 +--- a/net/ipv4/metrics.c ++++ b/net/ipv4/metrics.c +@@ -1,5 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0-only + #include ++#include + #include + #include + #include +@@ -28,6 +29,7 @@ static int ip_metrics_convert(struct net *net, struct nlattr *fc_mx, + return -EINVAL; + } + ++ type = array_index_nospec(type, RTAX_MAX + 1); + if (type == RTAX_CC_ALGO) { + char tmp[TCP_CA_NAME_MAX]; + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 93825ec968aa4..a74965a6a54f4 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -429,6 +429,7 @@ void tcp_init_sock(struct sock *sk) + + /* There's a bubble in the pipe until at least the first ACK. */ + tp->app_limited = ~0U; ++ tp->rate_app_limited = 1; + + /* See draft-stevens-tcpca-spec-01 for discussion of the + * initialization of these values. +@@ -2675,6 +2676,7 @@ int tcp_disconnect(struct sock *sk, int flags) + tp->last_oow_ack_time = 0; + /* There's a bubble in the pipe until at least the first ACK. */ + tp->app_limited = ~0U; ++ tp->rate_app_limited = 1; + tp->rack.mstamp = 0; + tp->rack.advanced = 0; + tp->rack.reo_wnd_steps = 1; +diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c +index 4a6396d574a0d..fd4da1019e44c 100644 +--- a/net/ipv6/ip6_gre.c ++++ b/net/ipv6/ip6_gre.c +@@ -1137,14 +1137,16 @@ static void ip6gre_tnl_link_config_route(struct ip6_tnl *t, int set_mtu, + dev->needed_headroom = dst_len; + + if (set_mtu) { +- dev->mtu = rt->dst.dev->mtu - t_hlen; ++ int mtu = rt->dst.dev->mtu - t_hlen; ++ + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) +- dev->mtu -= 8; ++ mtu -= 8; + if (dev->type == ARPHRD_ETHER) +- dev->mtu -= ETH_HLEN; ++ mtu -= ETH_HLEN; + +- if (dev->mtu < IPV6_MIN_MTU) +- dev->mtu = IPV6_MIN_MTU; ++ if (mtu < IPV6_MIN_MTU) ++ mtu = IPV6_MIN_MTU; ++ WRITE_ONCE(dev->mtu, mtu); + } + } + ip6_rt_put(rt); +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 878a08c40fffd..acc75975edded 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -1430,6 +1430,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) + struct __ip6_tnl_parm *p = &t->parms; + struct flowi6 *fl6 = &t->fl.u.ip6; + int t_hlen; ++ int mtu; + + memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); + memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); +@@ -1472,12 +1473,13 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) + dev->hard_header_len = rt->dst.dev->hard_header_len + + t_hlen; + +- dev->mtu = rt->dst.dev->mtu - t_hlen; ++ mtu = rt->dst.dev->mtu - t_hlen; + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) +- dev->mtu -= 8; ++ mtu -= 8; + +- if (dev->mtu < IPV6_MIN_MTU) +- dev->mtu = IPV6_MIN_MTU; ++ if (mtu < IPV6_MIN_MTU) ++ mtu = IPV6_MIN_MTU; ++ WRITE_ONCE(dev->mtu, mtu); + } + ip6_rt_put(rt); + } +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index 117d374695fe6..1179608955f5f 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -1083,10 +1083,12 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) + + if (tdev && !netif_is_l3_master(tdev)) { + int t_hlen = tunnel->hlen + sizeof(struct iphdr); ++ int mtu; + +- dev->mtu = tdev->mtu - t_hlen; +- if (dev->mtu < IPV6_MIN_MTU) +- dev->mtu = IPV6_MIN_MTU; ++ mtu = tdev->mtu - t_hlen; ++ if (mtu < IPV6_MIN_MTU) ++ mtu = IPV6_MIN_MTU; ++ WRITE_ONCE(dev->mtu, mtu); + } + } + +diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c +index 421b2c89ce12a..d001e254badad 100644 +--- a/net/l2tp/l2tp_core.c ++++ b/net/l2tp/l2tp_core.c +@@ -1171,8 +1171,10 @@ static void l2tp_tunnel_destruct(struct sock *sk) + } + + /* Remove hooks into tunnel socket */ ++ write_lock_bh(&sk->sk_callback_lock); + sk->sk_destruct = tunnel->old_sk_destruct; + sk->sk_user_data = NULL; ++ write_unlock_bh(&sk->sk_callback_lock); + + /* Call the original destructor */ + if (sk->sk_destruct) +@@ -1491,20 +1493,27 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, + sock = sockfd_lookup(tunnel->fd, &ret); + if (!sock) + goto err; +- +- ret = l2tp_validate_socket(sock->sk, net, tunnel->encap); +- if (ret < 0) +- goto err_sock; + } + ++ sk = sock->sk; ++ write_lock_bh(&sk->sk_callback_lock); ++ ret = l2tp_validate_socket(sk, net, tunnel->encap); ++ if (ret < 0) ++ goto err_inval_sock; ++ rcu_assign_sk_user_data(sk, tunnel); ++ write_unlock_bh(&sk->sk_callback_lock); ++ + tunnel->l2tp_net = net; + pn = l2tp_pernet(net); + ++ sock_hold(sk); ++ tunnel->sock = sk; ++ + spin_lock_bh(&pn->l2tp_tunnel_list_lock); + list_for_each_entry(tunnel_walk, &pn->l2tp_tunnel_list, list) { + if (tunnel_walk->tunnel_id == tunnel->tunnel_id) { + spin_unlock_bh(&pn->l2tp_tunnel_list_lock); +- ++ sock_put(sk); + ret = -EEXIST; + goto err_sock; + } +@@ -1512,10 +1521,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, + list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); + spin_unlock_bh(&pn->l2tp_tunnel_list_lock); + +- sk = sock->sk; +- sock_hold(sk); +- tunnel->sock = sk; +- + if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { + struct udp_tunnel_sock_cfg udp_cfg = { + .sk_user_data = tunnel, +@@ -1525,8 +1530,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, + }; + + setup_udp_tunnel_sock(net, sock, &udp_cfg); +- } else { +- sk->sk_user_data = tunnel; + } + + tunnel->old_sk_destruct = sk->sk_destruct; +@@ -1541,6 +1544,11 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, + return 0; + + err_sock: ++ write_lock_bh(&sk->sk_callback_lock); ++ rcu_assign_sk_user_data(sk, NULL); ++err_inval_sock: ++ write_unlock_bh(&sk->sk_callback_lock); ++ + if (tunnel->fd < 0) + sock_release(sock); + else +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index 7626f3e1c70a7..cec4b16170a0b 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -27,22 +27,16 @@ + #include + #include + +-/* FIXME: Examine ipfilter's timeouts and conntrack transitions more +- closely. They're more complex. --RR +- +- And so for me for SCTP :D -Kiran */ +- + static const char *const sctp_conntrack_names[] = { +- "NONE", +- "CLOSED", +- "COOKIE_WAIT", +- "COOKIE_ECHOED", +- "ESTABLISHED", +- "SHUTDOWN_SENT", +- "SHUTDOWN_RECD", +- "SHUTDOWN_ACK_SENT", +- "HEARTBEAT_SENT", +- "HEARTBEAT_ACKED", ++ [SCTP_CONNTRACK_NONE] = "NONE", ++ [SCTP_CONNTRACK_CLOSED] = "CLOSED", ++ [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE_WAIT", ++ [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE_ECHOED", ++ [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED", ++ [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTDOWN_SENT", ++ [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTDOWN_RECD", ++ [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT", ++ [SCTP_CONNTRACK_HEARTBEAT_SENT] = "HEARTBEAT_SENT", + }; + + #define SECS * HZ +@@ -54,12 +48,11 @@ static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = { + [SCTP_CONNTRACK_CLOSED] = 10 SECS, + [SCTP_CONNTRACK_COOKIE_WAIT] = 3 SECS, + [SCTP_CONNTRACK_COOKIE_ECHOED] = 3 SECS, +- [SCTP_CONNTRACK_ESTABLISHED] = 5 DAYS, ++ [SCTP_CONNTRACK_ESTABLISHED] = 210 SECS, + [SCTP_CONNTRACK_SHUTDOWN_SENT] = 300 SECS / 1000, + [SCTP_CONNTRACK_SHUTDOWN_RECD] = 300 SECS / 1000, + [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = 3 SECS, + [SCTP_CONNTRACK_HEARTBEAT_SENT] = 30 SECS, +- [SCTP_CONNTRACK_HEARTBEAT_ACKED] = 210 SECS, + }; + + #define SCTP_FLAG_HEARTBEAT_VTAG_FAILED 1 +@@ -73,7 +66,6 @@ static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = { + #define sSR SCTP_CONNTRACK_SHUTDOWN_RECD + #define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT + #define sHS SCTP_CONNTRACK_HEARTBEAT_SENT +-#define sHA SCTP_CONNTRACK_HEARTBEAT_ACKED + #define sIV SCTP_CONNTRACK_MAX + + /* +@@ -96,9 +88,6 @@ SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite + CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of + the SHUTDOWN chunk. Connection is closed. + HEARTBEAT_SENT - We have seen a HEARTBEAT in a new flow. +-HEARTBEAT_ACKED - We have seen a HEARTBEAT-ACK in the direction opposite to +- that of the HEARTBEAT chunk. Secondary connection is +- established. + */ + + /* TODO +@@ -115,33 +104,33 @@ cookie echoed to closed. + static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = { + { + /* ORIGINAL */ +-/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA */ +-/* init */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCW, sHA}, +-/* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA}, +-/* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, +-/* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA, sCL, sSS}, +-/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA, sHA}, +-/* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* Can't have Stale cookie*/ +-/* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* 5.2.4 - Big TODO */ +-/* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* Can't come in orig dir */ +-/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL, sHA}, +-/* heartbeat */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA}, +-/* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA} ++/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS */ ++/* init */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCW}, ++/* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL}, ++/* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, ++/* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA, sCL}, ++/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA}, ++/* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't have Stale cookie*/ ++/* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL},/* 5.2.4 - Big TODO */ ++/* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */ ++/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL}, ++/* heartbeat */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, ++/* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, + }, + { + /* REPLY */ +-/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA */ +-/* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA},/* INIT in sCL Big TODO */ +-/* init_ack */ {sIV, sCW, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA}, +-/* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV, sCL}, +-/* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV, sSR}, +-/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV, sHA}, +-/* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV, sHA}, +-/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA},/* Can't come in reply dir */ +-/* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV, sHA}, +-/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV, sHA}, +-/* heartbeat */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA}, +-/* heartbeat_ack*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHA, sHA} ++/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS */ ++/* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV},/* INIT in sCL Big TODO */ ++/* init_ack */ {sIV, sCW, sCW, sCE, sES, sSS, sSR, sSA, sIV}, ++/* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV}, ++/* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV}, ++/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV}, ++/* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV}, ++/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */ ++/* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV}, ++/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV}, ++/* heartbeat */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, ++/* heartbeat_ack*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sES}, + } + }; + +@@ -412,22 +401,29 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { + /* Special cases of Verification tag check (Sec 8.5.1) */ + if (sch->type == SCTP_CID_INIT) { +- /* Sec 8.5.1 (A) */ ++ /* (A) vtag MUST be zero */ + if (sh->vtag != 0) + goto out_unlock; + } else if (sch->type == SCTP_CID_ABORT) { +- /* Sec 8.5.1 (B) */ +- if (sh->vtag != ct->proto.sctp.vtag[dir] && +- sh->vtag != ct->proto.sctp.vtag[!dir]) ++ /* (B) vtag MUST match own vtag if T flag is unset OR ++ * MUST match peer's vtag if T flag is set ++ */ ++ if ((!(sch->flags & SCTP_CHUNK_FLAG_T) && ++ sh->vtag != ct->proto.sctp.vtag[dir]) || ++ ((sch->flags & SCTP_CHUNK_FLAG_T) && ++ sh->vtag != ct->proto.sctp.vtag[!dir])) + goto out_unlock; + } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { +- /* Sec 8.5.1 (C) */ +- if (sh->vtag != ct->proto.sctp.vtag[dir] && +- sh->vtag != ct->proto.sctp.vtag[!dir] && +- sch->flags & SCTP_CHUNK_FLAG_T) ++ /* (C) vtag MUST match own vtag if T flag is unset OR ++ * MUST match peer's vtag if T flag is set ++ */ ++ if ((!(sch->flags & SCTP_CHUNK_FLAG_T) && ++ sh->vtag != ct->proto.sctp.vtag[dir]) || ++ ((sch->flags & SCTP_CHUNK_FLAG_T) && ++ sh->vtag != ct->proto.sctp.vtag[!dir])) + goto out_unlock; + } else if (sch->type == SCTP_CID_COOKIE_ECHO) { +- /* Sec 8.5.1 (D) */ ++ /* (D) vtag must be same as init_vtag as found in INIT_ACK */ + if (sh->vtag != ct->proto.sctp.vtag[dir]) + goto out_unlock; + } else if (sch->type == SCTP_CID_HEARTBEAT) { +@@ -501,8 +497,12 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + } + + ct->proto.sctp.state = new_state; +- if (old_state != new_state) ++ if (old_state != new_state) { + nf_conntrack_event_cache(IPCT_PROTOINFO, ct); ++ if (new_state == SCTP_CONNTRACK_ESTABLISHED && ++ !test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) ++ nf_conntrack_event_cache(IPCT_ASSURED, ct); ++ } + } + spin_unlock_bh(&ct->lock); + +@@ -516,14 +516,6 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + + nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); + +- if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED && +- dir == IP_CT_DIR_REPLY && +- new_state == SCTP_CONNTRACK_ESTABLISHED) { +- pr_debug("Setting assured bit\n"); +- set_bit(IPS_ASSURED_BIT, &ct->status); +- nf_conntrack_event_cache(IPCT_ASSURED, ct); +- } +- + return NF_ACCEPT; + + out_unlock: +diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c +index b8cc3339a2495..aed967e2f30fb 100644 +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -1158,6 +1158,16 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, + nf_ct_kill_acct(ct, ctinfo, skb); + return NF_ACCEPT; + } ++ ++ if (index == TCP_SYN_SET && old_state == TCP_CONNTRACK_SYN_SENT) { ++ /* do not renew timeout on SYN retransmit. ++ * ++ * Else port reuse by client or NAT middlebox can keep ++ * entry alive indefinitely (including nat info). ++ */ ++ return NF_ACCEPT; ++ } ++ + /* ESTABLISHED without SEEN_REPLY, i.e. mid-connection + * pickup with loose=1. Avoid large ESTABLISHED timeout. + */ +diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c +index a3faeacaa1cbb..43c3c3be6defc 100644 +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -581,7 +581,6 @@ enum nf_ct_sysctl_index { + NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_RECD, + NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT, + NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_SENT, +- NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_ACKED, + #endif + #ifdef CONFIG_NF_CT_PROTO_DCCP + NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_REQUEST, +@@ -851,12 +850,6 @@ static struct ctl_table nf_ct_sysctl_table[] = { + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, +- [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_ACKED] = { +- .procname = "nf_conntrack_sctp_timeout_heartbeat_acked", +- .maxlen = sizeof(unsigned int), +- .mode = 0644, +- .proc_handler = proc_dointvec_jiffies, +- }, + #endif + #ifdef CONFIG_NF_CT_PROTO_DCCP + [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_REQUEST] = { +@@ -985,7 +978,6 @@ static void nf_conntrack_standalone_init_sctp_sysctl(struct net *net, + XASSIGN(SHUTDOWN_RECD, sn); + XASSIGN(SHUTDOWN_ACK_SENT, sn); + XASSIGN(HEARTBEAT_SENT, sn); +- XASSIGN(HEARTBEAT_ACKED, sn); + #undef XASSIGN + #endif + } +diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c +index ee7c29e0a9d7b..093eea02f9d28 100644 +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -389,23 +389,37 @@ static void nft_rbtree_gc(struct work_struct *work) + struct nft_rbtree *priv; + struct rb_node *node; + struct nft_set *set; ++ struct net *net; ++ u8 genmask; + + priv = container_of(work, struct nft_rbtree, gc_work.work); + set = nft_set_container_of(priv); ++ net = read_pnet(&set->net); ++ genmask = nft_genmask_cur(net); + + write_lock_bh(&priv->lock); + write_seqcount_begin(&priv->count); + for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) { + rbe = rb_entry(node, struct nft_rbtree_elem, node); + ++ if (!nft_set_elem_active(&rbe->ext, genmask)) ++ continue; ++ ++ /* elements are reversed in the rbtree for historical reasons, ++ * from highest to lowest value, that is why end element is ++ * always visited before the start element. ++ */ + if (nft_rbtree_interval_end(rbe)) { + rbe_end = rbe; + continue; + } + if (!nft_set_elem_expired(&rbe->ext)) + continue; +- if (nft_set_elem_mark_busy(&rbe->ext)) ++ ++ if (nft_set_elem_mark_busy(&rbe->ext)) { ++ rbe_end = NULL; + continue; ++ } + + if (rbe_prev) { + rb_erase(&rbe_prev->node, &priv->root); +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 86b70385dce3b..a232fcbd721c4 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -569,7 +569,9 @@ static int netlink_insert(struct sock *sk, u32 portid) + if (nlk_sk(sk)->bound) + goto err; + +- nlk_sk(sk)->portid = portid; ++ /* portid can be read locklessly from netlink_getname(). */ ++ WRITE_ONCE(nlk_sk(sk)->portid, portid); ++ + sock_hold(sk); + + err = __netlink_insert(table, sk); +@@ -1078,9 +1080,11 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, + return -EINVAL; + + if (addr->sa_family == AF_UNSPEC) { +- sk->sk_state = NETLINK_UNCONNECTED; +- nlk->dst_portid = 0; +- nlk->dst_group = 0; ++ /* paired with READ_ONCE() in netlink_getsockbyportid() */ ++ WRITE_ONCE(sk->sk_state, NETLINK_UNCONNECTED); ++ /* dst_portid and dst_group can be read locklessly */ ++ WRITE_ONCE(nlk->dst_portid, 0); ++ WRITE_ONCE(nlk->dst_group, 0); + return 0; + } + if (addr->sa_family != AF_NETLINK) +@@ -1101,9 +1105,11 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, + err = netlink_autobind(sock); + + if (err == 0) { +- sk->sk_state = NETLINK_CONNECTED; +- nlk->dst_portid = nladdr->nl_pid; +- nlk->dst_group = ffs(nladdr->nl_groups); ++ /* paired with READ_ONCE() in netlink_getsockbyportid() */ ++ WRITE_ONCE(sk->sk_state, NETLINK_CONNECTED); ++ /* dst_portid and dst_group can be read locklessly */ ++ WRITE_ONCE(nlk->dst_portid, nladdr->nl_pid); ++ WRITE_ONCE(nlk->dst_group, ffs(nladdr->nl_groups)); + } + + return err; +@@ -1120,10 +1126,12 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, + nladdr->nl_pad = 0; + + if (peer) { +- nladdr->nl_pid = nlk->dst_portid; +- nladdr->nl_groups = netlink_group_mask(nlk->dst_group); ++ /* Paired with WRITE_ONCE() in netlink_connect() */ ++ nladdr->nl_pid = READ_ONCE(nlk->dst_portid); ++ nladdr->nl_groups = netlink_group_mask(READ_ONCE(nlk->dst_group)); + } else { +- nladdr->nl_pid = nlk->portid; ++ /* Paired with WRITE_ONCE() in netlink_insert() */ ++ nladdr->nl_pid = READ_ONCE(nlk->portid); + netlink_lock_table(); + nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; + netlink_unlock_table(); +@@ -1150,8 +1158,9 @@ static struct sock *netlink_getsockbyportid(struct sock *ssk, u32 portid) + + /* Don't bother queuing skb if kernel socket has no input function */ + nlk = nlk_sk(sock); +- if (sock->sk_state == NETLINK_CONNECTED && +- nlk->dst_portid != nlk_sk(ssk)->portid) { ++ /* dst_portid and sk_state can be changed in netlink_connect() */ ++ if (READ_ONCE(sock->sk_state) == NETLINK_CONNECTED && ++ READ_ONCE(nlk->dst_portid) != nlk_sk(ssk)->portid) { + sock_put(sock); + return ERR_PTR(-ECONNREFUSED); + } +@@ -1887,8 +1896,9 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) + goto out; + netlink_skb_flags |= NETLINK_SKB_DST; + } else { +- dst_portid = nlk->dst_portid; +- dst_group = nlk->dst_group; ++ /* Paired with WRITE_ONCE() in netlink_connect() */ ++ dst_portid = READ_ONCE(nlk->dst_portid); ++ dst_group = READ_ONCE(nlk->dst_group); + } + + /* Paired with WRITE_ONCE() in netlink_insert() */ +diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c +index a8da88db7893f..4e7c968cde2dc 100644 +--- a/net/netrom/nr_timer.c ++++ b/net/netrom/nr_timer.c +@@ -121,6 +121,7 @@ static void nr_heartbeat_expiry(struct timer_list *t) + is accepted() it isn't 'dead' so doesn't get removed. */ + if (sock_flag(sk, SOCK_DESTROY) || + (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { ++ sock_hold(sk); + bh_unlock_sock(sk); + nr_destroy_socket(sk); + goto out; +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index cc997518f79d1..edadebb3efd2a 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -159,6 +159,7 @@ static void local_cleanup(struct nfc_llcp_local *local) + cancel_work_sync(&local->rx_work); + cancel_work_sync(&local->timeout_work); + kfree_skb(local->rx_pending); ++ local->rx_pending = NULL; + del_timer_sync(&local->sdreq_timer); + cancel_work_sync(&local->sdreq_timeout_work); + nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs); +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 506ebae1f72cf..b7bd8c3e31586 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -1622,6 +1622,7 @@ static void taprio_reset(struct Qdisc *sch) + int i; + + hrtimer_cancel(&q->advance_timer); ++ + if (q->qdiscs) { + for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++) + qdisc_reset(q->qdiscs[i]); +@@ -1644,6 +1645,7 @@ static void taprio_destroy(struct Qdisc *sch) + * happens in qdisc_create(), after taprio_init() has been called. + */ + hrtimer_cancel(&q->advance_timer); ++ qdisc_synchronize(sch); + + taprio_disable_offload(dev, q, NULL); + +diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c +index a825e74d01fca..614bc081ca501 100644 +--- a/net/sctp/bind_addr.c ++++ b/net/sctp/bind_addr.c +@@ -73,6 +73,12 @@ int sctp_bind_addr_copy(struct net *net, struct sctp_bind_addr *dest, + } + } + ++ /* If somehow no addresses were found that can be used with this ++ * scope, it's an error. ++ */ ++ if (list_empty(&dest->address_list)) ++ error = -ENETUNREACH; ++ + out: + if (error) + sctp_bind_addr_clean(dest); +diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c +index e13115bbe7196..0f4d39fdb48f2 100644 +--- a/net/sunrpc/xprtrdma/verbs.c ++++ b/net/sunrpc/xprtrdma/verbs.c +@@ -1037,7 +1037,6 @@ out4: + kfree(req->rl_sendbuf); + out3: + kfree(req->rl_rdmabuf); +- rpcrdma_regbuf_free(req->rl_sendbuf); + out2: + kfree(req); + out1: +diff --git a/scripts/tracing/ftrace-bisect.sh b/scripts/tracing/ftrace-bisect.sh +index 926701162bc83..bb4f59262bbe9 100755 +--- a/scripts/tracing/ftrace-bisect.sh ++++ b/scripts/tracing/ftrace-bisect.sh +@@ -12,7 +12,7 @@ + # (note, if this is a problem with function_graph tracing, then simply + # replace "function" with "function_graph" in the following steps). + # +-# # cd /sys/kernel/debug/tracing ++# # cd /sys/kernel/tracing + # # echo schedule > set_ftrace_filter + # # echo function > current_tracer + # +@@ -20,22 +20,40 @@ + # + # # echo nop > current_tracer + # +-# # cat available_filter_functions > ~/full-file ++# Starting with v5.1 this can be done with numbers, making it much faster: ++# ++# The old (slow) way, for kernels before v5.1. ++# ++# [old-way] # cat available_filter_functions > ~/full-file ++# ++# [old-way] *** Note *** this process will take several minutes to update the ++# [old-way] filters. Setting multiple functions is an O(n^2) operation, and we ++# [old-way] are dealing with thousands of functions. So go have coffee, talk ++# [old-way] with your coworkers, read facebook. And eventually, this operation ++# [old-way] will end. ++# ++# The new way (using numbers) is an O(n) operation, and usually takes less than a second. ++# ++# seq `wc -l available_filter_functions | cut -d' ' -f1` > ~/full-file ++# ++# This will create a sequence of numbers that match the functions in ++# available_filter_functions, and when echoing in a number into the ++# set_ftrace_filter file, it will enable the corresponding function in ++# O(1) time. Making enabling all functions O(n) where n is the number of ++# functions to enable. ++# ++# For either the new or old way, the rest of the operations remain the same. ++# + # # ftrace-bisect ~/full-file ~/test-file ~/non-test-file + # # cat ~/test-file > set_ftrace_filter + # +-# *** Note *** this will take several minutes. Setting multiple functions is +-# an O(n^2) operation, and we are dealing with thousands of functions. So go +-# have coffee, talk with your coworkers, read facebook. And eventually, this +-# operation will end. +-# + # # echo function > current_tracer + # + # If it crashes, we know that ~/test-file has a bad function. + # + # Reboot back to test kernel. + # +-# # cd /sys/kernel/debug/tracing ++# # cd /sys/kernel/tracing + # # mv ~/test-file ~/full-file + # + # If it didn't crash. +diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile +index cca5a3012fee2..221eaadffb09c 100644 +--- a/security/tomoyo/Makefile ++++ b/security/tomoyo/Makefile +@@ -10,7 +10,7 @@ endef + quiet_cmd_policy = POLICY $@ + cmd_policy = ($(call do_policy,profile); $(call do_policy,exception_policy); $(call do_policy,domain_policy); $(call do_policy,manager); $(call do_policy,stat)) >$@ + +-$(obj)/builtin-policy.h: $(wildcard $(obj)/policy/*.conf $(src)/policy/*.conf.default) FORCE ++$(obj)/builtin-policy.h: $(wildcard $(obj)/policy/*.conf $(srctree)/$(src)/policy/*.conf.default) FORCE + $(call if_changed,policy) + + $(obj)/common.o: $(obj)/builtin-policy.h +diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c +index 39ea9bda13947..db663e7d17a42 100644 +--- a/sound/soc/fsl/fsl-asoc-card.c ++++ b/sound/soc/fsl/fsl-asoc-card.c +@@ -112,11 +112,11 @@ static const struct snd_soc_dapm_route audio_map[] = { + + static const struct snd_soc_dapm_route audio_map_ac97[] = { + /* 1st half -- Normal DAPM routes */ +- {"Playback", NULL, "AC97 Playback"}, +- {"AC97 Capture", NULL, "Capture"}, ++ {"AC97 Playback", NULL, "CPU AC97 Playback"}, ++ {"CPU AC97 Capture", NULL, "AC97 Capture"}, + /* 2nd half -- ASRC DAPM routes */ +- {"AC97 Playback", NULL, "ASRC-Playback"}, +- {"ASRC-Capture", NULL, "AC97 Capture"}, ++ {"CPU AC97 Playback", NULL, "ASRC-Playback"}, ++ {"ASRC-Capture", NULL, "CPU AC97 Capture"}, + }; + + /* Add all possible widgets into here without being redundant */ +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index f7f2d29f1bfed..b33746d586337 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -87,21 +87,21 @@ static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0); + + static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { + SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, +- MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv), ++ MICFIL_OUTGAIN_CHX_SHIFT(0), 0x8, 0xF, gain_tlv), + SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL, +- MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0x7, gain_tlv), ++ MICFIL_OUTGAIN_CHX_SHIFT(1), 0x8, 0xF, gain_tlv), + SOC_SINGLE_SX_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL, +- MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0x7, gain_tlv), ++ MICFIL_OUTGAIN_CHX_SHIFT(2), 0x8, 0xF, gain_tlv), + SOC_SINGLE_SX_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL, +- MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0x7, gain_tlv), ++ MICFIL_OUTGAIN_CHX_SHIFT(3), 0x8, 0xF, gain_tlv), + SOC_SINGLE_SX_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL, +- MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0x7, gain_tlv), ++ MICFIL_OUTGAIN_CHX_SHIFT(4), 0x8, 0xF, gain_tlv), + SOC_SINGLE_SX_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL, +- MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0x7, gain_tlv), ++ MICFIL_OUTGAIN_CHX_SHIFT(5), 0x8, 0xF, gain_tlv), + SOC_SINGLE_SX_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL, +- MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0x7, gain_tlv), ++ MICFIL_OUTGAIN_CHX_SHIFT(6), 0x8, 0xF, gain_tlv), + SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL, +- MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0x7, gain_tlv), ++ MICFIL_OUTGAIN_CHX_SHIFT(7), 0x8, 0xF, gain_tlv), + SOC_ENUM_EXT("MICFIL Quality Select", + fsl_micfil_quality_enum, + snd_soc_get_enum_double, snd_soc_put_enum_double), +diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c +index ed18bc69e0954..0ab35c3dc7d2f 100644 +--- a/sound/soc/fsl/fsl_ssi.c ++++ b/sound/soc/fsl/fsl_ssi.c +@@ -1147,14 +1147,14 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { + .symmetric_channels = 1, + .probe = fsl_ssi_dai_probe, + .playback = { +- .stream_name = "AC97 Playback", ++ .stream_name = "CPU AC97 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S20, + }, + .capture = { +- .stream_name = "AC97 Capture", ++ .stream_name = "CPU AC97 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index ccf5580442d29..dfd67243faac0 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -136,6 +136,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, + "panic", + "do_exit", + "do_task_dead", ++ "make_task_dead", + "__module_put_and_exit", + "complete_and_exit", + "__reiserfs_panic", +@@ -143,7 +144,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, + "fortify_panic", + "usercopy_abort", + "machine_real_restart", +- "rewind_stack_do_exit", ++ "rewind_stack_and_make_dead", + "cpu_bringup_and_idle", + }; + +diff --git a/tools/testing/selftests/bpf/prog_tests/jeq_infer_not_null.c b/tools/testing/selftests/bpf/prog_tests/jeq_infer_not_null.c +deleted file mode 100644 +index 3add34df57678..0000000000000 +--- a/tools/testing/selftests/bpf/prog_tests/jeq_infer_not_null.c ++++ /dev/null +@@ -1,9 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +- +-#include +-#include "jeq_infer_not_null_fail.skel.h" +- +-void test_jeq_infer_not_null(void) +-{ +- RUN_TESTS(jeq_infer_not_null_fail); +-} +diff --git a/tools/testing/selftests/bpf/progs/jeq_infer_not_null_fail.c b/tools/testing/selftests/bpf/progs/jeq_infer_not_null_fail.c +deleted file mode 100644 +index f46965053acb2..0000000000000 +--- a/tools/testing/selftests/bpf/progs/jeq_infer_not_null_fail.c ++++ /dev/null +@@ -1,42 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +- +-#include "vmlinux.h" +-#include +-#include "bpf_misc.h" +- +-char _license[] SEC("license") = "GPL"; +- +-struct { +- __uint(type, BPF_MAP_TYPE_HASH); +- __uint(max_entries, 1); +- __type(key, u64); +- __type(value, u64); +-} m_hash SEC(".maps"); +- +-SEC("?raw_tp") +-__failure __msg("R8 invalid mem access 'map_value_or_null") +-int jeq_infer_not_null_ptr_to_btfid(void *ctx) +-{ +- struct bpf_map *map = (struct bpf_map *)&m_hash; +- struct bpf_map *inner_map = map->inner_map_meta; +- u64 key = 0, ret = 0, *val; +- +- val = bpf_map_lookup_elem(map, &key); +- /* Do not mark ptr as non-null if one of them is +- * PTR_TO_BTF_ID (R9), reject because of invalid +- * access to map value (R8). +- * +- * Here, we need to inline those insns to access +- * R8 directly, since compiler may use other reg +- * once it figures out val==inner_map. +- */ +- asm volatile("r8 = %[val];\n" +- "r9 = %[inner_map];\n" +- "if r8 != r9 goto +1;\n" +- "%[ret] = *(u64 *)(r8 +0);\n" +- : [ret] "+r"(ret) +- : [inner_map] "r"(inner_map), [val] "r"(val) +- : "r8", "r9"); +- +- return ret; +-} diff --git a/patch/kernel/archive/odroidxu4-5.4/patch-5.4.231-232.patch b/patch/kernel/archive/odroidxu4-5.4/patch-5.4.231-232.patch new file mode 100644 index 0000000000..a876dddddb --- /dev/null +++ b/patch/kernel/archive/odroidxu4-5.4/patch-5.4.231-232.patch @@ -0,0 +1,9585 @@ +diff --git a/Makefile b/Makefile +index 3cbbc82e2ddf2..87828284236e3 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 5 + PATCHLEVEL = 4 +-SUBLEVEL = 231 ++SUBLEVEL = 232 + EXTRAVERSION = + NAME = Kleptomaniac Octopus + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index 502c4ac45c29e..8732229f0588c 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -1705,7 +1705,7 @@ + sd_emmc_b: sd@5000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0x5000 0x0 0x800>; +- interrupts = ; ++ interrupts = ; + status = "disabled"; + clocks = <&clkc CLKID_SD_EMMC_B>, + <&clkc CLKID_SD_EMMC_B_CLK0>, +@@ -1717,7 +1717,7 @@ + sd_emmc_c: mmc@7000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0x7000 0x0 0x800>; +- interrupts = ; ++ interrupts = ; + status = "disabled"; + clocks = <&clkc CLKID_SD_EMMC_C>, + <&clkc CLKID_SD_EMMC_C_CLK0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index d2d255a988a81..6b495587eee2d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2317,7 +2317,7 @@ + sd_emmc_a: sd@ffe03000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0xffe03000 0x0 0x800>; +- interrupts = ; ++ interrupts = ; + status = "disabled"; + clocks = <&clkc CLKID_SD_EMMC_A>, + <&clkc CLKID_SD_EMMC_A_CLK0>, +@@ -2329,7 +2329,7 @@ + sd_emmc_b: sd@ffe05000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0xffe05000 0x0 0x800>; +- interrupts = ; ++ interrupts = ; + status = "disabled"; + clocks = <&clkc CLKID_SD_EMMC_B>, + <&clkc CLKID_SD_EMMC_B_CLK0>, +@@ -2341,7 +2341,7 @@ + sd_emmc_c: mmc@ffe07000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0xffe07000 0x0 0x800>; +- interrupts = ; ++ interrupts = ; + status = "disabled"; + clocks = <&clkc CLKID_SD_EMMC_C>, + <&clkc CLKID_SD_EMMC_C_CLK0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index ad7bc0eec6682..0c667ec15f8cf 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -528,21 +528,21 @@ + sd_emmc_a: mmc@70000 { + compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc"; + reg = <0x0 0x70000 0x0 0x800>; +- interrupts = ; ++ interrupts = ; + status = "disabled"; + }; + + sd_emmc_b: mmc@72000 { + compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc"; + reg = <0x0 0x72000 0x0 0x800>; +- interrupts = ; ++ interrupts = ; + status = "disabled"; + }; + + sd_emmc_c: mmc@74000 { + compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc"; + reg = <0x0 0x74000 0x0 0x800>; +- interrupts = ; ++ interrupts = ; + status = "disabled"; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h b/arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h +index 93b44efdbc527..35a60b0d3a4f0 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h ++++ b/arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h +@@ -585,7 +585,7 @@ + #define MX8MM_IOMUXC_UART1_RXD_GPIO5_IO22 0x234 0x49C 0x000 0x5 0x0 + #define MX8MM_IOMUXC_UART1_RXD_TPSMP_HDATA24 0x234 0x49C 0x000 0x7 0x0 + #define MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX 0x238 0x4A0 0x000 0x0 0x0 +-#define MX8MM_IOMUXC_UART1_TXD_UART1_DTE_RX 0x238 0x4A0 0x4F4 0x0 0x0 ++#define MX8MM_IOMUXC_UART1_TXD_UART1_DTE_RX 0x238 0x4A0 0x4F4 0x0 0x1 + #define MX8MM_IOMUXC_UART1_TXD_ECSPI3_MOSI 0x238 0x4A0 0x000 0x1 0x0 + #define MX8MM_IOMUXC_UART1_TXD_GPIO5_IO23 0x238 0x4A0 0x000 0x5 0x0 + #define MX8MM_IOMUXC_UART1_TXD_TPSMP_HDATA25 0x238 0x4A0 0x000 0x7 0x0 +diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c +index 1d976f2ebff0f..2496cb2c55511 100644 +--- a/arch/parisc/kernel/firmware.c ++++ b/arch/parisc/kernel/firmware.c +@@ -1229,7 +1229,7 @@ static char __attribute__((aligned(64))) iodc_dbuf[4096]; + */ + int pdc_iodc_print(const unsigned char *str, unsigned count) + { +- unsigned int i; ++ unsigned int i, found = 0; + unsigned long flags; + + for (i = 0; i < count;) { +@@ -1238,6 +1238,7 @@ int pdc_iodc_print(const unsigned char *str, unsigned count) + iodc_dbuf[i+0] = '\r'; + iodc_dbuf[i+1] = '\n'; + i += 2; ++ found = 1; + goto print; + default: + iodc_dbuf[i] = str[i]; +@@ -1254,7 +1255,7 @@ print: + __pa(iodc_retbuf), 0, __pa(iodc_dbuf), i, 0); + spin_unlock_irqrestore(&pdc_lock, flags); + +- return i; ++ return i - found; + } + + #if !defined(BOOTLOADER) +diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c +index 9f6ff7bc06f9a..7407fee7d8182 100644 +--- a/arch/parisc/kernel/ptrace.c ++++ b/arch/parisc/kernel/ptrace.c +@@ -128,6 +128,12 @@ long arch_ptrace(struct task_struct *child, long request, + unsigned long tmp; + long ret = -EIO; + ++ unsigned long user_regs_struct_size = sizeof(struct user_regs_struct); ++#ifdef CONFIG_64BIT ++ if (is_compat_task()) ++ user_regs_struct_size /= 2; ++#endif ++ + switch (request) { + + /* Read the word at location addr in the USER area. For ptraced +@@ -183,14 +189,14 @@ long arch_ptrace(struct task_struct *child, long request, + return copy_regset_to_user(child, + task_user_regset_view(current), + REGSET_GENERAL, +- 0, sizeof(struct user_regs_struct), ++ 0, user_regs_struct_size, + datap); + + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + return copy_regset_from_user(child, + task_user_regset_view(current), + REGSET_GENERAL, +- 0, sizeof(struct user_regs_struct), ++ 0, user_regs_struct_size, + datap); + + case PTRACE_GETFPREGS: /* Get the child FPU state. */ +@@ -304,6 +310,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, + } + } + break; ++ case PTRACE_GETREGS: ++ case PTRACE_SETREGS: ++ case PTRACE_GETFPREGS: ++ case PTRACE_SETFPREGS: ++ return arch_ptrace(child, request, addr, data); + + default: + ret = compat_ptrace_request(child, request, addr, data); +diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c +index b0e4241e7609d..d42f2e091201a 100644 +--- a/arch/powerpc/perf/imc-pmu.c ++++ b/arch/powerpc/perf/imc-pmu.c +@@ -21,7 +21,7 @@ + * Used to avoid races in counting the nest-pmu units during hotplug + * register and unregister + */ +-static DEFINE_SPINLOCK(nest_init_lock); ++static DEFINE_MUTEX(nest_init_lock); + static DEFINE_PER_CPU(struct imc_pmu_ref *, local_nest_imc_refc); + static struct imc_pmu **per_nest_pmu_arr; + static cpumask_t nest_imc_cpumask; +@@ -1605,7 +1605,7 @@ static void imc_common_mem_free(struct imc_pmu *pmu_ptr) + static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr) + { + if (pmu_ptr->domain == IMC_DOMAIN_NEST) { +- spin_lock(&nest_init_lock); ++ mutex_lock(&nest_init_lock); + if (nest_pmus == 1) { + cpuhp_remove_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE); + kfree(nest_imc_refc); +@@ -1615,7 +1615,7 @@ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr) + + if (nest_pmus > 0) + nest_pmus--; +- spin_unlock(&nest_init_lock); ++ mutex_unlock(&nest_init_lock); + } + + /* Free core_imc memory */ +@@ -1772,11 +1772,11 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id + * rest. To handle the cpuhotplug callback unregister, we track + * the number of nest pmus in "nest_pmus". + */ +- spin_lock(&nest_init_lock); ++ mutex_lock(&nest_init_lock); + if (nest_pmus == 0) { + ret = init_nest_pmu_ref(); + if (ret) { +- spin_unlock(&nest_init_lock); ++ mutex_unlock(&nest_init_lock); + kfree(per_nest_pmu_arr); + per_nest_pmu_arr = NULL; + goto err_free_mem; +@@ -1784,7 +1784,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id + /* Register for cpu hotplug notification. */ + ret = nest_pmu_cpumask_init(); + if (ret) { +- spin_unlock(&nest_init_lock); ++ mutex_unlock(&nest_init_lock); + kfree(nest_imc_refc); + kfree(per_nest_pmu_arr); + per_nest_pmu_arr = NULL; +@@ -1792,7 +1792,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id + } + } + nest_pmus++; +- spin_unlock(&nest_init_lock); ++ mutex_unlock(&nest_init_lock); + break; + case IMC_DOMAIN_CORE: + ret = core_imc_pmu_cpumask_init(); +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index aed3ba97575bf..1641d82014127 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -75,6 +75,9 @@ ifeq ($(CONFIG_PERF_EVENTS),y) + KBUILD_CFLAGS += -fno-omit-frame-pointer + endif + ++# Avoid generating .eh_frame sections. ++KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables ++ + KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax) + KBUILD_AFLAGS_MODULE += $(call as-option,-Wa$(comma)-mno-relax) + +diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c +index c54bd3c799552..9d1ec8c8b7183 100644 +--- a/arch/riscv/mm/cacheflush.c ++++ b/arch/riscv/mm/cacheflush.c +@@ -71,6 +71,8 @@ void flush_icache_pte(pte_t pte) + { + struct page *page = pte_page(pte); + +- if (!test_and_set_bit(PG_dcache_clean, &page->flags)) ++ if (!test_bit(PG_dcache_clean, &page->flags)) { + flush_icache_all(); ++ set_bit(PG_dcache_clean, &page->flags); ++ } + } +diff --git a/arch/s390/boot/compressed/decompressor.c b/arch/s390/boot/compressed/decompressor.c +index 45046630c56ac..c42ab33bd4524 100644 +--- a/arch/s390/boot/compressed/decompressor.c ++++ b/arch/s390/boot/compressed/decompressor.c +@@ -80,6 +80,6 @@ void *decompress_kernel(void) + void *output = (void *)decompress_offset; + + __decompress(_compressed_start, _compressed_end - _compressed_start, +- NULL, NULL, output, 0, NULL, error); ++ NULL, NULL, output, vmlinux.image_size, NULL, error); + return output; + } +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 93727f8092ee4..cf37a61729972 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -3948,12 +3948,11 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu, + { + unsigned long val; + ++ memset(dbgregs, 0, sizeof(*dbgregs)); + memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db)); + kvm_get_dr(vcpu, 6, &val); + dbgregs->dr6 = val; + dbgregs->dr7 = vcpu->arch.dr7; +- dbgregs->flags = 0; +- memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved)); + } + + static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index fbb1676aa33f1..c06f618b1aa3c 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -3096,7 +3096,7 @@ int sata_down_spd_limit(struct ata_link *link, u32 spd_limit) + */ + if (spd > 1) + mask &= (1 << (spd - 1)) - 1; +- else ++ else if (link->sata_spd) + return -EINVAL; + + /* were we already at the bottom? */ +diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c +index f8c29b888e6b4..98cbb18f17fa3 100644 +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -781,7 +781,13 @@ static int __init sunxi_rsb_init(void) + return ret; + } + +- return platform_driver_register(&sunxi_rsb_driver); ++ ret = platform_driver_register(&sunxi_rsb_driver); ++ if (ret) { ++ bus_unregister(&sunxi_rsb_bus); ++ return ret; ++ } ++ ++ return 0; + } + module_init(sunxi_rsb_init); + +diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c +index 3a43e5d6ed3b2..4fe36d549d615 100644 +--- a/drivers/firewire/core-cdev.c ++++ b/drivers/firewire/core-cdev.c +@@ -818,8 +818,10 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg) + + r = container_of(resource, struct inbound_transaction_resource, + resource); +- if (is_fcp_request(r->request)) ++ if (is_fcp_request(r->request)) { ++ kfree(r->data); + goto out; ++ } + + if (a->length != fw_get_response_length(r->request)) { + ret = -EINVAL; +diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c +index eb98018ab420e..ed31b08855f94 100644 +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -1022,6 +1022,8 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) + /* first try to find a slot in an existing linked list entry */ + for (prsv = efi_memreserve_root->next; prsv; ) { + rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB); ++ if (!rsv) ++ return -ENOMEM; + index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size); + if (index < rsv->size) { + rsv->entry[index].base = addr; +diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c +index 5d343dc8e5354..5f577357c3e7e 100644 +--- a/drivers/firmware/efi/memattr.c ++++ b/drivers/firmware/efi/memattr.c +@@ -32,7 +32,7 @@ int __init efi_memattr_init(void) + return -ENOMEM; + } + +- if (tbl->version > 1) { ++ if (tbl->version > 2) { + pr_warn("Unexpected EFI Memory Attributes table version %d\n", + tbl->version); + goto unmap; +diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c +index 559839a960b60..04452520fd811 100644 +--- a/drivers/fpga/stratix10-soc.c ++++ b/drivers/fpga/stratix10-soc.c +@@ -218,9 +218,9 @@ static int s10_ops_write_init(struct fpga_manager *mgr, + /* Allocate buffers from the service layer's pool. */ + for (i = 0; i < NUM_SVC_BUFS; i++) { + kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE); +- if (!kbuf) { ++ if (IS_ERR(kbuf)) { + s10_free_buffers(mgr); +- ret = -ENOMEM; ++ ret = PTR_ERR(kbuf); + goto init_done; + } + +diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c +index c8ccc99e214fa..84a60d2d8e8ad 100644 +--- a/drivers/fsi/fsi-sbefifo.c ++++ b/drivers/fsi/fsi-sbefifo.c +@@ -640,7 +640,7 @@ static void sbefifo_collect_async_ffdc(struct sbefifo *sbefifo) + } + ffdc_iov.iov_base = ffdc; + ffdc_iov.iov_len = SBEFIFO_MAX_FFDC_SIZE; +- iov_iter_kvec(&ffdc_iter, WRITE, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE); ++ iov_iter_kvec(&ffdc_iter, READ, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE); + cmd[0] = cpu_to_be32(2); + cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_SBE_FFDC); + rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter); +@@ -737,7 +737,7 @@ int sbefifo_submit(struct device *dev, const __be32 *command, size_t cmd_len, + rbytes = (*resp_len) * sizeof(__be32); + resp_iov.iov_base = response; + resp_iov.iov_len = rbytes; +- iov_iter_kvec(&resp_iter, WRITE, &resp_iov, 1, rbytes); ++ iov_iter_kvec(&resp_iter, READ, &resp_iov, 1, rbytes); + + /* Perform the command */ + mutex_lock(&sbefifo->lock); +@@ -817,7 +817,7 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf, + /* Prepare iov iterator */ + resp_iov.iov_base = buf; + resp_iov.iov_len = len; +- iov_iter_init(&resp_iter, WRITE, &resp_iov, 1, len); ++ iov_iter_init(&resp_iter, READ, &resp_iov, 1, len); + + /* Perform the command */ + mutex_lock(&sbefifo->lock); +diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c +index 1107a5e7229e4..ac3ae14a4c079 100644 +--- a/drivers/i2c/busses/i2c-rk3x.c ++++ b/drivers/i2c/busses/i2c-rk3x.c +@@ -79,7 +79,7 @@ enum { + #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ + + /** +- * struct i2c_spec_values: ++ * struct i2c_spec_values - I2C specification values for various modes + * @min_hold_start_ns: min hold time (repeated) START condition + * @min_low_ns: min LOW period of the SCL clock + * @min_high_ns: min HIGH period of the SCL cloc +@@ -135,7 +135,7 @@ static const struct i2c_spec_values fast_mode_plus_spec = { + }; + + /** +- * struct rk3x_i2c_calced_timings: ++ * struct rk3x_i2c_calced_timings - calculated V1 timings + * @div_low: Divider output for low + * @div_high: Divider output for high + * @tuning: Used to adjust setup/hold data time, +@@ -158,7 +158,7 @@ enum rk3x_i2c_state { + }; + + /** +- * struct rk3x_i2c_soc_data: ++ * struct rk3x_i2c_soc_data - SOC-specific data + * @grf_offset: offset inside the grf regmap for setting the i2c type + * @calc_timings: Callback function for i2c timing information calculated + */ +@@ -238,7 +238,8 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) + } + + /** +- * Generate a START condition, which triggers a REG_INT_START interrupt. ++ * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt. ++ * @i2c: target controller data + */ + static void rk3x_i2c_start(struct rk3x_i2c *i2c) + { +@@ -257,8 +258,8 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c) + } + + /** +- * Generate a STOP condition, which triggers a REG_INT_STOP interrupt. +- * ++ * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt. ++ * @i2c: target controller data + * @error: Error code to return in rk3x_i2c_xfer + */ + static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) +@@ -297,7 +298,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) + } + + /** +- * Setup a read according to i2c->msg ++ * rk3x_i2c_prepare_read - Setup a read according to i2c->msg ++ * @i2c: target controller data + */ + static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) + { +@@ -328,7 +330,8 @@ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) + } + + /** +- * Fill the transmit buffer with data from i2c->msg ++ * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg ++ * @i2c: target controller data + */ + static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) + { +@@ -531,11 +534,10 @@ out: + } + + /** +- * Get timing values of I2C specification +- * ++ * rk3x_i2c_get_spec - Get timing values of I2C specification + * @speed: Desired SCL frequency + * +- * Returns: Matched i2c spec values. ++ * Return: Matched i2c_spec_values. + */ + static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) + { +@@ -548,13 +550,12 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) + } + + /** +- * Calculate divider values for desired SCL frequency +- * ++ * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency + * @clk_rate: I2C input clock rate + * @t: Known I2C timing information + * @t_calc: Caculated rk3x private timings that would be written into regs + * +- * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case ++ * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case + * a best-effort divider value is returned in divs. If the target rate is + * too high, we silently use the highest possible rate. + */ +@@ -709,13 +710,12 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate, + } + + /** +- * Calculate timing values for desired SCL frequency +- * ++ * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency + * @clk_rate: I2C input clock rate + * @t: Known I2C timing information + * @t_calc: Caculated rk3x private timings that would be written into regs + * +- * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case ++ * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case + * a best-effort divider value is returned in divs. If the target rate is + * too high, we silently use the highest possible rate. + * The following formulas are v1's method to calculate timings. +@@ -959,14 +959,14 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long + } + + /** +- * Setup I2C registers for an I2C operation specified by msgs, num. +- * +- * Must be called with i2c->lock held. +- * ++ * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num. ++ * @i2c: target controller data + * @msgs: I2C msgs to process + * @num: Number of msgs + * +- * returns: Number of I2C msgs processed or negative in case of error ++ * Must be called with i2c->lock held. ++ * ++ * Return: Number of I2C msgs processed or negative in case of error + */ + static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) + { +diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c +index f908476fa095d..a4e0e2b129bcf 100644 +--- a/drivers/iio/accel/hid-sensor-accel-3d.c ++++ b/drivers/iio/accel/hid-sensor-accel-3d.c +@@ -279,6 +279,7 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev, + hid_sensor_convert_timestamp( + &accel_state->common_attributes, + *(int64_t *)raw_data); ++ ret = 0; + break; + default: + break; +diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c +index 72d8fa94ab31c..86fdfea329799 100644 +--- a/drivers/iio/adc/berlin2-adc.c ++++ b/drivers/iio/adc/berlin2-adc.c +@@ -289,8 +289,10 @@ static int berlin2_adc_probe(struct platform_device *pdev) + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); +- if (!indio_dev) ++ if (!indio_dev) { ++ of_node_put(parent_np); + return -ENOMEM; ++ } + + priv = iio_priv(indio_dev); + platform_set_drvdata(pdev, indio_dev); +diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c +index c2948defa7853..0c92eb30f0d85 100644 +--- a/drivers/iio/adc/stm32-dfsdm-adc.c ++++ b/drivers/iio/adc/stm32-dfsdm-adc.c +@@ -1544,6 +1544,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = { + }, + {} + }; ++MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match); + + static int stm32_dfsdm_adc_probe(struct platform_device *pdev) + { +diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c +index fb77c3ff5a3e4..0a76081747580 100644 +--- a/drivers/iio/adc/twl6030-gpadc.c ++++ b/drivers/iio/adc/twl6030-gpadc.c +@@ -57,6 +57,18 @@ + #define TWL6030_GPADCS BIT(1) + #define TWL6030_GPADCR BIT(0) + ++#define USB_VBUS_CTRL_SET 0x04 ++#define USB_ID_CTRL_SET 0x06 ++ ++#define TWL6030_MISC1 0xE4 ++#define VBUS_MEAS 0x01 ++#define ID_MEAS 0x01 ++ ++#define VAC_MEAS 0x04 ++#define VBAT_MEAS 0x02 ++#define BB_MEAS 0x01 ++ ++ + /** + * struct twl6030_chnl_calib - channel calibration + * @gain: slope coefficient for ideal curve +@@ -927,6 +939,26 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) + return ret; + } + ++ ret = twl_i2c_write_u8(TWL_MODULE_USB, VBUS_MEAS, USB_VBUS_CTRL_SET); ++ if (ret < 0) { ++ dev_err(dev, "failed to wire up inputs\n"); ++ return ret; ++ } ++ ++ ret = twl_i2c_write_u8(TWL_MODULE_USB, ID_MEAS, USB_ID_CTRL_SET); ++ if (ret < 0) { ++ dev_err(dev, "failed to wire up inputs\n"); ++ return ret; ++ } ++ ++ ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, ++ VBAT_MEAS | BB_MEAS | VAC_MEAS, ++ TWL6030_MISC1); ++ if (ret < 0) { ++ dev_err(dev, "failed to wire up inputs\n"); ++ return ret; ++ } ++ + indio_dev->name = DRIVER_NAME; + indio_dev->dev.parent = dev; + indio_dev->info = &twl6030_gpadc_iio_info; +diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c +index efd977f70f9ea..607e2636a6d16 100644 +--- a/drivers/infiniband/hw/hfi1/file_ops.c ++++ b/drivers/infiniband/hw/hfi1/file_ops.c +@@ -1363,12 +1363,15 @@ static int user_exp_rcv_setup(struct hfi1_filedata *fd, unsigned long arg, + addr = arg + offsetof(struct hfi1_tid_info, tidcnt); + if (copy_to_user((void __user *)addr, &tinfo.tidcnt, + sizeof(tinfo.tidcnt))) +- return -EFAULT; ++ ret = -EFAULT; + + addr = arg + offsetof(struct hfi1_tid_info, length); +- if (copy_to_user((void __user *)addr, &tinfo.length, ++ if (!ret && copy_to_user((void __user *)addr, &tinfo.length, + sizeof(tinfo.length))) + ret = -EFAULT; ++ ++ if (ret) ++ hfi1_user_exp_rcv_invalid(fd, &tinfo); + } + + return ret; +diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c +index 62e6ffa9ad78e..1d060ae47933e 100644 +--- a/drivers/infiniband/hw/usnic/usnic_uiom.c ++++ b/drivers/infiniband/hw/usnic/usnic_uiom.c +@@ -281,8 +281,8 @@ iter_chunk: + size = pa_end - pa_start + PAGE_SIZE; + usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x", + va_start, &pa_start, size, flags); +- err = iommu_map(pd->domain, va_start, pa_start, +- size, flags); ++ err = iommu_map_atomic(pd->domain, va_start, ++ pa_start, size, flags); + if (err) { + usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n", + va_start, &pa_start, size, err); +@@ -298,8 +298,8 @@ iter_chunk: + size = pa - pa_start + PAGE_SIZE; + usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x\n", + va_start, &pa_start, size, flags); +- err = iommu_map(pd->domain, va_start, pa_start, +- size, flags); ++ err = iommu_map_atomic(pd->domain, va_start, ++ pa_start, size, flags); + if (err) { + usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n", + va_start, &pa_start, size, err); +diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c +index 69ecf37053a81..3c3cc6af0a1ef 100644 +--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c ++++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c +@@ -2171,6 +2171,14 @@ int ipoib_intf_init(struct ib_device *hca, u8 port, const char *name, + rn->attach_mcast = ipoib_mcast_attach; + rn->detach_mcast = ipoib_mcast_detach; + rn->hca = hca; ++ ++ rc = netif_set_real_num_tx_queues(dev, 1); ++ if (rc) ++ goto out; ++ ++ rc = netif_set_real_num_rx_queues(dev, 1); ++ if (rc) ++ goto out; + } + + priv->rn_ops = dev->netdev_ops; +diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h +index 0282c4c55e9da..6b2e88da30766 100644 +--- a/drivers/input/serio/i8042-x86ia64io.h ++++ b/drivers/input/serio/i8042-x86ia64io.h +@@ -67,25 +67,84 @@ static inline void i8042_write_command(int val) + + #include + +-static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { ++#define SERIO_QUIRK_NOKBD BIT(0) ++#define SERIO_QUIRK_NOAUX BIT(1) ++#define SERIO_QUIRK_NOMUX BIT(2) ++#define SERIO_QUIRK_FORCEMUX BIT(3) ++#define SERIO_QUIRK_UNLOCK BIT(4) ++#define SERIO_QUIRK_PROBE_DEFER BIT(5) ++#define SERIO_QUIRK_RESET_ALWAYS BIT(6) ++#define SERIO_QUIRK_RESET_NEVER BIT(7) ++#define SERIO_QUIRK_DIECT BIT(8) ++#define SERIO_QUIRK_DUMBKBD BIT(9) ++#define SERIO_QUIRK_NOLOOP BIT(10) ++#define SERIO_QUIRK_NOTIMEOUT BIT(11) ++#define SERIO_QUIRK_KBDRESET BIT(12) ++#define SERIO_QUIRK_DRITEK BIT(13) ++#define SERIO_QUIRK_NOPNP BIT(14) ++ ++/* Quirk table for different mainboards. Options similar or identical to i8042 ++ * module parameters. ++ * ORDERING IS IMPORTANT! The first match will be apllied and the rest ignored. ++ * This allows entries to overwrite vendor wide quirks on a per device basis. ++ * Where this is irrelevant, entries are sorted case sensitive by DMI_SYS_VENDOR ++ * and/or DMI_BOARD_VENDOR to make it easier to avoid dublicate entries. ++ */ ++static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { + { +- /* +- * Arima-Rioworks HDAMB - +- * AUX LOOP command does not raise AUX IRQ +- */ + .matches = { +- DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"), +- DMI_MATCH(DMI_BOARD_NAME, "HDAMB"), +- DMI_MATCH(DMI_BOARD_VERSION, "Rev E"), ++ DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* ASUS G1S */ + .matches = { +- DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), +- DMI_MATCH(DMI_BOARD_NAME, "G1S"), +- DMI_MATCH(DMI_BOARD_VERSION, "1.0"), ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "X750LN"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) ++ }, ++ { ++ /* Asus X450LCP */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_NEVER) ++ }, ++ { ++ /* ASUS ZenBook UX425UA */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425UA"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER) ++ }, ++ { ++ /* ASUS ZenBook UM325UA */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER) ++ }, ++ /* ++ * On some Asus laptops, just running self tests cause problems. ++ */ ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_NEVER) ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */ ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_NEVER) + }, + { + /* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */ +@@ -94,585 +153,681 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { + DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"), + DMI_MATCH(DMI_BOARD_VERSION, "REV 2.X"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { ++ /* ASUS G1S */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_MATCH(DMI_PRODUCT_NAME, "X750LN"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), ++ DMI_MATCH(DMI_BOARD_NAME, "G1S"), ++ DMI_MATCH(DMI_BOARD_VERSION, "1.0"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), +- DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { ++ /* Acer Aspire 5710 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), +- DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Dell Embedded Box PC 3000 */ ++ /* Acer Aspire 7738 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* OQO Model 01 */ ++ /* Acer Aspire 5536 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "OQO"), +- DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "00"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* ULI EV4873 - AUX LOOP does not work properly */ ++ /* ++ * Acer Aspire 5738z ++ * Touchpad stops working in mux mode when dis- + re-enabled ++ * with the touchpad enable/disable toggle hotkey ++ */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ULI"), +- DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "5a"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Microsoft Virtual Machine */ ++ /* Acer Aspire One 150 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Medion MAM 2070 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), +- DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "5a"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A114-31"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Medion Akoya E7225 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Medion"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A314-31"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Blue FB5601 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "blue"), +- DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "M606"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A315-31"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Gigabyte M912 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "M912"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "01"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-132"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Gigabyte M1022M netbook */ + .matches = { +- DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."), +- DMI_MATCH(DMI_BOARD_NAME, "M1022E"), +- DMI_MATCH(DMI_BOARD_VERSION, "1.02"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-332"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Gigabyte Spring Peak - defines wrong chassis type */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-432"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Gigabyte T1005 - defines wrong chassis type ("Other") */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "T1005"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate Spin B118-RN"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, ++ /* ++ * Some Wistron based laptops need us to explicitly enable the 'Dritek ++ * keyboard extension' to make their extra keys start generating scancodes. ++ * Originally, this was just confined to older laptops, but a few Acer laptops ++ * have turned up in 2007 that also need this again. ++ */ + { +- /* Gigabyte T1005M/P - defines wrong chassis type ("Other") */ ++ /* Acer Aspire 5100 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "T1005M/P"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { ++ /* Acer Aspire 5610 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { ++ /* Acer Aspire 5630 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"), +- DMI_MATCH(DMI_PRODUCT_NAME, "C15B"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { ++ /* Acer Aspire 5650 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"), +- DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, +- { } +-}; +- +-/* +- * Some Fujitsu notebooks are having trouble with touchpads if +- * active multiplexing mode is activated. Luckily they don't have +- * external PS/2 ports so we can safely disable it. +- * ... apparently some Toshibas don't like MUX mode either and +- * die horrible death on reboot. +- */ +-static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { + { +- /* Fujitsu Lifebook P7010/P7010D */ ++ /* Acer Aspire 5680 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { +- /* Fujitsu Lifebook P7010 */ ++ /* Acer Aspire 5720 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), +- DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { +- /* Fujitsu Lifebook P5020D */ ++ /* Acer Aspire 9110 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { +- /* Fujitsu Lifebook S2000 */ ++ /* Acer TravelMate 660 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { +- /* Fujitsu Lifebook S6230 */ ++ /* Acer TravelMate 2490 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { +- /* Fujitsu Lifebook T725 laptop */ ++ /* Acer TravelMate 4280 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_DRITEK) + }, + { +- /* Fujitsu Lifebook U745 */ ++ /* Amoi M636/A737 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Fujitsu T70H */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), ++ DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Fujitsu-Siemens Lifebook T3010 */ ++ /* Compal HEL80I */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), ++ DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Fujitsu-Siemens Lifebook E4010 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Fujitsu-Siemens Amilo Pro 2010 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), +- DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Fujitsu-Siemens Amilo Pro 2030 */ ++ /* Advent 4211 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), +- DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), ++ DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* +- * No data is coming from the touchscreen unless KBC +- * is in legacy mode. +- */ +- /* Panasonic CF-29 */ ++ /* Dell Embedded Box PC 3000 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), +- DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* +- * HP Pavilion DV4017EA - +- * errors on MUX ports are reported without raising AUXDATA +- * causing "spurious NAK" messages. +- */ ++ /* Dell XPS M1530 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* +- * HP Pavilion ZT1000 - +- * like DV4017EA does not raise AUXERR for errors on MUX ports. +- */ ++ /* Dell Vostro 1510 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook ZT1000"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* +- * HP Pavilion DV4270ca - +- * like DV4017EA does not raise AUXERR for errors on MUX ports. +- */ ++ /* Dell Vostro V13 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT) + }, + { ++ /* Dell Vostro 1320 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { ++ /* Dell Vostro 1520 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), +- DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { ++ /* Dell Vostro 1720 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), +- DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) ++ }, ++ { ++ /* Entroware Proteus */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Entroware"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS) + }, ++ /* ++ * Some Fujitsu notebooks are having trouble with touchpads if ++ * active multiplexing mode is activated. Luckily they don't have ++ * external PS/2 ports so we can safely disable it. ++ * ... apparently some Toshibas don't like MUX mode either and ++ * die horrible death on reboot. ++ */ + { ++ /* Fujitsu Lifebook P7010/P7010D */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Sharp Actius MM20 */ ++ /* Fujitsu Lifebook P5020D */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "SHARP"), +- DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Sony Vaio FS-115b */ ++ /* Fujitsu Lifebook S2000 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), +- DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* +- * Sony Vaio FZ-240E - +- * reset and GET ID commands issued via KBD port are +- * sometimes being delivered to AUX3. +- */ ++ /* Fujitsu Lifebook S6230 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), +- DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* +- * Most (all?) VAIOs do not have external PS/2 ports nor +- * they implement active multiplexing properly, and +- * MUX discovery usually messes up keyboard/touchpad. +- */ ++ /* Fujitsu Lifebook T725 laptop */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), +- DMI_MATCH(DMI_BOARD_NAME, "VAIO"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT) + }, + { +- /* Amoi M636/A737 */ ++ /* Fujitsu Lifebook U745 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), +- DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Lenovo 3000 n100 */ ++ /* Fujitsu T70H */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_NAME, "076804U"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Lenovo XiaoXin Air 12 */ ++ /* Fujitsu A544 laptop */ ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_NAME, "80UN"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT) + }, + { ++ /* Fujitsu AH544 laptop */ ++ /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT) ++ }, ++ { ++ /* Fujitsu U574 laptop */ ++ /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT) ++ }, ++ { ++ /* Fujitsu UH554 laptop */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK UH544"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT) ++ }, ++ { ++ /* Fujitsu Lifebook P7010 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) ++ }, ++ { ++ /* Fujitsu-Siemens Lifebook T3010 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Acer Aspire 5710 */ ++ /* Fujitsu-Siemens Lifebook E4010 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Acer Aspire 7738 */ ++ /* Fujitsu-Siemens Amilo Pro 2010 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Gericom Bellagio */ ++ /* Fujitsu-Siemens Amilo Pro 2030 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), +- DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* IBM 2656 */ ++ /* Gigabyte M912 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "IBM"), +- DMI_MATCH(DMI_PRODUCT_NAME, "2656"), ++ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "M912"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "01"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Dell XPS M1530 */ ++ /* Gigabyte Spring Peak - defines wrong chassis type */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"), ++ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Compal HEL80I */ ++ /* Gigabyte T1005 - defines wrong chassis type ("Other") */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), ++ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "T1005"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Dell Vostro 1510 */ ++ /* Gigabyte T1005M/P - defines wrong chassis type ("Other") */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), ++ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "T1005M/P"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, ++ /* ++ * Some laptops need keyboard reset before probing for the trackpad to get ++ * it detected, initialised & finally work. ++ */ + { +- /* Acer Aspire 5536 */ ++ /* Gigabyte P35 v2 - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), ++ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_KBDRESET) + }, +- { +- /* Dell Vostro V13 */ ++ { ++ /* Aorus branded Gigabyte X3 Plus - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), ++ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "X3"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_KBDRESET) + }, + { +- /* Newer HP Pavilion dv4 models */ ++ /* Gigabyte P34 - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), ++ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "P34"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_KBDRESET) + }, + { +- /* Asus X450LCP */ ++ /* Gigabyte P57 - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"), ++ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "P57"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_KBDRESET) + }, + { +- /* Avatar AVIU-145A6 */ ++ /* Gericom Bellagio */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Intel"), +- DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* TUXEDO BU1406 */ ++ /* Gigabyte M1022M netbook */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), +- DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."), ++ DMI_MATCH(DMI_BOARD_NAME, "M1022E"), ++ DMI_MATCH(DMI_BOARD_VERSION, "1.02"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Lenovo LaVie Z */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { + /* +- * Acer Aspire 5738z +- * Touchpad stops working in mux mode when dis- + re-enabled +- * with the touchpad enable/disable toggle hotkey ++ * HP Pavilion DV4017EA - ++ * errors on MUX ports are reported without raising AUXDATA ++ * causing "spurious NAK" messages. + */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Entroware Proteus */ ++ /* ++ * HP Pavilion ZT1000 - ++ * like DV4017EA does not raise AUXERR for errors on MUX ports. ++ */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Entroware"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook ZT1000"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, +- { } +-}; +- +-static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = { + { + /* +- * Sony Vaio VGN-CS series require MUX or the touch sensor +- * buttons will disturb touchpad operation ++ * HP Pavilion DV4270ca - ++ * like DV4017EA does not raise AUXERR for errors on MUX ports. + */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), +- DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, +- { } +-}; +- +-/* +- * On some Asus laptops, just running self tests cause problems. +- */ +-static const struct dmi_system_id i8042_dmi_noselftest_table[] = { + { ++ /* Newer HP Pavilion dv4 models */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ +- }, +- }, { +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */ ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT) + }, +- { } +-}; +-static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { + { +- /* MSI Wind U-100 */ ++ /* IBM 2656 */ + .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "U-100"), +- DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), ++ DMI_MATCH(DMI_SYS_VENDOR, "IBM"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "2656"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* LG Electronics X110 */ ++ /* Avatar AVIU-145A6 */ + .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "X110"), +- DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "Intel"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Acer Aspire One 150 */ ++ /* Intel MBO Desktop D845PESV */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), ++ DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOPNP) + }, + { ++ /* ++ * Intel NUC D54250WYK - does not have i8042 controller but ++ * declares PS/2 devices in DSDT. ++ */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A114-31"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), ++ DMI_MATCH(DMI_BOARD_NAME, "D54250WYK"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOPNP) + }, + { ++ /* Lenovo 3000 n100 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A314-31"), ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "076804U"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { ++ /* Lenovo XiaoXin Air 12 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A315-31"), ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "80UN"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { ++ /* Lenovo LaVie Z */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-132"), ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { ++ /* Lenovo Ideapad U455 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-332"), ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "20046"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { ++ /* Lenovo ThinkPad L460 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-432"), ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { ++ /* Lenovo ThinkPad Twist S230u */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate Spin B118-RN"), ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "33474HU"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Advent 4211 */ ++ /* LG Electronics X110 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."), ++ DMI_MATCH(DMI_BOARD_NAME, "X110"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { + /* Medion Akoya Mini E1210 */ +@@ -680,6 +835,7 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), + DMI_MATCH(DMI_PRODUCT_NAME, "E1210"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { + /* Medion Akoya E1222 */ +@@ -687,48 +843,62 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), + DMI_MATCH(DMI_PRODUCT_NAME, "E122X"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { +- /* Mivvy M310 */ ++ /* MSI Wind U-100 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"), +- DMI_MATCH(DMI_PRODUCT_NAME, "N10"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), ++ DMI_MATCH(DMI_BOARD_NAME, "U-100"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOPNP) + }, + { +- /* Dell Vostro 1320 */ ++ /* ++ * No data is coming from the touchscreen unless KBC ++ * is in legacy mode. ++ */ ++ /* Panasonic CF-29 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Dell Vostro 1520 */ ++ /* Medion Akoya E7225 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Medion"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Dell Vostro 1720 */ ++ /* Microsoft Virtual Machine */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Lenovo Ideapad U455 */ ++ /* Medion MAM 2070 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_NAME, "20046"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "5a"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Lenovo ThinkPad L460 */ ++ /* TUXEDO BU1406 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { + /* Clevo P650RS, 650RP6, Sager NP8152-S, and others */ +@@ -736,282 +906,318 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { + DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), + DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) ++ }, ++ { ++ /* OQO Model 01 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "OQO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "00"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Lenovo ThinkPad Twist S230u */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_NAME, "33474HU"), ++ DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "C15B"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* Entroware Proteus */ ++ /* Acer Aspire 5 A515 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Entroware"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"), +- DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "PK"), ++ DMI_MATCH(DMI_BOARD_NAME, "Grumpy_PK"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOPNP) + }, +- { } +-}; +- +-#ifdef CONFIG_PNP +-static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = { + { +- /* Intel MBO Desktop D845PESV */ ++ /* ULI EV4873 - AUX LOOP does not work properly */ + .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), +- DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), ++ DMI_MATCH(DMI_SYS_VENDOR, "ULI"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "5a"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { + /* +- * Intel NUC D54250WYK - does not have i8042 controller but +- * declares PS/2 devices in DSDT. ++ * Arima-Rioworks HDAMB - ++ * AUX LOOP command does not raise AUX IRQ + */ + .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "D54250WYK"), +- DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"), ++ DMI_MATCH(DMI_BOARD_NAME, "HDAMB"), ++ DMI_MATCH(DMI_BOARD_VERSION, "Rev E"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, + { +- /* MSI Wind U-100 */ ++ /* Sharp Actius MM20 */ + .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "U-100"), +- DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), ++ DMI_MATCH(DMI_SYS_VENDOR, "SHARP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Acer Aspire 5 A515 */ ++ /* ++ * Sony Vaio FZ-240E - ++ * reset and GET ID commands issued via KBD port are ++ * sometimes being delivered to AUX3. ++ */ + .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "Grumpy_PK"), +- DMI_MATCH(DMI_BOARD_VENDOR, "PK"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, +- { } +-}; +- +-static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = { + { ++ /* ++ * Most (all?) VAIOs do not have external PS/2 ports nor ++ * they implement active multiplexing properly, and ++ * MUX discovery usually messes up keyboard/touchpad. ++ */ + .matches = { +- DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_BOARD_NAME, "VAIO"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { ++ /* Sony Vaio FS-115b */ + .matches = { +- DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { ++ /* ++ * Sony Vaio VGN-CS series require MUX or the touch sensor ++ * buttons will disturb touchpad operation ++ */ + .matches = { +- DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_FORCEMUX) + }, + { + .matches = { +- DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ ++ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, +- { } +-}; +-#endif +- +-static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = { + { +- /* Dell Vostro V13 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), ++ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { +- /* Newer HP Pavilion dv4 models */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), +- DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), ++ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, ++ /* ++ * A lot of modern Clevo barebones have touchpad and/or keyboard issues ++ * after suspend fixable with nomux + reset + noloop + nopnp. Luckily, ++ * none of them have an external PS/2 port so this can safely be set for ++ * all of them. These two are based on a Clevo design, but have the ++ * board_name changed. ++ */ + { +- /* Fujitsu A544 laptop */ +- /* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "TUXEDO"), ++ DMI_MATCH(DMI_BOARD_NAME, "AURA1501"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Fujitsu AH544 laptop */ +- /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "TUXEDO"), ++ DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Fujitsu Lifebook T725 laptop */ ++ /* Mivvy M310 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"), ++ DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "N10"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, ++ /* ++ * Some laptops need keyboard reset before probing for the trackpad to get ++ * it detected, initialised & finally work. ++ */ + { +- /* Fujitsu U574 laptop */ +- /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */ ++ /* Schenker XMG C504 - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"), ++ DMI_MATCH(DMI_SYS_VENDOR, "XMG"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "C504"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_KBDRESET) + }, + { +- /* Fujitsu UH554 laptop */ ++ /* Blue FB5601 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK UH544"), ++ DMI_MATCH(DMI_SYS_VENDOR, "blue"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "M606"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOLOOP) + }, +- { } +-}; +- +-/* +- * Some Wistron based laptops need us to explicitly enable the 'Dritek +- * keyboard extension' to make their extra keys start generating scancodes. +- * Originally, this was just confined to older laptops, but a few Acer laptops +- * have turned up in 2007 that also need this again. +- */ +-static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = { ++ /* ++ * A lot of modern Clevo barebones have touchpad and/or keyboard issues ++ * after suspend fixable with nomux + reset + noloop + nopnp. Luckily, ++ * none of them have an external PS/2 port so this can safely be set for ++ * all of them. ++ * Clevo barebones come with board_vendor and/or system_vendor set to ++ * either the very generic string "Notebook" and/or a different value ++ * for each individual reseller. The only somewhat universal way to ++ * identify them is by board_name. ++ */ + { +- /* Acer Aspire 5100 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), ++ DMI_MATCH(DMI_BOARD_NAME, "LAPQC71A"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Acer Aspire 5610 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), ++ DMI_MATCH(DMI_BOARD_NAME, "LAPQC71B"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Acer Aspire 5630 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), ++ DMI_MATCH(DMI_BOARD_NAME, "N140CU"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Acer Aspire 5650 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), ++ DMI_MATCH(DMI_BOARD_NAME, "N141CU"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Acer Aspire 5680 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), ++ DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Acer Aspire 5720 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"), ++ DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, ++ /* ++ * At least one modern Clevo barebone has the touchpad connected both ++ * via PS/2 and i2c interface. This causes a race condition between the ++ * psmouse and i2c-hid driver. Since the full capability of the touchpad ++ * is available via the i2c interface and the device has no external ++ * PS/2 port, it is safe to just ignore all ps2 mouses here to avoid ++ * this issue. The known affected device is the ++ * TUXEDO InfinityBook S17 Gen6 / Clevo NS70MU which comes with one of ++ * the two different dmi strings below. NS50MU is not a typo! ++ */ + { +- /* Acer Aspire 9110 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), ++ DMI_MATCH(DMI_BOARD_NAME, "NS50MU"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOAUX | SERIO_QUIRK_NOMUX | ++ SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP | ++ SERIO_QUIRK_NOPNP) + }, + { +- /* Acer TravelMate 660 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), ++ DMI_MATCH(DMI_BOARD_NAME, "NS50_70MU"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOAUX | SERIO_QUIRK_NOMUX | ++ SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP | ++ SERIO_QUIRK_NOPNP) + }, + { +- /* Acer TravelMate 2490 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), ++ DMI_MATCH(DMI_BOARD_NAME, "NJ50_70CU"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Acer TravelMate 4280 */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), +- DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"), ++ DMI_MATCH(DMI_BOARD_NAME, "PB50_70DFx,DDx"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, +- { } +-}; +- +-/* +- * Some laptops need keyboard reset before probing for the trackpad to get +- * it detected, initialised & finally work. +- */ +-static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = { + { +- /* Gigabyte P35 v2 - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"), ++ DMI_MATCH(DMI_BOARD_NAME, "PCX0DX"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, +- { +- /* Aorus branded Gigabyte X3 Plus - Elantech touchpad */ ++ { + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "X3"), ++ DMI_MATCH(DMI_BOARD_NAME, "X170SM"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { +- /* Gigabyte P34 - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "P34"), ++ DMI_MATCH(DMI_BOARD_NAME, "X170KM-G"), + }, ++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | ++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, ++ { } ++}; ++ ++#ifdef CONFIG_PNP ++static const struct dmi_system_id i8042_dmi_laptop_table[] __initconst = { + { +- /* Gigabyte P57 - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +- DMI_MATCH(DMI_PRODUCT_NAME, "P57"), ++ DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ + }, + }, + { +- /* Schenker XMG C504 - Elantech touchpad */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "XMG"), +- DMI_MATCH(DMI_PRODUCT_NAME, "C504"), ++ DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ + }, + }, +- { } +-}; +- +-static const struct dmi_system_id i8042_dmi_probe_defer_table[] __initconst = { + { +- /* ASUS ZenBook UX425UA */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425UA"), ++ DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ + }, + }, + { +- /* ASUS ZenBook UM325UA */ + .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"), ++ DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ + }, + }, + { } + }; ++#endif + + #endif /* CONFIG_X86 */ + +@@ -1166,11 +1372,6 @@ static int __init i8042_pnp_init(void) + bool pnp_data_busted = false; + int err; + +-#ifdef CONFIG_X86 +- if (dmi_check_system(i8042_dmi_nopnp_table)) +- i8042_nopnp = true; +-#endif +- + if (i8042_nopnp) { + pr_info("PNP detection disabled\n"); + return 0; +@@ -1274,6 +1475,59 @@ static inline int i8042_pnp_init(void) { return 0; } + static inline void i8042_pnp_exit(void) { } + #endif /* CONFIG_PNP */ + ++ ++#ifdef CONFIG_X86 ++static void __init i8042_check_quirks(void) ++{ ++ const struct dmi_system_id *device_quirk_info; ++ uintptr_t quirks; ++ ++ device_quirk_info = dmi_first_match(i8042_dmi_quirk_table); ++ if (!device_quirk_info) ++ return; ++ ++ quirks = (uintptr_t)device_quirk_info->driver_data; ++ ++ if (quirks & SERIO_QUIRK_NOKBD) ++ i8042_nokbd = true; ++ if (quirks & SERIO_QUIRK_NOAUX) ++ i8042_noaux = true; ++ if (quirks & SERIO_QUIRK_NOMUX) ++ i8042_nomux = true; ++ if (quirks & SERIO_QUIRK_FORCEMUX) ++ i8042_nomux = false; ++ if (quirks & SERIO_QUIRK_UNLOCK) ++ i8042_unlock = true; ++ if (quirks & SERIO_QUIRK_PROBE_DEFER) ++ i8042_probe_defer = true; ++ /* Honor module parameter when value is not default */ ++ if (i8042_reset == I8042_RESET_DEFAULT) { ++ if (quirks & SERIO_QUIRK_RESET_ALWAYS) ++ i8042_reset = I8042_RESET_ALWAYS; ++ if (quirks & SERIO_QUIRK_RESET_NEVER) ++ i8042_reset = I8042_RESET_NEVER; ++ } ++ if (quirks & SERIO_QUIRK_DIECT) ++ i8042_direct = true; ++ if (quirks & SERIO_QUIRK_DUMBKBD) ++ i8042_dumbkbd = true; ++ if (quirks & SERIO_QUIRK_NOLOOP) ++ i8042_noloop = true; ++ if (quirks & SERIO_QUIRK_NOTIMEOUT) ++ i8042_notimeout = true; ++ if (quirks & SERIO_QUIRK_KBDRESET) ++ i8042_kbdreset = true; ++ if (quirks & SERIO_QUIRK_DRITEK) ++ i8042_dritek = true; ++#ifdef CONFIG_PNP ++ if (quirks & SERIO_QUIRK_NOPNP) ++ i8042_nopnp = true; ++#endif ++} ++#else ++static inline void i8042_check_quirks(void) {} ++#endif ++ + static int __init i8042_platform_init(void) + { + int retval; +@@ -1296,45 +1550,17 @@ static int __init i8042_platform_init(void) + i8042_kbd_irq = I8042_MAP_IRQ(1); + i8042_aux_irq = I8042_MAP_IRQ(12); + +- retval = i8042_pnp_init(); +- if (retval) +- return retval; +- + #if defined(__ia64__) +- i8042_reset = I8042_RESET_ALWAYS; ++ i8042_reset = I8042_RESET_ALWAYS; + #endif + +-#ifdef CONFIG_X86 +- /* Honor module parameter when value is not default */ +- if (i8042_reset == I8042_RESET_DEFAULT) { +- if (dmi_check_system(i8042_dmi_reset_table)) +- i8042_reset = I8042_RESET_ALWAYS; +- +- if (dmi_check_system(i8042_dmi_noselftest_table)) +- i8042_reset = I8042_RESET_NEVER; +- } +- +- if (dmi_check_system(i8042_dmi_noloop_table)) +- i8042_noloop = true; +- +- if (dmi_check_system(i8042_dmi_nomux_table)) +- i8042_nomux = true; +- +- if (dmi_check_system(i8042_dmi_forcemux_table)) +- i8042_nomux = false; +- +- if (dmi_check_system(i8042_dmi_notimeout_table)) +- i8042_notimeout = true; +- +- if (dmi_check_system(i8042_dmi_dritek_table)) +- i8042_dritek = true; +- +- if (dmi_check_system(i8042_dmi_kbdreset_table)) +- i8042_kbdreset = true; ++ i8042_check_quirks(); + +- if (dmi_check_system(i8042_dmi_probe_defer_table)) +- i8042_probe_defer = true; ++ retval = i8042_pnp_init(); ++ if (retval) ++ return retval; + ++#ifdef CONFIG_X86 + /* + * A20 was already enabled during early kernel init. But some buggy + * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to +diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c +index c392930253a30..b79309928d786 100644 +--- a/drivers/iommu/amd_iommu.c ++++ b/drivers/iommu/amd_iommu.c +@@ -3098,7 +3098,8 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, + } + + static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova, +- phys_addr_t paddr, size_t page_size, int iommu_prot) ++ phys_addr_t paddr, size_t page_size, int iommu_prot, ++ gfp_t gfp) + { + struct protection_domain *domain = to_pdomain(dom); + int prot = 0; +@@ -3113,7 +3114,7 @@ static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova, + prot |= IOMMU_PROT_IW; + + mutex_lock(&domain->api_lock); +- ret = iommu_map_page(domain, iova, paddr, page_size, prot, GFP_KERNEL); ++ ret = iommu_map_page(domain, iova, paddr, page_size, prot, gfp); + mutex_unlock(&domain->api_lock); + + domain_flush_np_cache(domain, iova, page_size); +diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c +index 02c2fb551f381..4f64c3a9ee88d 100644 +--- a/drivers/iommu/arm-smmu-v3.c ++++ b/drivers/iommu/arm-smmu-v3.c +@@ -2451,7 +2451,7 @@ out_unlock: + } + + static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops; + +diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c +index 2185ea5191c15..775acae84d7d2 100644 +--- a/drivers/iommu/arm-smmu.c ++++ b/drivers/iommu/arm-smmu.c +@@ -1160,7 +1160,7 @@ rpm_put: + } + + static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops; + struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu; +diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c +index 9c3e630c6c4c8..4fc8fb92d45ef 100644 +--- a/drivers/iommu/dma-iommu.c ++++ b/drivers/iommu/dma-iommu.c +@@ -477,7 +477,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, + if (!iova) + return DMA_MAPPING_ERROR; + +- if (iommu_map(domain, iova, phys - iova_off, size, prot)) { ++ if (iommu_map_atomic(domain, iova, phys - iova_off, size, prot)) { + iommu_dma_free_iova(cookie, iova, size); + return DMA_MAPPING_ERROR; + } +@@ -612,7 +612,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, size_t size, + arch_dma_prep_coherent(sg_page(sg), sg->length); + } + +- if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, ioprot) ++ if (iommu_map_sg_atomic(domain, iova, sgt.sgl, sgt.orig_nents, ioprot) + < size) + goto out_free_sg; + +@@ -872,7 +872,7 @@ static int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, + * We'll leave any physical concatenation to the IOMMU driver's + * implementation - it knows better than we do. + */ +- if (iommu_map_sg(domain, iova, sg, nents, prot) < iova_len) ++ if (iommu_map_sg_atomic(domain, iova, sg, nents, prot) < iova_len) + goto out_free_iova; + + return __finalise_sg(dev, sg, nents, iova); +diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c +index 31a9b9885653f..acf21e4237949 100644 +--- a/drivers/iommu/exynos-iommu.c ++++ b/drivers/iommu/exynos-iommu.c +@@ -1077,7 +1077,7 @@ static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size, + */ + static int exynos_iommu_map(struct iommu_domain *iommu_domain, + unsigned long l_iova, phys_addr_t paddr, size_t size, +- int prot) ++ int prot, gfp_t gfp) + { + struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain); + sysmmu_pte_t *entry; +diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c +index ff120d7ed3424..2a53fa7d2b47d 100644 +--- a/drivers/iommu/intel-iommu.c ++++ b/drivers/iommu/intel-iommu.c +@@ -5458,7 +5458,7 @@ static void intel_iommu_aux_detach_device(struct iommu_domain *domain, + + static int intel_iommu_map(struct iommu_domain *domain, + unsigned long iova, phys_addr_t hpa, +- size_t size, int iommu_prot) ++ size_t size, int iommu_prot, gfp_t gfp) + { + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + u64 max_addr; +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index c5758fb696cc8..ef8f0d1ac5ab1 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -1858,8 +1858,8 @@ static size_t iommu_pgsize(struct iommu_domain *domain, + return pgsize; + } + +-int iommu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++int __iommu_map(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + const struct iommu_ops *ops = domain->ops; + unsigned long orig_iova = iova; +@@ -1896,8 +1896,8 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, + + pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx\n", + iova, &paddr, pgsize); ++ ret = ops->map(domain, iova, paddr, pgsize, prot, gfp); + +- ret = ops->map(domain, iova, paddr, pgsize, prot); + if (ret) + break; + +@@ -1917,8 +1917,22 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, + + return ret; + } ++ ++int iommu_map(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t paddr, size_t size, int prot) ++{ ++ might_sleep(); ++ return __iommu_map(domain, iova, paddr, size, prot, GFP_KERNEL); ++} + EXPORT_SYMBOL_GPL(iommu_map); + ++int iommu_map_atomic(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t paddr, size_t size, int prot) ++{ ++ return __iommu_map(domain, iova, paddr, size, prot, GFP_ATOMIC); ++} ++EXPORT_SYMBOL_GPL(iommu_map_atomic); ++ + static size_t __iommu_unmap(struct iommu_domain *domain, + unsigned long iova, size_t size, + struct iommu_iotlb_gather *iotlb_gather) +@@ -1995,8 +2009,9 @@ size_t iommu_unmap_fast(struct iommu_domain *domain, + } + EXPORT_SYMBOL_GPL(iommu_unmap_fast); + +-size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, +- struct scatterlist *sg, unsigned int nents, int prot) ++size_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova, ++ struct scatterlist *sg, unsigned int nents, int prot, ++ gfp_t gfp) + { + size_t len = 0, mapped = 0; + phys_addr_t start; +@@ -2007,7 +2022,9 @@ size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, + phys_addr_t s_phys = sg_phys(sg); + + if (len && s_phys != start + len) { +- ret = iommu_map(domain, iova + mapped, start, len, prot); ++ ret = __iommu_map(domain, iova + mapped, start, ++ len, prot, gfp); ++ + if (ret) + goto out_err; + +@@ -2035,8 +2052,22 @@ out_err: + return 0; + + } ++ ++size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, ++ struct scatterlist *sg, unsigned int nents, int prot) ++{ ++ might_sleep(); ++ return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_KERNEL); ++} + EXPORT_SYMBOL_GPL(iommu_map_sg); + ++size_t iommu_map_sg_atomic(struct iommu_domain *domain, unsigned long iova, ++ struct scatterlist *sg, unsigned int nents, int prot) ++{ ++ return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_ATOMIC); ++} ++EXPORT_SYMBOL_GPL(iommu_map_sg_atomic); ++ + int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr, + phys_addr_t paddr, u64 size, int prot) + { +diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c +index 584eefab1dbcd..33874c7aea42c 100644 +--- a/drivers/iommu/ipmmu-vmsa.c ++++ b/drivers/iommu/ipmmu-vmsa.c +@@ -724,7 +724,7 @@ static void ipmmu_detach_device(struct iommu_domain *io_domain, + } + + static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); + +diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c +index cba0097eba39c..696a6c53a69fd 100644 +--- a/drivers/iommu/msm_iommu.c ++++ b/drivers/iommu/msm_iommu.c +@@ -504,7 +504,7 @@ fail: + } + + static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t pa, size_t len, int prot) ++ phys_addr_t pa, size_t len, int prot, gfp_t gfp) + { + struct msm_priv *priv = to_msm_priv(domain); + unsigned long flags; +diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c +index 18d7c818a174c..dad44e10b3314 100644 +--- a/drivers/iommu/mtk_iommu.c ++++ b/drivers/iommu/mtk_iommu.c +@@ -427,7 +427,7 @@ static void mtk_iommu_detach_device(struct iommu_domain *domain, + } + + static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct mtk_iommu_domain *dom = to_mtk_domain(domain); + struct mtk_iommu_data *data = mtk_iommu_get_m4u_data(); +diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c +index e31bd281e59d6..fa602bfe69512 100644 +--- a/drivers/iommu/mtk_iommu_v1.c ++++ b/drivers/iommu/mtk_iommu_v1.c +@@ -295,7 +295,7 @@ static void mtk_iommu_detach_device(struct iommu_domain *domain, + } + + static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct mtk_iommu_domain *dom = to_mtk_domain(domain); + unsigned int page_num = size >> MT2701_IOMMU_PAGE_SHIFT; +diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c +index 09c6e1c680db9..be551cc34be45 100644 +--- a/drivers/iommu/omap-iommu.c ++++ b/drivers/iommu/omap-iommu.c +@@ -1339,7 +1339,7 @@ static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz) + } + + static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, +- phys_addr_t pa, size_t bytes, int prot) ++ phys_addr_t pa, size_t bytes, int prot, gfp_t gfp) + { + struct omap_iommu_domain *omap_domain = to_omap_domain(domain); + struct device *dev = omap_domain->dev; +diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c +index b6e546b62a7cb..e377f7771e30b 100644 +--- a/drivers/iommu/qcom_iommu.c ++++ b/drivers/iommu/qcom_iommu.c +@@ -419,7 +419,7 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de + } + + static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + int ret; + unsigned long flags; +diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c +index 0df091934361b..96f37d9d4d93c 100644 +--- a/drivers/iommu/rockchip-iommu.c ++++ b/drivers/iommu/rockchip-iommu.c +@@ -758,7 +758,7 @@ unwind: + } + + static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct rk_iommu_domain *rk_domain = to_rk_domain(domain); + unsigned long flags; +diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c +index 3b0b18e23187c..1137f3ddcb851 100644 +--- a/drivers/iommu/s390-iommu.c ++++ b/drivers/iommu/s390-iommu.c +@@ -265,7 +265,7 @@ undo_cpu_trans: + } + + static int s390_iommu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct s390_domain *s390_domain = to_s390_domain(domain); + int flags = ZPCI_PTE_VALID, rc = 0; +diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c +index 3924f7c055440..3fb7ba72507de 100644 +--- a/drivers/iommu/tegra-gart.c ++++ b/drivers/iommu/tegra-gart.c +@@ -178,7 +178,7 @@ static inline int __gart_iommu_map(struct gart_device *gart, unsigned long iova, + } + + static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t pa, size_t bytes, int prot) ++ phys_addr_t pa, size_t bytes, int prot, gfp_t gfp) + { + struct gart_device *gart = gart_handle; + int ret; +diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c +index dd486233e2828..576be3f245daa 100644 +--- a/drivers/iommu/tegra-smmu.c ++++ b/drivers/iommu/tegra-smmu.c +@@ -651,7 +651,7 @@ static void tegra_smmu_set_pte(struct tegra_smmu_as *as, unsigned long iova, + } + + static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + struct tegra_smmu_as *as = to_smmu_as(domain); + dma_addr_t pte_dma; +diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c +index 60e659a24f90b..37e2267acf295 100644 +--- a/drivers/iommu/virtio-iommu.c ++++ b/drivers/iommu/virtio-iommu.c +@@ -715,7 +715,7 @@ static int viommu_attach_dev(struct iommu_domain *domain, struct device *dev) + } + + static int viommu_map(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot) ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + { + int ret; + u32 flags; +diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c +index aef235203d571..69eeff7a7d165 100644 +--- a/drivers/mmc/core/sdio_bus.c ++++ b/drivers/mmc/core/sdio_bus.c +@@ -269,6 +269,12 @@ static void sdio_release_func(struct device *dev) + if (!(func->card->quirks & MMC_QUIRK_NONSTD_SDIO)) + sdio_free_func_cis(func); + ++ /* ++ * We have now removed the link to the tuples in the ++ * card structure, so remove the reference. ++ */ ++ put_device(&func->card->dev); ++ + kfree(func->info); + kfree(func->tmpbuf); + kfree(func); +@@ -299,6 +305,12 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) + + device_initialize(&func->dev); + ++ /* ++ * We may link to tuples in the card structure, ++ * we need make sure we have a reference to it. ++ */ ++ get_device(&func->card->dev); ++ + func->dev.parent = &card->dev; + func->dev.bus = &sdio_bus_type; + func->dev.release = sdio_release_func; +@@ -352,10 +364,9 @@ int sdio_add_func(struct sdio_func *func) + */ + void sdio_remove_func(struct sdio_func *func) + { +- if (!sdio_func_present(func)) +- return; ++ if (sdio_func_present(func)) ++ device_del(&func->dev); + +- device_del(&func->dev); + of_node_put(func->dev.of_node); + put_device(&func->dev); + } +diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c +index 9a5aaac29099b..e45053284fdc9 100644 +--- a/drivers/mmc/core/sdio_cis.c ++++ b/drivers/mmc/core/sdio_cis.c +@@ -383,12 +383,6 @@ int sdio_read_func_cis(struct sdio_func *func) + if (ret) + return ret; + +- /* +- * Since we've linked to tuples in the card structure, +- * we must make sure we have a reference to it. +- */ +- get_device(&func->card->dev); +- + /* + * Vendor/device id is optional for function CIS, so + * copy it from the card structure as needed. +@@ -414,11 +408,5 @@ void sdio_free_func_cis(struct sdio_func *func) + } + + func->tuples = NULL; +- +- /* +- * We have now removed the link to the tuples in the +- * card structure, so remove the reference. +- */ +- put_device(&func->card->dev); + } + +diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c +index 7083d8ddd4951..7874b266a4448 100644 +--- a/drivers/mmc/host/mmc_spi.c ++++ b/drivers/mmc/host/mmc_spi.c +@@ -1420,7 +1420,7 @@ static int mmc_spi_probe(struct spi_device *spi) + + status = mmc_add_host(mmc); + if (status != 0) +- goto fail_add_host; ++ goto fail_glue_init; + + /* + * Index 0 is card detect +@@ -1428,7 +1428,7 @@ static int mmc_spi_probe(struct spi_device *spi) + */ + status = mmc_gpiod_request_cd(mmc, NULL, 0, false, 1, NULL); + if (status == -EPROBE_DEFER) +- goto fail_add_host; ++ goto fail_gpiod_request; + if (!status) { + /* + * The platform has a CD GPIO signal that may support +@@ -1443,7 +1443,7 @@ static int mmc_spi_probe(struct spi_device *spi) + /* Index 1 is write protect/read only */ + status = mmc_gpiod_request_ro(mmc, NULL, 1, 0, NULL); + if (status == -EPROBE_DEFER) +- goto fail_add_host; ++ goto fail_gpiod_request; + if (!status) + has_ro = true; + +@@ -1457,7 +1457,7 @@ static int mmc_spi_probe(struct spi_device *spi) + ? ", cd polling" : ""); + return 0; + +-fail_add_host: ++fail_gpiod_request: + mmc_remove_host(mmc); + fail_glue_init: + if (host->dma_dev) +diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c +index f3f86ef68ae0c..8b6cf2bf9025a 100644 +--- a/drivers/net/bonding/bond_debugfs.c ++++ b/drivers/net/bonding/bond_debugfs.c +@@ -76,7 +76,7 @@ void bond_debug_reregister(struct bonding *bond) + + d = debugfs_rename(bonding_debug_root, bond->debug_dir, + bonding_debug_root, bond->dev->name); +- if (d) { ++ if (!IS_ERR(d)) { + bond->debug_dir = d; + } else { + netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n"); +diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma.c b/drivers/net/ethernet/broadcom/bgmac-bcma.c +index 2d52754afc33a..7d844b0ea0da0 100644 +--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c ++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c +@@ -228,12 +228,12 @@ static int bgmac_probe(struct bcma_device *core) + bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; + bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1; + bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY; +- if (ci->pkg == BCMA_PKG_ID_BCM47188 || +- ci->pkg == BCMA_PKG_ID_BCM47186) { ++ if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) || ++ (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) { + bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII; + bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED; + } +- if (ci->pkg == BCMA_PKG_ID_BCM5358) ++ if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM5358) + bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII; + break; + case BCMA_CHIP_ID_BCM53573: +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 3636849f63656..ef8225b7445d3 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -8205,10 +8205,14 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init) + netdev_err(bp->dev, "ring reservation/IRQ init failure rc: %d\n", rc); + return rc; + } +- if (tcs && (bp->tx_nr_rings_per_tc * tcs != bp->tx_nr_rings)) { ++ if (tcs && (bp->tx_nr_rings_per_tc * tcs != ++ bp->tx_nr_rings - bp->tx_nr_rings_xdp)) { + netdev_err(bp->dev, "tx ring reservation failure\n"); + netdev_reset_tc(bp->dev); +- bp->tx_nr_rings_per_tc = bp->tx_nr_rings; ++ if (bp->tx_nr_rings_xdp) ++ bp->tx_nr_rings_per_tc = bp->tx_nr_rings_xdp; ++ else ++ bp->tx_nr_rings_per_tc = bp->tx_nr_rings; + return -ENOMEM; + } + return 0; +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index d612b23c2e3f9..3f983d69f10eb 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -2702,7 +2702,7 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu) + struct i40e_pf *pf = vsi->back; + + if (i40e_enabled_xdp_vsi(vsi)) { +- int frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; ++ int frame_size = new_mtu + I40E_PACKET_HDR_PAD; + + if (frame_size > i40e_max_xdp_frame_size(vsi)) + return -EINVAL; +@@ -12535,6 +12535,8 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, + } + + br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); ++ if (!br_spec) ++ return -EINVAL; + + nla_for_each_nested(attr, br_spec, rem) { + __u16 mode; +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index 7d28563ab7946..ae1d305672259 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -3211,7 +3211,7 @@ static int __init ice_module_init(void) + pr_info("%s - version %s\n", ice_driver_string, ice_drv_ver); + pr_info("%s\n", ice_copyright); + +- ice_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, KBUILD_MODNAME); ++ ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME); + if (!ice_wq) { + pr_err("Failed to create workqueue\n"); + return -ENOMEM; +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h +index fa49ef2afde5f..0142ca226bf50 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h +@@ -67,6 +67,8 @@ + #define IXGBE_RXBUFFER_4K 4096 + #define IXGBE_MAX_RXBUFFER 16384 /* largest size for a single descriptor */ + ++#define IXGBE_PKT_HDR_PAD (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2)) ++ + /* Attempt to maximize the headroom available for incoming frames. We + * use a 2K buffer for receives and need 1536/1534 to store the data for + * the frame. This leaves us with 512 bytes of room. From that we need +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +index f8aa1a0b89c5d..a864b91065e33 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -6721,6 +6721,18 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter) + ixgbe_free_rx_resources(adapter->rx_ring[i]); + } + ++/** ++ * ixgbe_max_xdp_frame_size - returns the maximum allowed frame size for XDP ++ * @adapter: device handle, pointer to adapter ++ */ ++static int ixgbe_max_xdp_frame_size(struct ixgbe_adapter *adapter) ++{ ++ if (PAGE_SIZE >= 8192 || adapter->flags2 & IXGBE_FLAG2_RX_LEGACY) ++ return IXGBE_RXBUFFER_2K; ++ else ++ return IXGBE_RXBUFFER_3K; ++} ++ + /** + * ixgbe_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure +@@ -6732,18 +6744,12 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + +- if (adapter->xdp_prog) { +- int new_frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + +- VLAN_HLEN; +- int i; +- +- for (i = 0; i < adapter->num_rx_queues; i++) { +- struct ixgbe_ring *ring = adapter->rx_ring[i]; ++ if (ixgbe_enabled_xdp_adapter(adapter)) { ++ int new_frame_size = new_mtu + IXGBE_PKT_HDR_PAD; + +- if (new_frame_size > ixgbe_rx_bufsz(ring)) { +- e_warn(probe, "Requested MTU size is not supported with XDP\n"); +- return -EINVAL; +- } ++ if (new_frame_size > ixgbe_max_xdp_frame_size(adapter)) { ++ e_warn(probe, "Requested MTU size is not supported with XDP\n"); ++ return -EINVAL; + } + } + +diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c +index f9c303d76658a..d0841836cf705 100644 +--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c +@@ -190,6 +190,7 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq) + .oper = IONIC_Q_ENABLE, + }, + }; ++ int ret; + + idev = &lif->ionic->idev; + dev = lif->ionic->dev; +@@ -197,16 +198,24 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq) + dev_dbg(dev, "q_enable.index %d q_enable.qtype %d\n", + ctx.cmd.q_control.index, ctx.cmd.q_control.type); + ++ if (qcq->flags & IONIC_QCQ_F_INTR) ++ ionic_intr_clean(idev->intr_ctrl, qcq->intr.index); ++ ++ ret = ionic_adminq_post_wait(lif, &ctx); ++ if (ret) ++ return ret; ++ ++ if (qcq->napi.poll) ++ napi_enable(&qcq->napi); ++ + if (qcq->flags & IONIC_QCQ_F_INTR) { + irq_set_affinity_hint(qcq->intr.vector, + &qcq->intr.affinity_mask); +- napi_enable(&qcq->napi); +- ionic_intr_clean(idev->intr_ctrl, qcq->intr.index); + ionic_intr_mask(idev->intr_ctrl, qcq->intr.index, + IONIC_INTR_MASK_CLEAR); + } + +- return ionic_adminq_post_wait(lif, &ctx); ++ return 0; + } + + static int ionic_qcq_disable(struct ionic_qcq *qcq) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +index bfc4a92f1d92b..78be62ecc9a9a 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +@@ -505,6 +505,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) + plat_dat->has_gmac4 = 1; + plat_dat->pmt = 1; + plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); ++ if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) ++ plat_dat->rx_clk_runs_in_lpi = 1; + + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +index e436fa160c7d6..59165c0560d74 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +@@ -520,9 +520,9 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, + return 0; + } + +- val |= PPSCMDx(index, 0x2); + val |= TRGTMODSELx(index, 0x2); + val |= PPSEN0; ++ writel(val, ioaddr + MAC_PPS_CONTROL); + + writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index)); + +@@ -547,6 +547,7 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, + writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index)); + + /* Finally, activate it */ ++ val |= PPSCMDx(index, 0x2); + writel(val, ioaddr + MAC_PPS_CONTROL); + return 0; + } +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 3079e52546663..6a3b0f76d9729 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -932,7 +932,8 @@ static void stmmac_mac_link_up(struct phylink_config *config, + + stmmac_mac_set(priv, priv->ioaddr, true); + if (phy && priv->dma_cap.eee) { +- priv->eee_active = phy_init_eee(phy, 1) >= 0; ++ priv->eee_active = ++ phy_init_eee(phy, !priv->plat->rx_clk_runs_in_lpi) >= 0; + priv->eee_enabled = stmmac_eee_init(priv); + stmmac_set_eee_pls(priv, priv->hw, true); + } +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +index a2ff9b4727ecd..6388bae68b659 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -554,7 +554,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) + dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst"); + + plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode"); +- if (plat->force_thresh_dma_mode) { ++ if (plat->force_thresh_dma_mode && plat->force_sf_dma_mode) { + plat->force_sf_dma_mode = 0; + dev_warn(&pdev->dev, + "force_sf_dma_mode is ignored if force_thresh_dma_mode is set.\n"); +diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c +index e8f2ca625837f..39151ec6f65e2 100644 +--- a/drivers/net/phy/meson-gxl.c ++++ b/drivers/net/phy/meson-gxl.c +@@ -235,6 +235,8 @@ static struct phy_driver meson_gxl_phy[] = { + .config_intr = meson_gxl_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .read_mmd = genphy_read_mmd_unsupported, ++ .write_mmd = genphy_write_mmd_unsupported, + }, { + PHY_ID_MATCH_EXACT(0x01803301), + .name = "Meson G12A Internal PHY", +@@ -245,6 +247,8 @@ static struct phy_driver meson_gxl_phy[] = { + .config_intr = meson_gxl_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ .read_mmd = genphy_read_mmd_unsupported, ++ .write_mmd = genphy_write_mmd_unsupported, + }, + }; + +diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c +index fc5895f85cee2..a552bb1665b8a 100644 +--- a/drivers/net/usb/kalmia.c ++++ b/drivers/net/usb/kalmia.c +@@ -65,8 +65,8 @@ kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, + init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT); + if (status != 0) { + netdev_err(dev->net, +- "Error sending init packet. Status %i, length %i\n", +- status, act_len); ++ "Error sending init packet. Status %i\n", ++ status); + return status; + } + else if (act_len != init_msg_len) { +@@ -83,8 +83,8 @@ kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, + + if (status != 0) + netdev_err(dev->net, +- "Error receiving init result. Status %i, length %i\n", +- status, act_len); ++ "Error receiving init result. Status %i\n", ++ status); + else if (act_len != expected_len) + netdev_err(dev->net, "Unexpected init result length: %i\n", + act_len); +diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c +index 17c9c63b8eebb..ce7862dac2b75 100644 +--- a/drivers/net/usb/plusb.c ++++ b/drivers/net/usb/plusb.c +@@ -57,9 +57,7 @@ + static inline int + pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index) + { +- return usbnet_read_cmd(dev, req, +- USB_DIR_IN | USB_TYPE_VENDOR | +- USB_RECIP_DEVICE, ++ return usbnet_write_cmd(dev, req, USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, index, NULL, 0); + } + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 579df7c5411d3..5212d9cb03728 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -1910,8 +1910,8 @@ static int virtnet_close(struct net_device *dev) + cancel_delayed_work_sync(&vi->refill); + + for (i = 0; i < vi->max_queue_pairs; i++) { +- xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq); + napi_disable(&vi->rq[i].napi); ++ xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq); + virtnet_napi_tx_disable(&vi->sq[i].napi); + } + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index 6439adcd2f995..cd146bbca670b 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -87,6 +87,9 @@ + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ + (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) + ++#define BRCMF_MAX_CHANSPEC_LIST \ ++ (BRCMF_DCMD_MEDLEN / sizeof(__le32) - 1) ++ + static bool check_vif_up(struct brcmf_cfg80211_vif *vif) + { + if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) { +@@ -6067,6 +6070,13 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg, + band->channels[i].flags = IEEE80211_CHAN_DISABLED; + + total = le32_to_cpu(list->count); ++ if (total > BRCMF_MAX_CHANSPEC_LIST) { ++ bphy_err(drvr, "Invalid count of channel Spec. (%u)\n", ++ total); ++ err = -EINVAL; ++ goto fail_pbuf; ++ } ++ + for (i = 0; i < total; i++) { + ch.chspec = (u16)le32_to_cpu(list->element[i]); + cfg->d11inf.decchspec(&ch); +@@ -6212,6 +6222,13 @@ static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg) + band = cfg_to_wiphy(cfg)->bands[NL80211_BAND_2GHZ]; + list = (struct brcmf_chanspec_list *)pbuf; + num_chan = le32_to_cpu(list->count); ++ if (num_chan > BRCMF_MAX_CHANSPEC_LIST) { ++ bphy_err(drvr, "Invalid count of channel Spec. (%u)\n", ++ num_chan); ++ kfree(pbuf); ++ return -EINVAL; ++ } ++ + for (i = 0; i < num_chan; i++) { + ch.chspec = (u16)le32_to_cpu(list->element[i]); + cfg->d11inf.decchspec(&ch); +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 5d62d1042c0e6..a58711c488509 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3199,7 +3199,6 @@ static const struct pci_device_id nvme_id_table[] = { + NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x1c5c, 0x1504), /* SK Hynix PC400 */ + .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, }, +- { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, + { PCI_DEVICE(0x2646, 0x2263), /* KINGSTON A2000 NVMe SSD */ + .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, + { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001), +@@ -3209,6 +3208,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_SINGLE_VECTOR | + NVME_QUIRK_128_BYTES_SQES | + NVME_QUIRK_SHARED_TAGS }, ++ ++ { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, + { 0, } + }; + MODULE_DEVICE_TABLE(pci, nvme_id_table); +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 9b07e8c7689ab..f74fc6481731d 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -1362,8 +1362,10 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + else { + queue = nvmet_fc_alloc_target_queue(iod->assoc, 0, + be16_to_cpu(rqst->assoc_cmd.sqsize)); +- if (!queue) ++ if (!queue) { + ret = VERR_QUEUE_ALLOC_FAIL; ++ nvmet_fc_tgt_a_put(iod->assoc); ++ } + } + } + +diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c +index c0f4324d8f7c8..cde1d77845fee 100644 +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -439,7 +439,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) + if (config->cells) { + rval = nvmem_add_cells(nvmem, config->cells, config->ncells); + if (rval) +- goto err_teardown_compat; ++ goto err_remove_cells; + } + + rval = nvmem_add_cells_from_table(nvmem); +@@ -456,7 +456,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) + + err_remove_cells: + nvmem_device_remove_all_cells(nvmem); +-err_teardown_compat: + if (config->compat) + nvmem_sysfs_remove_compat(nvmem, config); + err_device_del: +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c +index 22aca6d182c0c..2c1e799b029e7 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c +@@ -115,7 +115,7 @@ static int aspeed_disable_sig(struct aspeed_pinmux_data *ctx, + int ret = 0; + + if (!exprs) +- return true; ++ return -EINVAL; + + while (*exprs && !ret) { + ret = aspeed_sig_expr_disable(ctx, *exprs); +diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c +index e0cb76f7e5407..32c6326337f73 100644 +--- a/drivers/pinctrl/intel/pinctrl-intel.c ++++ b/drivers/pinctrl/intel/pinctrl-intel.c +@@ -1510,6 +1510,12 @@ int intel_pinctrl_probe_by_uid(struct platform_device *pdev) + EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid); + + #ifdef CONFIG_PM_SLEEP ++static bool __intel_gpio_is_direct_irq(u32 value) ++{ ++ return (value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) && ++ (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO); ++} ++ + static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin) + { + const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); +@@ -1543,8 +1549,7 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int + * See https://bugzilla.kernel.org/show_bug.cgi?id=214749. + */ + value = readl(intel_get_padcfg(pctrl, pin, PADCFG0)); +- if ((value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) && +- (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO)) ++ if (__intel_gpio_is_direct_irq(value)) + return true; + + return false; +@@ -1656,7 +1661,12 @@ int intel_pinctrl_resume_noirq(struct device *dev) + void __iomem *padcfg; + u32 val; + +- if (!intel_pinctrl_should_save(pctrl, desc->number)) ++ if (!(intel_pinctrl_should_save(pctrl, desc->number) || ++ /* ++ * If the firmware mangled the register contents too much, ++ * check the saved value for the Direct IRQ mode. ++ */ ++ __intel_gpio_is_direct_irq(pads[i].padcfg0))) + continue; + + padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG0); +diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c +index 20c89023d312e..ce5be6f0b7aac 100644 +--- a/drivers/pinctrl/pinctrl-single.c ++++ b/drivers/pinctrl/pinctrl-single.c +@@ -345,6 +345,8 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector, + if (!pcs->fmask) + return 0; + function = pinmux_generic_get_function(pctldev, fselector); ++ if (!function) ++ return -EINVAL; + func = function->data; + if (!func) + return -EINVAL; +diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c +index b5dd1caae5e92..9320a0a92bb2f 100644 +--- a/drivers/scsi/iscsi_tcp.c ++++ b/drivers/scsi/iscsi_tcp.c +@@ -770,7 +770,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, + enum iscsi_host_param param, char *buf) + { + struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost); +- struct iscsi_session *session = tcp_sw_host->session; ++ struct iscsi_session *session; + struct iscsi_conn *conn; + struct iscsi_tcp_conn *tcp_conn; + struct iscsi_sw_tcp_conn *tcp_sw_conn; +@@ -779,6 +779,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, + + switch (param) { + case ISCSI_HOST_PARAM_IPADDRESS: ++ session = tcp_sw_host->session; + if (!session) + return -ENOTCONN; + +@@ -867,12 +868,14 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, + if (!cls_session) + goto remove_host; + session = cls_session->dd_data; +- tcp_sw_host = iscsi_host_priv(shost); +- tcp_sw_host->session = session; + + shost->can_queue = session->scsi_cmds_max; + if (iscsi_tcp_r2tpool_alloc(session)) + goto remove_session; ++ ++ /* We are now fully setup so expose the session to sysfs. */ ++ tcp_sw_host = iscsi_host_priv(shost); ++ tcp_sw_host->session = session; + return cls_session; + + remove_session: +diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c +index 3fd109fd9335d..d236322ced30e 100644 +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -1130,8 +1130,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, + * that no LUN is present, so don't add sdev in these cases. + * Two specific examples are: + * 1) NetApp targets: return PQ=1, PDT=0x1f +- * 2) IBM/2145 targets: return PQ=1, PDT=0 +- * 3) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved" ++ * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved" + * in the UFI 1.0 spec (we cannot rely on reserved bits). + * + * References: +@@ -1145,8 +1144,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, + * PDT=00h Direct-access device (floppy) + * PDT=1Fh none (no FDD connected to the requested logical unit) + */ +- if (((result[0] >> 5) == 1 || +- (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f)) && ++ if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) && ++ (result[0] & 0x1f) == 0x1f && + !scsi_is_wlun(lun)) { + SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, + "scsi scan: peripheral device type" +diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c +index 7143d03f0e027..18fbbe510d018 100644 +--- a/drivers/target/target_core_file.c ++++ b/drivers/target/target_core_file.c +@@ -340,7 +340,7 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd, + len += sg->length; + } + +- iov_iter_bvec(&iter, READ, bvec, sgl_nents, len); ++ iov_iter_bvec(&iter, is_write, bvec, sgl_nents, len); + if (is_write) + ret = vfs_iter_write(fd, &iter, &pos, 0); + else +@@ -477,7 +477,7 @@ fd_execute_write_same(struct se_cmd *cmd) + len += se_dev->dev_attrib.block_size; + } + +- iov_iter_bvec(&iter, READ, bvec, nolb, len); ++ iov_iter_bvec(&iter, WRITE, bvec, nolb, len); + ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0); + + kfree(bvec); +diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c +index feeba3966617b..6928ebf0be9c7 100644 +--- a/drivers/target/target_core_tmr.c ++++ b/drivers/target/target_core_tmr.c +@@ -82,8 +82,8 @@ static bool __target_check_io_state(struct se_cmd *se_cmd, + { + struct se_session *sess = se_cmd->se_sess; + +- assert_spin_locked(&sess->sess_cmd_lock); +- WARN_ON_ONCE(!irqs_disabled()); ++ lockdep_assert_held(&sess->sess_cmd_lock); ++ + /* + * If command already reached CMD_T_COMPLETE state within + * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown, +diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c +index 890fa7ddaa7f3..bdc7bb7a1b929 100644 +--- a/drivers/tty/serial/8250/8250_dma.c ++++ b/drivers/tty/serial/8250/8250_dma.c +@@ -46,19 +46,39 @@ static void __dma_rx_complete(void *param) + struct uart_8250_dma *dma = p->dma; + struct tty_port *tty_port = &p->port.state->port; + struct dma_tx_state state; ++ enum dma_status dma_status; + int count; + +- dma->rx_running = 0; +- dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); ++ /* ++ * New DMA Rx can be started during the completion handler before it ++ * could acquire port's lock and it might still be ongoing. Don't to ++ * anything in such case. ++ */ ++ dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); ++ if (dma_status == DMA_IN_PROGRESS) ++ return; + + count = dma->rx_size - state.residue; + + tty_insert_flip_string(tty_port, dma->rx_buf, count); + p->port.icount.rx += count; ++ dma->rx_running = 0; + + tty_flip_buffer_push(tty_port); + } + ++static void dma_rx_complete(void *param) ++{ ++ struct uart_8250_port *p = param; ++ struct uart_8250_dma *dma = p->dma; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p->port.lock, flags); ++ if (dma->rx_running) ++ __dma_rx_complete(p); ++ spin_unlock_irqrestore(&p->port.lock, flags); ++} ++ + int serial8250_tx_dma(struct uart_8250_port *p) + { + struct uart_8250_dma *dma = p->dma; +@@ -121,7 +141,7 @@ int serial8250_rx_dma(struct uart_8250_port *p) + return -EBUSY; + + dma->rx_running = 1; +- desc->callback = __dma_rx_complete; ++ desc->callback = dma_rx_complete; + desc->callback_param = p; + + dma->rx_cookie = dmaengine_submit(desc); +diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c +index 778f83ea22493..e61fd04a0d8d0 100644 +--- a/drivers/tty/vt/vc_screen.c ++++ b/drivers/tty/vt/vc_screen.c +@@ -265,10 +265,6 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) + + uni_mode = use_unicode(inode); + attr = use_attributes(inode); +- ret = -ENXIO; +- vc = vcs_vc(inode, &viewed); +- if (!vc) +- goto unlock_out; + + ret = -EINVAL; + if (pos < 0) +@@ -288,6 +284,11 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) + ssize_t orig_count; + long p = pos; + ++ ret = -ENXIO; ++ vc = vcs_vc(inode, &viewed); ++ if (!vc) ++ goto unlock_out; ++ + /* Check whether we are above size each round, + * as copy_to_user at the end of this loop + * could sleep. +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 35a11f7bcb658..1346c600ebedf 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -527,6 +527,9 @@ static const struct usb_device_id usb_quirk_list[] = { + /* DJI CineSSD */ + { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Alcor Link AK9563 SC Reader used in 2022 Lenovo ThinkPads */ ++ { USB_DEVICE(0x2ce3, 0x9563), .driver_info = USB_QUIRK_NO_LPM }, ++ + /* DELL USB GEN2 */ + { USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME }, + +diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c +index aed35276e0e0c..2dcdeb52fc293 100644 +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -102,7 +102,7 @@ static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val) + readl(base + offset); + } + +-static void dwc3_qcom_vbus_overrride_enable(struct dwc3_qcom *qcom, bool enable) ++static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable) + { + if (enable) { + dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL, +@@ -123,7 +123,7 @@ static int dwc3_qcom_vbus_notifier(struct notifier_block *nb, + struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, vbus_nb); + + /* enable vbus override for device mode */ +- dwc3_qcom_vbus_overrride_enable(qcom, event); ++ dwc3_qcom_vbus_override_enable(qcom, event); + qcom->mode = event ? USB_DR_MODE_PERIPHERAL : USB_DR_MODE_HOST; + + return NOTIFY_DONE; +@@ -135,7 +135,7 @@ static int dwc3_qcom_host_notifier(struct notifier_block *nb, + struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, host_nb); + + /* disable vbus override in host mode */ +- dwc3_qcom_vbus_overrride_enable(qcom, !event); ++ dwc3_qcom_vbus_override_enable(qcom, !event); + qcom->mode = event ? USB_DR_MODE_HOST : USB_DR_MODE_PERIPHERAL; + + return NOTIFY_DONE; +@@ -669,8 +669,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev) + qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev); + + /* enable vbus override for device mode */ +- if (qcom->mode == USB_DR_MODE_PERIPHERAL) +- dwc3_qcom_vbus_overrride_enable(qcom, true); ++ if (qcom->mode != USB_DR_MODE_HOST) ++ dwc3_qcom_vbus_override_enable(qcom, true); + + /* register extcon to override sw_vbus on Vbus change later */ + ret = dwc3_qcom_register_extcon(qcom); +diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c +index 431ab6d07497f..5fe7490367734 100644 +--- a/drivers/usb/gadget/function/f_fs.c ++++ b/drivers/usb/gadget/function/f_fs.c +@@ -278,8 +278,10 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) + struct usb_request *req = ffs->ep0req; + int ret; + +- if (!req) ++ if (!req) { ++ spin_unlock_irq(&ffs->ev.waitq.lock); + return -EINVAL; ++ } + + req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); + +diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c +index 1aa1bd991ef43..c840f03996fb6 100644 +--- a/drivers/usb/typec/altmodes/displayport.c ++++ b/drivers/usb/typec/altmodes/displayport.c +@@ -522,10 +522,10 @@ int dp_altmode_probe(struct typec_altmode *alt) + /* FIXME: Port can only be DFP_U. */ + + /* Make sure we have compatiple pin configurations */ +- if (!(DP_CAP_DFP_D_PIN_ASSIGN(port->vdo) & +- DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo)) && +- !(DP_CAP_UFP_D_PIN_ASSIGN(port->vdo) & +- DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo))) ++ if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & ++ DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && ++ !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & ++ DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) + return -ENODEV; + + ret = sysfs_create_group(&alt->dev.kobj, &dp_altmode_group); +diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c +index 673af5937489f..e487928289392 100644 +--- a/drivers/video/fbdev/core/fbcon.c ++++ b/drivers/video/fbdev/core/fbcon.c +@@ -2497,9 +2497,12 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, + h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres)) + return -EINVAL; + ++ if (font->width > 32 || font->height > 32) ++ return -EINVAL; ++ + /* Make sure drawing engine can handle the font */ +- if (!(info->pixmap.blit_x & (1 << (font->width - 1))) || +- !(info->pixmap.blit_y & (1 << (font->height - 1)))) ++ if (!(info->pixmap.blit_x & BIT(font->width - 1)) || ++ !(info->pixmap.blit_y & BIT(font->height - 1))) + return -EINVAL; + + /* Make sure driver can handle the font length */ +diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c +index a5abdec58fe26..53fb34f074c74 100644 +--- a/drivers/video/fbdev/smscufx.c ++++ b/drivers/video/fbdev/smscufx.c +@@ -1622,7 +1622,7 @@ static int ufx_usb_probe(struct usb_interface *interface, + struct usb_device *usbdev; + struct ufx_data *dev; + struct fb_info *info; +- int retval; ++ int retval = -ENOMEM; + u32 id_rev, fpga_rev; + + /* usb initialization */ +@@ -1654,15 +1654,17 @@ static int ufx_usb_probe(struct usb_interface *interface, + + if (!ufx_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { + dev_err(dev->gdev, "ufx_alloc_urb_list failed\n"); +- goto e_nomem; ++ goto put_ref; + } + + /* We don't register a new USB class. Our client interface is fbdev */ + + /* allocates framebuffer driver structure, not framebuffer memory */ + info = framebuffer_alloc(0, &usbdev->dev); +- if (!info) +- goto e_nomem; ++ if (!info) { ++ dev_err(dev->gdev, "framebuffer_alloc failed\n"); ++ goto free_urb_list; ++ } + + dev->info = info; + info->par = dev; +@@ -1705,22 +1707,34 @@ static int ufx_usb_probe(struct usb_interface *interface, + check_warn_goto_error(retval, "unable to find common mode for display and adapter"); + + retval = ufx_reg_set_bits(dev, 0x4000, 0x00000001); +- check_warn_goto_error(retval, "error %d enabling graphics engine", retval); ++ if (retval < 0) { ++ dev_err(dev->gdev, "error %d enabling graphics engine", retval); ++ goto setup_modes; ++ } + + /* ready to begin using device */ + atomic_set(&dev->usb_active, 1); + + dev_dbg(dev->gdev, "checking var"); + retval = ufx_ops_check_var(&info->var, info); +- check_warn_goto_error(retval, "error %d ufx_ops_check_var", retval); ++ if (retval < 0) { ++ dev_err(dev->gdev, "error %d ufx_ops_check_var", retval); ++ goto reset_active; ++ } + + dev_dbg(dev->gdev, "setting par"); + retval = ufx_ops_set_par(info); +- check_warn_goto_error(retval, "error %d ufx_ops_set_par", retval); ++ if (retval < 0) { ++ dev_err(dev->gdev, "error %d ufx_ops_set_par", retval); ++ goto reset_active; ++ } + + dev_dbg(dev->gdev, "registering framebuffer"); + retval = register_framebuffer(info); +- check_warn_goto_error(retval, "error %d register_framebuffer", retval); ++ if (retval < 0) { ++ dev_err(dev->gdev, "error %d register_framebuffer", retval); ++ goto reset_active; ++ } + + dev_info(dev->gdev, "SMSC UDX USB device /dev/fb%d attached. %dx%d resolution." + " Using %dK framebuffer memory\n", info->node, +@@ -1728,21 +1742,23 @@ static int ufx_usb_probe(struct usb_interface *interface, + + return 0; + +-error: +- fb_dealloc_cmap(&info->cmap); +-destroy_modedb: ++reset_active: ++ atomic_set(&dev->usb_active, 0); ++setup_modes: + fb_destroy_modedb(info->monspecs.modedb); + vfree(info->screen_base); + fb_destroy_modelist(&info->modelist); ++error: ++ fb_dealloc_cmap(&info->cmap); ++destroy_modedb: + framebuffer_release(info); ++free_urb_list: ++ if (dev->urbs.count > 0) ++ ufx_free_urb_list(dev); + put_ref: + kref_put(&dev->kref, ufx_free); /* ref for framebuffer */ + kref_put(&dev->kref, ufx_free); /* last ref from kref_init */ + return retval; +- +-e_nomem: +- retval = -ENOMEM; +- goto put_ref; + } + + static void ufx_usb_disconnect(struct usb_interface *interface) +diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c +index aafc8d98bf9fd..370f648cb4b1a 100644 +--- a/drivers/watchdog/diag288_wdt.c ++++ b/drivers/watchdog/diag288_wdt.c +@@ -86,7 +86,7 @@ static int __diag288(unsigned int func, unsigned int timeout, + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (err) : "d"(__func), "d"(__timeout), +- "d"(__action), "d"(__len) : "1", "cc"); ++ "d"(__action), "d"(__len) : "1", "cc", "memory"); + return err; + } + +@@ -272,12 +272,21 @@ static int __init diag288_init(void) + char ebc_begin[] = { + 194, 197, 199, 201, 213 + }; ++ char *ebc_cmd; + + watchdog_set_nowayout(&wdt_dev, nowayout_info); + + if (MACHINE_IS_VM) { +- if (__diag288_vm(WDT_FUNC_INIT, 15, +- ebc_begin, sizeof(ebc_begin)) != 0) { ++ ebc_cmd = kmalloc(sizeof(ebc_begin), GFP_KERNEL); ++ if (!ebc_cmd) { ++ pr_err("The watchdog cannot be initialized\n"); ++ return -ENOMEM; ++ } ++ memcpy(ebc_cmd, ebc_begin, sizeof(ebc_begin)); ++ ret = __diag288_vm(WDT_FUNC_INIT, 15, ++ ebc_cmd, sizeof(ebc_begin)); ++ kfree(ebc_cmd); ++ if (ret != 0) { + pr_err("The watchdog cannot be initialized\n"); + return -EINVAL; + } +diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c +index 9439de2ca0e45..9c267e27d9d95 100644 +--- a/drivers/xen/pvcalls-back.c ++++ b/drivers/xen/pvcalls-back.c +@@ -129,13 +129,13 @@ static bool pvcalls_conn_back_read(void *opaque) + if (masked_prod < masked_cons) { + vec[0].iov_base = data->in + masked_prod; + vec[0].iov_len = wanted; +- iov_iter_kvec(&msg.msg_iter, WRITE, vec, 1, wanted); ++ iov_iter_kvec(&msg.msg_iter, READ, vec, 1, wanted); + } else { + vec[0].iov_base = data->in + masked_prod; + vec[0].iov_len = array_size - masked_prod; + vec[1].iov_base = data->in; + vec[1].iov_len = wanted - vec[0].iov_len; +- iov_iter_kvec(&msg.msg_iter, WRITE, vec, 2, wanted); ++ iov_iter_kvec(&msg.msg_iter, READ, vec, 2, wanted); + } + + atomic_set(&map->read, 0); +@@ -188,13 +188,13 @@ static bool pvcalls_conn_back_write(struct sock_mapping *map) + if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) { + vec[0].iov_base = data->out + pvcalls_mask(cons, array_size); + vec[0].iov_len = size; +- iov_iter_kvec(&msg.msg_iter, READ, vec, 1, size); ++ iov_iter_kvec(&msg.msg_iter, WRITE, vec, 1, size); + } else { + vec[0].iov_base = data->out + pvcalls_mask(cons, array_size); + vec[0].iov_len = array_size - pvcalls_mask(cons, array_size); + vec[1].iov_base = data->out; + vec[1].iov_len = size - vec[0].iov_len; +- iov_iter_kvec(&msg.msg_iter, READ, vec, 2, size); ++ iov_iter_kvec(&msg.msg_iter, WRITE, vec, 2, size); + } + + atomic_set(&map->write, 0); +diff --git a/fs/aio.c b/fs/aio.c +index fb92c32a6f1e9..1ec5a773d09c5 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -336,6 +336,9 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + spin_lock(&mm->ioctx_lock); + rcu_read_lock(); + table = rcu_dereference(mm->ioctx_table); ++ if (!table) ++ goto out_unlock; ++ + for (i = 0; i < table->nr; i++) { + struct kioctx *ctx; + +@@ -349,6 +352,7 @@ static int aio_ring_mremap(struct vm_area_struct *vma) + } + } + ++out_unlock: + rcu_read_unlock(); + spin_unlock(&mm->ioctx_lock); + return res; +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 548de841cee53..3fa972a43b5e1 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -354,6 +354,7 @@ void btrfs_free_device(struct btrfs_device *device) + static void free_fs_devices(struct btrfs_fs_devices *fs_devices) + { + struct btrfs_device *device; ++ + WARN_ON(fs_devices->opened); + while (!list_empty(&fs_devices->devices)) { + device = list_entry(fs_devices->devices.next, +@@ -1401,6 +1402,17 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) + if (!fs_devices->opened) { + seed_devices = fs_devices->seed; + fs_devices->seed = NULL; ++ ++ /* ++ * If the struct btrfs_fs_devices is not assembled with any ++ * other device, it can be re-initialized during the next mount ++ * without the needing device-scan step. Therefore, it can be ++ * fully freed. ++ */ ++ if (fs_devices->num_devices == 1) { ++ list_del(&fs_devices->fs_list); ++ free_fs_devices(fs_devices); ++ } + } + mutex_unlock(&uuid_mutex); + +@@ -1701,7 +1713,7 @@ again: + goto out; + } + +- while (1) { ++ while (search_start < search_end) { + l = path->nodes[0]; + slot = path->slots[0]; + if (slot >= btrfs_header_nritems(l)) { +@@ -1724,6 +1736,9 @@ again: + if (key.type != BTRFS_DEV_EXTENT_KEY) + goto next; + ++ if (key.offset > search_end) ++ break; ++ + if (key.offset > search_start) { + hole_size = key.offset - search_start; + +@@ -1794,6 +1809,7 @@ next: + else + ret = 0; + ++ ASSERT(max_hole_start + max_hole_size <= search_end); + out: + btrfs_free_path(path); + *start = max_hole_start; +diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c +index df1aace5df501..9385d0bb276dd 100644 +--- a/fs/btrfs/zlib.c ++++ b/fs/btrfs/zlib.c +@@ -74,7 +74,7 @@ static struct list_head *zlib_alloc_workspace(unsigned int level) + + workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL), + zlib_inflate_workspacesize()); +- workspace->strm.workspace = kvmalloc(workspacesize, GFP_KERNEL); ++ workspace->strm.workspace = kvzalloc(workspacesize, GFP_KERNEL); + workspace->level = level; + workspace->buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!workspace->strm.workspace || !workspace->buf) +diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c +index 37fb71797b341..3bf81fe5f10a3 100644 +--- a/fs/ceph/mds_client.c ++++ b/fs/ceph/mds_client.c +@@ -3151,6 +3151,12 @@ static void handle_session(struct ceph_mds_session *session, + break; + + case CEPH_SESSION_FLUSHMSG: ++ /* flush cap releases */ ++ spin_lock(&session->s_cap_lock); ++ if (session->s_num_cap_releases) ++ ceph_flush_cap_releases(mdsc, session); ++ spin_unlock(&session->s_cap_lock); ++ + send_flushmsg_ack(mdsc, session, seq); + break; + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index ef71d9cda5851..939be9df0207e 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -612,7 +612,7 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + { + struct page *node_page; + nid_t nid; +- unsigned int ofs_in_node, max_addrs; ++ unsigned int ofs_in_node, max_addrs, base; + block_t source_blkaddr; + + nid = le32_to_cpu(sum->nid); +@@ -638,11 +638,17 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + return false; + } + +- max_addrs = IS_INODE(node_page) ? DEF_ADDRS_PER_INODE : +- DEF_ADDRS_PER_BLOCK; +- if (ofs_in_node >= max_addrs) { +- f2fs_err(sbi, "Inconsistent ofs_in_node:%u in summary, ino:%u, nid:%u, max:%u", +- ofs_in_node, dni->ino, dni->nid, max_addrs); ++ if (IS_INODE(node_page)) { ++ base = offset_in_addr(F2FS_INODE(node_page)); ++ max_addrs = DEF_ADDRS_PER_INODE; ++ } else { ++ base = 0; ++ max_addrs = DEF_ADDRS_PER_BLOCK; ++ } ++ ++ if (base + ofs_in_node >= max_addrs) { ++ f2fs_err(sbi, "Inconsistent blkaddr offset: base:%u, ofs_in_node:%u, max:%u, ino:%u, nid:%u", ++ base, ofs_in_node, max_addrs, dni->ino, dni->nid); + f2fs_put_page(node_page, 1); + return false; + } +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index 91b9dac6b2cc0..262783cd79cc3 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -1130,7 +1130,14 @@ static int nilfs_ioctl_set_alloc_range(struct inode *inode, void __user *argp) + + minseg = range[0] + segbytes - 1; + do_div(minseg, segbytes); ++ ++ if (range[1] < 4096) ++ goto out; ++ + maxseg = NILFS_SB2_OFFSET_BYTES(range[1]); ++ if (maxseg < segbytes) ++ goto out; ++ + do_div(maxseg, segbytes); + maxseg--; + +diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c +index 049768a22388e..b1015e97f37b7 100644 +--- a/fs/nilfs2/super.c ++++ b/fs/nilfs2/super.c +@@ -403,6 +403,15 @@ int nilfs_resize_fs(struct super_block *sb, __u64 newsize) + if (newsize > devsize) + goto out; + ++ /* ++ * Prevent underflow in second superblock position calculation. ++ * The exact minimum size check is done in nilfs_sufile_resize(). ++ */ ++ if (newsize < 4096) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ + /* + * Write lock is required to protect some functions depending + * on the number of segments, the number of reserved segments, +diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c +index 74ef3d313686f..6541e29a8b200 100644 +--- a/fs/nilfs2/the_nilfs.c ++++ b/fs/nilfs2/the_nilfs.c +@@ -517,9 +517,15 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, + { + struct nilfs_super_block **sbp = nilfs->ns_sbp; + struct buffer_head **sbh = nilfs->ns_sbh; +- u64 sb2off = NILFS_SB2_OFFSET_BYTES(nilfs->ns_bdev->bd_inode->i_size); ++ u64 sb2off, devsize = nilfs->ns_bdev->bd_inode->i_size; + int valid[2], swp = 0; + ++ if (devsize < NILFS_SEG_MIN_BLOCKS * NILFS_MIN_BLOCK_SIZE + 4096) { ++ nilfs_msg(sb, KERN_ERR, "device size too small"); ++ return -EINVAL; ++ } ++ sb2off = NILFS_SB2_OFFSET_BYTES(devsize); ++ + sbp[0] = nilfs_read_super_block(sb, NILFS_SB_OFFSET_BYTES, blocksize, + &sbh[0]); + sbp[1] = nilfs_read_super_block(sb, sb2off, blocksize, &sbh[1]); +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index d9633e5a5ddd2..0bdfef023d345 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -723,9 +723,7 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask, + page = device_private_entry_to_page(swpent); + } + if (page) { +- int mapcount = page_mapcount(page); +- +- if (mapcount >= 2) ++ if (page_mapcount(page) >= 2 || hugetlb_pmd_shared(pte)) + mss->shared_hugetlb += huge_page_size(hstate_vma(vma)); + else + mss->private_hugetlb += huge_page_size(hstate_vma(vma)); +diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h +index 236664d691419..ccfaf8c81958d 100644 +--- a/fs/squashfs/squashfs_fs.h ++++ b/fs/squashfs/squashfs_fs.h +@@ -183,7 +183,7 @@ static inline int squashfs_block_size(__le32 raw) + #define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ + sizeof(u64)) + /* xattr id lookup table defines */ +-#define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id)) ++#define SQUASHFS_XATTR_BYTES(A) (((u64) (A)) * sizeof(struct squashfs_xattr_id)) + + #define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \ + SQUASHFS_METADATA_SIZE) +diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h +index 166e98806265b..8f9445e290e72 100644 +--- a/fs/squashfs/squashfs_fs_sb.h ++++ b/fs/squashfs/squashfs_fs_sb.h +@@ -63,7 +63,7 @@ struct squashfs_sb_info { + long long bytes_used; + unsigned int inodes; + unsigned int fragments; +- int xattr_ids; ++ unsigned int xattr_ids; + unsigned int ids; + }; + #endif +diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h +index d8a270d3ac4cb..f1a463d8bfa02 100644 +--- a/fs/squashfs/xattr.h ++++ b/fs/squashfs/xattr.h +@@ -10,12 +10,12 @@ + + #ifdef CONFIG_SQUASHFS_XATTR + extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, +- u64 *, int *); ++ u64 *, unsigned int *); + extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, + unsigned int *, unsigned long long *); + #else + static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, +- u64 start, u64 *xattr_table_start, int *xattr_ids) ++ u64 start, u64 *xattr_table_start, unsigned int *xattr_ids) + { + struct squashfs_xattr_id_table *id_table; + +diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c +index 087cab8c78f4e..c8469c656e0dc 100644 +--- a/fs/squashfs/xattr_id.c ++++ b/fs/squashfs/xattr_id.c +@@ -56,7 +56,7 @@ int squashfs_xattr_lookup(struct super_block *sb, unsigned int index, + * Read uncompressed xattr id lookup table indexes from disk into memory + */ + __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 table_start, +- u64 *xattr_table_start, int *xattr_ids) ++ u64 *xattr_table_start, unsigned int *xattr_ids) + { + struct squashfs_sb_info *msblk = sb->s_fs_info; + unsigned int len, indexes; +diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c +index 8cc3faa624049..3a78a189ea018 100644 +--- a/fs/xfs/libxfs/xfs_defer.c ++++ b/fs/xfs/libxfs/xfs_defer.c +@@ -16,6 +16,8 @@ + #include "xfs_inode.h" + #include "xfs_inode_item.h" + #include "xfs_trace.h" ++#include "xfs_icache.h" ++#include "xfs_log.h" + + /* + * Deferred Operations in XFS +@@ -178,6 +180,19 @@ static const struct xfs_defer_op_type *defer_op_types[] = { + [XFS_DEFER_OPS_TYPE_AGFL_FREE] = &xfs_agfl_free_defer_type, + }; + ++static void ++xfs_defer_create_intent( ++ struct xfs_trans *tp, ++ struct xfs_defer_pending *dfp, ++ bool sort) ++{ ++ const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; ++ ++ if (!dfp->dfp_intent) ++ dfp->dfp_intent = ops->create_intent(tp, &dfp->dfp_work, ++ dfp->dfp_count, sort); ++} ++ + /* + * For each pending item in the intake list, log its intent item and the + * associated extents, then add the entire intake list to the end of +@@ -187,17 +202,11 @@ STATIC void + xfs_defer_create_intents( + struct xfs_trans *tp) + { +- struct list_head *li; + struct xfs_defer_pending *dfp; +- const struct xfs_defer_op_type *ops; + + list_for_each_entry(dfp, &tp->t_dfops, dfp_list) { +- ops = defer_op_types[dfp->dfp_type]; +- dfp->dfp_intent = ops->create_intent(tp, dfp->dfp_count); + trace_xfs_defer_create_intent(tp->t_mountp, dfp); +- list_sort(tp->t_mountp, &dfp->dfp_work, ops->diff_items); +- list_for_each(li, &dfp->dfp_work) +- ops->log_item(tp, dfp->dfp_intent, li); ++ xfs_defer_create_intent(tp, dfp, true); + } + } + +@@ -353,6 +362,106 @@ xfs_defer_cancel_list( + } + } + ++/* ++ * Prevent a log intent item from pinning the tail of the log by logging a ++ * done item to release the intent item; and then log a new intent item. ++ * The caller should provide a fresh transaction and roll it after we're done. ++ */ ++static int ++xfs_defer_relog( ++ struct xfs_trans **tpp, ++ struct list_head *dfops) ++{ ++ struct xlog *log = (*tpp)->t_mountp->m_log; ++ struct xfs_defer_pending *dfp; ++ xfs_lsn_t threshold_lsn = NULLCOMMITLSN; ++ ++ ++ ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES); ++ ++ list_for_each_entry(dfp, dfops, dfp_list) { ++ /* ++ * If the log intent item for this deferred op is not a part of ++ * the current log checkpoint, relog the intent item to keep ++ * the log tail moving forward. We're ok with this being racy ++ * because an incorrect decision means we'll be a little slower ++ * at pushing the tail. ++ */ ++ if (dfp->dfp_intent == NULL || ++ xfs_log_item_in_current_chkpt(dfp->dfp_intent)) ++ continue; ++ ++ /* ++ * Figure out where we need the tail to be in order to maintain ++ * the minimum required free space in the log. Only sample ++ * the log threshold once per call. ++ */ ++ if (threshold_lsn == NULLCOMMITLSN) { ++ threshold_lsn = xlog_grant_push_threshold(log, 0); ++ if (threshold_lsn == NULLCOMMITLSN) ++ break; ++ } ++ if (XFS_LSN_CMP(dfp->dfp_intent->li_lsn, threshold_lsn) >= 0) ++ continue; ++ ++ trace_xfs_defer_relog_intent((*tpp)->t_mountp, dfp); ++ XFS_STATS_INC((*tpp)->t_mountp, defer_relog); ++ dfp->dfp_intent = xfs_trans_item_relog(dfp->dfp_intent, *tpp); ++ } ++ ++ if ((*tpp)->t_flags & XFS_TRANS_DIRTY) ++ return xfs_defer_trans_roll(tpp); ++ return 0; ++} ++ ++/* ++ * Log an intent-done item for the first pending intent, and finish the work ++ * items. ++ */ ++static int ++xfs_defer_finish_one( ++ struct xfs_trans *tp, ++ struct xfs_defer_pending *dfp) ++{ ++ const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type]; ++ void *state = NULL; ++ struct list_head *li, *n; ++ int error; ++ ++ trace_xfs_defer_pending_finish(tp->t_mountp, dfp); ++ ++ dfp->dfp_done = ops->create_done(tp, dfp->dfp_intent, dfp->dfp_count); ++ list_for_each_safe(li, n, &dfp->dfp_work) { ++ list_del(li); ++ dfp->dfp_count--; ++ error = ops->finish_item(tp, li, dfp->dfp_done, &state); ++ if (error == -EAGAIN) { ++ /* ++ * Caller wants a fresh transaction; put the work item ++ * back on the list and log a new log intent item to ++ * replace the old one. See "Requesting a Fresh ++ * Transaction while Finishing Deferred Work" above. ++ */ ++ list_add(li, &dfp->dfp_work); ++ dfp->dfp_count++; ++ dfp->dfp_done = NULL; ++ dfp->dfp_intent = NULL; ++ xfs_defer_create_intent(tp, dfp, false); ++ } ++ ++ if (error) ++ goto out; ++ } ++ ++ /* Done with the dfp, free it. */ ++ list_del(&dfp->dfp_list); ++ kmem_free(dfp); ++out: ++ if (ops->finish_cleanup) ++ ops->finish_cleanup(tp, state, error); ++ return error; ++} ++ + /* + * Finish all the pending work. This involves logging intent items for + * any work items that wandered in since the last transaction roll (if +@@ -366,11 +475,7 @@ xfs_defer_finish_noroll( + struct xfs_trans **tp) + { + struct xfs_defer_pending *dfp; +- struct list_head *li; +- struct list_head *n; +- void *state; + int error = 0; +- const struct xfs_defer_op_type *ops; + LIST_HEAD(dop_pending); + + ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); +@@ -379,87 +484,44 @@ xfs_defer_finish_noroll( + + /* Until we run out of pending work to finish... */ + while (!list_empty(&dop_pending) || !list_empty(&(*tp)->t_dfops)) { +- /* log intents and pull in intake items */ +- xfs_defer_create_intents(*tp); +- list_splice_tail_init(&(*tp)->t_dfops, &dop_pending); +- + /* +- * Roll the transaction. ++ * Deferred items that are created in the process of finishing ++ * other deferred work items should be queued at the head of ++ * the pending list, which puts them ahead of the deferred work ++ * that was created by the caller. This keeps the number of ++ * pending work items to a minimum, which decreases the amount ++ * of time that any one intent item can stick around in memory, ++ * pinning the log tail. + */ ++ xfs_defer_create_intents(*tp); ++ list_splice_init(&(*tp)->t_dfops, &dop_pending); ++ + error = xfs_defer_trans_roll(tp); + if (error) +- goto out; ++ goto out_shutdown; ++ ++ /* Possibly relog intent items to keep the log moving. */ ++ error = xfs_defer_relog(tp, &dop_pending); ++ if (error) ++ goto out_shutdown; + +- /* Log an intent-done item for the first pending item. */ + dfp = list_first_entry(&dop_pending, struct xfs_defer_pending, + dfp_list); +- ops = defer_op_types[dfp->dfp_type]; +- trace_xfs_defer_pending_finish((*tp)->t_mountp, dfp); +- dfp->dfp_done = ops->create_done(*tp, dfp->dfp_intent, +- dfp->dfp_count); +- +- /* Finish the work items. */ +- state = NULL; +- list_for_each_safe(li, n, &dfp->dfp_work) { +- list_del(li); +- dfp->dfp_count--; +- error = ops->finish_item(*tp, li, dfp->dfp_done, +- &state); +- if (error == -EAGAIN) { +- /* +- * Caller wants a fresh transaction; +- * put the work item back on the list +- * and jump out. +- */ +- list_add(li, &dfp->dfp_work); +- dfp->dfp_count++; +- break; +- } else if (error) { +- /* +- * Clean up after ourselves and jump out. +- * xfs_defer_cancel will take care of freeing +- * all these lists and stuff. +- */ +- if (ops->finish_cleanup) +- ops->finish_cleanup(*tp, state, error); +- goto out; +- } +- } +- if (error == -EAGAIN) { +- /* +- * Caller wants a fresh transaction, so log a +- * new log intent item to replace the old one +- * and roll the transaction. See "Requesting +- * a Fresh Transaction while Finishing +- * Deferred Work" above. +- */ +- dfp->dfp_intent = ops->create_intent(*tp, +- dfp->dfp_count); +- dfp->dfp_done = NULL; +- list_for_each(li, &dfp->dfp_work) +- ops->log_item(*tp, dfp->dfp_intent, li); +- } else { +- /* Done with the dfp, free it. */ +- list_del(&dfp->dfp_list); +- kmem_free(dfp); +- } +- +- if (ops->finish_cleanup) +- ops->finish_cleanup(*tp, state, error); +- } +- +-out: +- if (error) { +- xfs_defer_trans_abort(*tp, &dop_pending); +- xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); +- trace_xfs_defer_finish_error(*tp, error); +- xfs_defer_cancel_list((*tp)->t_mountp, &dop_pending); +- xfs_defer_cancel(*tp); +- return error; ++ error = xfs_defer_finish_one(*tp, dfp); ++ if (error && error != -EAGAIN) ++ goto out_shutdown; + } + + trace_xfs_defer_finish_done(*tp, _RET_IP_); + return 0; ++ ++out_shutdown: ++ xfs_defer_trans_abort(*tp, &dop_pending); ++ xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); ++ trace_xfs_defer_finish_error(*tp, error); ++ xfs_defer_cancel_list((*tp)->t_mountp, &dop_pending); ++ xfs_defer_cancel(*tp); ++ return error; + } + + int +@@ -560,3 +622,137 @@ xfs_defer_move( + + xfs_defer_reset(stp); + } ++ ++/* ++ * Prepare a chain of fresh deferred ops work items to be completed later. Log ++ * recovery requires the ability to put off until later the actual finishing ++ * work so that it can process unfinished items recovered from the log in ++ * correct order. ++ * ++ * Create and log intent items for all the work that we're capturing so that we ++ * can be assured that the items will get replayed if the system goes down ++ * before log recovery gets a chance to finish the work it put off. The entire ++ * deferred ops state is transferred to the capture structure and the ++ * transaction is then ready for the caller to commit it. If there are no ++ * intent items to capture, this function returns NULL. ++ * ++ * If capture_ip is not NULL, the capture structure will obtain an extra ++ * reference to the inode. ++ */ ++static struct xfs_defer_capture * ++xfs_defer_ops_capture( ++ struct xfs_trans *tp, ++ struct xfs_inode *capture_ip) ++{ ++ struct xfs_defer_capture *dfc; ++ ++ if (list_empty(&tp->t_dfops)) ++ return NULL; ++ ++ /* Create an object to capture the defer ops. */ ++ dfc = kmem_zalloc(sizeof(*dfc), KM_NOFS); ++ INIT_LIST_HEAD(&dfc->dfc_list); ++ INIT_LIST_HEAD(&dfc->dfc_dfops); ++ ++ xfs_defer_create_intents(tp); ++ ++ /* Move the dfops chain and transaction state to the capture struct. */ ++ list_splice_init(&tp->t_dfops, &dfc->dfc_dfops); ++ dfc->dfc_tpflags = tp->t_flags & XFS_TRANS_LOWMODE; ++ tp->t_flags &= ~XFS_TRANS_LOWMODE; ++ ++ /* Capture the remaining block reservations along with the dfops. */ ++ dfc->dfc_blkres = tp->t_blk_res - tp->t_blk_res_used; ++ dfc->dfc_rtxres = tp->t_rtx_res - tp->t_rtx_res_used; ++ ++ /* Preserve the log reservation size. */ ++ dfc->dfc_logres = tp->t_log_res; ++ ++ /* ++ * Grab an extra reference to this inode and attach it to the capture ++ * structure. ++ */ ++ if (capture_ip) { ++ ihold(VFS_I(capture_ip)); ++ dfc->dfc_capture_ip = capture_ip; ++ } ++ ++ return dfc; ++} ++ ++/* Release all resources that we used to capture deferred ops. */ ++void ++xfs_defer_ops_release( ++ struct xfs_mount *mp, ++ struct xfs_defer_capture *dfc) ++{ ++ xfs_defer_cancel_list(mp, &dfc->dfc_dfops); ++ if (dfc->dfc_capture_ip) ++ xfs_irele(dfc->dfc_capture_ip); ++ kmem_free(dfc); ++} ++ ++/* ++ * Capture any deferred ops and commit the transaction. This is the last step ++ * needed to finish a log intent item that we recovered from the log. If any ++ * of the deferred ops operate on an inode, the caller must pass in that inode ++ * so that the reference can be transferred to the capture structure. The ++ * caller must hold ILOCK_EXCL on the inode, and must unlock it before calling ++ * xfs_defer_ops_continue. ++ */ ++int ++xfs_defer_ops_capture_and_commit( ++ struct xfs_trans *tp, ++ struct xfs_inode *capture_ip, ++ struct list_head *capture_list) ++{ ++ struct xfs_mount *mp = tp->t_mountp; ++ struct xfs_defer_capture *dfc; ++ int error; ++ ++ ASSERT(!capture_ip || xfs_isilocked(capture_ip, XFS_ILOCK_EXCL)); ++ ++ /* If we don't capture anything, commit transaction and exit. */ ++ dfc = xfs_defer_ops_capture(tp, capture_ip); ++ if (!dfc) ++ return xfs_trans_commit(tp); ++ ++ /* Commit the transaction and add the capture structure to the list. */ ++ error = xfs_trans_commit(tp); ++ if (error) { ++ xfs_defer_ops_release(mp, dfc); ++ return error; ++ } ++ ++ list_add_tail(&dfc->dfc_list, capture_list); ++ return 0; ++} ++ ++/* ++ * Attach a chain of captured deferred ops to a new transaction and free the ++ * capture structure. If an inode was captured, it will be passed back to the ++ * caller with ILOCK_EXCL held and joined to the transaction with lockflags==0. ++ * The caller now owns the inode reference. ++ */ ++void ++xfs_defer_ops_continue( ++ struct xfs_defer_capture *dfc, ++ struct xfs_trans *tp, ++ struct xfs_inode **captured_ipp) ++{ ++ ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); ++ ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY)); ++ ++ /* Lock and join the captured inode to the new transaction. */ ++ if (dfc->dfc_capture_ip) { ++ xfs_ilock(dfc->dfc_capture_ip, XFS_ILOCK_EXCL); ++ xfs_trans_ijoin(tp, dfc->dfc_capture_ip, 0); ++ } ++ *captured_ipp = dfc->dfc_capture_ip; ++ ++ /* Move captured dfops chain and state to the transaction. */ ++ list_splice_init(&dfc->dfc_dfops, &tp->t_dfops); ++ tp->t_flags |= dfc->dfc_tpflags; ++ ++ kmem_free(dfc); ++} +diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h +index 7c28d7608ac62..4c3248d47a350 100644 +--- a/fs/xfs/libxfs/xfs_defer.h ++++ b/fs/xfs/libxfs/xfs_defer.h +@@ -7,6 +7,7 @@ + #define __XFS_DEFER_H__ + + struct xfs_defer_op_type; ++struct xfs_defer_capture; + + /* + * Header for deferred operation list. +@@ -28,7 +29,7 @@ enum xfs_defer_ops_type { + struct xfs_defer_pending { + struct list_head dfp_list; /* pending items */ + struct list_head dfp_work; /* work items */ +- void *dfp_intent; /* log intent item */ ++ struct xfs_log_item *dfp_intent; /* log intent item */ + void *dfp_done; /* log done item */ + unsigned int dfp_count; /* # extent items */ + enum xfs_defer_ops_type dfp_type; +@@ -43,15 +44,15 @@ void xfs_defer_move(struct xfs_trans *dtp, struct xfs_trans *stp); + + /* Description of a deferred type. */ + struct xfs_defer_op_type { +- void (*abort_intent)(void *); +- void *(*create_done)(struct xfs_trans *, void *, unsigned int); ++ struct xfs_log_item *(*create_intent)(struct xfs_trans *tp, ++ struct list_head *items, unsigned int count, bool sort); ++ void (*abort_intent)(struct xfs_log_item *intent); ++ void *(*create_done)(struct xfs_trans *tp, struct xfs_log_item *intent, ++ unsigned int count); + int (*finish_item)(struct xfs_trans *, struct list_head *, void *, + void **); + void (*finish_cleanup)(struct xfs_trans *, void *, int); + void (*cancel_item)(struct list_head *); +- int (*diff_items)(void *, struct list_head *, struct list_head *); +- void *(*create_intent)(struct xfs_trans *, uint); +- void (*log_item)(struct xfs_trans *, void *, struct list_head *); + unsigned int max_items; + }; + +@@ -61,4 +62,40 @@ extern const struct xfs_defer_op_type xfs_rmap_update_defer_type; + extern const struct xfs_defer_op_type xfs_extent_free_defer_type; + extern const struct xfs_defer_op_type xfs_agfl_free_defer_type; + ++/* ++ * This structure enables a dfops user to detach the chain of deferred ++ * operations from a transaction so that they can be continued later. ++ */ ++struct xfs_defer_capture { ++ /* List of other capture structures. */ ++ struct list_head dfc_list; ++ ++ /* Deferred ops state saved from the transaction. */ ++ struct list_head dfc_dfops; ++ unsigned int dfc_tpflags; ++ ++ /* Block reservations for the data and rt devices. */ ++ unsigned int dfc_blkres; ++ unsigned int dfc_rtxres; ++ ++ /* Log reservation saved from the transaction. */ ++ unsigned int dfc_logres; ++ ++ /* ++ * An inode reference that must be maintained to complete the deferred ++ * work. ++ */ ++ struct xfs_inode *dfc_capture_ip; ++}; ++ ++/* ++ * Functions to capture a chain of deferred operations and continue them later. ++ * This doesn't normally happen except log recovery. ++ */ ++int xfs_defer_ops_capture_and_commit(struct xfs_trans *tp, ++ struct xfs_inode *capture_ip, struct list_head *capture_list); ++void xfs_defer_ops_continue(struct xfs_defer_capture *d, struct xfs_trans *tp, ++ struct xfs_inode **captured_ipp); ++void xfs_defer_ops_release(struct xfs_mount *mp, struct xfs_defer_capture *d); ++ + #endif /* __XFS_DEFER_H__ */ +diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c +index 15d6f947620ff..93357072b19da 100644 +--- a/fs/xfs/libxfs/xfs_inode_fork.c ++++ b/fs/xfs/libxfs/xfs_inode_fork.c +@@ -592,7 +592,7 @@ void + xfs_iflush_fork( + xfs_inode_t *ip, + xfs_dinode_t *dip, +- xfs_inode_log_item_t *iip, ++ struct xfs_inode_log_item *iip, + int whichfork) + { + char *cp; +diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c +index 0ba7368b9a5f0..1d0e78e0099d9 100644 +--- a/fs/xfs/libxfs/xfs_trans_inode.c ++++ b/fs/xfs/libxfs/xfs_trans_inode.c +@@ -27,7 +27,7 @@ xfs_trans_ijoin( + struct xfs_inode *ip, + uint lock_flags) + { +- xfs_inode_log_item_t *iip; ++ struct xfs_inode_log_item *iip; + + ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + if (ip->i_itemp == NULL) +diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c +index f16d5f196c6b1..5d9f8e4c4cdee 100644 +--- a/fs/xfs/xfs_aops.c ++++ b/fs/xfs/xfs_aops.c +@@ -495,7 +495,7 @@ xfs_map_blocks( + ssize_t count = i_blocksize(inode); + xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); + xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + count); +- xfs_fileoff_t cow_fsb = NULLFILEOFF; ++ xfs_fileoff_t cow_fsb; + struct xfs_bmbt_irec imap; + struct xfs_iext_cursor icur; + int retries = 0; +@@ -529,6 +529,8 @@ xfs_map_blocks( + * landed in a hole and we skip the block. + */ + retry: ++ cow_fsb = NULLFILEOFF; ++ wpc->fork = XFS_DATA_FORK; + xfs_ilock(ip, XFS_ILOCK_SHARED); + ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || + (ip->i_df.if_flags & XFS_IFEXTENTS)); +diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c +index 243e5e0f82a30..7b0c4d9679d96 100644 +--- a/fs/xfs/xfs_bmap_item.c ++++ b/fs/xfs/xfs_bmap_item.c +@@ -22,6 +22,7 @@ + #include "xfs_bmap_btree.h" + #include "xfs_trans_space.h" + #include "xfs_error.h" ++#include "xfs_quota.h" + + kmem_zone_t *xfs_bui_zone; + kmem_zone_t *xfs_bud_zone; +@@ -124,34 +125,6 @@ xfs_bui_item_release( + xfs_bui_release(BUI_ITEM(lip)); + } + +-static const struct xfs_item_ops xfs_bui_item_ops = { +- .iop_size = xfs_bui_item_size, +- .iop_format = xfs_bui_item_format, +- .iop_unpin = xfs_bui_item_unpin, +- .iop_release = xfs_bui_item_release, +-}; +- +-/* +- * Allocate and initialize an bui item with the given number of extents. +- */ +-struct xfs_bui_log_item * +-xfs_bui_init( +- struct xfs_mount *mp) +- +-{ +- struct xfs_bui_log_item *buip; +- +- buip = kmem_zone_zalloc(xfs_bui_zone, 0); +- +- xfs_log_item_init(mp, &buip->bui_item, XFS_LI_BUI, &xfs_bui_item_ops); +- buip->bui_format.bui_nextents = XFS_BUI_MAX_FAST_EXTENTS; +- buip->bui_format.bui_id = (uintptr_t)(void *)buip; +- atomic_set(&buip->bui_next_extent, 0); +- atomic_set(&buip->bui_refcount, 2); +- +- return buip; +-} +- + static inline struct xfs_bud_log_item *BUD_ITEM(struct xfs_log_item *lip) + { + return container_of(lip, struct xfs_bud_log_item, bud_item); +@@ -278,27 +251,6 @@ xfs_bmap_update_diff_items( + return ba->bi_owner->i_ino - bb->bi_owner->i_ino; + } + +-/* Get an BUI. */ +-STATIC void * +-xfs_bmap_update_create_intent( +- struct xfs_trans *tp, +- unsigned int count) +-{ +- struct xfs_bui_log_item *buip; +- +- ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS); +- ASSERT(tp != NULL); +- +- buip = xfs_bui_init(tp->t_mountp); +- ASSERT(buip != NULL); +- +- /* +- * Get a log_item_desc to point at the new item. +- */ +- xfs_trans_add_item(tp, &buip->bui_item); +- return buip; +-} +- + /* Set the map extent flags for this mapping. */ + static void + xfs_trans_set_bmap_flags( +@@ -326,16 +278,12 @@ xfs_trans_set_bmap_flags( + STATIC void + xfs_bmap_update_log_item( + struct xfs_trans *tp, +- void *intent, +- struct list_head *item) ++ struct xfs_bui_log_item *buip, ++ struct xfs_bmap_intent *bmap) + { +- struct xfs_bui_log_item *buip = intent; +- struct xfs_bmap_intent *bmap; + uint next_extent; + struct xfs_map_extent *map; + +- bmap = container_of(item, struct xfs_bmap_intent, bi_list); +- + tp->t_flags |= XFS_TRANS_DIRTY; + set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags); + +@@ -355,14 +303,35 @@ xfs_bmap_update_log_item( + bmap->bi_bmap.br_state); + } + ++static struct xfs_log_item * ++xfs_bmap_update_create_intent( ++ struct xfs_trans *tp, ++ struct list_head *items, ++ unsigned int count, ++ bool sort) ++{ ++ struct xfs_mount *mp = tp->t_mountp; ++ struct xfs_bui_log_item *buip = xfs_bui_init(mp); ++ struct xfs_bmap_intent *bmap; ++ ++ ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS); ++ ++ xfs_trans_add_item(tp, &buip->bui_item); ++ if (sort) ++ list_sort(mp, items, xfs_bmap_update_diff_items); ++ list_for_each_entry(bmap, items, bi_list) ++ xfs_bmap_update_log_item(tp, buip, bmap); ++ return &buip->bui_item; ++} ++ + /* Get an BUD so we can process all the deferred rmap updates. */ + STATIC void * + xfs_bmap_update_create_done( + struct xfs_trans *tp, +- void *intent, ++ struct xfs_log_item *intent, + unsigned int count) + { +- return xfs_trans_get_bud(tp, intent); ++ return xfs_trans_get_bud(tp, BUI_ITEM(intent)); + } + + /* Process a deferred rmap update. */ +@@ -398,9 +367,9 @@ xfs_bmap_update_finish_item( + /* Abort all pending BUIs. */ + STATIC void + xfs_bmap_update_abort_intent( +- void *intent) ++ struct xfs_log_item *intent) + { +- xfs_bui_release(intent); ++ xfs_bui_release(BUI_ITEM(intent)); + } + + /* Cancel a deferred rmap update. */ +@@ -416,10 +385,8 @@ xfs_bmap_update_cancel_item( + + const struct xfs_defer_op_type xfs_bmap_update_defer_type = { + .max_items = XFS_BUI_MAX_FAST_EXTENTS, +- .diff_items = xfs_bmap_update_diff_items, + .create_intent = xfs_bmap_update_create_intent, + .abort_intent = xfs_bmap_update_abort_intent, +- .log_item = xfs_bmap_update_log_item, + .create_done = xfs_bmap_update_create_done, + .finish_item = xfs_bmap_update_finish_item, + .cancel_item = xfs_bmap_update_cancel_item, +@@ -431,8 +398,8 @@ const struct xfs_defer_op_type xfs_bmap_update_defer_type = { + */ + int + xfs_bui_recover( +- struct xfs_trans *parent_tp, +- struct xfs_bui_log_item *buip) ++ struct xfs_bui_log_item *buip, ++ struct list_head *capture_list) + { + int error = 0; + unsigned int bui_type; +@@ -440,15 +407,13 @@ xfs_bui_recover( + xfs_fsblock_t startblock_fsb; + xfs_fsblock_t inode_fsb; + xfs_filblks_t count; +- bool op_ok; + struct xfs_bud_log_item *budp; +- enum xfs_bmap_intent_type type; + int whichfork; + xfs_exntst_t state; + struct xfs_trans *tp; + struct xfs_inode *ip = NULL; + struct xfs_bmbt_irec irec; +- struct xfs_mount *mp = parent_tp->t_mountp; ++ struct xfs_mount *mp = buip->bui_item.li_mountp; + + ASSERT(!test_bit(XFS_BUI_RECOVERED, &buip->bui_flags)); + +@@ -468,16 +433,19 @@ xfs_bui_recover( + XFS_FSB_TO_DADDR(mp, bmap->me_startblock)); + inode_fsb = XFS_BB_TO_FSB(mp, XFS_FSB_TO_DADDR(mp, + XFS_INO_TO_FSB(mp, bmap->me_owner))); +- switch (bmap->me_flags & XFS_BMAP_EXTENT_TYPE_MASK) { ++ state = (bmap->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ? ++ XFS_EXT_UNWRITTEN : XFS_EXT_NORM; ++ whichfork = (bmap->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ? ++ XFS_ATTR_FORK : XFS_DATA_FORK; ++ bui_type = bmap->me_flags & XFS_BMAP_EXTENT_TYPE_MASK; ++ switch (bui_type) { + case XFS_BMAP_MAP: + case XFS_BMAP_UNMAP: +- op_ok = true; + break; + default: +- op_ok = false; +- break; ++ return -EFSCORRUPTED; + } +- if (!op_ok || startblock_fsb == 0 || ++ if (startblock_fsb == 0 || + bmap->me_len == 0 || + inode_fsb == 0 || + startblock_fsb >= mp->m_sb.sb_dblocks || +@@ -493,52 +461,37 @@ xfs_bui_recover( + return -EFSCORRUPTED; + } + +- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, +- XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK), 0, 0, &tp); ++ /* Grab the inode. */ ++ error = xfs_iget(mp, NULL, bmap->me_owner, 0, 0, &ip); + if (error) + return error; +- /* +- * Recovery stashes all deferred ops during intent processing and +- * finishes them on completion. Transfer current dfops state to this +- * transaction and transfer the result back before we return. +- */ +- xfs_defer_move(tp, parent_tp); +- budp = xfs_trans_get_bud(tp, buip); + +- /* Grab the inode. */ +- error = xfs_iget(mp, tp, bmap->me_owner, 0, XFS_ILOCK_EXCL, &ip); ++ error = xfs_qm_dqattach(ip); + if (error) +- goto err_inode; ++ goto err_rele; + + if (VFS_I(ip)->i_nlink == 0) + xfs_iflags_set(ip, XFS_IRECOVERY); + +- /* Process deferred bmap item. */ +- state = (bmap->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ? +- XFS_EXT_UNWRITTEN : XFS_EXT_NORM; +- whichfork = (bmap->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ? +- XFS_ATTR_FORK : XFS_DATA_FORK; +- bui_type = bmap->me_flags & XFS_BMAP_EXTENT_TYPE_MASK; +- switch (bui_type) { +- case XFS_BMAP_MAP: +- case XFS_BMAP_UNMAP: +- type = bui_type; +- break; +- default: +- XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); +- error = -EFSCORRUPTED; +- goto err_inode; +- } ++ /* Allocate transaction and do the work. */ ++ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, ++ XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK), 0, 0, &tp); ++ if (error) ++ goto err_rele; ++ ++ budp = xfs_trans_get_bud(tp, buip); ++ xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, 0); + + count = bmap->me_len; +- error = xfs_trans_log_finish_bmap_update(tp, budp, type, ip, whichfork, +- bmap->me_startoff, bmap->me_startblock, &count, state); ++ error = xfs_trans_log_finish_bmap_update(tp, budp, bui_type, ip, ++ whichfork, bmap->me_startoff, bmap->me_startblock, ++ &count, state); + if (error) +- goto err_inode; ++ goto err_cancel; + + if (count > 0) { +- ASSERT(type == XFS_BMAP_UNMAP); ++ ASSERT(bui_type == XFS_BMAP_UNMAP); + irec.br_startblock = bmap->me_startblock; + irec.br_blockcount = count; + irec.br_startoff = bmap->me_startoff; +@@ -547,19 +500,78 @@ xfs_bui_recover( + } + + set_bit(XFS_BUI_RECOVERED, &buip->bui_flags); +- xfs_defer_move(parent_tp, tp); +- error = xfs_trans_commit(tp); ++ /* ++ * Commit transaction, which frees the transaction and saves the inode ++ * for later replay activities. ++ */ ++ error = xfs_defer_ops_capture_and_commit(tp, ip, capture_list); ++ if (error) ++ goto err_unlock; ++ + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_irele(ip); ++ return 0; + +- return error; +- +-err_inode: +- xfs_defer_move(parent_tp, tp); ++err_cancel: + xfs_trans_cancel(tp); +- if (ip) { +- xfs_iunlock(ip, XFS_ILOCK_EXCL); +- xfs_irele(ip); +- } ++err_unlock: ++ xfs_iunlock(ip, XFS_ILOCK_EXCL); ++err_rele: ++ xfs_irele(ip); + return error; + } ++ ++/* Relog an intent item to push the log tail forward. */ ++static struct xfs_log_item * ++xfs_bui_item_relog( ++ struct xfs_log_item *intent, ++ struct xfs_trans *tp) ++{ ++ struct xfs_bud_log_item *budp; ++ struct xfs_bui_log_item *buip; ++ struct xfs_map_extent *extp; ++ unsigned int count; ++ ++ count = BUI_ITEM(intent)->bui_format.bui_nextents; ++ extp = BUI_ITEM(intent)->bui_format.bui_extents; ++ ++ tp->t_flags |= XFS_TRANS_DIRTY; ++ budp = xfs_trans_get_bud(tp, BUI_ITEM(intent)); ++ set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags); ++ ++ buip = xfs_bui_init(tp->t_mountp); ++ memcpy(buip->bui_format.bui_extents, extp, count * sizeof(*extp)); ++ atomic_set(&buip->bui_next_extent, count); ++ xfs_trans_add_item(tp, &buip->bui_item); ++ set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags); ++ return &buip->bui_item; ++} ++ ++static const struct xfs_item_ops xfs_bui_item_ops = { ++ .iop_size = xfs_bui_item_size, ++ .iop_format = xfs_bui_item_format, ++ .iop_unpin = xfs_bui_item_unpin, ++ .iop_release = xfs_bui_item_release, ++ .iop_relog = xfs_bui_item_relog, ++}; ++ ++/* ++ * Allocate and initialize an bui item with the given number of extents. ++ */ ++struct xfs_bui_log_item * ++xfs_bui_init( ++ struct xfs_mount *mp) ++ ++{ ++ struct xfs_bui_log_item *buip; ++ ++ buip = kmem_zone_zalloc(xfs_bui_zone, 0); ++ ++ xfs_log_item_init(mp, &buip->bui_item, XFS_LI_BUI, &xfs_bui_item_ops); ++ buip->bui_format.bui_nextents = XFS_BUI_MAX_FAST_EXTENTS; ++ buip->bui_format.bui_id = (uintptr_t)(void *)buip; ++ atomic_set(&buip->bui_next_extent, 0); ++ atomic_set(&buip->bui_refcount, 2); ++ ++ return buip; ++} +diff --git a/fs/xfs/xfs_bmap_item.h b/fs/xfs/xfs_bmap_item.h +index ad479cc73de84..a95e99c269790 100644 +--- a/fs/xfs/xfs_bmap_item.h ++++ b/fs/xfs/xfs_bmap_item.h +@@ -77,6 +77,7 @@ extern struct kmem_zone *xfs_bud_zone; + struct xfs_bui_log_item *xfs_bui_init(struct xfs_mount *); + void xfs_bui_item_free(struct xfs_bui_log_item *); + void xfs_bui_release(struct xfs_bui_log_item *); +-int xfs_bui_recover(struct xfs_trans *parent_tp, struct xfs_bui_log_item *buip); ++int xfs_bui_recover(struct xfs_bui_log_item *buip, ++ struct list_head *capture_list); + + #endif /* __XFS_BMAP_ITEM_H__ */ +diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c +index a05a1074e8f81..de3cdce892fda 100644 +--- a/fs/xfs/xfs_extfree_item.c ++++ b/fs/xfs/xfs_extfree_item.c +@@ -139,44 +139,6 @@ xfs_efi_item_release( + xfs_efi_release(EFI_ITEM(lip)); + } + +-static const struct xfs_item_ops xfs_efi_item_ops = { +- .iop_size = xfs_efi_item_size, +- .iop_format = xfs_efi_item_format, +- .iop_unpin = xfs_efi_item_unpin, +- .iop_release = xfs_efi_item_release, +-}; +- +- +-/* +- * Allocate and initialize an efi item with the given number of extents. +- */ +-struct xfs_efi_log_item * +-xfs_efi_init( +- struct xfs_mount *mp, +- uint nextents) +- +-{ +- struct xfs_efi_log_item *efip; +- uint size; +- +- ASSERT(nextents > 0); +- if (nextents > XFS_EFI_MAX_FAST_EXTENTS) { +- size = (uint)(sizeof(xfs_efi_log_item_t) + +- ((nextents - 1) * sizeof(xfs_extent_t))); +- efip = kmem_zalloc(size, 0); +- } else { +- efip = kmem_zone_zalloc(xfs_efi_zone, 0); +- } +- +- xfs_log_item_init(mp, &efip->efi_item, XFS_LI_EFI, &xfs_efi_item_ops); +- efip->efi_format.efi_nextents = nextents; +- efip->efi_format.efi_id = (uintptr_t)(void *)efip; +- atomic_set(&efip->efi_next_extent, 0); +- atomic_set(&efip->efi_refcount, 2); +- +- return efip; +-} +- + /* + * Copy an EFI format buffer from the given buf, and into the destination + * EFI format structure. +@@ -412,41 +374,16 @@ xfs_extent_free_diff_items( + XFS_FSB_TO_AGNO(mp, rb->xefi_startblock); + } + +-/* Get an EFI. */ +-STATIC void * +-xfs_extent_free_create_intent( +- struct xfs_trans *tp, +- unsigned int count) +-{ +- struct xfs_efi_log_item *efip; +- +- ASSERT(tp != NULL); +- ASSERT(count > 0); +- +- efip = xfs_efi_init(tp->t_mountp, count); +- ASSERT(efip != NULL); +- +- /* +- * Get a log_item_desc to point at the new item. +- */ +- xfs_trans_add_item(tp, &efip->efi_item); +- return efip; +-} +- + /* Log a free extent to the intent item. */ + STATIC void + xfs_extent_free_log_item( + struct xfs_trans *tp, +- void *intent, +- struct list_head *item) ++ struct xfs_efi_log_item *efip, ++ struct xfs_extent_free_item *free) + { +- struct xfs_efi_log_item *efip = intent; +- struct xfs_extent_free_item *free; + uint next_extent; + struct xfs_extent *extp; + +- free = container_of(item, struct xfs_extent_free_item, xefi_list); +- + tp->t_flags |= XFS_TRANS_DIRTY; + set_bit(XFS_LI_DIRTY, &efip->efi_item.li_flags); + +@@ -462,14 +399,35 @@ xfs_extent_free_log_item( + extp->ext_len = free->xefi_blockcount; + } + ++static struct xfs_log_item * ++xfs_extent_free_create_intent( ++ struct xfs_trans *tp, ++ struct list_head *items, ++ unsigned int count, ++ bool sort) ++{ ++ struct xfs_mount *mp = tp->t_mountp; ++ struct xfs_efi_log_item *efip = xfs_efi_init(mp, count); ++ struct xfs_extent_free_item *free; ++ ++ ASSERT(count > 0); ++ ++ xfs_trans_add_item(tp, &efip->efi_item); ++ if (sort) ++ list_sort(mp, items, xfs_extent_free_diff_items); ++ list_for_each_entry(free, items, xefi_list) ++ xfs_extent_free_log_item(tp, efip, free); ++ return &efip->efi_item; ++} ++ + /* Get an EFD so we can process all the free extents. */ + STATIC void * + xfs_extent_free_create_done( + struct xfs_trans *tp, +- void *intent, ++ struct xfs_log_item *intent, + unsigned int count) + { +- return xfs_trans_get_efd(tp, intent, count); ++ return xfs_trans_get_efd(tp, EFI_ITEM(intent), count); + } + + /* Process a free extent. */ +@@ -495,9 +453,9 @@ xfs_extent_free_finish_item( + /* Abort all pending EFIs. */ + STATIC void + xfs_extent_free_abort_intent( +- void *intent) ++ struct xfs_log_item *intent) + { +- xfs_efi_release(intent); ++ xfs_efi_release(EFI_ITEM(intent)); + } + + /* Cancel a free extent. */ +@@ -513,10 +471,8 @@ xfs_extent_free_cancel_item( + + const struct xfs_defer_op_type xfs_extent_free_defer_type = { + .max_items = XFS_EFI_MAX_FAST_EXTENTS, +- .diff_items = xfs_extent_free_diff_items, + .create_intent = xfs_extent_free_create_intent, + .abort_intent = xfs_extent_free_abort_intent, +- .log_item = xfs_extent_free_log_item, + .create_done = xfs_extent_free_create_done, + .finish_item = xfs_extent_free_finish_item, + .cancel_item = xfs_extent_free_cancel_item, +@@ -579,10 +535,8 @@ xfs_agfl_free_finish_item( + /* sub-type with special handling for AGFL deferred frees */ + const struct xfs_defer_op_type xfs_agfl_free_defer_type = { + .max_items = XFS_EFI_MAX_FAST_EXTENTS, +- .diff_items = xfs_extent_free_diff_items, + .create_intent = xfs_extent_free_create_intent, + .abort_intent = xfs_extent_free_abort_intent, +- .log_item = xfs_extent_free_log_item, + .create_done = xfs_extent_free_create_done, + .finish_item = xfs_agfl_free_finish_item, + .cancel_item = xfs_extent_free_cancel_item, +@@ -594,9 +548,10 @@ const struct xfs_defer_op_type xfs_agfl_free_defer_type = { + */ + int + xfs_efi_recover( +- struct xfs_mount *mp, +- struct xfs_efi_log_item *efip) ++ struct xfs_efi_log_item *efip, ++ struct list_head *capture_list) + { ++ struct xfs_mount *mp = efip->efi_item.li_mountp; + struct xfs_efd_log_item *efdp; + struct xfs_trans *tp; + int i; +@@ -645,10 +600,76 @@ xfs_efi_recover( + } + + set_bit(XFS_EFI_RECOVERED, &efip->efi_flags); +- error = xfs_trans_commit(tp); +- return error; ++ ++ return xfs_defer_ops_capture_and_commit(tp, NULL, capture_list); + + abort_error: + xfs_trans_cancel(tp); + return error; + } ++ ++/* Relog an intent item to push the log tail forward. */ ++static struct xfs_log_item * ++xfs_efi_item_relog( ++ struct xfs_log_item *intent, ++ struct xfs_trans *tp) ++{ ++ struct xfs_efd_log_item *efdp; ++ struct xfs_efi_log_item *efip; ++ struct xfs_extent *extp; ++ unsigned int count; ++ ++ count = EFI_ITEM(intent)->efi_format.efi_nextents; ++ extp = EFI_ITEM(intent)->efi_format.efi_extents; ++ ++ tp->t_flags |= XFS_TRANS_DIRTY; ++ efdp = xfs_trans_get_efd(tp, EFI_ITEM(intent), count); ++ efdp->efd_next_extent = count; ++ memcpy(efdp->efd_format.efd_extents, extp, count * sizeof(*extp)); ++ set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags); ++ ++ efip = xfs_efi_init(tp->t_mountp, count); ++ memcpy(efip->efi_format.efi_extents, extp, count * sizeof(*extp)); ++ atomic_set(&efip->efi_next_extent, count); ++ xfs_trans_add_item(tp, &efip->efi_item); ++ set_bit(XFS_LI_DIRTY, &efip->efi_item.li_flags); ++ return &efip->efi_item; ++} ++ ++static const struct xfs_item_ops xfs_efi_item_ops = { ++ .iop_size = xfs_efi_item_size, ++ .iop_format = xfs_efi_item_format, ++ .iop_unpin = xfs_efi_item_unpin, ++ .iop_release = xfs_efi_item_release, ++ .iop_relog = xfs_efi_item_relog, ++}; ++ ++/* ++ * Allocate and initialize an efi item with the given number of extents. ++ */ ++struct xfs_efi_log_item * ++xfs_efi_init( ++ struct xfs_mount *mp, ++ uint nextents) ++ ++{ ++ struct xfs_efi_log_item *efip; ++ uint size; ++ ++ ASSERT(nextents > 0); ++ if (nextents > XFS_EFI_MAX_FAST_EXTENTS) { ++ size = (uint)(sizeof(struct xfs_efi_log_item) + ++ ((nextents - 1) * sizeof(xfs_extent_t))); ++ efip = kmem_zalloc(size, 0); ++ } else { ++ efip = kmem_zone_zalloc(xfs_efi_zone, 0); ++ } ++ ++ xfs_log_item_init(mp, &efip->efi_item, XFS_LI_EFI, &xfs_efi_item_ops); ++ efip->efi_format.efi_nextents = nextents; ++ efip->efi_format.efi_id = (uintptr_t)(void *)efip; ++ atomic_set(&efip->efi_next_extent, 0); ++ atomic_set(&efip->efi_refcount, 2); ++ ++ return efip; ++} +diff --git a/fs/xfs/xfs_extfree_item.h b/fs/xfs/xfs_extfree_item.h +index 16aaab06d4ecc..883f0f1d8989d 100644 +--- a/fs/xfs/xfs_extfree_item.h ++++ b/fs/xfs/xfs_extfree_item.h +@@ -50,25 +50,25 @@ struct kmem_zone; + * of commit failure or log I/O errors. Note that the EFD is not inserted in the + * AIL, so at this point both the EFI and EFD are freed. + */ +-typedef struct xfs_efi_log_item { ++struct xfs_efi_log_item { + struct xfs_log_item efi_item; + atomic_t efi_refcount; + atomic_t efi_next_extent; + unsigned long efi_flags; /* misc flags */ + xfs_efi_log_format_t efi_format; +-} xfs_efi_log_item_t; ++}; + + /* + * This is the "extent free done" log item. It is used to log + * the fact that some extents earlier mentioned in an efi item + * have been freed. + */ +-typedef struct xfs_efd_log_item { ++struct xfs_efd_log_item { + struct xfs_log_item efd_item; +- xfs_efi_log_item_t *efd_efip; ++ struct xfs_efi_log_item *efd_efip; + uint efd_next_extent; + xfs_efd_log_format_t efd_format; +-} xfs_efd_log_item_t; ++}; + + /* + * Max number of extents in fast allocation path. +@@ -78,13 +78,13 @@ typedef struct xfs_efd_log_item { + extern struct kmem_zone *xfs_efi_zone; + extern struct kmem_zone *xfs_efd_zone; + +-xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); ++struct xfs_efi_log_item *xfs_efi_init(struct xfs_mount *, uint); + int xfs_efi_copy_format(xfs_log_iovec_t *buf, + xfs_efi_log_format_t *dst_efi_fmt); +-void xfs_efi_item_free(xfs_efi_log_item_t *); ++void xfs_efi_item_free(struct xfs_efi_log_item *); + void xfs_efi_release(struct xfs_efi_log_item *); + +-int xfs_efi_recover(struct xfs_mount *mp, +- struct xfs_efi_log_item *efip); ++int xfs_efi_recover(struct xfs_efi_log_item *efip, ++ struct list_head *capture_list); + + #endif /* __XFS_EXTFREE_ITEM_H__ */ +diff --git a/fs/xfs/xfs_icreate_item.c b/fs/xfs/xfs_icreate_item.c +index 3ebd1b7f49d82..7d940b289db54 100644 +--- a/fs/xfs/xfs_icreate_item.c ++++ b/fs/xfs/xfs_icreate_item.c +@@ -10,6 +10,7 @@ + #include "xfs_trans.h" + #include "xfs_trans_priv.h" + #include "xfs_icreate_item.h" ++#include "xfs_log_priv.h" + #include "xfs_log.h" + + kmem_zone_t *xfs_icreate_zone; /* inode create item zone */ +diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c +index e5a90a0b8f8a2..02f77a359972e 100644 +--- a/fs/xfs/xfs_inode.c ++++ b/fs/xfs/xfs_inode.c +@@ -2555,7 +2555,7 @@ xfs_ifree_cluster( + xfs_daddr_t blkno; + xfs_buf_t *bp; + xfs_inode_t *ip; +- xfs_inode_log_item_t *iip; ++ struct xfs_inode_log_item *iip; + struct xfs_log_item *lip; + struct xfs_perag *pag; + struct xfs_ino_geometry *igeo = M_IGEO(mp); +@@ -2617,7 +2617,7 @@ xfs_ifree_cluster( + */ + list_for_each_entry(lip, &bp->b_li_list, li_bio_list) { + if (lip->li_type == XFS_LI_INODE) { +- iip = (xfs_inode_log_item_t *)lip; ++ iip = (struct xfs_inode_log_item *)lip; + ASSERT(iip->ili_logged == 1); + lip->li_cb = xfs_istale_done; + xfs_trans_ail_copy_lsn(mp->m_ail, +diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c +index 76a60526af94f..83b8f5655636e 100644 +--- a/fs/xfs/xfs_inode_item.c ++++ b/fs/xfs/xfs_inode_item.c +@@ -781,7 +781,7 @@ xfs_iflush_abort( + xfs_inode_t *ip, + bool stale) + { +- xfs_inode_log_item_t *iip = ip->i_itemp; ++ struct xfs_inode_log_item *iip = ip->i_itemp; + + if (iip) { + if (test_bit(XFS_LI_IN_AIL, &iip->ili_item.li_flags)) { +diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h +index 07a60e74c39c8..ad667fd4ae622 100644 +--- a/fs/xfs/xfs_inode_item.h ++++ b/fs/xfs/xfs_inode_item.h +@@ -13,7 +13,7 @@ struct xfs_bmbt_rec; + struct xfs_inode; + struct xfs_mount; + +-typedef struct xfs_inode_log_item { ++struct xfs_inode_log_item { + struct xfs_log_item ili_item; /* common portion */ + struct xfs_inode *ili_inode; /* inode ptr */ + xfs_lsn_t ili_flush_lsn; /* lsn at last flush */ +@@ -23,7 +23,7 @@ typedef struct xfs_inode_log_item { + unsigned int ili_last_fields; /* fields when flushed */ + unsigned int ili_fields; /* fields to be logged */ + unsigned int ili_fsync_fields; /* logged since last fsync */ +-} xfs_inode_log_item_t; ++}; + + static inline int xfs_inode_clean(xfs_inode_t *ip) + { +diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c +index aa375cf53021a..cc5c0c835884e 100644 +--- a/fs/xfs/xfs_iwalk.c ++++ b/fs/xfs/xfs_iwalk.c +@@ -55,6 +55,9 @@ struct xfs_iwalk_ag { + /* Where do we start the traversal? */ + xfs_ino_t startino; + ++ /* What was the last inode number we saw when iterating the inobt? */ ++ xfs_ino_t lastino; ++ + /* Array of inobt records we cache. */ + struct xfs_inobt_rec_incore *recs; + +@@ -300,6 +303,9 @@ xfs_iwalk_ag_start( + return error; + XFS_WANT_CORRUPTED_RETURN(mp, *has_more == 1); + ++ iwag->lastino = XFS_AGINO_TO_INO(mp, agno, ++ irec->ir_startino + XFS_INODES_PER_CHUNK - 1); ++ + /* + * If the LE lookup yielded an inobt record before the cursor position, + * skip it and see if there's another one after it. +@@ -346,15 +352,17 @@ xfs_iwalk_run_callbacks( + struct xfs_mount *mp = iwag->mp; + struct xfs_trans *tp = iwag->tp; + struct xfs_inobt_rec_incore *irec; +- xfs_agino_t restart; ++ xfs_agino_t next_agino; + int error; + ++ next_agino = XFS_INO_TO_AGINO(mp, iwag->lastino) + 1; ++ + ASSERT(iwag->nr_recs > 0); + + /* Delete cursor but remember the last record we cached... */ + xfs_iwalk_del_inobt(tp, curpp, agi_bpp, 0); + irec = &iwag->recs[iwag->nr_recs - 1]; +- restart = irec->ir_startino + XFS_INODES_PER_CHUNK - 1; ++ ASSERT(next_agino >= irec->ir_startino + XFS_INODES_PER_CHUNK); + + error = xfs_iwalk_ag_recs(iwag); + if (error) +@@ -371,7 +379,7 @@ xfs_iwalk_run_callbacks( + if (error) + return error; + +- return xfs_inobt_lookup(*curpp, restart, XFS_LOOKUP_GE, has_more); ++ return xfs_inobt_lookup(*curpp, next_agino, XFS_LOOKUP_GE, has_more); + } + + /* Walk all inodes in a single AG, from @iwag->startino to the end of the AG. */ +@@ -395,6 +403,7 @@ xfs_iwalk_ag( + + while (!error && has_more) { + struct xfs_inobt_rec_incore *irec; ++ xfs_ino_t rec_fsino; + + cond_resched(); + if (xfs_pwork_want_abort(&iwag->pwork)) +@@ -406,6 +415,15 @@ xfs_iwalk_ag( + if (error || !has_more) + break; + ++ /* Make sure that we always move forward. */ ++ rec_fsino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino); ++ if (iwag->lastino != NULLFSINO && iwag->lastino >= rec_fsino) { ++ ASSERT(iwag->lastino < rec_fsino); ++ error = -EFSCORRUPTED; ++ goto out; ++ } ++ iwag->lastino = rec_fsino + XFS_INODES_PER_CHUNK - 1; ++ + /* No allocated inodes in this chunk; skip it. */ + if (iwag->skip_empty && irec->ir_freecount == irec->ir_count) { + error = xfs_btree_increment(cur, 0, &has_more); +@@ -534,6 +552,7 @@ xfs_iwalk( + .trim_start = 1, + .skip_empty = 1, + .pwork = XFS_PWORK_SINGLE_THREADED, ++ .lastino = NULLFSINO, + }; + xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino); + int error; +@@ -622,6 +641,7 @@ xfs_iwalk_threaded( + iwag->data = data; + iwag->startino = startino; + iwag->sz_recs = xfs_iwalk_prefetch(inode_records); ++ iwag->lastino = NULLFSINO; + xfs_pwork_queue(&pctl, &iwag->pwork); + startino = XFS_AGINO_TO_INO(mp, agno + 1, 0); + if (flags & XFS_INOBT_WALK_SAME_AG) +@@ -695,6 +715,7 @@ xfs_inobt_walk( + .startino = startino, + .sz_recs = xfs_inobt_walk_prefetch(inobt_records), + .pwork = XFS_PWORK_SINGLE_THREADED, ++ .lastino = NULLFSINO, + }; + xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino); + int error; +diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c +index 63c0f1e9d1018..03a52b3919b82 100644 +--- a/fs/xfs/xfs_log.c ++++ b/fs/xfs/xfs_log.c +@@ -369,6 +369,25 @@ xlog_tic_add_region(xlog_ticket_t *tic, uint len, uint type) + tic->t_res_num++; + } + ++bool ++xfs_log_writable( ++ struct xfs_mount *mp) ++{ ++ /* ++ * Never write to the log on norecovery mounts, if the block device is ++ * read-only, or if the filesystem is shutdown. Read-only mounts still ++ * allow internal writes for log recovery and unmount purposes, so don't ++ * restrict that case here. ++ */ ++ if (mp->m_flags & XFS_MOUNT_NORECOVERY) ++ return false; ++ if (xfs_readonly_buftarg(mp->m_log->l_targ)) ++ return false; ++ if (XFS_FORCED_SHUTDOWN(mp)) ++ return false; ++ return true; ++} ++ + /* + * Replenish the byte reservation required by moving the grant write head. + */ +@@ -895,15 +914,8 @@ xfs_log_unmount_write(xfs_mount_t *mp) + #endif + int error; + +- /* +- * Don't write out unmount record on norecovery mounts or ro devices. +- * Or, if we are doing a forced umount (typically because of IO errors). +- */ +- if (mp->m_flags & XFS_MOUNT_NORECOVERY || +- xfs_readonly_buftarg(log->l_targ)) { +- ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); ++ if (!xfs_log_writable(mp)) + return 0; +- } + + error = xfs_log_force(mp, XFS_LOG_SYNC); + ASSERT(error || !(XLOG_FORCED_SHUTDOWN(log))); +@@ -1537,14 +1549,14 @@ xlog_commit_record( + } + + /* +- * Push on the buffer cache code if we ever use more than 75% of the on-disk +- * log space. This code pushes on the lsn which would supposedly free up +- * the 25% which we want to leave free. We may need to adopt a policy which +- * pushes on an lsn which is further along in the log once we reach the high +- * water mark. In this manner, we would be creating a low water mark. ++ * Compute the LSN that we'd need to push the log tail towards in order to have ++ * (a) enough on-disk log space to log the number of bytes specified, (b) at ++ * least 25% of the log space free, and (c) at least 256 blocks free. If the ++ * log free space already meets all three thresholds, this function returns ++ * NULLCOMMITLSN. + */ +-STATIC void +-xlog_grant_push_ail( ++xfs_lsn_t ++xlog_grant_push_threshold( + struct xlog *log, + int need_bytes) + { +@@ -1570,7 +1582,7 @@ xlog_grant_push_ail( + free_threshold = max(free_threshold, (log->l_logBBsize >> 2)); + free_threshold = max(free_threshold, 256); + if (free_blocks >= free_threshold) +- return; ++ return NULLCOMMITLSN; + + xlog_crack_atomic_lsn(&log->l_tail_lsn, &threshold_cycle, + &threshold_block); +@@ -1590,13 +1602,33 @@ xlog_grant_push_ail( + if (XFS_LSN_CMP(threshold_lsn, last_sync_lsn) > 0) + threshold_lsn = last_sync_lsn; + ++ return threshold_lsn; ++} ++ ++/* ++ * Push the tail of the log if we need to do so to maintain the free log space ++ * thresholds set out by xlog_grant_push_threshold. We may need to adopt a ++ * policy which pushes on an lsn which is further along in the log once we ++ * reach the high water mark. In this manner, we would be creating a low water ++ * mark. ++ */ ++STATIC void ++xlog_grant_push_ail( ++ struct xlog *log, ++ int need_bytes) ++{ ++ xfs_lsn_t threshold_lsn; ++ ++ threshold_lsn = xlog_grant_push_threshold(log, need_bytes); ++ if (threshold_lsn == NULLCOMMITLSN || XLOG_FORCED_SHUTDOWN(log)) ++ return; ++ + /* + * Get the transaction layer to kick the dirty buffers out to + * disk asynchronously. No point in trying to do this if + * the filesystem is shutting down. + */ +- if (!XLOG_FORCED_SHUTDOWN(log)) +- xfs_ail_push(log->l_ailp, threshold_lsn); ++ xfs_ail_push(log->l_ailp, threshold_lsn); + } + + /* +diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h +index 84e06805160f8..dc9229e7ddaaa 100644 +--- a/fs/xfs/xfs_log.h ++++ b/fs/xfs/xfs_log.h +@@ -132,6 +132,7 @@ int xfs_log_reserve(struct xfs_mount *mp, + int xfs_log_regrant(struct xfs_mount *mp, struct xlog_ticket *tic); + void xfs_log_unmount(struct xfs_mount *mp); + int xfs_log_force_umount(struct xfs_mount *mp, int logerror); ++bool xfs_log_writable(struct xfs_mount *mp); + + struct xlog_ticket *xfs_log_ticket_get(struct xlog_ticket *ticket); + void xfs_log_ticket_put(struct xlog_ticket *ticket); +@@ -146,4 +147,6 @@ void xfs_log_quiesce(struct xfs_mount *mp); + bool xfs_log_check_lsn(struct xfs_mount *, xfs_lsn_t); + bool xfs_log_in_recovery(struct xfs_mount *); + ++xfs_lsn_t xlog_grant_push_threshold(struct xlog *log, int need_bytes); ++ + #endif /* __XFS_LOG_H__ */ +diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c +index 550fd5de2404a..ae9b8efcfa545 100644 +--- a/fs/xfs/xfs_log_cil.c ++++ b/fs/xfs/xfs_log_cil.c +@@ -1178,21 +1178,19 @@ out_shutdown: + */ + bool + xfs_log_item_in_current_chkpt( +- struct xfs_log_item *lip) ++ struct xfs_log_item *lip) + { +- struct xfs_cil_ctx *ctx; ++ struct xfs_cil *cil = lip->li_mountp->m_log->l_cilp; + + if (list_empty(&lip->li_cil)) + return false; + +- ctx = lip->li_mountp->m_log->l_cilp->xc_ctx; +- + /* + * li_seq is written on the first commit of a log item to record the + * first checkpoint it is written to. Hence if it is different to the + * current sequence, we're in a new checkpoint. + */ +- if (XFS_LSN_CMP(lip->li_seq, ctx->sequence) != 0) ++ if (XFS_LSN_CMP(lip->li_seq, READ_ONCE(cil->xc_current_sequence)) != 0) + return false; + return true; + } +diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c +index 46b1e255f55fc..6c60cdd10d330 100644 +--- a/fs/xfs/xfs_log_recover.c ++++ b/fs/xfs/xfs_log_recover.c +@@ -2206,6 +2206,8 @@ xlog_recover_get_buf_lsn( + case XFS_ABTC_MAGIC: + case XFS_RMAP_CRC_MAGIC: + case XFS_REFC_CRC_MAGIC: ++ case XFS_FIBT_CRC_MAGIC: ++ case XFS_FIBT_MAGIC: + case XFS_IBT_CRC_MAGIC: + case XFS_IBT_MAGIC: { + struct xfs_btree_block *btb = blk; +@@ -3384,7 +3386,7 @@ xlog_recover_efd_pass2( + struct xlog_recover_item *item) + { + xfs_efd_log_format_t *efd_formatp; +- xfs_efi_log_item_t *efip = NULL; ++ struct xfs_efi_log_item *efip = NULL; + struct xfs_log_item *lip; + uint64_t efi_id; + struct xfs_ail_cursor cur; +@@ -3405,7 +3407,7 @@ xlog_recover_efd_pass2( + lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); + while (lip != NULL) { + if (lip->li_type == XFS_LI_EFI) { +- efip = (xfs_efi_log_item_t *)lip; ++ efip = (struct xfs_efi_log_item *)lip; + if (efip->efi_format.efi_id == efi_id) { + /* + * Drop the EFD reference to the EFI. This +@@ -4585,9 +4587,9 @@ xlog_recover_process_data( + /* Recover the EFI if necessary. */ + STATIC int + xlog_recover_process_efi( +- struct xfs_mount *mp, + struct xfs_ail *ailp, +- struct xfs_log_item *lip) ++ struct xfs_log_item *lip, ++ struct list_head *capture_list) + { + struct xfs_efi_log_item *efip; + int error; +@@ -4600,7 +4602,7 @@ xlog_recover_process_efi( + return 0; + + spin_unlock(&ailp->ail_lock); +- error = xfs_efi_recover(mp, efip); ++ error = xfs_efi_recover(efip, capture_list); + spin_lock(&ailp->ail_lock); + + return error; +@@ -4625,9 +4627,9 @@ xlog_recover_cancel_efi( + /* Recover the RUI if necessary. */ + STATIC int + xlog_recover_process_rui( +- struct xfs_mount *mp, + struct xfs_ail *ailp, +- struct xfs_log_item *lip) ++ struct xfs_log_item *lip, ++ struct list_head *capture_list) + { + struct xfs_rui_log_item *ruip; + int error; +@@ -4640,7 +4642,7 @@ xlog_recover_process_rui( + return 0; + + spin_unlock(&ailp->ail_lock); +- error = xfs_rui_recover(mp, ruip); ++ error = xfs_rui_recover(ruip, capture_list); + spin_lock(&ailp->ail_lock); + + return error; +@@ -4665,9 +4667,9 @@ xlog_recover_cancel_rui( + /* Recover the CUI if necessary. */ + STATIC int + xlog_recover_process_cui( +- struct xfs_trans *parent_tp, + struct xfs_ail *ailp, +- struct xfs_log_item *lip) ++ struct xfs_log_item *lip, ++ struct list_head *capture_list) + { + struct xfs_cui_log_item *cuip; + int error; +@@ -4680,7 +4682,7 @@ xlog_recover_process_cui( + return 0; + + spin_unlock(&ailp->ail_lock); +- error = xfs_cui_recover(parent_tp, cuip); ++ error = xfs_cui_recover(cuip, capture_list); + spin_lock(&ailp->ail_lock); + + return error; +@@ -4705,9 +4707,9 @@ xlog_recover_cancel_cui( + /* Recover the BUI if necessary. */ + STATIC int + xlog_recover_process_bui( +- struct xfs_trans *parent_tp, + struct xfs_ail *ailp, +- struct xfs_log_item *lip) ++ struct xfs_log_item *lip, ++ struct list_head *capture_list) + { + struct xfs_bui_log_item *buip; + int error; +@@ -4720,7 +4722,7 @@ xlog_recover_process_bui( + return 0; + + spin_unlock(&ailp->ail_lock); +- error = xfs_bui_recover(parent_tp, buip); ++ error = xfs_bui_recover(buip, capture_list); + spin_lock(&ailp->ail_lock); + + return error; +@@ -4759,37 +4761,66 @@ static inline bool xlog_item_is_intent(struct xfs_log_item *lip) + /* Take all the collected deferred ops and finish them in order. */ + static int + xlog_finish_defer_ops( +- struct xfs_trans *parent_tp) ++ struct xfs_mount *mp, ++ struct list_head *capture_list) + { +- struct xfs_mount *mp = parent_tp->t_mountp; ++ struct xfs_defer_capture *dfc, *next; + struct xfs_trans *tp; +- int64_t freeblks; +- uint resblks; +- int error; ++ struct xfs_inode *ip; ++ int error = 0; + +- /* +- * We're finishing the defer_ops that accumulated as a result of +- * recovering unfinished intent items during log recovery. We +- * reserve an itruncate transaction because it is the largest +- * permanent transaction type. Since we're the only user of the fs +- * right now, take 93% (15/16) of the available free blocks. Use +- * weird math to avoid a 64-bit division. +- */ +- freeblks = percpu_counter_sum(&mp->m_fdblocks); +- if (freeblks <= 0) +- return -ENOSPC; +- resblks = min_t(int64_t, UINT_MAX, freeblks); +- resblks = (resblks * 15) >> 4; +- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, resblks, +- 0, XFS_TRANS_RESERVE, &tp); +- if (error) +- return error; +- /* transfer all collected dfops to this transaction */ +- xfs_defer_move(tp, parent_tp); ++ list_for_each_entry_safe(dfc, next, capture_list, dfc_list) { ++ struct xfs_trans_res resv; ++ ++ /* ++ * Create a new transaction reservation from the captured ++ * information. Set logcount to 1 to force the new transaction ++ * to regrant every roll so that we can make forward progress ++ * in recovery no matter how full the log might be. ++ */ ++ resv.tr_logres = dfc->dfc_logres; ++ resv.tr_logcount = 1; ++ resv.tr_logflags = XFS_TRANS_PERM_LOG_RES; ++ ++ error = xfs_trans_alloc(mp, &resv, dfc->dfc_blkres, ++ dfc->dfc_rtxres, XFS_TRANS_RESERVE, &tp); ++ if (error) ++ return error; ++ ++ /* ++ * Transfer to this new transaction all the dfops we captured ++ * from recovering a single intent item. ++ */ ++ list_del_init(&dfc->dfc_list); ++ xfs_defer_ops_continue(dfc, tp, &ip); ++ ++ error = xfs_trans_commit(tp); ++ if (ip) { ++ xfs_iunlock(ip, XFS_ILOCK_EXCL); ++ xfs_irele(ip); ++ } ++ if (error) ++ return error; ++ } + +- return xfs_trans_commit(tp); ++ ASSERT(list_empty(capture_list)); ++ return 0; + } + ++/* Release all the captured defer ops and capture structures in this list. */ ++static void ++xlog_abort_defer_ops( ++ struct xfs_mount *mp, ++ struct list_head *capture_list) ++{ ++ struct xfs_defer_capture *dfc; ++ struct xfs_defer_capture *next; ++ ++ list_for_each_entry_safe(dfc, next, capture_list, dfc_list) { ++ list_del_init(&dfc->dfc_list); ++ xfs_defer_ops_release(mp, dfc); ++ } ++} + /* + * When this is called, all of the log intent items which did not have + * corresponding log done items should be in the AIL. What we do now +@@ -4810,35 +4841,23 @@ STATIC int + xlog_recover_process_intents( + struct xlog *log) + { +- struct xfs_trans *parent_tp; ++ LIST_HEAD(capture_list); + struct xfs_ail_cursor cur; + struct xfs_log_item *lip; + struct xfs_ail *ailp; +- int error; ++ int error = 0; + #if defined(DEBUG) || defined(XFS_WARN) + xfs_lsn_t last_lsn; + #endif + +- /* +- * The intent recovery handlers commit transactions to complete recovery +- * for individual intents, but any new deferred operations that are +- * queued during that process are held off until the very end. The +- * purpose of this transaction is to serve as a container for deferred +- * operations. Each intent recovery handler must transfer dfops here +- * before its local transaction commits, and we'll finish the entire +- * list below. +- */ +- error = xfs_trans_alloc_empty(log->l_mp, &parent_tp); +- if (error) +- return error; +- + ailp = log->l_ailp; + spin_lock(&ailp->ail_lock); +- lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); + #if defined(DEBUG) || defined(XFS_WARN) + last_lsn = xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block); + #endif +- while (lip != NULL) { ++ for (lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); ++ lip != NULL; ++ lip = xfs_trans_ail_cursor_next(ailp, &cur)) { + /* + * We're done when we see something other than an intent. + * There should be no intents left in the AIL now. +@@ -4860,35 +4879,40 @@ xlog_recover_process_intents( + + /* + * NOTE: If your intent processing routine can create more +- * deferred ops, you /must/ attach them to the dfops in this +- * routine or else those subsequent intents will get ++ * deferred ops, you /must/ attach them to the capture list in ++ * the recover routine or else those subsequent intents will be + * replayed in the wrong order! + */ + switch (lip->li_type) { + case XFS_LI_EFI: +- error = xlog_recover_process_efi(log->l_mp, ailp, lip); ++ error = xlog_recover_process_efi(ailp, lip, &capture_list); + break; + case XFS_LI_RUI: +- error = xlog_recover_process_rui(log->l_mp, ailp, lip); ++ error = xlog_recover_process_rui(ailp, lip, &capture_list); + break; + case XFS_LI_CUI: +- error = xlog_recover_process_cui(parent_tp, ailp, lip); ++ error = xlog_recover_process_cui(ailp, lip, &capture_list); + break; + case XFS_LI_BUI: +- error = xlog_recover_process_bui(parent_tp, ailp, lip); ++ error = xlog_recover_process_bui(ailp, lip, &capture_list); + break; + } + if (error) +- goto out; +- lip = xfs_trans_ail_cursor_next(ailp, &cur); ++ break; + } +-out: ++ + xfs_trans_ail_cursor_done(&cur); + spin_unlock(&ailp->ail_lock); +- if (!error) +- error = xlog_finish_defer_ops(parent_tp); +- xfs_trans_cancel(parent_tp); ++ if (error) ++ goto err; + ++ error = xlog_finish_defer_ops(log->l_mp, &capture_list); ++ if (error) ++ goto err; ++ ++ return 0; ++err: ++ xlog_abort_defer_ops(log->l_mp, &capture_list); + return error; + } + +diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c +index bbcf48a625b2a..2860966af6c20 100644 +--- a/fs/xfs/xfs_mount.c ++++ b/fs/xfs/xfs_mount.c +@@ -1218,8 +1218,7 @@ xfs_fs_writable( + int + xfs_log_sbcount(xfs_mount_t *mp) + { +- /* allow this to proceed during the freeze sequence... */ +- if (!xfs_fs_writable(mp, SB_FREEZE_COMPLETE)) ++ if (!xfs_log_writable(mp)) + return 0; + + /* +diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c +index d5708d40ad877..fa1018a6e6777 100644 +--- a/fs/xfs/xfs_refcount_item.c ++++ b/fs/xfs/xfs_refcount_item.c +@@ -123,40 +123,6 @@ xfs_cui_item_release( + xfs_cui_release(CUI_ITEM(lip)); + } + +-static const struct xfs_item_ops xfs_cui_item_ops = { +- .iop_size = xfs_cui_item_size, +- .iop_format = xfs_cui_item_format, +- .iop_unpin = xfs_cui_item_unpin, +- .iop_release = xfs_cui_item_release, +-}; +- +-/* +- * Allocate and initialize an cui item with the given number of extents. +- */ +-struct xfs_cui_log_item * +-xfs_cui_init( +- struct xfs_mount *mp, +- uint nextents) +- +-{ +- struct xfs_cui_log_item *cuip; +- +- ASSERT(nextents > 0); +- if (nextents > XFS_CUI_MAX_FAST_EXTENTS) +- cuip = kmem_zalloc(xfs_cui_log_item_sizeof(nextents), +- 0); +- else +- cuip = kmem_zone_zalloc(xfs_cui_zone, 0); +- +- xfs_log_item_init(mp, &cuip->cui_item, XFS_LI_CUI, &xfs_cui_item_ops); +- cuip->cui_format.cui_nextents = nextents; +- cuip->cui_format.cui_id = (uintptr_t)(void *)cuip; +- atomic_set(&cuip->cui_next_extent, 0); +- atomic_set(&cuip->cui_refcount, 2); +- +- return cuip; +-} +- + static inline struct xfs_cud_log_item *CUD_ITEM(struct xfs_log_item *lip) + { + return container_of(lip, struct xfs_cud_log_item, cud_item); +@@ -284,27 +250,6 @@ xfs_refcount_update_diff_items( + XFS_FSB_TO_AGNO(mp, rb->ri_startblock); + } + +-/* Get an CUI. */ +-STATIC void * +-xfs_refcount_update_create_intent( +- struct xfs_trans *tp, +- unsigned int count) +-{ +- struct xfs_cui_log_item *cuip; +- +- ASSERT(tp != NULL); +- ASSERT(count > 0); +- +- cuip = xfs_cui_init(tp->t_mountp, count); +- ASSERT(cuip != NULL); +- +- /* +- * Get a log_item_desc to point at the new item. +- */ +- xfs_trans_add_item(tp, &cuip->cui_item); +- return cuip; +-} +- + /* Set the phys extent flags for this reverse mapping. */ + static void + xfs_trans_set_refcount_flags( +@@ -328,16 +273,12 @@ xfs_trans_set_refcount_flags( + STATIC void + xfs_refcount_update_log_item( + struct xfs_trans *tp, +- void *intent, +- struct list_head *item) ++ struct xfs_cui_log_item *cuip, ++ struct xfs_refcount_intent *refc) + { +- struct xfs_cui_log_item *cuip = intent; +- struct xfs_refcount_intent *refc; + uint next_extent; + struct xfs_phys_extent *ext; + +- refc = container_of(item, struct xfs_refcount_intent, ri_list); +- + tp->t_flags |= XFS_TRANS_DIRTY; + set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags); + +@@ -354,14 +295,35 @@ xfs_refcount_update_log_item( + xfs_trans_set_refcount_flags(ext, refc->ri_type); + } + ++static struct xfs_log_item * ++xfs_refcount_update_create_intent( ++ struct xfs_trans *tp, ++ struct list_head *items, ++ unsigned int count, ++ bool sort) ++{ ++ struct xfs_mount *mp = tp->t_mountp; ++ struct xfs_cui_log_item *cuip = xfs_cui_init(mp, count); ++ struct xfs_refcount_intent *refc; ++ ++ ASSERT(count > 0); ++ ++ xfs_trans_add_item(tp, &cuip->cui_item); ++ if (sort) ++ list_sort(mp, items, xfs_refcount_update_diff_items); ++ list_for_each_entry(refc, items, ri_list) ++ xfs_refcount_update_log_item(tp, cuip, refc); ++ return &cuip->cui_item; ++} ++ + /* Get an CUD so we can process all the deferred refcount updates. */ + STATIC void * + xfs_refcount_update_create_done( + struct xfs_trans *tp, +- void *intent, ++ struct xfs_log_item *intent, + unsigned int count) + { +- return xfs_trans_get_cud(tp, intent); ++ return xfs_trans_get_cud(tp, CUI_ITEM(intent)); + } + + /* Process a deferred refcount update. */ +@@ -411,9 +373,9 @@ xfs_refcount_update_finish_cleanup( + /* Abort all pending CUIs. */ + STATIC void + xfs_refcount_update_abort_intent( +- void *intent) ++ struct xfs_log_item *intent) + { +- xfs_cui_release(intent); ++ xfs_cui_release(CUI_ITEM(intent)); + } + + /* Cancel a deferred refcount update. */ +@@ -429,10 +391,8 @@ xfs_refcount_update_cancel_item( + + const struct xfs_defer_op_type xfs_refcount_update_defer_type = { + .max_items = XFS_CUI_MAX_FAST_EXTENTS, +- .diff_items = xfs_refcount_update_diff_items, + .create_intent = xfs_refcount_update_create_intent, + .abort_intent = xfs_refcount_update_abort_intent, +- .log_item = xfs_refcount_update_log_item, + .create_done = xfs_refcount_update_create_done, + .finish_item = xfs_refcount_update_finish_item, + .finish_cleanup = xfs_refcount_update_finish_cleanup, +@@ -445,8 +405,8 @@ const struct xfs_defer_op_type xfs_refcount_update_defer_type = { + */ + int + xfs_cui_recover( +- struct xfs_trans *parent_tp, +- struct xfs_cui_log_item *cuip) ++ struct xfs_cui_log_item *cuip, ++ struct list_head *capture_list) + { + int i; + int error = 0; +@@ -462,7 +422,7 @@ xfs_cui_recover( + xfs_extlen_t new_len; + struct xfs_bmbt_irec irec; + bool requeue_only = false; +- struct xfs_mount *mp = parent_tp->t_mountp; ++ struct xfs_mount *mp = cuip->cui_item.li_mountp; + + ASSERT(!test_bit(XFS_CUI_RECOVERED, &cuip->cui_flags)); + +@@ -517,12 +477,7 @@ xfs_cui_recover( + mp->m_refc_maxlevels * 2, 0, XFS_TRANS_RESERVE, &tp); + if (error) + return error; +- /* +- * Recovery stashes all deferred ops during intent processing and +- * finishes them on completion. Transfer current dfops state to this +- * transaction and transfer the result back before we return. +- */ +- xfs_defer_move(tp, parent_tp); ++ + cudp = xfs_trans_get_cud(tp, cuip); + + for (i = 0; i < cuip->cui_format.cui_nextents; i++) { +@@ -580,13 +535,71 @@ xfs_cui_recover( + + xfs_refcount_finish_one_cleanup(tp, rcur, error); + set_bit(XFS_CUI_RECOVERED, &cuip->cui_flags); +- xfs_defer_move(parent_tp, tp); +- error = xfs_trans_commit(tp); +- return error; ++ return xfs_defer_ops_capture_and_commit(tp, NULL, capture_list); + + abort_error: + xfs_refcount_finish_one_cleanup(tp, rcur, error); +- xfs_defer_move(parent_tp, tp); + xfs_trans_cancel(tp); + return error; + } ++ ++/* Relog an intent item to push the log tail forward. */ ++static struct xfs_log_item * ++xfs_cui_item_relog( ++ struct xfs_log_item *intent, ++ struct xfs_trans *tp) ++{ ++ struct xfs_cud_log_item *cudp; ++ struct xfs_cui_log_item *cuip; ++ struct xfs_phys_extent *extp; ++ unsigned int count; ++ ++ count = CUI_ITEM(intent)->cui_format.cui_nextents; ++ extp = CUI_ITEM(intent)->cui_format.cui_extents; ++ ++ tp->t_flags |= XFS_TRANS_DIRTY; ++ cudp = xfs_trans_get_cud(tp, CUI_ITEM(intent)); ++ set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags); ++ ++ cuip = xfs_cui_init(tp->t_mountp, count); ++ memcpy(cuip->cui_format.cui_extents, extp, count * sizeof(*extp)); ++ atomic_set(&cuip->cui_next_extent, count); ++ xfs_trans_add_item(tp, &cuip->cui_item); ++ set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags); ++ return &cuip->cui_item; ++} ++ ++static const struct xfs_item_ops xfs_cui_item_ops = { ++ .iop_size = xfs_cui_item_size, ++ .iop_format = xfs_cui_item_format, ++ .iop_unpin = xfs_cui_item_unpin, ++ .iop_release = xfs_cui_item_release, ++ .iop_relog = xfs_cui_item_relog, ++}; ++ ++/* ++ * Allocate and initialize an cui item with the given number of extents. ++ */ ++struct xfs_cui_log_item * ++xfs_cui_init( ++ struct xfs_mount *mp, ++ uint nextents) ++ ++{ ++ struct xfs_cui_log_item *cuip; ++ ++ ASSERT(nextents > 0); ++ if (nextents > XFS_CUI_MAX_FAST_EXTENTS) ++ cuip = kmem_zalloc(xfs_cui_log_item_sizeof(nextents), ++ 0); ++ else ++ cuip = kmem_zone_zalloc(xfs_cui_zone, 0); ++ ++ xfs_log_item_init(mp, &cuip->cui_item, XFS_LI_CUI, &xfs_cui_item_ops); ++ cuip->cui_format.cui_nextents = nextents; ++ cuip->cui_format.cui_id = (uintptr_t)(void *)cuip; ++ atomic_set(&cuip->cui_next_extent, 0); ++ atomic_set(&cuip->cui_refcount, 2); ++ ++ return cuip; ++} +diff --git a/fs/xfs/xfs_refcount_item.h b/fs/xfs/xfs_refcount_item.h +index e47530f30489d..de5f48ff4f74e 100644 +--- a/fs/xfs/xfs_refcount_item.h ++++ b/fs/xfs/xfs_refcount_item.h +@@ -80,6 +80,7 @@ extern struct kmem_zone *xfs_cud_zone; + struct xfs_cui_log_item *xfs_cui_init(struct xfs_mount *, uint); + void xfs_cui_item_free(struct xfs_cui_log_item *); + void xfs_cui_release(struct xfs_cui_log_item *); +-int xfs_cui_recover(struct xfs_trans *parent_tp, struct xfs_cui_log_item *cuip); ++int xfs_cui_recover(struct xfs_cui_log_item *cuip, ++ struct list_head *capture_list); + + #endif /* __XFS_REFCOUNT_ITEM_H__ */ +diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c +index 02f84d9a511c3..ba1dbb6c40632 100644 +--- a/fs/xfs/xfs_rmap_item.c ++++ b/fs/xfs/xfs_rmap_item.c +@@ -122,39 +122,6 @@ xfs_rui_item_release( + xfs_rui_release(RUI_ITEM(lip)); + } + +-static const struct xfs_item_ops xfs_rui_item_ops = { +- .iop_size = xfs_rui_item_size, +- .iop_format = xfs_rui_item_format, +- .iop_unpin = xfs_rui_item_unpin, +- .iop_release = xfs_rui_item_release, +-}; +- +-/* +- * Allocate and initialize an rui item with the given number of extents. +- */ +-struct xfs_rui_log_item * +-xfs_rui_init( +- struct xfs_mount *mp, +- uint nextents) +- +-{ +- struct xfs_rui_log_item *ruip; +- +- ASSERT(nextents > 0); +- if (nextents > XFS_RUI_MAX_FAST_EXTENTS) +- ruip = kmem_zalloc(xfs_rui_log_item_sizeof(nextents), 0); +- else +- ruip = kmem_zone_zalloc(xfs_rui_zone, 0); +- +- xfs_log_item_init(mp, &ruip->rui_item, XFS_LI_RUI, &xfs_rui_item_ops); +- ruip->rui_format.rui_nextents = nextents; +- ruip->rui_format.rui_id = (uintptr_t)(void *)ruip; +- atomic_set(&ruip->rui_next_extent, 0); +- atomic_set(&ruip->rui_refcount, 2); +- +- return ruip; +-} +- + /* + * Copy an RUI format buffer from the given buf, and into the destination + * RUI format structure. The RUI/RUD items were designed not to need any +@@ -352,41 +319,16 @@ xfs_rmap_update_diff_items( + XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock); + } + +-/* Get an RUI. */ +-STATIC void * +-xfs_rmap_update_create_intent( +- struct xfs_trans *tp, +- unsigned int count) +-{ +- struct xfs_rui_log_item *ruip; +- +- ASSERT(tp != NULL); +- ASSERT(count > 0); +- +- ruip = xfs_rui_init(tp->t_mountp, count); +- ASSERT(ruip != NULL); +- +- /* +- * Get a log_item_desc to point at the new item. +- */ +- xfs_trans_add_item(tp, &ruip->rui_item); +- return ruip; +-} +- + /* Log rmap updates in the intent item. */ + STATIC void + xfs_rmap_update_log_item( + struct xfs_trans *tp, +- void *intent, +- struct list_head *item) ++ struct xfs_rui_log_item *ruip, ++ struct xfs_rmap_intent *rmap) + { +- struct xfs_rui_log_item *ruip = intent; +- struct xfs_rmap_intent *rmap; + uint next_extent; + struct xfs_map_extent *map; + +- rmap = container_of(item, struct xfs_rmap_intent, ri_list); +- + tp->t_flags |= XFS_TRANS_DIRTY; + set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags); + +@@ -406,14 +348,35 @@ xfs_rmap_update_log_item( + rmap->ri_bmap.br_state); + } + ++static struct xfs_log_item * ++xfs_rmap_update_create_intent( ++ struct xfs_trans *tp, ++ struct list_head *items, ++ unsigned int count, ++ bool sort) ++{ ++ struct xfs_mount *mp = tp->t_mountp; ++ struct xfs_rui_log_item *ruip = xfs_rui_init(mp, count); ++ struct xfs_rmap_intent *rmap; ++ ++ ASSERT(count > 0); ++ ++ xfs_trans_add_item(tp, &ruip->rui_item); ++ if (sort) ++ list_sort(mp, items, xfs_rmap_update_diff_items); ++ list_for_each_entry(rmap, items, ri_list) ++ xfs_rmap_update_log_item(tp, ruip, rmap); ++ return &ruip->rui_item; ++} ++ + /* Get an RUD so we can process all the deferred rmap updates. */ + STATIC void * + xfs_rmap_update_create_done( + struct xfs_trans *tp, +- void *intent, ++ struct xfs_log_item *intent, + unsigned int count) + { +- return xfs_trans_get_rud(tp, intent); ++ return xfs_trans_get_rud(tp, RUI_ITEM(intent)); + } + + /* Process a deferred rmap update. */ +@@ -455,9 +418,9 @@ xfs_rmap_update_finish_cleanup( + /* Abort all pending RUIs. */ + STATIC void + xfs_rmap_update_abort_intent( +- void *intent) ++ struct xfs_log_item *intent) + { +- xfs_rui_release(intent); ++ xfs_rui_release(RUI_ITEM(intent)); + } + + /* Cancel a deferred rmap update. */ +@@ -473,10 +436,8 @@ xfs_rmap_update_cancel_item( + + const struct xfs_defer_op_type xfs_rmap_update_defer_type = { + .max_items = XFS_RUI_MAX_FAST_EXTENTS, +- .diff_items = xfs_rmap_update_diff_items, + .create_intent = xfs_rmap_update_create_intent, + .abort_intent = xfs_rmap_update_abort_intent, +- .log_item = xfs_rmap_update_log_item, + .create_done = xfs_rmap_update_create_done, + .finish_item = xfs_rmap_update_finish_item, + .finish_cleanup = xfs_rmap_update_finish_cleanup, +@@ -489,9 +450,10 @@ const struct xfs_defer_op_type xfs_rmap_update_defer_type = { + */ + int + xfs_rui_recover( +- struct xfs_mount *mp, +- struct xfs_rui_log_item *ruip) ++ struct xfs_rui_log_item *ruip, ++ struct list_head *capture_list) + { ++ struct xfs_mount *mp = ruip->rui_item.li_mountp; + int i; + int error = 0; + struct xfs_map_extent *rmap; +@@ -598,11 +560,70 @@ xfs_rui_recover( + + xfs_rmap_finish_one_cleanup(tp, rcur, error); + set_bit(XFS_RUI_RECOVERED, &ruip->rui_flags); +- error = xfs_trans_commit(tp); +- return error; ++ return xfs_defer_ops_capture_and_commit(tp, NULL, capture_list); + + abort_error: + xfs_rmap_finish_one_cleanup(tp, rcur, error); + xfs_trans_cancel(tp); + return error; + } ++ ++/* Relog an intent item to push the log tail forward. */ ++static struct xfs_log_item * ++xfs_rui_item_relog( ++ struct xfs_log_item *intent, ++ struct xfs_trans *tp) ++{ ++ struct xfs_rud_log_item *rudp; ++ struct xfs_rui_log_item *ruip; ++ struct xfs_map_extent *extp; ++ unsigned int count; ++ ++ count = RUI_ITEM(intent)->rui_format.rui_nextents; ++ extp = RUI_ITEM(intent)->rui_format.rui_extents; ++ ++ tp->t_flags |= XFS_TRANS_DIRTY; ++ rudp = xfs_trans_get_rud(tp, RUI_ITEM(intent)); ++ set_bit(XFS_LI_DIRTY, &rudp->rud_item.li_flags); ++ ++ ruip = xfs_rui_init(tp->t_mountp, count); ++ memcpy(ruip->rui_format.rui_extents, extp, count * sizeof(*extp)); ++ atomic_set(&ruip->rui_next_extent, count); ++ xfs_trans_add_item(tp, &ruip->rui_item); ++ set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags); ++ return &ruip->rui_item; ++} ++ ++static const struct xfs_item_ops xfs_rui_item_ops = { ++ .iop_size = xfs_rui_item_size, ++ .iop_format = xfs_rui_item_format, ++ .iop_unpin = xfs_rui_item_unpin, ++ .iop_release = xfs_rui_item_release, ++ .iop_relog = xfs_rui_item_relog, ++}; ++ ++/* ++ * Allocate and initialize an rui item with the given number of extents. ++ */ ++struct xfs_rui_log_item * ++xfs_rui_init( ++ struct xfs_mount *mp, ++ uint nextents) ++ ++{ ++ struct xfs_rui_log_item *ruip; ++ ++ ASSERT(nextents > 0); ++ if (nextents > XFS_RUI_MAX_FAST_EXTENTS) ++ ruip = kmem_zalloc(xfs_rui_log_item_sizeof(nextents), 0); ++ else ++ ruip = kmem_zone_zalloc(xfs_rui_zone, 0); ++ ++ xfs_log_item_init(mp, &ruip->rui_item, XFS_LI_RUI, &xfs_rui_item_ops); ++ ruip->rui_format.rui_nextents = nextents; ++ ruip->rui_format.rui_id = (uintptr_t)(void *)ruip; ++ atomic_set(&ruip->rui_next_extent, 0); ++ atomic_set(&ruip->rui_refcount, 2); ++ ++ return ruip; ++} +diff --git a/fs/xfs/xfs_rmap_item.h b/fs/xfs/xfs_rmap_item.h +index 8708e4a5aa5c3..5cf4acb0e915e 100644 +--- a/fs/xfs/xfs_rmap_item.h ++++ b/fs/xfs/xfs_rmap_item.h +@@ -82,6 +82,7 @@ int xfs_rui_copy_format(struct xfs_log_iovec *buf, + struct xfs_rui_log_format *dst_rui_fmt); + void xfs_rui_item_free(struct xfs_rui_log_item *); + void xfs_rui_release(struct xfs_rui_log_item *); +-int xfs_rui_recover(struct xfs_mount *mp, struct xfs_rui_log_item *ruip); ++int xfs_rui_recover(struct xfs_rui_log_item *ruip, ++ struct list_head *capture_list); + + #endif /* __XFS_RMAP_ITEM_H__ */ +diff --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c +index f70f1255220b3..20e0534a772c9 100644 +--- a/fs/xfs/xfs_stats.c ++++ b/fs/xfs/xfs_stats.c +@@ -23,6 +23,7 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) + uint64_t xs_xstrat_bytes = 0; + uint64_t xs_write_bytes = 0; + uint64_t xs_read_bytes = 0; ++ uint64_t defer_relog = 0; + + static const struct xstats_entry { + char *desc; +@@ -70,10 +71,13 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) + xs_xstrat_bytes += per_cpu_ptr(stats, i)->s.xs_xstrat_bytes; + xs_write_bytes += per_cpu_ptr(stats, i)->s.xs_write_bytes; + xs_read_bytes += per_cpu_ptr(stats, i)->s.xs_read_bytes; ++ defer_relog += per_cpu_ptr(stats, i)->s.defer_relog; + } + + len += scnprintf(buf + len, PATH_MAX-len, "xpc %Lu %Lu %Lu\n", + xs_xstrat_bytes, xs_write_bytes, xs_read_bytes); ++ len += scnprintf(buf + len, PATH_MAX-len, "defer_relog %llu\n", ++ defer_relog); + len += scnprintf(buf + len, PATH_MAX-len, "debug %u\n", + #if defined(DEBUG) + 1); +diff --git a/fs/xfs/xfs_stats.h b/fs/xfs/xfs_stats.h +index 34d704f703d25..43ffba74f045e 100644 +--- a/fs/xfs/xfs_stats.h ++++ b/fs/xfs/xfs_stats.h +@@ -137,6 +137,7 @@ struct __xfsstats { + uint64_t xs_xstrat_bytes; + uint64_t xs_write_bytes; + uint64_t xs_read_bytes; ++ uint64_t defer_relog; + }; + + #define xfsstats_offset(f) (offsetof(struct __xfsstats, f)/sizeof(uint32_t)) +diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c +index f1407900aeef9..9e73d2b29911d 100644 +--- a/fs/xfs/xfs_super.c ++++ b/fs/xfs/xfs_super.c +@@ -1914,13 +1914,13 @@ xfs_init_zones(void) + if (!xfs_buf_item_zone) + goto out_destroy_trans_zone; + +- xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) + ++ xfs_efd_zone = kmem_zone_init((sizeof(struct xfs_efd_log_item) + + ((XFS_EFD_MAX_FAST_EXTENTS - 1) * + sizeof(xfs_extent_t))), "xfs_efd_item"); + if (!xfs_efd_zone) + goto out_destroy_buf_item_zone; + +- xfs_efi_zone = kmem_zone_init((sizeof(xfs_efi_log_item_t) + ++ xfs_efi_zone = kmem_zone_init((sizeof(struct xfs_efi_log_item) + + ((XFS_EFI_MAX_FAST_EXTENTS - 1) * + sizeof(xfs_extent_t))), "xfs_efi_item"); + if (!xfs_efi_zone) +@@ -1934,8 +1934,8 @@ xfs_init_zones(void) + goto out_destroy_efi_zone; + + xfs_ili_zone = +- kmem_zone_init_flags(sizeof(xfs_inode_log_item_t), "xfs_ili", +- KM_ZONE_SPREAD, NULL); ++ kmem_zone_init_flags(sizeof(struct xfs_inode_log_item), ++ "xfs_ili", KM_ZONE_SPREAD, NULL); + if (!xfs_ili_zone) + goto out_destroy_inode_zone; + xfs_icreate_zone = kmem_zone_init(sizeof(struct xfs_icreate_item), +diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h +index f94908125e8f9..4b58183954064 100644 +--- a/fs/xfs/xfs_trace.h ++++ b/fs/xfs/xfs_trace.h +@@ -2418,6 +2418,7 @@ DEFINE_DEFER_PENDING_EVENT(xfs_defer_create_intent); + DEFINE_DEFER_PENDING_EVENT(xfs_defer_cancel_list); + DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_finish); + DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_abort); ++DEFINE_DEFER_PENDING_EVENT(xfs_defer_relog_intent); + + #define DEFINE_BMAP_FREE_DEFERRED_EVENT DEFINE_PHYS_EXTENT_DEFERRED_EVENT + DEFINE_BMAP_FREE_DEFERRED_EVENT(xfs_bmap_free_defer); +diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h +index 64d7f171ebd32..941647027f00f 100644 +--- a/fs/xfs/xfs_trans.h ++++ b/fs/xfs/xfs_trans.h +@@ -77,6 +77,8 @@ struct xfs_item_ops { + void (*iop_release)(struct xfs_log_item *); + xfs_lsn_t (*iop_committed)(struct xfs_log_item *, xfs_lsn_t); + void (*iop_error)(struct xfs_log_item *, xfs_buf_t *); ++ struct xfs_log_item *(*iop_relog)(struct xfs_log_item *intent, ++ struct xfs_trans *tp); + }; + + /* +@@ -244,4 +246,12 @@ void xfs_trans_buf_copy_type(struct xfs_buf *dst_bp, + + extern kmem_zone_t *xfs_trans_zone; + ++static inline struct xfs_log_item * ++xfs_trans_item_relog( ++ struct xfs_log_item *lip, ++ struct xfs_trans *tp) ++{ ++ return lip->li_ops->iop_relog(lip, tp); ++} ++ + #endif /* __XFS_TRANS_H__ */ +diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h +index c7507135c2a05..311dd8e921826 100644 +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -396,7 +397,10 @@ static inline struct hstate *hstate_sizelog(int page_size_log) + if (!page_size_log) + return &default_hstate; + +- return size_to_hstate(1UL << page_size_log); ++ if (page_size_log < BITS_PER_LONG) ++ return size_to_hstate(1UL << page_size_log); ++ ++ return NULL; + } + + static inline struct hstate *hstate_vma(struct vm_area_struct *vma) +@@ -744,4 +748,16 @@ static inline spinlock_t *huge_pte_lock(struct hstate *h, + return ptl; + } + ++#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE ++static inline bool hugetlb_pmd_shared(pte_t *pte) ++{ ++ return page_count(virt_to_page(pte)) > 1; ++} ++#else ++static inline bool hugetlb_pmd_shared(pte_t *pte) ++{ ++ return false; ++} ++#endif ++ + #endif /* _LINUX_HUGETLB_H */ +diff --git a/include/linux/iommu.h b/include/linux/iommu.h +index 29bac5345563a..6ca3fb2873d7d 100644 +--- a/include/linux/iommu.h ++++ b/include/linux/iommu.h +@@ -256,7 +256,7 @@ struct iommu_ops { + int (*attach_dev)(struct iommu_domain *domain, struct device *dev); + void (*detach_dev)(struct iommu_domain *domain, struct device *dev); + int (*map)(struct iommu_domain *domain, unsigned long iova, +- phys_addr_t paddr, size_t size, int prot); ++ phys_addr_t paddr, size_t size, int prot, gfp_t gfp); + size_t (*unmap)(struct iommu_domain *domain, unsigned long iova, + size_t size, struct iommu_iotlb_gather *iotlb_gather); + void (*flush_iotlb_all)(struct iommu_domain *domain); +@@ -421,6 +421,8 @@ extern struct iommu_domain *iommu_get_domain_for_dev(struct device *dev); + extern struct iommu_domain *iommu_get_dma_domain(struct device *dev); + extern int iommu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot); ++extern int iommu_map_atomic(struct iommu_domain *domain, unsigned long iova, ++ phys_addr_t paddr, size_t size, int prot); + extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, + size_t size); + extern size_t iommu_unmap_fast(struct iommu_domain *domain, +@@ -428,6 +430,9 @@ extern size_t iommu_unmap_fast(struct iommu_domain *domain, + struct iommu_iotlb_gather *iotlb_gather); + extern size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, + struct scatterlist *sg,unsigned int nents, int prot); ++extern size_t iommu_map_sg_atomic(struct iommu_domain *domain, ++ unsigned long iova, struct scatterlist *sg, ++ unsigned int nents, int prot); + extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova); + extern void iommu_set_fault_handler(struct iommu_domain *domain, + iommu_fault_handler_t handler, void *token); +@@ -662,6 +667,13 @@ static inline int iommu_map(struct iommu_domain *domain, unsigned long iova, + return -ENODEV; + } + ++static inline int iommu_map_atomic(struct iommu_domain *domain, ++ unsigned long iova, phys_addr_t paddr, ++ size_t size, int prot) ++{ ++ return -ENODEV; ++} ++ + static inline size_t iommu_unmap(struct iommu_domain *domain, + unsigned long iova, size_t size) + { +@@ -682,6 +694,13 @@ static inline size_t iommu_map_sg(struct iommu_domain *domain, + return 0; + } + ++static inline size_t iommu_map_sg_atomic(struct iommu_domain *domain, ++ unsigned long iova, struct scatterlist *sg, ++ unsigned int nents, int prot) ++{ ++ return 0; ++} ++ + static inline void iommu_flush_tlb_all(struct iommu_domain *domain) + { + } +diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h +index 0b35747c9837a..88b107e20fc7c 100644 +--- a/include/linux/stmmac.h ++++ b/include/linux/stmmac.h +@@ -178,6 +178,7 @@ struct plat_stmmacenet_data { + int rss_en; + int mac_port_sel_speed; + bool en_tx_lpi_clockgating; ++ bool rx_clk_runs_in_lpi; + int has_xgmac; + bool sph_disable; + }; +diff --git a/include/net/sock.h b/include/net/sock.h +index 5fa255b1e0a65..976433438c6f2 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -2167,6 +2167,19 @@ static inline __must_check bool skb_set_owner_sk_safe(struct sk_buff *skb, struc + return false; + } + ++static inline struct sk_buff *skb_clone_and_charge_r(struct sk_buff *skb, struct sock *sk) ++{ ++ skb = skb_clone(skb, sk_gfp_mask(sk, GFP_ATOMIC)); ++ if (skb) { ++ if (sk_rmem_schedule(sk, skb, skb->truesize)) { ++ skb_set_owner_r(skb, sk); ++ return skb; ++ } ++ __kfree_skb(skb); ++ } ++ return NULL; ++} ++ + void sk_reset_timer(struct sock *sk, struct timer_list *timer, + unsigned long expires); + +diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c +index 9dd83eb74a9da..8c19a5438d0ee 100644 +--- a/kernel/sched/psi.c ++++ b/kernel/sched/psi.c +@@ -1092,10 +1092,11 @@ void psi_trigger_destroy(struct psi_trigger *t) + + group = t->group; + /* +- * Wakeup waiters to stop polling. Can happen if cgroup is deleted +- * from under a polling process. ++ * Wakeup waiters to stop polling and clear the queue to prevent it from ++ * being accessed later. Can happen if cgroup is deleted from under a ++ * polling process. + */ +- wake_up_interruptible(&t->event_wait); ++ wake_up_pollfree(&t->event_wait); + + mutex_lock(&group->trigger_lock); + +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 8b87f1f74e325..306fbe14747bf 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -8298,9 +8298,6 @@ buffer_percent_write(struct file *filp, const char __user *ubuf, + if (val > 100) + return -EINVAL; + +- if (!val) +- val = 1; +- + tr->buffer_percent = val; + + (*ppos)++; +diff --git a/mm/memblock.c b/mm/memblock.c +index 84a14b63e9129..a75cc65f03307 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -1546,13 +1546,7 @@ void __init __memblock_free_late(phys_addr_t base, phys_addr_t size) + end = PFN_DOWN(base + size); + + for (; cursor < end; cursor++) { +- /* +- * Reserved pages are always initialized by the end of +- * memblock_free_all() (by memmap_init() and, if deferred +- * initialization is enabled, memmap_init_reserved_pages()), so +- * these pages can be released directly to the buddy allocator. +- */ +- __free_pages_core(pfn_to_page(cursor), 0); ++ memblock_free_pages(pfn_to_page(cursor), cursor, 0); + totalram_pages_inc(); + } + } +diff --git a/mm/mempolicy.c b/mm/mempolicy.c +index f7b231f67156b..36c2a9619ba56 100644 +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -571,7 +571,8 @@ static int queue_pages_hugetlb(pte_t *pte, unsigned long hmask, + goto unlock; + /* With MPOL_MF_MOVE, we migrate only unshared hugepage. */ + if (flags & (MPOL_MF_MOVE_ALL) || +- (flags & MPOL_MF_MOVE && page_mapcount(page) == 1)) ++ (flags & MPOL_MF_MOVE && page_mapcount(page) == 1 && ++ !hugetlb_pmd_shared(pte))) + isolate_huge_page(page, qp->pagelist); + unlock: + spin_unlock(ptl); +diff --git a/mm/swapfile.c b/mm/swapfile.c +index f6964212c6c8f..d6bdacaedc95c 100644 +--- a/mm/swapfile.c ++++ b/mm/swapfile.c +@@ -1061,6 +1061,7 @@ start_over: + goto check_out; + pr_debug("scan_swap_map of si %d failed to find offset\n", + si->type); ++ cond_resched(); + + spin_lock(&swap_avail_lock); + nextsi: +@@ -1950,10 +1951,14 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd, + + pte_unmap(pte); + swap_map = &si->swap_map[offset]; +- vmf.vma = vma; +- vmf.address = addr; +- vmf.pmd = pmd; +- page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, &vmf); ++ page = lookup_swap_cache(entry, vma, addr); ++ if (!page) { ++ vmf.vma = vma; ++ vmf.address = addr; ++ vmf.pmd = pmd; ++ page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, ++ &vmf); ++ } + if (!page) { + if (*swap_map == 0 || *swap_map == SWAP_MAP_BAD) + goto try_next; +diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c +index 01e33724d10c3..43cb7aab4eed6 100644 +--- a/net/bridge/br_netfilter_hooks.c ++++ b/net/bridge/br_netfilter_hooks.c +@@ -871,6 +871,7 @@ static unsigned int ip_sabotage_in(void *priv, + if (nf_bridge && !nf_bridge->in_prerouting && + !netif_is_l3_master(skb->dev) && + !netif_is_l3_slave(skb->dev)) { ++ nf_bridge_info_free(skb); + state->okfn(state->net, state->sk, skb); + return NF_STOLEN; + } +diff --git a/net/can/j1939/address-claim.c b/net/can/j1939/address-claim.c +index f33c473279278..ca4ad6cdd5cbf 100644 +--- a/net/can/j1939/address-claim.c ++++ b/net/can/j1939/address-claim.c +@@ -165,6 +165,46 @@ static void j1939_ac_process(struct j1939_priv *priv, struct sk_buff *skb) + * leaving this function. + */ + ecu = j1939_ecu_get_by_name_locked(priv, name); ++ ++ if (ecu && ecu->addr == skcb->addr.sa) { ++ /* The ISO 11783-5 standard, in "4.5.2 - Address claim ++ * requirements", states: ++ * d) No CF shall begin, or resume, transmission on the ++ * network until 250 ms after it has successfully claimed ++ * an address except when responding to a request for ++ * address-claimed. ++ * ++ * But "Figure 6" and "Figure 7" in "4.5.4.2 - Address-claim ++ * prioritization" show that the CF begins the transmission ++ * after 250 ms from the first AC (address-claimed) message ++ * even if it sends another AC message during that time window ++ * to resolve the address contention with another CF. ++ * ++ * As stated in "4.4.2.3 - Address-claimed message": ++ * In order to successfully claim an address, the CF sending ++ * an address claimed message shall not receive a contending ++ * claim from another CF for at least 250 ms. ++ * ++ * As stated in "4.4.3.2 - NAME management (NM) message": ++ * 1) A commanding CF can ++ * d) request that a CF with a specified NAME transmit ++ * the address-claimed message with its current NAME. ++ * 2) A target CF shall ++ * d) send an address-claimed message in response to a ++ * request for a matching NAME ++ * ++ * Taking the above arguments into account, the 250 ms wait is ++ * requested only during network initialization. ++ * ++ * Do not restart the timer on AC message if both the NAME and ++ * the address match and so if the address has already been ++ * claimed (timer has expired) or the AC message has been sent ++ * to resolve the contention with another CF (timer is still ++ * running). ++ */ ++ goto out_ecu_put; ++ } ++ + if (!ecu && j1939_address_is_unicast(skcb->addr.sa)) + ecu = j1939_ecu_create_locked(priv, name); + +diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c +index 9ca19dfe3e839..9c8c7c5dc9c36 100644 +--- a/net/can/j1939/transport.c ++++ b/net/can/j1939/transport.c +@@ -1087,10 +1087,6 @@ static bool j1939_session_deactivate(struct j1939_session *session) + bool active; + + j1939_session_list_lock(priv); +- /* This function should be called with a session ref-count of at +- * least 2. +- */ +- WARN_ON_ONCE(kref_read(&session->kref) < 2); + active = j1939_session_deactivate_locked(session); + j1939_session_list_unlock(priv); + +diff --git a/net/core/dev.c b/net/core/dev.c +index 296bed9431f3b..615cdaac3e729 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -9467,7 +9467,7 @@ void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, + + BUILD_BUG_ON(n > sizeof(*stats64) / sizeof(u64)); + for (i = 0; i < n; i++) +- dst[i] = atomic_long_read(&src[i]); ++ dst[i] = (unsigned long)atomic_long_read(&src[i]); + /* zero out counters that only exist in rtnl_link_stats64 */ + memset((char *)stats64 + n * sizeof(u64), 0, + sizeof(*stats64) - n * sizeof(u64)); +diff --git a/net/core/filter.c b/net/core/filter.c +index 71fcb4e7edae4..051b9710d7b5e 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4617,7 +4617,6 @@ static int bpf_fib_set_fwd_params(struct bpf_fib_lookup *params, + memcpy(params->smac, dev->dev_addr, ETH_ALEN); + params->h_vlan_TCI = 0; + params->h_vlan_proto = 0; +- params->ifindex = dev->ifindex; + + return 0; + } +@@ -4714,6 +4713,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params, + dev = nhc->nhc_dev; + + params->rt_metric = res.fi->fib_priority; ++ params->ifindex = dev->ifindex; + + /* xdp and cls_bpf programs are run in RCU-bh so + * rcu_read_lock_bh is not needed here +@@ -4839,6 +4839,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, + + dev = res.nh->fib_nh_dev; + params->rt_metric = res.f6i->fib6_metric; ++ params->ifindex = dev->ifindex; + + /* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is + * not needed here. +diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c +index 1bf267d36a9c8..c2844fb442c4f 100644 +--- a/net/dccp/ipv6.c ++++ b/net/dccp/ipv6.c +@@ -541,11 +541,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk, + *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL); + /* Clone pktoptions received with SYN, if we own the req */ + if (*own_req && ireq->pktopts) { +- newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC); ++ newnp->pktoptions = skb_clone_and_charge_r(ireq->pktopts, newsk); + consume_skb(ireq->pktopts); + ireq->pktopts = NULL; +- if (newnp->pktoptions) +- skb_set_owner_r(newnp->pktoptions, newsk); + } + + return newsk; +@@ -605,7 +603,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) + --ANK (980728) + */ + if (np->rxopt.all) +- opt_skb = skb_clone(skb, GFP_ATOMIC); ++ opt_skb = skb_clone_and_charge_r(skb, sk); + + if (sk->sk_state == DCCP_OPEN) { /* Fast path */ + if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len)) +@@ -669,7 +667,6 @@ ipv6_pktoptions: + np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); + if (ipv6_opt_accepted(sk, opt_skb, + &DCCP_SKB_CB(opt_skb)->header.h6)) { +- skb_set_owner_r(opt_skb, sk); + memmove(IP6CB(opt_skb), + &DCCP_SKB_CB(opt_skb)->header.h6, + sizeof(struct inet6_skb_parm)); +diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c +index 390bedde21a56..06261603e083b 100644 +--- a/net/ipv6/datagram.c ++++ b/net/ipv6/datagram.c +@@ -50,7 +50,7 @@ static void ip6_datagram_flow_key_init(struct flowi6 *fl6, struct sock *sk) + fl6->flowi6_mark = sk->sk_mark; + fl6->fl6_dport = inet->inet_dport; + fl6->fl6_sport = inet->inet_sport; +- fl6->flowlabel = np->flow_label; ++ fl6->flowlabel = ip6_make_flowinfo(np->tclass, np->flow_label); + fl6->flowi6_uid = sk->sk_uid; + + if (!fl6->flowi6_oif) +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index e84b79357b2ff..da8611a75d2aa 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -264,6 +264,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, + fl6.flowi6_proto = IPPROTO_TCP; + fl6.daddr = sk->sk_v6_daddr; + fl6.saddr = saddr ? *saddr : np->saddr; ++ fl6.flowlabel = ip6_make_flowinfo(np->tclass, np->flow_label); + fl6.flowi6_oif = sk->sk_bound_dev_if; + fl6.flowi6_mark = sk->sk_mark; + fl6.fl6_dport = usin->sin6_port; +@@ -1318,14 +1319,11 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * + + /* Clone pktoptions received with SYN, if we own the req */ + if (ireq->pktopts) { +- newnp->pktoptions = skb_clone(ireq->pktopts, +- sk_gfp_mask(sk, GFP_ATOMIC)); ++ newnp->pktoptions = skb_clone_and_charge_r(ireq->pktopts, newsk); + consume_skb(ireq->pktopts); + ireq->pktopts = NULL; +- if (newnp->pktoptions) { ++ if (newnp->pktoptions) + tcp_v6_restore_cb(newnp->pktoptions); +- skb_set_owner_r(newnp->pktoptions, newsk); +- } + } + } else { + if (!req_unhash && found_dup_sk) { +@@ -1393,7 +1391,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) + --ANK (980728) + */ + if (np->rxopt.all) +- opt_skb = skb_clone(skb, sk_gfp_mask(sk, GFP_ATOMIC)); ++ opt_skb = skb_clone_and_charge_r(skb, sk); + + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ + struct dst_entry *dst; +@@ -1475,7 +1473,6 @@ ipv6_pktoptions: + if (np->repflow) + np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); + if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) { +- skb_set_owner_r(opt_skb, sk); + tcp_v6_restore_cb(opt_skb); + opt_skb = xchg(&np->pktoptions, opt_skb); + } else { +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index d5e3656fc67ca..3a55a392e0218 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -1428,6 +1428,7 @@ static int mpls_dev_sysctl_register(struct net_device *dev, + free: + kfree(table); + out: ++ mdev->sysctl = NULL; + return -ENOBUFS; + } + +@@ -1437,6 +1438,9 @@ static void mpls_dev_sysctl_unregister(struct net_device *dev, + struct net *net = dev_net(dev); + struct ctl_table *table; + ++ if (!mdev->sysctl) ++ return; ++ + table = mdev->sysctl->ctl_table_arg; + unregister_net_sysctl_table(mdev->sysctl); + kfree(table); +diff --git a/net/netfilter/nft_tproxy.c b/net/netfilter/nft_tproxy.c +index b97ab1198b03f..a0e30bf4a845c 100644 +--- a/net/netfilter/nft_tproxy.c ++++ b/net/netfilter/nft_tproxy.c +@@ -289,6 +289,13 @@ static int nft_tproxy_dump(struct sk_buff *skb, + return 0; + } + ++static int nft_tproxy_validate(const struct nft_ctx *ctx, ++ const struct nft_expr *expr, ++ const struct nft_data **data) ++{ ++ return nft_chain_validate_hooks(ctx->chain, 1 << NF_INET_PRE_ROUTING); ++} ++ + static struct nft_expr_type nft_tproxy_type; + static const struct nft_expr_ops nft_tproxy_ops = { + .type = &nft_tproxy_type, +@@ -296,6 +303,7 @@ static const struct nft_expr_ops nft_tproxy_ops = { + .eval = nft_tproxy_eval, + .init = nft_tproxy_init, + .dump = nft_tproxy_dump, ++ .validate = nft_tproxy_validate, + }; + + static struct nft_expr_type nft_tproxy_type __read_mostly = { +diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c +index 58d5373c513c7..7da77ddba5f4d 100644 +--- a/net/netrom/af_netrom.c ++++ b/net/netrom/af_netrom.c +@@ -378,6 +378,11 @@ static int nr_listen(struct socket *sock, int backlog) + struct sock *sk = sock->sk; + + lock_sock(sk); ++ if (sock->state != SS_UNCONNECTED) { ++ release_sock(sk); ++ return -EINVAL; ++ } ++ + if (sk->sk_state != TCP_LISTEN) { + memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN); + sk->sk_max_ack_backlog = backlog; +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index a8a8396dd9838..4c537e74b18c7 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -941,14 +941,14 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) + key = kzalloc(sizeof(*key), GFP_KERNEL); + if (!key) { + error = -ENOMEM; +- goto err_kfree_key; ++ goto err_kfree_flow; + } + + ovs_match_init(&match, key, false, &mask); + error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], + a[OVS_FLOW_ATTR_MASK], log); + if (error) +- goto err_kfree_flow; ++ goto err_kfree_key; + + ovs_flow_mask_key(&new_flow->key, key, true, &mask); + +@@ -956,14 +956,14 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) + error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID], + key, log); + if (error) +- goto err_kfree_flow; ++ goto err_kfree_key; + + /* Validate actions. */ + error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS], + &new_flow->key, &acts, log); + if (error) { + OVS_NLERR(log, "Flow actions may not be safe on all matching packets."); +- goto err_kfree_flow; ++ goto err_kfree_key; + } + + reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false, +@@ -1063,10 +1063,10 @@ err_unlock_ovs: + kfree_skb(reply); + err_kfree_acts: + ovs_nla_free_flow_actions(acts); +-err_kfree_flow: +- ovs_flow_free(new_flow, false); + err_kfree_key: + kfree(key); ++err_kfree_flow: ++ ovs_flow_free(new_flow, false); + error: + return error; + } +diff --git a/net/rds/message.c b/net/rds/message.c +index 92b6b22884d4c..be6a0a073b12a 100644 +--- a/net/rds/message.c ++++ b/net/rds/message.c +@@ -104,9 +104,9 @@ static void rds_rm_zerocopy_callback(struct rds_sock *rs, + spin_lock_irqsave(&q->lock, flags); + head = &q->zcookie_head; + if (!list_empty(head)) { +- info = list_entry(head, struct rds_msg_zcopy_info, +- rs_zcookie_next); +- if (info && rds_zcookie_add(info, cookie)) { ++ info = list_first_entry(head, struct rds_msg_zcopy_info, ++ rs_zcookie_next); ++ if (rds_zcookie_add(info, cookie)) { + spin_unlock_irqrestore(&q->lock, flags); + kfree(rds_info_from_znotifier(znotif)); + /* caller invokes rds_wake_sk_sleep() */ +diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c +index 95dda29058a0e..6fb158172ddc2 100644 +--- a/net/rose/af_rose.c ++++ b/net/rose/af_rose.c +@@ -465,6 +465,12 @@ static int rose_listen(struct socket *sock, int backlog) + { + struct sock *sk = sock->sk; + ++ lock_sock(sk); ++ if (sock->state != SS_UNCONNECTED) { ++ release_sock(sk); ++ return -EINVAL; ++ } ++ + if (sk->sk_state != TCP_LISTEN) { + struct rose_sock *rose = rose_sk(sk); + +@@ -474,8 +480,10 @@ static int rose_listen(struct socket *sock, int backlog) + memset(rose->dest_digis, 0, AX25_ADDR_LEN * ROSE_MAX_DIGIS); + sk->sk_max_ack_backlog = backlog; + sk->sk_state = TCP_LISTEN; ++ release_sock(sk); + return 0; + } ++ release_sock(sk); + + return -EOPNOTSUPP; + } +diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c +index 8184c87da8bec..27cb82b6237da 100644 +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -405,7 +405,10 @@ static void htb_activate_prios(struct htb_sched *q, struct htb_class *cl) + while (cl->cmode == HTB_MAY_BORROW && p && mask) { + m = mask; + while (m) { +- int prio = ffz(~m); ++ unsigned int prio = ffz(~m); ++ ++ if (WARN_ON_ONCE(prio >= ARRAY_SIZE(p->inner.clprio))) ++ break; + m &= ~(1 << prio); + + if (p->inner.clprio[prio].feed.rb_node) +diff --git a/net/sctp/diag.c b/net/sctp/diag.c +index 5a918e74bb82b..2d0318a7352c2 100644 +--- a/net/sctp/diag.c ++++ b/net/sctp/diag.c +@@ -349,11 +349,9 @@ static int sctp_sock_filter(struct sctp_endpoint *ep, struct sctp_transport *tsp + struct sctp_comm_param *commp = p; + struct sock *sk = ep->base.sk; + const struct inet_diag_req_v2 *r = commp->r; +- struct sctp_association *assoc = +- list_entry(ep->asocs.next, struct sctp_association, asocs); + + /* find the ep only once through the transports by this condition */ +- if (tsp->asoc != assoc) ++ if (!list_is_first(&tsp->asoc->asocs, &ep->asocs)) + return 0; + + if (r->sdiag_family != AF_UNSPEC && sk->sk_family != r->sdiag_family) +diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c +index 0f4d39fdb48f2..cfae1a871578f 100644 +--- a/net/sunrpc/xprtrdma/verbs.c ++++ b/net/sunrpc/xprtrdma/verbs.c +@@ -1034,9 +1034,9 @@ struct rpcrdma_req *rpcrdma_req_create(struct rpcrdma_xprt *r_xprt, size_t size, + return req; + + out4: +- kfree(req->rl_sendbuf); ++ rpcrdma_regbuf_free(req->rl_sendbuf); + out3: +- kfree(req->rl_rdmabuf); ++ rpcrdma_regbuf_free(req->rl_rdmabuf); + out2: + kfree(req); + out1: +diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c +index c94aa587e0c92..43dd489ad6db9 100644 +--- a/net/x25/af_x25.c ++++ b/net/x25/af_x25.c +@@ -492,6 +492,12 @@ static int x25_listen(struct socket *sock, int backlog) + int rc = -EOPNOTSUPP; + + lock_sock(sk); ++ if (sock->state != SS_UNCONNECTED) { ++ rc = -EINVAL; ++ release_sock(sk); ++ return rc; ++ } ++ + if (sk->sk_state != TCP_LISTEN) { + memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN); + sk->sk_max_ack_backlog = backlog; +diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c +index e120df0a6da13..4d8d7cf3d1994 100644 +--- a/net/xfrm/xfrm_input.c ++++ b/net/xfrm/xfrm_input.c +@@ -274,8 +274,7 @@ static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) + goto out; + + if (x->props.flags & XFRM_STATE_DECAP_DSCP) +- ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)), +- ipipv6_hdr(skb)); ++ ipv6_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipipv6_hdr(skb)); + if (!(x->props.flags & XFRM_STATE_NOECN)) + ipip6_ecn_decapsulate(skb); + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index d181dc31cd8d6..51f65d634a15e 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -1093,6 +1093,7 @@ static const struct hda_device_id snd_hda_id_conexant[] = { + HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), ++ HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto), +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 413d4886f3d28..75c1645dd5c14 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -770,7 +770,7 @@ do_sku: + alc_setup_gpio(codec, 0x02); + break; + case 7: +- alc_setup_gpio(codec, 0x03); ++ alc_setup_gpio(codec, 0x04); + break; + case 5: + default: +diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c +index 3edb4e25797de..4a74ccf7cf3e6 100644 +--- a/sound/pci/hda/patch_via.c ++++ b/sound/pci/hda/patch_via.c +@@ -821,6 +821,9 @@ static int add_secret_dac_path(struct hda_codec *codec) + return 0; + nums = snd_hda_get_connections(codec, spec->gen.mixer_nid, conn, + ARRAY_SIZE(conn) - 1); ++ if (nums < 0) ++ return nums; ++ + for (i = 0; i < nums; i++) { + if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT) + return 0; +diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c +index dd3a873777eb5..00975e86473c5 100644 +--- a/sound/pci/lx6464es/lx_core.c ++++ b/sound/pci/lx6464es/lx_core.c +@@ -493,12 +493,11 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, + dev_dbg(chip->card->dev, + "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", + *r_needed, *r_freed); +- for (i = 0; i < MAX_STREAM_BUFFER; ++i) { +- for (i = 0; i != chip->rmh.stat_len; ++i) +- dev_dbg(chip->card->dev, +- " stat[%d]: %x, %x\n", i, +- chip->rmh.stat[i], +- chip->rmh.stat[i] & MASK_DATA_SIZE); ++ for (i = 0; i < MAX_STREAM_BUFFER && i < chip->rmh.stat_len; ++ ++i) { ++ dev_dbg(chip->card->dev, " stat[%d]: %x, %x\n", i, ++ chip->rmh.stat[i], ++ chip->rmh.stat[i] & MASK_DATA_SIZE); + } + } + +diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c +index 8be7d83f0ce9a..732405587c5a4 100644 +--- a/sound/soc/codecs/cs42l56.c ++++ b/sound/soc/codecs/cs42l56.c +@@ -1192,18 +1192,12 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, + if (pdata) { + cs42l56->pdata = *pdata; + } else { +- pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), +- GFP_KERNEL); +- if (!pdata) +- return -ENOMEM; +- + if (i2c_client->dev.of_node) { + ret = cs42l56_handle_of_data(i2c_client, + &cs42l56->pdata); + if (ret != 0) + return ret; + } +- cs42l56->pdata = *pdata; + } + + if (cs42l56->pdata.gpio_nreset) { +diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c +index 921c09cdb4800..0c1c8628b9917 100644 +--- a/sound/soc/intel/boards/bytcr_rt5651.c ++++ b/sound/soc/intel/boards/bytcr_rt5651.c +@@ -919,7 +919,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) + if (adev) { + snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name), + "i2c-%s", acpi_dev_name(adev)); +- put_device(&adev->dev); + byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); +@@ -928,6 +927,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) + + codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, + byt_rt5651_codec_name); ++ acpi_dev_put(adev); + if (!codec_dev) + return -EPROBE_DEFER; + +diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c +index b3cdd10c83ae1..c30e450fa9702 100644 +--- a/sound/soc/sof/intel/hda-dai.c ++++ b/sound/soc/sof/intel/hda-dai.c +@@ -211,6 +211,10 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, + int stream_tag; + int ret; + ++ link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); ++ if (!link) ++ return -EINVAL; ++ + /* get stored dma data if resuming from system suspend */ + link_dev = snd_soc_dai_get_dma_data(dai, substream); + if (!link_dev) { +@@ -231,10 +235,6 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, + if (ret < 0) + return ret; + +- link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); +- if (!link) +- return -EINVAL; +- + /* set the stream tag in the codec dai dma params */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); +diff --git a/sound/synth/emux/emux_nrpn.c b/sound/synth/emux/emux_nrpn.c +index 1ac22676d4648..641dc02ff709e 100644 +--- a/sound/synth/emux/emux_nrpn.c ++++ b/sound/synth/emux/emux_nrpn.c +@@ -349,6 +349,9 @@ int + snd_emux_xg_control(struct snd_emux_port *port, struct snd_midi_channel *chan, + int param) + { ++ if (param >= ARRAY_SIZE(chan->control)) ++ return -EINVAL; ++ + return send_converted_effect(xg_effects, ARRAY_SIZE(xg_effects), + port, chan, param, + chan->control[param], +diff --git a/tools/testing/selftests/bpf/verifier/search_pruning.c b/tools/testing/selftests/bpf/verifier/search_pruning.c +index 7e50cb80873a5..7e36078f8f482 100644 +--- a/tools/testing/selftests/bpf/verifier/search_pruning.c ++++ b/tools/testing/selftests/bpf/verifier/search_pruning.c +@@ -154,3 +154,39 @@ + .result_unpriv = ACCEPT, + .insn_processed = 15, + }, ++/* The test performs a conditional 64-bit write to a stack location ++ * fp[-8], this is followed by an unconditional 8-bit write to fp[-8], ++ * then data is read from fp[-8]. This sequence is unsafe. ++ * ++ * The test would be mistakenly marked as safe w/o dst register parent ++ * preservation in verifier.c:copy_register_state() function. ++ * ++ * Note the usage of BPF_F_TEST_STATE_FREQ to force creation of the ++ * checkpoint state after conditional 64-bit assignment. ++ */ ++{ ++ "write tracking and register parent chain bug", ++ .insns = { ++ /* r6 = ktime_get_ns() */ ++ BPF_EMIT_CALL(BPF_FUNC_ktime_get_ns), ++ BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), ++ /* r0 = ktime_get_ns() */ ++ BPF_EMIT_CALL(BPF_FUNC_ktime_get_ns), ++ /* if r0 > r6 goto +1 */ ++ BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_6, 1), ++ /* *(u64 *)(r10 - 8) = 0xdeadbeef */ ++ BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0xdeadbeef), ++ /* r1 = 42 */ ++ BPF_MOV64_IMM(BPF_REG_1, 42), ++ /* *(u8 *)(r10 - 8) = r1 */ ++ BPF_STX_MEM(BPF_B, BPF_REG_FP, BPF_REG_1, -8), ++ /* r2 = *(u64 *)(r10 - 8) */ ++ BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_FP, -8), ++ /* exit(0) */ ++ BPF_MOV64_IMM(BPF_REG_0, 0), ++ BPF_EXIT_INSN(), ++ }, ++ .flags = BPF_F_TEST_STATE_FREQ, ++ .errstr = "invalid read from stack off -8+1 size 8", ++ .result = REJECT, ++}, +diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh +new file mode 100644 +index 0000000000000..6986086035d6c +--- /dev/null ++++ b/tools/testing/selftests/net/fib_tests.sh +@@ -0,0 +1,1727 @@ ++#!/bin/bash ++# SPDX-License-Identifier: GPL-2.0 ++ ++# This test is for checking IPv4 and IPv6 FIB behavior in response to ++# different events. ++ ++ret=0 ++# Kselftest framework requirement - SKIP code is 4. ++ksft_skip=4 ++ ++# all tests in this script. Can be overridden with -t option ++TESTS="unregister down carrier nexthop suppress ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter" ++ ++VERBOSE=0 ++PAUSE_ON_FAIL=no ++PAUSE=no ++IP="ip -netns ns1" ++NS_EXEC="ip netns exec ns1" ++ ++which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping) ++ ++log_test() ++{ ++ local rc=$1 ++ local expected=$2 ++ local msg="$3" ++ ++ if [ ${rc} -eq ${expected} ]; then ++ printf " TEST: %-60s [ OK ]\n" "${msg}" ++ nsuccess=$((nsuccess+1)) ++ else ++ ret=1 ++ nfail=$((nfail+1)) ++ printf " TEST: %-60s [FAIL]\n" "${msg}" ++ if [ "${PAUSE_ON_FAIL}" = "yes" ]; then ++ echo ++ echo "hit enter to continue, 'q' to quit" ++ read a ++ [ "$a" = "q" ] && exit 1 ++ fi ++ fi ++ ++ if [ "${PAUSE}" = "yes" ]; then ++ echo ++ echo "hit enter to continue, 'q' to quit" ++ read a ++ [ "$a" = "q" ] && exit 1 ++ fi ++} ++ ++setup() ++{ ++ set -e ++ ip netns add ns1 ++ ip netns set ns1 auto ++ $IP link set dev lo up ++ ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1 ++ ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1 ++ ++ $IP link add dummy0 type dummy ++ $IP link set dev dummy0 up ++ $IP address add 198.51.100.1/24 dev dummy0 ++ $IP -6 address add 2001:db8:1::1/64 dev dummy0 ++ set +e ++ ++} ++ ++cleanup() ++{ ++ $IP link del dev dummy0 &> /dev/null ++ ip netns del ns1 ++ ip netns del ns2 &> /dev/null ++} ++ ++get_linklocal() ++{ ++ local dev=$1 ++ local addr ++ ++ addr=$($IP -6 -br addr show dev ${dev} | \ ++ awk '{ ++ for (i = 3; i <= NF; ++i) { ++ if ($i ~ /^fe80/) ++ print $i ++ } ++ }' ++ ) ++ addr=${addr/\/*} ++ ++ [ -z "$addr" ] && return 1 ++ ++ echo $addr ++ ++ return 0 ++} ++ ++fib_unreg_unicast_test() ++{ ++ echo ++ echo "Single path route test" ++ ++ setup ++ ++ echo " Start point" ++ $IP route get fibmatch 198.51.100.2 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ set -e ++ $IP link del dev dummy0 ++ set +e ++ ++ echo " Nexthop device deleted" ++ $IP route get fibmatch 198.51.100.2 &> /dev/null ++ log_test $? 2 "IPv4 fibmatch - no route" ++ $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null ++ log_test $? 2 "IPv6 fibmatch - no route" ++ ++ cleanup ++} ++ ++fib_unreg_multipath_test() ++{ ++ ++ echo ++ echo "Multipath route test" ++ ++ setup ++ ++ set -e ++ $IP link add dummy1 type dummy ++ $IP link set dev dummy1 up ++ $IP address add 192.0.2.1/24 dev dummy1 ++ $IP -6 address add 2001:db8:2::1/64 dev dummy1 ++ ++ $IP route add 203.0.113.0/24 \ ++ nexthop via 198.51.100.2 dev dummy0 \ ++ nexthop via 192.0.2.2 dev dummy1 ++ $IP -6 route add 2001:db8:3::/64 \ ++ nexthop via 2001:db8:1::2 dev dummy0 \ ++ nexthop via 2001:db8:2::2 dev dummy1 ++ set +e ++ ++ echo " Start point" ++ $IP route get fibmatch 203.0.113.1 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ set -e ++ $IP link del dev dummy0 ++ set +e ++ ++ echo " One nexthop device deleted" ++ $IP route get fibmatch 203.0.113.1 &> /dev/null ++ log_test $? 2 "IPv4 - multipath route removed on delete" ++ ++ $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null ++ # In IPv6 we do not flush the entire multipath route. ++ log_test $? 0 "IPv6 - multipath down to single path" ++ ++ set -e ++ $IP link del dev dummy1 ++ set +e ++ ++ echo " Second nexthop device deleted" ++ $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null ++ log_test $? 2 "IPv6 - no route" ++ ++ cleanup ++} ++ ++fib_unreg_test() ++{ ++ fib_unreg_unicast_test ++ fib_unreg_multipath_test ++} ++ ++fib_down_unicast_test() ++{ ++ echo ++ echo "Single path, admin down" ++ ++ setup ++ ++ echo " Start point" ++ $IP route get fibmatch 198.51.100.2 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ set -e ++ $IP link set dev dummy0 down ++ set +e ++ ++ echo " Route deleted on down" ++ $IP route get fibmatch 198.51.100.2 &> /dev/null ++ log_test $? 2 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null ++ log_test $? 2 "IPv6 fibmatch" ++ ++ cleanup ++} ++ ++fib_down_multipath_test_do() ++{ ++ local down_dev=$1 ++ local up_dev=$2 ++ ++ $IP route get fibmatch 203.0.113.1 \ ++ oif $down_dev &> /dev/null ++ log_test $? 2 "IPv4 fibmatch on down device" ++ $IP -6 route get fibmatch 2001:db8:3::1 \ ++ oif $down_dev &> /dev/null ++ log_test $? 2 "IPv6 fibmatch on down device" ++ ++ $IP route get fibmatch 203.0.113.1 \ ++ oif $up_dev &> /dev/null ++ log_test $? 0 "IPv4 fibmatch on up device" ++ $IP -6 route get fibmatch 2001:db8:3::1 \ ++ oif $up_dev &> /dev/null ++ log_test $? 0 "IPv6 fibmatch on up device" ++ ++ $IP route get fibmatch 203.0.113.1 | \ ++ grep $down_dev | grep -q "dead linkdown" ++ log_test $? 0 "IPv4 flags on down device" ++ $IP -6 route get fibmatch 2001:db8:3::1 | \ ++ grep $down_dev | grep -q "dead linkdown" ++ log_test $? 0 "IPv6 flags on down device" ++ ++ $IP route get fibmatch 203.0.113.1 | \ ++ grep $up_dev | grep -q "dead linkdown" ++ log_test $? 1 "IPv4 flags on up device" ++ $IP -6 route get fibmatch 2001:db8:3::1 | \ ++ grep $up_dev | grep -q "dead linkdown" ++ log_test $? 1 "IPv6 flags on up device" ++} ++ ++fib_down_multipath_test() ++{ ++ echo ++ echo "Admin down multipath" ++ ++ setup ++ ++ set -e ++ $IP link add dummy1 type dummy ++ $IP link set dev dummy1 up ++ ++ $IP address add 192.0.2.1/24 dev dummy1 ++ $IP -6 address add 2001:db8:2::1/64 dev dummy1 ++ ++ $IP route add 203.0.113.0/24 \ ++ nexthop via 198.51.100.2 dev dummy0 \ ++ nexthop via 192.0.2.2 dev dummy1 ++ $IP -6 route add 2001:db8:3::/64 \ ++ nexthop via 2001:db8:1::2 dev dummy0 \ ++ nexthop via 2001:db8:2::2 dev dummy1 ++ set +e ++ ++ echo " Verify start point" ++ $IP route get fibmatch 203.0.113.1 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ ++ $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ set -e ++ $IP link set dev dummy0 down ++ set +e ++ ++ echo " One device down, one up" ++ fib_down_multipath_test_do "dummy0" "dummy1" ++ ++ set -e ++ $IP link set dev dummy0 up ++ $IP link set dev dummy1 down ++ set +e ++ ++ echo " Other device down and up" ++ fib_down_multipath_test_do "dummy1" "dummy0" ++ ++ set -e ++ $IP link set dev dummy0 down ++ set +e ++ ++ echo " Both devices down" ++ $IP route get fibmatch 203.0.113.1 &> /dev/null ++ log_test $? 2 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null ++ log_test $? 2 "IPv6 fibmatch" ++ ++ $IP link del dev dummy1 ++ cleanup ++} ++ ++fib_down_test() ++{ ++ fib_down_unicast_test ++ fib_down_multipath_test ++} ++ ++# Local routes should not be affected when carrier changes. ++fib_carrier_local_test() ++{ ++ echo ++ echo "Local carrier tests - single path" ++ ++ setup ++ ++ set -e ++ $IP link set dev dummy0 carrier on ++ set +e ++ ++ echo " Start point" ++ $IP route get fibmatch 198.51.100.1 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ $IP route get fibmatch 198.51.100.1 | \ ++ grep -q "linkdown" ++ log_test $? 1 "IPv4 - no linkdown flag" ++ $IP -6 route get fibmatch 2001:db8:1::1 | \ ++ grep -q "linkdown" ++ log_test $? 1 "IPv6 - no linkdown flag" ++ ++ set -e ++ $IP link set dev dummy0 carrier off ++ sleep 1 ++ set +e ++ ++ echo " Carrier off on nexthop" ++ $IP route get fibmatch 198.51.100.1 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ $IP route get fibmatch 198.51.100.1 | \ ++ grep -q "linkdown" ++ log_test $? 1 "IPv4 - linkdown flag set" ++ $IP -6 route get fibmatch 2001:db8:1::1 | \ ++ grep -q "linkdown" ++ log_test $? 1 "IPv6 - linkdown flag set" ++ ++ set -e ++ $IP address add 192.0.2.1/24 dev dummy0 ++ $IP -6 address add 2001:db8:2::1/64 dev dummy0 ++ set +e ++ ++ echo " Route to local address with carrier down" ++ $IP route get fibmatch 192.0.2.1 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ $IP route get fibmatch 192.0.2.1 | \ ++ grep -q "linkdown" ++ log_test $? 1 "IPv4 linkdown flag set" ++ $IP -6 route get fibmatch 2001:db8:2::1 | \ ++ grep -q "linkdown" ++ log_test $? 1 "IPv6 linkdown flag set" ++ ++ cleanup ++} ++ ++fib_carrier_unicast_test() ++{ ++ ret=0 ++ ++ echo ++ echo "Single path route carrier test" ++ ++ setup ++ ++ set -e ++ $IP link set dev dummy0 carrier on ++ set +e ++ ++ echo " Start point" ++ $IP route get fibmatch 198.51.100.2 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ $IP route get fibmatch 198.51.100.2 | \ ++ grep -q "linkdown" ++ log_test $? 1 "IPv4 no linkdown flag" ++ $IP -6 route get fibmatch 2001:db8:1::2 | \ ++ grep -q "linkdown" ++ log_test $? 1 "IPv6 no linkdown flag" ++ ++ set -e ++ $IP link set dev dummy0 carrier off ++ sleep 1 ++ set +e ++ ++ echo " Carrier down" ++ $IP route get fibmatch 198.51.100.2 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ $IP route get fibmatch 198.51.100.2 | \ ++ grep -q "linkdown" ++ log_test $? 0 "IPv4 linkdown flag set" ++ $IP -6 route get fibmatch 2001:db8:1::2 | \ ++ grep -q "linkdown" ++ log_test $? 0 "IPv6 linkdown flag set" ++ ++ set -e ++ $IP address add 192.0.2.1/24 dev dummy0 ++ $IP -6 address add 2001:db8:2::1/64 dev dummy0 ++ set +e ++ ++ echo " Second address added with carrier down" ++ $IP route get fibmatch 192.0.2.2 &> /dev/null ++ log_test $? 0 "IPv4 fibmatch" ++ $IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null ++ log_test $? 0 "IPv6 fibmatch" ++ ++ $IP route get fibmatch 192.0.2.2 | \ ++ grep -q "linkdown" ++ log_test $? 0 "IPv4 linkdown flag set" ++ $IP -6 route get fibmatch 2001:db8:2::2 | \ ++ grep -q "linkdown" ++ log_test $? 0 "IPv6 linkdown flag set" ++ ++ cleanup ++} ++ ++fib_carrier_test() ++{ ++ fib_carrier_local_test ++ fib_carrier_unicast_test ++} ++ ++fib_rp_filter_test() ++{ ++ echo ++ echo "IPv4 rp_filter tests" ++ ++ setup ++ ++ set -e ++ ip netns add ns2 ++ ip netns set ns2 auto ++ ++ ip -netns ns2 link set dev lo up ++ ++ $IP link add name veth1 type veth peer name veth2 ++ $IP link set dev veth2 netns ns2 ++ $IP address add 192.0.2.1/24 dev veth1 ++ ip -netns ns2 address add 192.0.2.1/24 dev veth2 ++ $IP link set dev veth1 up ++ ip -netns ns2 link set dev veth2 up ++ ++ $IP link set dev lo address 52:54:00:6a:c7:5e ++ $IP link set dev veth1 address 52:54:00:6a:c7:5e ++ ip -netns ns2 link set dev lo address 52:54:00:6a:c7:5e ++ ip -netns ns2 link set dev veth2 address 52:54:00:6a:c7:5e ++ ++ # 1. (ns2) redirect lo's egress to veth2's egress ++ ip netns exec ns2 tc qdisc add dev lo parent root handle 1: fq_codel ++ ip netns exec ns2 tc filter add dev lo parent 1: protocol arp basic \ ++ action mirred egress redirect dev veth2 ++ ip netns exec ns2 tc filter add dev lo parent 1: protocol ip basic \ ++ action mirred egress redirect dev veth2 ++ ++ # 2. (ns1) redirect veth1's ingress to lo's ingress ++ $NS_EXEC tc qdisc add dev veth1 ingress ++ $NS_EXEC tc filter add dev veth1 ingress protocol arp basic \ ++ action mirred ingress redirect dev lo ++ $NS_EXEC tc filter add dev veth1 ingress protocol ip basic \ ++ action mirred ingress redirect dev lo ++ ++ # 3. (ns1) redirect lo's egress to veth1's egress ++ $NS_EXEC tc qdisc add dev lo parent root handle 1: fq_codel ++ $NS_EXEC tc filter add dev lo parent 1: protocol arp basic \ ++ action mirred egress redirect dev veth1 ++ $NS_EXEC tc filter add dev lo parent 1: protocol ip basic \ ++ action mirred egress redirect dev veth1 ++ ++ # 4. (ns2) redirect veth2's ingress to lo's ingress ++ ip netns exec ns2 tc qdisc add dev veth2 ingress ++ ip netns exec ns2 tc filter add dev veth2 ingress protocol arp basic \ ++ action mirred ingress redirect dev lo ++ ip netns exec ns2 tc filter add dev veth2 ingress protocol ip basic \ ++ action mirred ingress redirect dev lo ++ ++ $NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1 ++ $NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1 ++ $NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1 ++ ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1 ++ ip netns exec ns2 sysctl -qw net.ipv4.conf.all.accept_local=1 ++ ip netns exec ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1 ++ set +e ++ ++ run_cmd "ip netns exec ns2 ping -w1 -c1 192.0.2.1" ++ log_test $? 0 "rp_filter passes local packets" ++ ++ run_cmd "ip netns exec ns2 ping -w1 -c1 127.0.0.1" ++ log_test $? 0 "rp_filter passes loopback packets" ++ ++ cleanup ++} ++ ++################################################################################ ++# Tests on nexthop spec ++ ++# run 'ip route add' with given spec ++add_rt() ++{ ++ local desc="$1" ++ local erc=$2 ++ local vrf=$3 ++ local pfx=$4 ++ local gw=$5 ++ local dev=$6 ++ local cmd out rc ++ ++ [ "$vrf" = "-" ] && vrf="default" ++ [ -n "$gw" ] && gw="via $gw" ++ [ -n "$dev" ] && dev="dev $dev" ++ ++ cmd="$IP route add vrf $vrf $pfx $gw $dev" ++ if [ "$VERBOSE" = "1" ]; then ++ printf "\n COMMAND: $cmd\n" ++ fi ++ ++ out=$(eval $cmd 2>&1) ++ rc=$? ++ if [ "$VERBOSE" = "1" -a -n "$out" ]; then ++ echo " $out" ++ fi ++ log_test $rc $erc "$desc" ++} ++ ++fib4_nexthop() ++{ ++ echo ++ echo "IPv4 nexthop tests" ++ ++ echo "<<< write me >>>" ++} ++ ++fib6_nexthop() ++{ ++ local lldummy=$(get_linklocal dummy0) ++ local llv1=$(get_linklocal dummy0) ++ ++ if [ -z "$lldummy" ]; then ++ echo "Failed to get linklocal address for dummy0" ++ return 1 ++ fi ++ if [ -z "$llv1" ]; then ++ echo "Failed to get linklocal address for veth1" ++ return 1 ++ fi ++ ++ echo ++ echo "IPv6 nexthop tests" ++ ++ add_rt "Directly connected nexthop, unicast address" 0 \ ++ - 2001:db8:101::/64 2001:db8:1::2 ++ add_rt "Directly connected nexthop, unicast address with device" 0 \ ++ - 2001:db8:102::/64 2001:db8:1::2 "dummy0" ++ add_rt "Gateway is linklocal address" 0 \ ++ - 2001:db8:103::1/64 $llv1 "veth0" ++ ++ # fails because LL address requires a device ++ add_rt "Gateway is linklocal address, no device" 2 \ ++ - 2001:db8:104::1/64 $llv1 ++ ++ # local address can not be a gateway ++ add_rt "Gateway can not be local unicast address" 2 \ ++ - 2001:db8:105::/64 2001:db8:1::1 ++ add_rt "Gateway can not be local unicast address, with device" 2 \ ++ - 2001:db8:106::/64 2001:db8:1::1 "dummy0" ++ add_rt "Gateway can not be a local linklocal address" 2 \ ++ - 2001:db8:107::1/64 $lldummy "dummy0" ++ ++ # VRF tests ++ add_rt "Gateway can be local address in a VRF" 0 \ ++ - 2001:db8:108::/64 2001:db8:51::2 ++ add_rt "Gateway can be local address in a VRF, with device" 0 \ ++ - 2001:db8:109::/64 2001:db8:51::2 "veth0" ++ add_rt "Gateway can be local linklocal address in a VRF" 0 \ ++ - 2001:db8:110::1/64 $llv1 "veth0" ++ ++ add_rt "Redirect to VRF lookup" 0 \ ++ - 2001:db8:111::/64 "" "red" ++ ++ add_rt "VRF route, gateway can be local address in default VRF" 0 \ ++ red 2001:db8:112::/64 2001:db8:51::1 ++ ++ # local address in same VRF fails ++ add_rt "VRF route, gateway can not be a local address" 2 \ ++ red 2001:db8:113::1/64 2001:db8:2::1 ++ add_rt "VRF route, gateway can not be a local addr with device" 2 \ ++ red 2001:db8:114::1/64 2001:db8:2::1 "dummy1" ++} ++ ++# Default VRF: ++# dummy0 - 198.51.100.1/24 2001:db8:1::1/64 ++# veth0 - 192.0.2.1/24 2001:db8:51::1/64 ++# ++# VRF red: ++# dummy1 - 192.168.2.1/24 2001:db8:2::1/64 ++# veth1 - 192.0.2.2/24 2001:db8:51::2/64 ++# ++# [ dummy0 veth0 ]--[ veth1 dummy1 ] ++ ++fib_nexthop_test() ++{ ++ setup ++ ++ set -e ++ ++ $IP -4 rule add pref 32765 table local ++ $IP -4 rule del pref 0 ++ $IP -6 rule add pref 32765 table local ++ $IP -6 rule del pref 0 ++ ++ $IP link add red type vrf table 1 ++ $IP link set red up ++ $IP -4 route add vrf red unreachable default metric 4278198272 ++ $IP -6 route add vrf red unreachable default metric 4278198272 ++ ++ $IP link add veth0 type veth peer name veth1 ++ $IP link set dev veth0 up ++ $IP address add 192.0.2.1/24 dev veth0 ++ $IP -6 address add 2001:db8:51::1/64 dev veth0 ++ ++ $IP link set dev veth1 vrf red up ++ $IP address add 192.0.2.2/24 dev veth1 ++ $IP -6 address add 2001:db8:51::2/64 dev veth1 ++ ++ $IP link add dummy1 type dummy ++ $IP link set dev dummy1 vrf red up ++ $IP address add 192.168.2.1/24 dev dummy1 ++ $IP -6 address add 2001:db8:2::1/64 dev dummy1 ++ set +e ++ ++ sleep 1 ++ fib4_nexthop ++ fib6_nexthop ++ ++ ( ++ $IP link del dev dummy1 ++ $IP link del veth0 ++ $IP link del red ++ ) 2>/dev/null ++ cleanup ++} ++ ++fib_suppress_test() ++{ ++ echo ++ echo "FIB rule with suppress_prefixlength" ++ setup ++ ++ $IP link add dummy1 type dummy ++ $IP link set dummy1 up ++ $IP -6 route add default dev dummy1 ++ $IP -6 rule add table main suppress_prefixlength 0 ++ ping -f -c 1000 -W 1 1234::1 >/dev/null 2>&1 ++ $IP -6 rule del table main suppress_prefixlength 0 ++ $IP link del dummy1 ++ ++ # If we got here without crashing, we're good. ++ log_test 0 0 "FIB rule suppress test" ++ ++ cleanup ++} ++ ++################################################################################ ++# Tests on route add and replace ++ ++run_cmd() ++{ ++ local cmd="$1" ++ local out ++ local stderr="2>/dev/null" ++ ++ if [ "$VERBOSE" = "1" ]; then ++ printf " COMMAND: $cmd\n" ++ stderr= ++ fi ++ ++ out=$(eval $cmd $stderr) ++ rc=$? ++ if [ "$VERBOSE" = "1" -a -n "$out" ]; then ++ echo " $out" ++ fi ++ ++ [ "$VERBOSE" = "1" ] && echo ++ ++ return $rc ++} ++ ++check_expected() ++{ ++ local out="$1" ++ local expected="$2" ++ local rc=0 ++ ++ [ "${out}" = "${expected}" ] && return 0 ++ ++ if [ -z "${out}" ]; then ++ if [ "$VERBOSE" = "1" ]; then ++ printf "\nNo route entry found\n" ++ printf "Expected:\n" ++ printf " ${expected}\n" ++ fi ++ return 1 ++ fi ++ ++ # tricky way to convert output to 1-line without ip's ++ # messy '\'; this drops all extra white space ++ out=$(echo ${out}) ++ if [ "${out}" != "${expected}" ]; then ++ rc=1 ++ if [ "${VERBOSE}" = "1" ]; then ++ printf " Unexpected route entry. Have:\n" ++ printf " ${out}\n" ++ printf " Expected:\n" ++ printf " ${expected}\n\n" ++ fi ++ fi ++ ++ return $rc ++} ++ ++# add route for a prefix, flushing any existing routes first ++# expected to be the first step of a test ++add_route6() ++{ ++ local pfx="$1" ++ local nh="$2" ++ local out ++ ++ if [ "$VERBOSE" = "1" ]; then ++ echo ++ echo " ##################################################" ++ echo ++ fi ++ ++ run_cmd "$IP -6 ro flush ${pfx}" ++ [ $? -ne 0 ] && exit 1 ++ ++ out=$($IP -6 ro ls match ${pfx}) ++ if [ -n "$out" ]; then ++ echo "Failed to flush routes for prefix used for tests." ++ exit 1 ++ fi ++ ++ run_cmd "$IP -6 ro add ${pfx} ${nh}" ++ if [ $? -ne 0 ]; then ++ echo "Failed to add initial route for test." ++ exit 1 ++ fi ++} ++ ++# add initial route - used in replace route tests ++add_initial_route6() ++{ ++ add_route6 "2001:db8:104::/64" "$1" ++} ++ ++check_route6() ++{ ++ local pfx ++ local expected="$1" ++ local out ++ local rc=0 ++ ++ set -- $expected ++ pfx=$1 ++ ++ out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//') ++ check_expected "${out}" "${expected}" ++} ++ ++route_cleanup() ++{ ++ $IP li del red 2>/dev/null ++ $IP li del dummy1 2>/dev/null ++ $IP li del veth1 2>/dev/null ++ $IP li del veth3 2>/dev/null ++ ++ cleanup &> /dev/null ++} ++ ++route_setup() ++{ ++ route_cleanup ++ setup ++ ++ [ "${VERBOSE}" = "1" ] && set -x ++ set -e ++ ++ ip netns add ns2 ++ ip netns set ns2 auto ++ ip -netns ns2 link set dev lo up ++ ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1 ++ ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1 ++ ++ $IP li add veth1 type veth peer name veth2 ++ $IP li add veth3 type veth peer name veth4 ++ ++ $IP li set veth1 up ++ $IP li set veth3 up ++ $IP li set veth2 netns ns2 up ++ $IP li set veth4 netns ns2 up ++ ip -netns ns2 li add dummy1 type dummy ++ ip -netns ns2 li set dummy1 up ++ ++ $IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad ++ $IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad ++ $IP addr add 172.16.101.1/24 dev veth1 ++ $IP addr add 172.16.103.1/24 dev veth3 ++ ++ ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad ++ ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad ++ ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad ++ ++ ip -netns ns2 addr add 172.16.101.2/24 dev veth2 ++ ip -netns ns2 addr add 172.16.103.2/24 dev veth4 ++ ip -netns ns2 addr add 172.16.104.1/24 dev dummy1 ++ ++ set +e ++} ++ ++# assumption is that basic add of a single path route works ++# otherwise just adding an address on an interface is broken ++ipv6_rt_add() ++{ ++ local rc ++ ++ echo ++ echo "IPv6 route add / append tests" ++ ++ # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL ++ add_route6 "2001:db8:104::/64" "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2" ++ log_test $? 2 "Attempt to add duplicate route - gw" ++ ++ # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL ++ add_route6 "2001:db8:104::/64" "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3" ++ log_test $? 2 "Attempt to add duplicate route - dev only" ++ ++ # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL ++ add_route6 "2001:db8:104::/64" "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64" ++ log_test $? 2 "Attempt to add duplicate route - reject route" ++ ++ # route append with same prefix adds a new route ++ # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND ++ add_route6 "2001:db8:104::/64" "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2" ++ check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" ++ log_test $? 0 "Append nexthop to existing route - gw" ++ ++ # insert mpath directly ++ add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" ++ log_test $? 0 "Add multipath route" ++ ++ add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ log_test $? 2 "Attempt to add duplicate multipath route" ++ ++ # insert of a second route without append but different metric ++ add_route6 "2001:db8:104::/64" "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256" ++ rc=$? ++ fi ++ log_test $rc 0 "Route add with different metrics" ++ ++ run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route6 "2001:db8:104::/64 via 2001:db8:103::3 dev veth3 metric 256 2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024" ++ rc=$? ++ fi ++ log_test $rc 0 "Route delete with metric" ++} ++ ++ipv6_rt_replace_single() ++{ ++ # single path with single path ++ # ++ add_initial_route6 "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2" ++ check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024" ++ log_test $? 0 "Single path with single path" ++ ++ # single path with multipath ++ # ++ add_initial_route6 "nexthop via 2001:db8:101::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2" ++ check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::3 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" ++ log_test $? 0 "Single path with multipath" ++ ++ # single path with single path using MULTIPATH attribute ++ # ++ add_initial_route6 "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2" ++ check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024" ++ log_test $? 0 "Single path with single path via multipath attribute" ++ ++ # route replace fails - invalid nexthop ++ add_initial_route6 "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2" ++ if [ $? -eq 0 ]; then ++ # previous command is expected to fail so if it returns 0 ++ # that means the test failed. ++ log_test 0 1 "Invalid nexthop" ++ else ++ check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024" ++ log_test $? 0 "Invalid nexthop" ++ fi ++ ++ # replace non-existent route ++ # - note use of change versus replace since ip adds NLM_F_CREATE ++ # for replace ++ add_initial_route6 "via 2001:db8:101::2" ++ run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2" ++ log_test $? 2 "Single path - replace of non-existent route" ++} ++ ++ipv6_rt_replace_mpath() ++{ ++ # multipath with multipath ++ add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3" ++ check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::3 dev veth1 weight 1 nexthop via 2001:db8:103::3 dev veth3 weight 1" ++ log_test $? 0 "Multipath with multipath" ++ ++ # multipath with single ++ add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3" ++ check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024" ++ log_test $? 0 "Multipath with single path" ++ ++ # multipath with single ++ add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3" ++ check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024" ++ log_test $? 0 "Multipath with single path via multipath attribute" ++ ++ # multipath with dev-only ++ add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1" ++ check_route6 "2001:db8:104::/64 dev veth1 metric 1024" ++ log_test $? 0 "Multipath with dev-only" ++ ++ # route replace fails - invalid nexthop 1 ++ add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3" ++ check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" ++ log_test $? 0 "Multipath - invalid first nexthop" ++ ++ # route replace fails - invalid nexthop 2 ++ add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3" ++ check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" ++ log_test $? 0 "Multipath - invalid second nexthop" ++ ++ # multipath non-existent route ++ add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3" ++ log_test $? 2 "Multipath - replace of non-existent route" ++} ++ ++ipv6_rt_replace() ++{ ++ echo ++ echo "IPv6 route replace tests" ++ ++ ipv6_rt_replace_single ++ ipv6_rt_replace_mpath ++} ++ ++ipv6_route_test() ++{ ++ route_setup ++ ++ ipv6_rt_add ++ ipv6_rt_replace ++ ++ route_cleanup ++} ++ ++ip_addr_metric_check() ++{ ++ ip addr help 2>&1 | grep -q metric ++ if [ $? -ne 0 ]; then ++ echo "iproute2 command does not support metric for addresses. Skipping test" ++ return 1 ++ fi ++ ++ return 0 ++} ++ ++ipv6_addr_metric_test() ++{ ++ local rc ++ ++ echo ++ echo "IPv6 prefix route tests" ++ ++ ip_addr_metric_check || return 1 ++ ++ setup ++ ++ set -e ++ $IP li add dummy1 type dummy ++ $IP li add dummy2 type dummy ++ $IP li set dummy1 up ++ $IP li set dummy2 up ++ ++ # default entry is metric 256 ++ run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64" ++ run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64" ++ set +e ++ ++ check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256" ++ log_test $? 0 "Default metric" ++ ++ set -e ++ run_cmd "$IP -6 addr flush dev dummy1" ++ run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257" ++ set +e ++ ++ check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257" ++ log_test $? 0 "User specified metric on first device" ++ ++ set -e ++ run_cmd "$IP -6 addr flush dev dummy2" ++ run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258" ++ set +e ++ ++ check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258" ++ log_test $? 0 "User specified metric on second device" ++ ++ run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258" ++ rc=$? ++ fi ++ log_test $rc 0 "Delete of address on first device" ++ ++ run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259" ++ rc=$? ++ fi ++ log_test $rc 0 "Modify metric of address" ++ ++ # verify prefix route removed on down ++ run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1" ++ run_cmd "$IP li set dev dummy2 down" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ out=$($IP -6 ro ls match 2001:db8:104::/64) ++ check_expected "${out}" "" ++ rc=$? ++ fi ++ log_test $rc 0 "Prefix route removed on link down" ++ ++ # verify prefix route re-inserted with assigned metric ++ run_cmd "$IP li set dev dummy2 up" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259" ++ rc=$? ++ fi ++ log_test $rc 0 "Prefix route with metric on link up" ++ ++ # verify peer metric added correctly ++ set -e ++ run_cmd "$IP -6 addr flush dev dummy2" ++ run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260" ++ set +e ++ ++ check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260" ++ log_test $? 0 "Set metric with peer route on local side" ++ check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260" ++ log_test $? 0 "Set metric with peer route on peer side" ++ ++ set -e ++ run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261" ++ set +e ++ ++ check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261" ++ log_test $? 0 "Modify metric and peer address on local side" ++ check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261" ++ log_test $? 0 "Modify metric and peer address on peer side" ++ ++ $IP li del dummy1 ++ $IP li del dummy2 ++ cleanup ++} ++ ++ipv6_route_metrics_test() ++{ ++ local rc ++ ++ echo ++ echo "IPv6 routes with metrics" ++ ++ route_setup ++ ++ # ++ # single path with metrics ++ # ++ run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route6 "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400" ++ rc=$? ++ fi ++ log_test $rc 0 "Single path route with mtu metric" ++ ++ ++ # ++ # multipath via separate routes with metrics ++ # ++ run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400" ++ run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route6 "2001:db8:112::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" ++ rc=$? ++ fi ++ log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first" ++ ++ # second route is coalesced to first to make a multipath route. ++ # MTU of the second path is hidden from display! ++ run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2" ++ run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route6 "2001:db8:113::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" ++ rc=$? ++ fi ++ log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd" ++ ++ run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2" ++ if [ $? -eq 0 ]; then ++ check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400" ++ log_test $? 0 " MTU of second leg" ++ fi ++ ++ # ++ # multipath with metrics ++ # ++ run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route6 "2001:db8:115::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" ++ rc=$? ++ fi ++ log_test $rc 0 "Multipath route with mtu metric" ++ ++ $IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300 ++ run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1" ++ log_test $? 0 "Using route with mtu metric" ++ ++ run_cmd "$IP -6 ro add 2001:db8:114::/64 via 2001:db8:101::2 congctl lock foo" ++ log_test $? 2 "Invalid metric (fails metric_convert)" ++ ++ route_cleanup ++} ++ ++# add route for a prefix, flushing any existing routes first ++# expected to be the first step of a test ++add_route() ++{ ++ local pfx="$1" ++ local nh="$2" ++ local out ++ ++ if [ "$VERBOSE" = "1" ]; then ++ echo ++ echo " ##################################################" ++ echo ++ fi ++ ++ run_cmd "$IP ro flush ${pfx}" ++ [ $? -ne 0 ] && exit 1 ++ ++ out=$($IP ro ls match ${pfx}) ++ if [ -n "$out" ]; then ++ echo "Failed to flush routes for prefix used for tests." ++ exit 1 ++ fi ++ ++ run_cmd "$IP ro add ${pfx} ${nh}" ++ if [ $? -ne 0 ]; then ++ echo "Failed to add initial route for test." ++ exit 1 ++ fi ++} ++ ++# add initial route - used in replace route tests ++add_initial_route() ++{ ++ add_route "172.16.104.0/24" "$1" ++} ++ ++check_route() ++{ ++ local pfx ++ local expected="$1" ++ local out ++ ++ set -- $expected ++ pfx=$1 ++ [ "${pfx}" = "unreachable" ] && pfx=$2 ++ ++ out=$($IP ro ls match ${pfx}) ++ check_expected "${out}" "${expected}" ++} ++ ++# assumption is that basic add of a single path route works ++# otherwise just adding an address on an interface is broken ++ipv4_rt_add() ++{ ++ local rc ++ ++ echo ++ echo "IPv4 route add / append tests" ++ ++ # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL ++ add_route "172.16.104.0/24" "via 172.16.101.2" ++ run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2" ++ log_test $? 2 "Attempt to add duplicate route - gw" ++ ++ # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL ++ add_route "172.16.104.0/24" "via 172.16.101.2" ++ run_cmd "$IP ro add 172.16.104.0/24 dev veth3" ++ log_test $? 2 "Attempt to add duplicate route - dev only" ++ ++ # route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL ++ add_route "172.16.104.0/24" "via 172.16.101.2" ++ run_cmd "$IP ro add unreachable 172.16.104.0/24" ++ log_test $? 2 "Attempt to add duplicate route - reject route" ++ ++ # iproute2 prepend only sets NLM_F_CREATE ++ # - adds a new route; does NOT convert existing route to ECMP ++ add_route "172.16.104.0/24" "via 172.16.101.2" ++ run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2" ++ check_route "172.16.104.0/24 via 172.16.103.2 dev veth3 172.16.104.0/24 via 172.16.101.2 dev veth1" ++ log_test $? 0 "Add new nexthop for existing prefix" ++ ++ # route append with same prefix adds a new route ++ # - iproute2 sets NLM_F_CREATE | NLM_F_APPEND ++ add_route "172.16.104.0/24" "via 172.16.101.2" ++ run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2" ++ check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.2 dev veth3" ++ log_test $? 0 "Append nexthop to existing route - gw" ++ ++ add_route "172.16.104.0/24" "via 172.16.101.2" ++ run_cmd "$IP ro append 172.16.104.0/24 dev veth3" ++ check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link" ++ log_test $? 0 "Append nexthop to existing route - dev only" ++ ++ add_route "172.16.104.0/24" "via 172.16.101.2" ++ run_cmd "$IP ro append unreachable 172.16.104.0/24" ++ check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24" ++ log_test $? 0 "Append nexthop to existing route - reject route" ++ ++ run_cmd "$IP ro flush 172.16.104.0/24" ++ run_cmd "$IP ro add unreachable 172.16.104.0/24" ++ run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2" ++ check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3" ++ log_test $? 0 "Append nexthop to existing reject route - gw" ++ ++ run_cmd "$IP ro flush 172.16.104.0/24" ++ run_cmd "$IP ro add unreachable 172.16.104.0/24" ++ run_cmd "$IP ro append 172.16.104.0/24 dev veth3" ++ check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link" ++ log_test $? 0 "Append nexthop to existing reject route - dev only" ++ ++ # insert mpath directly ++ add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ check_route "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1" ++ log_test $? 0 "add multipath route" ++ ++ add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ log_test $? 2 "Attempt to add duplicate multipath route" ++ ++ # insert of a second route without append but different metric ++ add_route "172.16.104.0/24" "via 172.16.101.2" ++ run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256" ++ rc=$? ++ fi ++ log_test $rc 0 "Route add with different metrics" ++ ++ run_cmd "$IP ro del 172.16.104.0/24 metric 512" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.3 dev veth3 metric 256" ++ rc=$? ++ fi ++ log_test $rc 0 "Route delete with metric" ++} ++ ++ipv4_rt_replace_single() ++{ ++ # single path with single path ++ # ++ add_initial_route "via 172.16.101.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2" ++ check_route "172.16.104.0/24 via 172.16.103.2 dev veth3" ++ log_test $? 0 "Single path with single path" ++ ++ # single path with multipath ++ # ++ add_initial_route "nexthop via 172.16.101.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2" ++ check_route "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1" ++ log_test $? 0 "Single path with multipath" ++ ++ # single path with reject ++ # ++ add_initial_route "nexthop via 172.16.101.2" ++ run_cmd "$IP ro replace unreachable 172.16.104.0/24" ++ check_route "unreachable 172.16.104.0/24" ++ log_test $? 0 "Single path with reject route" ++ ++ # single path with single path using MULTIPATH attribute ++ # ++ add_initial_route "via 172.16.101.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2" ++ check_route "172.16.104.0/24 via 172.16.103.2 dev veth3" ++ log_test $? 0 "Single path with single path via multipath attribute" ++ ++ # route replace fails - invalid nexthop ++ add_initial_route "via 172.16.101.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2" ++ if [ $? -eq 0 ]; then ++ # previous command is expected to fail so if it returns 0 ++ # that means the test failed. ++ log_test 0 1 "Invalid nexthop" ++ else ++ check_route "172.16.104.0/24 via 172.16.101.2 dev veth1" ++ log_test $? 0 "Invalid nexthop" ++ fi ++ ++ # replace non-existent route ++ # - note use of change versus replace since ip adds NLM_F_CREATE ++ # for replace ++ add_initial_route "via 172.16.101.2" ++ run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2" ++ log_test $? 2 "Single path - replace of non-existent route" ++} ++ ++ipv4_rt_replace_mpath() ++{ ++ # multipath with multipath ++ add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3" ++ check_route "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.3 dev veth3 weight 1" ++ log_test $? 0 "Multipath with multipath" ++ ++ # multipath with single ++ add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3" ++ check_route "172.16.104.0/24 via 172.16.101.3 dev veth1" ++ log_test $? 0 "Multipath with single path" ++ ++ # multipath with single ++ add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3" ++ check_route "172.16.104.0/24 via 172.16.101.3 dev veth1" ++ log_test $? 0 "Multipath with single path via multipath attribute" ++ ++ # multipath with reject ++ add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ run_cmd "$IP ro replace unreachable 172.16.104.0/24" ++ check_route "unreachable 172.16.104.0/24" ++ log_test $? 0 "Multipath with reject route" ++ ++ # route replace fails - invalid nexthop 1 ++ add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3" ++ check_route "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1" ++ log_test $? 0 "Multipath - invalid first nexthop" ++ ++ # route replace fails - invalid nexthop 2 ++ add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3" ++ check_route "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1" ++ log_test $? 0 "Multipath - invalid second nexthop" ++ ++ # multipath non-existent route ++ add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3" ++ log_test $? 2 "Multipath - replace of non-existent route" ++} ++ ++ipv4_rt_replace() ++{ ++ echo ++ echo "IPv4 route replace tests" ++ ++ ipv4_rt_replace_single ++ ipv4_rt_replace_mpath ++} ++ ++ipv4_route_test() ++{ ++ route_setup ++ ++ ipv4_rt_add ++ ipv4_rt_replace ++ ++ route_cleanup ++} ++ ++ipv4_addr_metric_test() ++{ ++ local rc ++ ++ echo ++ echo "IPv4 prefix route tests" ++ ++ ip_addr_metric_check || return 1 ++ ++ setup ++ ++ set -e ++ $IP li add dummy1 type dummy ++ $IP li add dummy2 type dummy ++ $IP li set dummy1 up ++ $IP li set dummy2 up ++ ++ # default entry is metric 256 ++ run_cmd "$IP addr add dev dummy1 172.16.104.1/24" ++ run_cmd "$IP addr add dev dummy2 172.16.104.2/24" ++ set +e ++ ++ check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2" ++ log_test $? 0 "Default metric" ++ ++ set -e ++ run_cmd "$IP addr flush dev dummy1" ++ run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257" ++ set +e ++ ++ check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257" ++ log_test $? 0 "User specified metric on first device" ++ ++ set -e ++ run_cmd "$IP addr flush dev dummy2" ++ run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258" ++ set +e ++ ++ check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258" ++ log_test $? 0 "User specified metric on second device" ++ ++ run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258" ++ rc=$? ++ fi ++ log_test $rc 0 "Delete of address on first device" ++ ++ run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259" ++ rc=$? ++ fi ++ log_test $rc 0 "Modify metric of address" ++ ++ # verify prefix route removed on down ++ run_cmd "$IP li set dev dummy2 down" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ out=$($IP ro ls match 172.16.104.0/24) ++ check_expected "${out}" "" ++ rc=$? ++ fi ++ log_test $rc 0 "Prefix route removed on link down" ++ ++ # verify prefix route re-inserted with assigned metric ++ run_cmd "$IP li set dev dummy2 up" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259" ++ rc=$? ++ fi ++ log_test $rc 0 "Prefix route with metric on link up" ++ ++ # explicitly check for metric changes on edge scenarios ++ run_cmd "$IP addr flush dev dummy2" ++ run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259" ++ run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260" ++ rc=$? ++ fi ++ log_test $rc 0 "Modify metric of .0/24 address" ++ ++ run_cmd "$IP addr flush dev dummy2" ++ run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260" ++ rc=$? ++ fi ++ log_test $rc 0 "Set metric of address with peer route" ++ ++ run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261" ++ rc=$? ++ fi ++ log_test $rc 0 "Modify metric and peer address for peer route" ++ ++ $IP li del dummy1 ++ $IP li del dummy2 ++ cleanup ++} ++ ++ipv4_route_metrics_test() ++{ ++ local rc ++ ++ echo ++ echo "IPv4 route add / append tests" ++ ++ route_setup ++ ++ run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400" ++ rc=$? ++ fi ++ log_test $rc 0 "Single path route with mtu metric" ++ ++ ++ run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2" ++ rc=$? ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1" ++ rc=$? ++ fi ++ log_test $rc 0 "Multipath route with mtu metric" ++ ++ $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300 ++ run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1" ++ log_test $? 0 "Using route with mtu metric" ++ ++ run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo" ++ log_test $? 2 "Invalid metric (fails metric_convert)" ++ ++ route_cleanup ++} ++ ++ipv4_route_v6_gw_test() ++{ ++ local rc ++ ++ echo ++ echo "IPv4 route with IPv6 gateway tests" ++ ++ route_setup ++ sleep 2 ++ ++ # ++ # single path route ++ # ++ run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2" ++ rc=$? ++ log_test $rc 0 "Single path route with IPv6 gateway" ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1" ++ fi ++ ++ run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1" ++ log_test $rc 0 "Single path route with IPv6 gateway - ping" ++ ++ run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2" ++ rc=$? ++ log_test $rc 0 "Single path route delete" ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.112.0/24" ++ fi ++ ++ # ++ # multipath - v6 then v4 ++ # ++ run_cmd "$IP ro add 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3" ++ rc=$? ++ log_test $rc 0 "Multipath route add - v6 nexthop then v4" ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1" ++ fi ++ ++ run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1" ++ log_test $? 2 " Multipath route delete - nexthops in wrong order" ++ ++ run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3" ++ log_test $? 0 " Multipath route delete exact match" ++ ++ # ++ # multipath - v4 then v6 ++ # ++ run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1" ++ rc=$? ++ log_test $rc 0 "Multipath route add - v4 nexthop then v6" ++ if [ $rc -eq 0 ]; then ++ check_route "172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 weight 1 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1" ++ fi ++ ++ run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3" ++ log_test $? 2 " Multipath route delete - nexthops in wrong order" ++ ++ run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1" ++ log_test $? 0 " Multipath route delete exact match" ++ ++ route_cleanup ++} ++ ++################################################################################ ++# usage ++ ++usage() ++{ ++ cat < Test(s) to run (default: all) ++ (options: $TESTS) ++ -p Pause on fail ++ -P Pause after each test before cleanup ++ -v verbose mode (show commands and output) ++EOF ++} ++ ++################################################################################ ++# main ++ ++while getopts :t:pPhv o ++do ++ case $o in ++ t) TESTS=$OPTARG;; ++ p) PAUSE_ON_FAIL=yes;; ++ P) PAUSE=yes;; ++ v) VERBOSE=$(($VERBOSE + 1));; ++ h) usage; exit 0;; ++ *) usage; exit 1;; ++ esac ++done ++ ++PEER_CMD="ip netns exec ${PEER_NS}" ++ ++# make sure we don't pause twice ++[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no ++ ++if [ "$(id -u)" -ne 0 ];then ++ echo "SKIP: Need root privileges" ++ exit $ksft_skip; ++fi ++ ++if [ ! -x "$(command -v ip)" ]; then ++ echo "SKIP: Could not run test without ip tool" ++ exit $ksft_skip ++fi ++ ++ip route help 2>&1 | grep -q fibmatch ++if [ $? -ne 0 ]; then ++ echo "SKIP: iproute2 too old, missing fibmatch" ++ exit $ksft_skip ++fi ++ ++# start clean ++cleanup &> /dev/null ++ ++for t in $TESTS ++do ++ case $t in ++ fib_unreg_test|unregister) fib_unreg_test;; ++ fib_down_test|down) fib_down_test;; ++ fib_carrier_test|carrier) fib_carrier_test;; ++ fib_rp_filter_test|rp_filter) fib_rp_filter_test;; ++ fib_nexthop_test|nexthop) fib_nexthop_test;; ++ fib_suppress_test|suppress) fib_suppress_test;; ++ ipv6_route_test|ipv6_rt) ipv6_route_test;; ++ ipv4_route_test|ipv4_rt) ipv4_route_test;; ++ ipv6_addr_metric) ipv6_addr_metric_test;; ++ ipv4_addr_metric) ipv4_addr_metric_test;; ++ ipv6_route_metrics) ipv6_route_metrics_test;; ++ ipv4_route_metrics) ipv4_route_metrics_test;; ++ ipv4_route_v6_gw) ipv4_route_v6_gw_test;; ++ ++ help) echo "Test names: $TESTS"; exit 0;; ++ esac ++done ++ ++if [ "$TESTS" != "none" ]; then ++ printf "\nTests passed: %3d\n" ${nsuccess} ++ printf "Tests failed: %3d\n" ${nfail} ++fi ++ ++exit $ret +diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh +index f190ad58e00d4..4d8845a68cf28 100644 +--- a/tools/testing/selftests/net/forwarding/lib.sh ++++ b/tools/testing/selftests/net/forwarding/lib.sh +@@ -562,14 +562,14 @@ sysctl_set() + local value=$1; shift + + SYSCTL_ORIG[$key]=$(sysctl -n $key) +- sysctl -qw $key=$value ++ sysctl -qw $key="$value" + } + + sysctl_restore() + { + local key=$1; shift + +- sysctl -qw $key=${SYSCTL_ORIG["$key"]} ++ sysctl -qw $key="${SYSCTL_ORIG[$key]}" + } + + forwarding_enable() +diff --git a/tools/testing/selftests/net/udpgso_bench.sh b/tools/testing/selftests/net/udpgso_bench.sh +index dc932fd653634..640bc43452faa 100755 +--- a/tools/testing/selftests/net/udpgso_bench.sh ++++ b/tools/testing/selftests/net/udpgso_bench.sh +@@ -7,6 +7,7 @@ readonly GREEN='\033[0;92m' + readonly YELLOW='\033[0;33m' + readonly RED='\033[0;31m' + readonly NC='\033[0m' # No Color ++readonly TESTPORT=8000 + + readonly KSFT_PASS=0 + readonly KSFT_FAIL=1 +@@ -56,11 +57,26 @@ trap wake_children EXIT + + run_one() { + local -r args=$@ ++ local nr_socks=0 ++ local i=0 ++ local -r timeout=10 ++ ++ ./udpgso_bench_rx -p "$TESTPORT" & ++ ./udpgso_bench_rx -p "$TESTPORT" -t & ++ ++ # Wait for the above test program to get ready to receive connections. ++ while [ "$i" -lt "$timeout" ]; do ++ nr_socks="$(ss -lnHi | grep -c "\*:${TESTPORT}")" ++ [ "$nr_socks" -eq 2 ] && break ++ i=$((i + 1)) ++ sleep 1 ++ done ++ if [ "$nr_socks" -ne 2 ]; then ++ echo "timed out while waiting for udpgso_bench_rx" ++ exit 1 ++ fi + +- ./udpgso_bench_rx & +- ./udpgso_bench_rx -t & +- +- ./udpgso_bench_tx ${args} ++ ./udpgso_bench_tx -p "$TESTPORT" ${args} + } + + run_in_netns() { +diff --git a/tools/testing/selftests/net/udpgso_bench_rx.c b/tools/testing/selftests/net/udpgso_bench_rx.c +index 6a193425c367f..4058c7451e70d 100644 +--- a/tools/testing/selftests/net/udpgso_bench_rx.c ++++ b/tools/testing/selftests/net/udpgso_bench_rx.c +@@ -250,7 +250,7 @@ static int recv_msg(int fd, char *buf, int len, int *gso_size) + static void do_flush_udp(int fd) + { + static char rbuf[ETH_MAX_MTU]; +- int ret, len, gso_size, budget = 256; ++ int ret, len, gso_size = 0, budget = 256; + + len = cfg_read_all ? sizeof(rbuf) : 0; + while (budget--) { +@@ -336,6 +336,8 @@ static void parse_opts(int argc, char **argv) + cfg_verify = true; + cfg_read_all = true; + break; ++ default: ++ exit(1); + } + } + +diff --git a/tools/testing/selftests/net/udpgso_bench_tx.c b/tools/testing/selftests/net/udpgso_bench_tx.c +index f1fdaa2702913..477392715a9ad 100644 +--- a/tools/testing/selftests/net/udpgso_bench_tx.c ++++ b/tools/testing/selftests/net/udpgso_bench_tx.c +@@ -62,6 +62,7 @@ static int cfg_payload_len = (1472 * 42); + static int cfg_port = 8000; + static int cfg_runtime_ms = -1; + static bool cfg_poll; ++static int cfg_poll_loop_timeout_ms = 2000; + static bool cfg_segment; + static bool cfg_sendmmsg; + static bool cfg_tcp; +@@ -235,16 +236,17 @@ static void flush_errqueue_recv(int fd) + } + } + +-static void flush_errqueue(int fd, const bool do_poll) ++static void flush_errqueue(int fd, const bool do_poll, ++ unsigned long poll_timeout, const bool poll_err) + { + if (do_poll) { + struct pollfd fds = {0}; + int ret; + + fds.fd = fd; +- ret = poll(&fds, 1, 500); ++ ret = poll(&fds, 1, poll_timeout); + if (ret == 0) { +- if (cfg_verbose) ++ if ((cfg_verbose) && (poll_err)) + fprintf(stderr, "poll timeout\n"); + } else if (ret < 0) { + error(1, errno, "poll"); +@@ -254,6 +256,20 @@ static void flush_errqueue(int fd, const bool do_poll) + flush_errqueue_recv(fd); + } + ++static void flush_errqueue_retry(int fd, unsigned long num_sends) ++{ ++ unsigned long tnow, tstop; ++ bool first_try = true; ++ ++ tnow = gettimeofday_ms(); ++ tstop = tnow + cfg_poll_loop_timeout_ms; ++ do { ++ flush_errqueue(fd, true, tstop - tnow, first_try); ++ first_try = false; ++ tnow = gettimeofday_ms(); ++ } while ((stat_zcopies != num_sends) && (tnow < tstop)); ++} ++ + static int send_tcp(int fd, char *data) + { + int ret, done = 0, count = 0; +@@ -413,7 +429,8 @@ static int send_udp_segment(int fd, char *data) + + static void usage(const char *filepath) + { +- error(1, 0, "Usage: %s [-46acmHPtTuvz] [-C cpu] [-D dst ip] [-l secs] [-M messagenr] [-p port] [-s sendsize] [-S gsosize]", ++ error(1, 0, "Usage: %s [-46acmHPtTuvz] [-C cpu] [-D dst ip] [-l secs] " ++ "[-L secs] [-M messagenr] [-p port] [-s sendsize] [-S gsosize]", + filepath); + } + +@@ -423,7 +440,7 @@ static void parse_opts(int argc, char **argv) + int max_len, hdrlen; + int c; + +- while ((c = getopt(argc, argv, "46acC:D:Hl:mM:p:s:PS:tTuvz")) != -1) { ++ while ((c = getopt(argc, argv, "46acC:D:Hl:L:mM:p:s:PS:tTuvz")) != -1) { + switch (c) { + case '4': + if (cfg_family != PF_UNSPEC) +@@ -452,6 +469,9 @@ static void parse_opts(int argc, char **argv) + case 'l': + cfg_runtime_ms = strtoul(optarg, NULL, 10) * 1000; + break; ++ case 'L': ++ cfg_poll_loop_timeout_ms = strtoul(optarg, NULL, 10) * 1000; ++ break; + case 'm': + cfg_sendmmsg = true; + break; +@@ -490,6 +510,8 @@ static void parse_opts(int argc, char **argv) + case 'z': + cfg_zerocopy = true; + break; ++ default: ++ exit(1); + } + } + +@@ -677,7 +699,7 @@ int main(int argc, char **argv) + num_sends += send_udp(fd, buf[i]); + num_msgs++; + if ((cfg_zerocopy && ((num_msgs & 0xF) == 0)) || cfg_tx_tstamp) +- flush_errqueue(fd, cfg_poll); ++ flush_errqueue(fd, cfg_poll, 500, true); + + if (cfg_msg_nr && num_msgs >= cfg_msg_nr) + break; +@@ -696,7 +718,7 @@ int main(int argc, char **argv) + } while (!interrupted && (cfg_runtime_ms == -1 || tnow < tstop)); + + if (cfg_zerocopy || cfg_tx_tstamp) +- flush_errqueue(fd, true); ++ flush_errqueue_retry(fd, num_sends); + + if (close(fd)) + error(1, errno, "close"); +diff --git a/tools/virtio/linux/bug.h b/tools/virtio/linux/bug.h +index b14c2c3b6b857..74aef964f5099 100644 +--- a/tools/virtio/linux/bug.h ++++ b/tools/virtio/linux/bug.h +@@ -1,11 +1,9 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-#ifndef BUG_H +-#define BUG_H ++#ifndef _LINUX_BUG_H ++#define _LINUX_BUG_H + + #define BUG_ON(__BUG_ON_cond) assert(!(__BUG_ON_cond)) + +-#define BUILD_BUG_ON(x) +- + #define BUG() abort() + +-#endif /* BUG_H */ ++#endif /* _LINUX_BUG_H */ +diff --git a/tools/virtio/linux/build_bug.h b/tools/virtio/linux/build_bug.h +new file mode 100644 +index 0000000000000..cdbb75e28a604 +--- /dev/null ++++ b/tools/virtio/linux/build_bug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _LINUX_BUILD_BUG_H ++#define _LINUX_BUILD_BUG_H ++ ++#define BUILD_BUG_ON(x) ++ ++#endif /* _LINUX_BUILD_BUG_H */ +diff --git a/tools/virtio/linux/cpumask.h b/tools/virtio/linux/cpumask.h +new file mode 100644 +index 0000000000000..307da69d6b26c +--- /dev/null ++++ b/tools/virtio/linux/cpumask.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _LINUX_CPUMASK_H ++#define _LINUX_CPUMASK_H ++ ++#include ++ ++#endif /* _LINUX_CPUMASK_H */ +diff --git a/tools/virtio/linux/gfp.h b/tools/virtio/linux/gfp.h +new file mode 100644 +index 0000000000000..43d146f236f14 +--- /dev/null ++++ b/tools/virtio/linux/gfp.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __LINUX_GFP_H ++#define __LINUX_GFP_H ++ ++#include ++ ++#endif +diff --git a/tools/virtio/linux/kernel.h b/tools/virtio/linux/kernel.h +index 6683b4a70b059..3325cdf229410 100644 +--- a/tools/virtio/linux/kernel.h ++++ b/tools/virtio/linux/kernel.h +@@ -10,6 +10,7 @@ + #include + + #include ++#include + #include + #include + #include +diff --git a/tools/virtio/linux/kmsan.h b/tools/virtio/linux/kmsan.h +new file mode 100644 +index 0000000000000..272b5aa285d5a +--- /dev/null ++++ b/tools/virtio/linux/kmsan.h +@@ -0,0 +1,12 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _LINUX_KMSAN_H ++#define _LINUX_KMSAN_H ++ ++#include ++ ++inline void kmsan_handle_dma(struct page *page, size_t offset, size_t size, ++ enum dma_data_direction dir) ++{ ++} ++ ++#endif /* _LINUX_KMSAN_H */ +diff --git a/tools/virtio/linux/scatterlist.h b/tools/virtio/linux/scatterlist.h +index 369ee308b6686..74d9e1825748e 100644 +--- a/tools/virtio/linux/scatterlist.h ++++ b/tools/virtio/linux/scatterlist.h +@@ -2,6 +2,7 @@ + #ifndef SCATTERLIST_H + #define SCATTERLIST_H + #include ++#include + + struct scatterlist { + unsigned long page_link; +diff --git a/tools/virtio/linux/topology.h b/tools/virtio/linux/topology.h +new file mode 100644 +index 0000000000000..910794afb993a +--- /dev/null ++++ b/tools/virtio/linux/topology.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _LINUX_TOPOLOGY_H ++#define _LINUX_TOPOLOGY_H ++ ++#include ++ ++#endif /* _LINUX_TOPOLOGY_H */